Using Rx to simplify an asynchronous Silverlight web service request - silverlight

I have written a simplified Silverlight client library for my WCF web service using Rx, however I notice sometimes I'm missing completed events.
public IObservable<XElement> GetReport(string reportName)
{
return from client in Observable.Return(new WebServiceClient())
from request in Observable.ToAsync<string>(client.GetReportDataAsync)(reportName)
from result in Observable.FromEvent<GetReportDataCompletedEventArgs>(client, "GetReportDataCompleted").Take(1)
from close in this.CloseClient(client)
select result.EventArgs.Result;
}
I believe the issue is caused by the fact that the web service is called and returns prior to subscribing to the completed event. I can't figure out how to get Rx to subscribe to the event prior to the Async call. I tried StartWith but that requires that the input and output types be the same, any ideas?

Seems like the best answer is to use Observable.CreateWithDisposable()
e.g.
public IObservable<XElement> GetReport(string reportName)
{
return from client in Observable.Return(new WebServiceClient())
from completed in Observable.CreateWithDisposable<GetReportDataCompletedEventArgs>(observer =>
{
var subscription = Observable.FromEvent<GetReportDataCompletedEventArgs>(client, "GetReportDataCompleted")
.Take(1)
.Select(e => e.EventArgs)
.Subscribe(observer);
client.GetReportDataAsync(reportName);
return subscription;
})
from close in this.CloseClient(client)
select completed.Result;
}
To make this easier to work with I refactored the CreateWithDisposable into a common function that can be used with all my web service calls, including automatically determining the event name from the event args type:
private IObservable<T> CallService<T>(ICommunicationObject serviceClient, Action start) where T : AsyncCompletedEventArgs
{
if (typeof(T) == typeof(AsyncCompletedEventArgs))
{
throw new InvalidOperationException("Event arguments type cannot be used to determine event name, use event name overload instead.");
}
string completedEventName = typeof(T).Name.TrimEnd("EventArgs");
return CallService<T>(serviceClient, start, completedEventName);
}
private IObservable<T> CallService<T>(ICommunicationObject serviceClient, Action start, string completedEventName) where T : AsyncCompletedEventArgs
{
return Observable.CreateWithDisposable<T>(observer =>
{
var subscription = Observable.FromEvent<T>(serviceClient, completedEventName).Take(1).Select(e => e.EventArgs).Subscribe(observer);
start();
return subscription;
});
}
// Example usage:
public IObservable<XElement> GetReport(string reportName)
{
return from client in Observable.Return(new WebServiceClient())
from completed in this.CallService<GetReportDataCompletedEventArgs>(client, () => client.GetReportDataAsync(reportName))
from close in this.CloseClient(client)
select completed.Result;
}
/// <summary>
/// Asynchronously closes the web service client
/// </summary>
/// <param name="client">The web service client to be closed.</param>
/// <returns>Returns a cold observable sequence of a single success Unit.</returns>
private IObservable<AsyncCompletedEventArgs> CloseClient(WebServiceClient client)
{
return this.CallService<AsyncCompletedEventArgs>(client, client.CloseAsync, "CloseCompleted");
}
Hope this helps someone else!

I need to use general WebClient.DownloadStringAsync so here my version.
First, wrap the event:
public static IObservable<IEvent<DownloadStringCompletedEventArgs>>
GetDownloadStringObservableEvent(this WebClient wc)
{
return Observable.FromEvent<DownloadStringCompletedEventArgs>(
wc, "DownloadStringCompleted");
}
Then create the extension method:
public static IObservable<string> GetDownloadString(this WebClient wc, Uri uri)
{
return Observable.CreateWithDisposable<string>(
observer => {
// Several downloads may be going on simultaneously. The token allows
// us to establish that we're retrieving the right one.
Guid token = Guid.NewGuid();
var stringDownloaded = wc.GetDownloadStringObservableEvent()
.Where(evt => ((Guid)evt.EventArgs.UserState) == token)
.Take(1); //implicitly unhooks handler after event is received
bool errorOccurred = false;
IDisposable unsubscribe =
stringDownloaded.Subscribe(
// OnNext action
ev => {
// Propagate the exception if one is reported.
if (ev.EventArgs.Error != null) {
errorOccurred = true;
observer.OnError(ev.EventArgs.Error);
} else if (!ev.EventArgs.Cancelled) {
observer.OnNext(ev.EventArgs.Result);
}
},
// OnError action (propagate exception)
ex => observer.OnError(ex),
// OnCompleted action
() => {
if (!errorOccurred) {
observer.OnCompleted();
}
});
try {
wc.DownloadStringAsync(uri, token);
} catch (Exception ex) {
observer.OnError(ex);
}
return unsubscribe;
}
);
}
Usage is simple:
wc.GetDownloadString(new Uri("http://myservice"))
.Subscribe(resultCallback , errorCallback);

Related

Cannot get an IdentityServer4 custom cookie handler working

I'm unable to get a custom cookie authentication handler working with IdentityServer4. I'm using ASP.NET Core Identity and have followed the official guide: https://identityserver4.readthedocs.io/en/release/topics/signin.html
I need to override the CookieAuthenticationEvents.ValidatePrincipal and CookieAuthenticationEvents.SignedIn event handlers.
I've written a class that inherits CookieAuthenticationEvents and overrides the two event handlers.
I'm assigning it to a custom cookie handler via:
var auth = services.AddAuthentication("MyCookies");
auth.AddCookie("MyCookies", options =>
{
options.Events = new RealtimeStatusCookieAuthEvents(Configuration);
});
Here's my code:
https://gist.github.com/Amethi/f3411038a9447d274c0b721698fc5e63
The event handlers don't fire, i.e. I'm expecting them to fire for each request (due to ValidatePrincipal) and when I come back to the site after closing the browser and sign-in using cookie authentication (SignedIn).
Anyone know what I'm doing wrong?
Update:
Even simplifying it as follows doesn't help. The event handlers don't fire.
var auth = services.AddAuthentication("CustomCookies").AddCookie("CustomCookies", options =>
{
options.Events = new CookieAuthenticationEvents
{
OnSignedIn = context =>
{
Console.WriteLine("{0} - {1}: {2}", DateTime.Now,
"OnSignedIn", context.Principal.Identity.Name);
return Task.CompletedTask;
},
OnValidatePrincipal = context =>
{
Console.WriteLine("{0} - {1}: {2}", DateTime.Now,
"OnValidatePrincipal", context.Principal.Identity.Name);
return Task.CompletedTask;
},
};
});
I managed to make my custom cookie authentication handler work by using the ConfigureApplicationCookie extension.
builder.Services.ConfigureApplicationCookie(config =>
{
config.Cookie.Name = "IdentityServer.Cookie";
config.EventsType = typeof(CustomCookieAuthenticationHandler);
config.LoginPath = "/Account/Login";
});
And register the CustomCookieAuthenticationHandler handler
builder.Services.AddScoped<CustomCookieAuthenticationHandler>();
This is the handler implementation:
public class CustomCookieAuthenticationHandler: CookieAuthenticationEvents
{
private readonly IUserRepository _userRepository;
public CustomCookieAuthenticationEvents(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public override Task ValidatePrincipal(CookieValidatePrincipalContext context)
{
// Your cookie authentication logic.
}
}
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-6.0

Angular 2 - undefinded when sharing variable with API data between component

Basically what i try to do is to hit my API once and save the result inside global variable in my Service, and then share and modify this value in my parent and child component with two helpers functions.
repairs.service.ts
public myItems:any[];
public GetRepairs = ():Observable<any> => {
this.headers = new Headers();
this.headers.set('Authorization', 'Bearer' + ' ' + JSON.parse(window.localStorage.getItem('token')));
return this._http.get(this.actionUrl +'repairs'{headers:this.headers})
.map((res) => {return res.json();
}).map((item) => {
let result:Array<any> = [];
if (item.items) {
item.items.forEach((item) => {
result.push(item);
});
}
this.myItems = result;
return this.myItems;
});
};
public GetItems() {
return this.myItems;
};
public UpdateItems(data:any[]) {
this.myItems = data;
};
And then in my main component i do
repairs.component.ts
export class RepairsComponent implements OnInit {
public myItems:any[];
constructor(private _userService:UserService,
private _RepairsService:RepairsService,
public _GlobalService:GlobalService) {
}
ngOnInit() {
this._userService.userAuthenticate();
this.getAllItems();
}
private getAllItems():void {
this._RepairsService
.GetRepairs()
.subscribe((data) => {
this._RepairsService.UpdateItems(data);
},
error => console.log(error),
() => {
this.myItems = this._RepairsService.GetItems();
});
}
}
This work just fine but when i try to invoke GetItems() in child component i get undefinded. I try to do it inside constructor and ngOnInit with the same result.
child.component.ts
export class ChildComponent {
private items:any[] = [];
constructor(private _RepairsService:RepairsService,
private _Configuration:Configuration) {
this.items = this._RepairsService.GetItems();
// undefinded
}
ngOnInit() {
this.items = this._RepairsService.GetItems();
// undefinded
}
}
From what i can see in the limited amount of code you shared, it would seem you are trying to get the items before the http get call finishes and saves the data. I think a better design pattern would be to make the GetItems() function also an observable or promise, and check if the data is there, if not call the http get call, and once that completes send the data back to the different components that need it.
As #MSwehli mentioned with async code execution you can't rely on the order of code lines. In this code:
ngOnInit() {
this.items = this._RepairsService.GetItems();
// undefinded
}
the async code in GetItems(); is scheduled for later execution into the event queue and then continued with the sync code. The scheduled code will be executed eventually but it's not determined when. It depends on the response of the server in this example.
If you return a Promise you can use .then(...) the chain the execution so that your code is only executed when the async execution is completed.
There are two errors/inconsistencies in your code:
userAuthenticate() call followed with getAllItems() call. These calls are async, user is not yet authenticated by the time getAllItems() is called, getAllItems will fail.
Solution here is to chain calls using rxjs flatMap:
//assuming userAuthenticate returns Observable
userService.userAuthenticate().flatMap(()=>{
return repairsService.GetRepairs();
}).subscribe(..process repairs..);
getAllItems() is called nearly at the same time as GetItems(). In most cases it fails also, because previous http request is not completed when GetItems() is called.
In my opinion early initialization is not necessary here, use service directly:
//ChildComponent
ngOnInit() {
this._RepairsService.GetRepairs().subscribe(..do anything with list of repairs i.e. assign to bindable property..);
}
You could add console.log statements in each part of the code to see the order of events in your app.

How do I make sure the UI is updated during long running processes in a WPF application?

In a WPF app that follows the MVVM pattern, I've run across a common issue where a user clicks on a button which fires an event in the ViewModel. This event should enable a "Please Wait" spinner animation, do some processing which may take a few seconds, then hide the spinner. I'm not really sure of a good pattern I can use to make sure the spinner animation always appears.
As an example, I have a login process which does the following:
Displays spinner (set property on VM to true, spinner is bound to it)
Attempt to connect to server (can take a few seconds depending on connection)
On a failure, display a failure message
On success, save off some info about the user so it's available to the rest of the app.
What I'm finding is that the spinner never actually appears. I have tried wrapping the longer-running process in a Task.Run call, but that hasn't seemed to help.
Here's an approximation of what the code looks like:
// When true, spinner should be visible
protected bool _authenticatingIsVisible = false;
public bool AuthenticatingIsVisible
{
get { return _authenticatingIsVisible; }
set
{
_authenticatingIsVisible = value;
NotifyOfPropertyChange(() => AuthenticatingIsVisible);
}
}
public void Login()
{
try
{
AuthenticationIsVisible = true;
AuthCode result = AuthCode.NoAuthenticated;
Task.Run(() => { result = _client.Authenticate() }).Wait();
AuthenticationIsVisible = false;
if (result == AuthCode.Authenticated)
{
// Bit of misc. code to set up the environment
// Another check to see if something has failed
// If it has, displays a dialog.
// ex.
var error = new Error("Something Failed", "Details Here", Answer.Ok);
var vm = new DialogViewModel() { Dialog = error };
_win.ShowDialog(vm);
return;
}
else
{
DisplayAuthMessage(result);
}
}
finally
{
AuthenticationIsVisible = false;
}
}
The proper way would be not to block the UI thread (which is what you are doing right now with .Wait()), and use AsyncAwait instead.
private Task<AuthCode> Authenticate()
{
return Task.Run<AuthCode>(()=>
{
return _client.Authenticate();
});
}
public async void Login()
{
AuthenticationIsVisible = true;
AuthCode result = await Authenticate();
AuthenticationIsVisible = false;
}

SignalR + WebAPI + AngularJS + HubContext, Client's still don't receive messages

For the last few days I have been trying to implement SignalR into my AngularJS/WebAPI application.
I have been able to successfully send/receive messages from client to client, however when I push messages purely from the Server, none of the clients receive any messages.
I have seen many people having the same problem, the answer always seems to be using GlobalHost.ConnectionManager.GetHubContext which I have been implementing, without error, however the clients still don't receive any of the messages.
I thought that perhaps it's because WebAPI calls are asynchronous and and therefore takes place on a different thread, but I can't be sure. Please could someone have a look and tell me what I'm doing wrong.
This is my Hub Class:
public class ChatHub : Hub
{
public void Send(string name, string message)
{
// Call the broadcastMessage
Clients.All.broadcastMessage(name, message);
}
public void RunMe()
{
System.Diagnostics.Debug.WriteLine("Client Started");
}
public static void Notify(string name, string message)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
hubContext.Clients.All.broadcastMessage(name, message);
}
}
This is the Angular Controller in Javascript:
$scope.chat = $.connection.chatHub;
$scope.chat.client.broadcastMessage = function (name, message) {
$scope.$apply(function () {
var scope = angular.element($('#discussion')).scope();
scope.chatMessage = message;
alert(message);
});
};
$.connection.hub.start()
.done(function ()
{
console.log('Now connected, connection ID=' + $.connection.hub.id);
$scope.chat.server.runMe();
})
.fail(function(){ console.log('Could not Connect!'); });
$('#sendmessage').click(function () {
$scope.chat.server.send("SERVER", $('#inputMessage').val());
});
This is the Controller that is trying to notify the clients from the server
public class UserController : ApiController
{
#region METHODS
[ActionName("Create")]
[HttpPost]
public HttpResponseMessage Create(JObject parameters)
{
//DYNAMIC DATA
dynamic data = parameters;
//CHECK IF CALL FAILED
if (data == null)
return Request.CreateResponse(HttpStatusCode.InternalServerError, "Request is null");
//PERFORM REQUEST
using (var svc = new UserService())
{
//SET Parameters
String Username = data.Username;
String Password = data.Password;
//NOTIFY USERS
ChatHub.Notify("SERVER", "SERVER MESSAGE");
//CREATE Response
var response = svc.Create(Username, Password);
//RESPOND
return Request.CreateResponse(HttpStatusCode.OK, response);
}
}
}
So just to reiterate, when the "sendmessage" button is clicked on my UI, it sends a message to the server which is then received again by the clients, this works 100%,
However when I call the static Notify method from the Controller None of the clients receive any messages.
Calling the function does not return any errors.
Please could someone help me!
<!--Reference the SignalR library. -->
<script src="Scripts/jquery.signalR-2.2.0.min.js"></script>
Check your jQuery.signalR version.
If you are using dependency injection, the example at ASP.NET is wrong, you have to set your GlobalHost.DependendcyResolver in the the Global.asax file. not in the startup class.

Surviving TPL, Delegates, Threads, and Invokes

I'm facing a serious problem of deadlock in a multithreaded desktop/windows application. I fear I'm not using the correct approach to delegates in a very async environment. Also, even though I "sink" my events into the calling UI thread, if possible, I still have to Invoke on the UI thread to see some action. Follows, is the details.
The application is basically a client for users of an online file storage service. That service exposes functionality through REST calls. I first created a managed code wrapper DLL for such calls that allows for a .NET consumer to create a static instance of this DLL and call the functions. I'll take the file upload operation as an example.
Now, in the wrapper, here is the public interface for a file upload:
public Int32 UploadFile(FileSystemObject FolderToUploadTo, FileInfo LocalFileAndPath, OperationProgressReportEventHandler onOperationProgressReport, FileSystemObjectUploadCompletedEventHandler onOperationCompleted) {
Int32 ReplyNumber = 0;
try {
var TheOperation = new UploadFileObjectOperation(FolderToUploadTo, LocalFileAndPath, _User.APIKey) {
onProgressReport = onOperationProgressReport,
onUploadCompleted = onOperationCompleted
};
//Add it to the pool of operations
OperationPool.Add(TheOperation);
//Start the operation through the factory
OperationFactory.StartNew(() => {
TheOperation.Start();
});
//Chain the *actual* TPL Task to flush after usage
TheOperation.InnerTask.ContinueWith(t => {
t.Dispose(); //Dispose the inner task
OperationPool.Remove(TheOperation); //Remove the operation from the pool
TheOperation = null; //Nullify the Operation
});
ReplyNumber = TheOperation.TaskId;
}
catch {
ReplyNumber = 0;
}
return ReplyNumber;
}
As you can see, the actual UI application, that will refer this DLL, will be sending delegates for progress and completed to the operation(s). Now, the body of the operation itself:
public class UploadFileObjectOperation : BaseOperation, IDisposable {
//Store
public FileSystemObjectUploadCompletedEventHandler onUploadCompleted;
//Constructors
//Disposing stuff
protected override void PerformWork() {
try {
//Init the WebClient
UploadClient.UploadProgressChanged += (UploadProgressChanged_s, UploadProgressChanged_e) => {
//This is my event in base class being raised
ReportProgress(UploadProgressChanged_e.ProgressPercentage, UploadProgressChanged_e);
};
UploadClient.UploadFileCompleted += (UploadFileCompleted_s, UploadFileCompleted_e) => {
if (UploadFileCompleted_e.Error != null) {
throw new ApplicationException("Upload failed. " + UploadFileCompleted_e.Error.Message);
}
JObject JSONLiveObject = JObject.Parse(Encoding.UTF8.GetString(UploadFileCompleted_e.Result));
if (String.Compare((String)JSONLiveObject["status"], Constants._CONST_RESTRESPONSE_STATUS_VALUE_FAIL, false) == 0) {
throw new ApplicationException("Upload response failed. " + (String)JSONLiveObject["result"]["message"]);
}
//Eureka! Success! We have an upload!
//This is my event being raised
UploadTaskCompleted(new UploadFileObjectOperationEventArg {
Error = null,
ResultSource = OperationResultSource.Fresh,
Status = OperationExitStatus.Success,
TaskId = TaskId,
UploadedFileSystemObject = _UploadedFile
});
};
//Start the async upload
UploadClient.UploadFileAsync(AddressOfRESTURI, UploadingMethod, _FileToUpload.FullName);
}
catch (OperationCanceledException exp_Canceled) {
UploadTaskCompleted(new UploadFileObjectOperationEventArg {
Error = exp_Canceled,
ResultSource = OperationResultSource.Fresh,
Status = OperationExitStatus.Canceled,
TaskId = TaskId,
UploadedFileSystemObject = _UploadedFile
});
// To ensure that the calling code knows the task was canceled
//throw;
}
catch (Exception exp) {
UploadTaskCompleted(new UploadFileObjectOperationEventArg {
Error = exp,
ResultSource = OperationResultSource.Fresh,
Status = OperationExitStatus.Error,
TaskId = TaskId,
UploadedFileSystemObject = _UploadedFile
});
// If the calling code also needs to know.
//throw;
}
}
protected void UploadTaskCompleted(UploadFileObjectOperationEventArg arg) {
if (onUploadCompleted == null)
return;
//Sinking into calling UI thread, if possible
if (onUploadCompleted.Target is Control) {
Control targetForm = onUploadCompleted.Target as Control;
targetForm.Invoke(onUploadCompleted, new object[] { arg });
}
else {
onUploadCompleted(arg);
}
Status = OperationRunningStatus.Completed;
}
}
The PerformWork() raises the two events: Progress reporting and completion. Note that while raising an event, I check if can get a route to the calling thread and push the event directly so to avoid invokes at UI.
Now, lets see how I'm using all of the above in a desktop client:
private void UploadFile(FileInfo DraggedFileInfo, FileSystemObject ParentDefination) {
SessionLifetimeStuff.APICore.UploadFile(ParentDefination, DraggedFileInfo,
(PercentageCompleted) => {
#region Progress
this.InvokeEx(f => {
UpdateTaskProgress(newTaskQueue.OID, PercentageCompleted.Progress, PercentageCompleted);
});
#endregion
}, (Result) => {
#region Completion
this.InvokeEx(f => {
switch (Result.Status) {
case OperationExitStatus.Success:
Console.WriteLine(String.Format("File: {0} uploaded to {1}", Result.UploadedFileSystemObject.DocumentFullname, Result.UploadedFileSystemObject.FolderId));
break;
case OperationExitStatus.Canceled:
DialogManager.ShowDialog(DialogTypeEnum.Warning, "Dropbox", "Upload canceled.", null, this);
break;
case OperationExitStatus.Error:
DialogManager.ShowDialog(DialogTypeEnum.Error, "Dropbox", "Upload failed.", Result.Error, this);
break;
}
});
#endregion
});
}
I'm using an extension method I found on Stackoverflow for adding the Invoking functionality:
public static class InvokeExtensions {
public static void InvokeEx<T>(this T #this, Action<T> action) where T : Control {
if (#this.InvokeRequired) {
#this.Invoke(action, new object[] { #this });
}
else {
if (!#this.IsHandleCreated)
return;
if (#this.IsDisposed)
throw new ObjectDisposedException("#this is disposed.");
action(#this);
}
}
public static IAsyncResult BeginInvokeEx<T>(this T #this, Action<T> action)
where T : Control {
return #this.BeginInvoke((Action)(() => #this.InvokeEx(action)));
}
public static void EndInvokeEx<T>(this T #this, IAsyncResult result)
where T : Control {
#this.EndInvoke(result);
}
}
In my code, i have commented out the invokes as I though i don't need then as the events being raised are coming in sinked. However, i realized that my UI was not doing anything at all. So, I added the InvokeEx({ code; }) and my UI started to shoe activity.
Now, why do I need to invoke?
If I attempt different operations from UI, eventually, my UI freezes although the application still behaves as normally functioning.
I found an old article at http://msdn.microsoft.com/en-us/library/ff649143.aspx#scag-ch06_topic4 that described the usage of delegates and I see that there is a IAsyncResult involved.
Could someone point me as to where I'm going wrong here?
Update:
Ok, with the invoking code commented on the UI, I get no activity at all. But upon using the this.InvokeEx or wrapping a work in this.BeginInvokeEx, I get UI updates but after a while, here are the two exceptions occurring (in this order):
Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.

Resources