Async await in mvvm silverlight 4 - wcf

In my silverlight mvvm application i am using wcf service to fill listbox which is taking time to load so i need to use async and await in that. how can i use it in the bellow code.
my code in view model:
private void GetLanguage()
{
ServiceAgent.GetLanguage((s, e) =>Language = e.Result);
}
my code in service agent
public void GetLanguage(EventHandler<languageCompletedEventArgs> callback)
{
_Proxy.languageCompleted += callback;
_Proxy.languageAsync();
}
Can anyone help me

You must use TaskCompletionSource to convert EAP (event asynchronous model) to TAP (task asynchronous model). First, add new method to your ServiceAgent (you can create this even as an extension method):
public Task<string> GetLanguageAsync(EventHandler<languageCompletedEventArgs> callback)
{
var tcs = new TaskCompletionSource<string>();
EventHandler<languageCompletedEventArgs> callback;
callback = (sender, e) =>
{
_Proxy.languageCompleted -= callback;
tcs.TrySetResult(e.Result);
};
_Proxy.languageCompleted += callback;
_Proxy.languageAsync();
return tcs.Task;
}
TCS will create a task which you can await then. By using the existing model, it will bridge the gap and make it consumable with async/await. You can now consume it in the view model:
private void GetLanguage()
{
Language = await ServiceAgent.GetLanguageAsync();
}

You can achieve using async and await in Silverlight 5 (or .NET 4) by using this library: AsyncTargetingPack. AsyncTargetingPack is on NuGet.
For a complete walkthrough, read this excellent article:
Using async and await in Silverlight 5 and .NET 4 in Visual Studio 11 with the async targeting pack

Related

Use cancellation token to cancel execution of multiple tasks executed using Task.WhenAll<tasks> method in asp.net core 3.1

I am working on an asp.net core application which has downloading files functionality. Using this function we can create multiple download tasks and execute them at once using Task.Whenall.
I am trying to implement cancel download functionality using which we can abort/cancel the complete download operation by clicking a cancel button on one of my razor pages (if I selected 100 files to download and clicked cancel after downloading 10 files, 90 remaining files should not be downloaded).
Currently it cannot be cancelled, once the download operation is started it continuously executes in background even if we close the download page unless all files fail/succeed to download. Exiting the application stops it.
Implementation is as follows.
DownloadsController class:
//variable declaration
CancellationTokenSource cts;
[HttpPost]
public async Task<IActionResult> Download_iles(DownloadFilesModel downloadFilesModel)
{
cts=new CancellationTokenSource();
var successFiles = await _downloadManager.DownloadAsyncpa(downloadFilesModel.param1, downloadFilesModel.param2, cts.Token);
}
ManageFileDownlods class:
public class ManageFileDownlods : BackgroundService, IManageFileDownlods
{
//Constructor
public ManageFileDownlods(IDownloadmaster downloadmaster)
{
_downloadmaster = downloadmaster;
}
public async Task<List<DownloadFile>>
DownloadAsync (funcparam1,funcparam2,CancellationToken cancellationToken=default)
{
// For each server in serverQueue these multiple tasks will execure
while (serverQueue.Count > 0)
{
//Multiple tasks created to downloadfiles
downloadTasksList.Add(ServerProcess(funcparam1, funcparam2, cancellationToken));
//Multiple tasks executed here to download files
try
{
await Task.WhenAll(downloadTasksList.ToArray());
}
catch()
{ }
}
}
private async Task<List<DownloadFile>> ServerProcess (funcparam1, funcparam2,
CancellationToken cancellationToken)
{
while (funcparam1.Count > 0)
{
//5 taks created in loop
for (int i = 0; i < 5; i++)
{
//Multiple tasks created to downloadfiles
fileDownlodTasks.Add(_downloadmaster.Download(param1, param2,
cancellationToken));
await Task.Delay(300);
}
try
{
//Multiple tasks executed here to download files
await Task.WhenAll(fileDownlodTasks.ToArray());
}
catch (TaskCanceledException ex)
{
Debug.WriteLine("execution stopped");
throw ex;
}
}
}
}
Downloadmaster Class:
public async Task<DownloadFile> Download (param1,param2,CancellationToken cancellationToken)
{
//actual function which initiated file download from server
var filecontents = DownloadFileFromServer (param1,param2, cancellationToken);
}
I've spent much time on internet, gone through a lot of different articles over cancellation of tasks, tried to implement multiple approaches given in these articles, but unable to cancel the operation.
Probably, you should add CancellationToken to the action parameters. ASP.NET MVC and ASP.NET Core map that parameter to HttpContext.RequestAborted token. More details here

Custom Result in Net 6 Minimal API

In ASP.NET Core 5 I had a custom Action Result as follows:
public class ErrorResult : ActionResult {
private readonly IList<Error> _errors;
public ErrorResult(IList<Error> errors) {
_errors = errors;
}
public override async Task ExecuteResultAsync(ActionContext context) {
// Code that creates Response
await result.ExecuteResultAsync(context);
}
}
Then on a Controller action I would have:
return new ErrorResult(errors);
How to do something similar in NET 6 Minimal APIs?
I have been looking at it and I think I should implement IResult.
But I am not sure if that is the solution or how to do it.
I have recently been playing around with minimal APIs and and working on global exception handling. Here is what I have come up with so far.
Create a class implementation of IResult
Create a constructor which will take an argument of the details you want going into your IResult response. APIErrorDetails is a custom implementation of mine similar to what you'd see in ProblemDetails in MVC. Method implementation is open to whatever your requirements are.
public class ExceptionAllResult : IResult
{
private readonly ApiErrorDetails _details;
public ExceptionAllResult(ApiErrorDetails details)
{
_details = details;
}
public async Task ExecuteAsync(HttpContext httpContext)
{
var jsonDetails = JsonSerializer.Serialize(_details);
httpContext.Response.ContentType = MediaTypeNames.Application.Json;
httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(jsonDetails);
httpContext.Response.StatusCode = _details.StatusCode;
await httpContext.Response.WriteAsync(jsonDetails);
}
}
Return result in your exception handling middleware in your Program.cs file.
app.UseExceptionHandler(
x =>
{
x.Run(
async context =>
{
// https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-6.0
var exceptionFeature = context.Features.Get<IExceptionHandlerPathFeature>();
// Whatever you want for null handling
if (exceptionFeature is null) throw new Exception();
// My result service for creating my API details from the HTTP context and exception. This returns the Result class seen in the code snippet above
var result = resultService.GetErrorResponse(exceptionFeature.Error, context);
await result.ExecuteAsync(context); // returns the custom result
});
}
);
If you still want to use MVC (Model-View-Controller), you still can use Custom ActionResult.
If you just want to use Minimal APIs to do the response, then you have to implement IResult, Task<IResult> or ValueTask<IResult>.
app.MapGet("/hello", () => Results.Ok(new { Message = "Hello World" }));
The following example uses the built-in result types to customize the response:
app.MapGet("/api/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound())
.Produces<Todo>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status404NotFound);
You can find more IResult implementation samples here: https://github.com/dotnet/aspnetcore/tree/main/src/Http/Http.Results/src
Link: Minimal APIs overview | Microsoft Docs

When calling a WCF RIA Service method using Invoke, does the return type affect when the Completed callback is executed?

I inherited a Silverlight 5 application. On the server side, it has a DomainContext (service) with a method marked as
[Invoke]
public void DoIt
{
do stuff for 10 seconds here
}
On the client side, it has a ViewModel method containing this:
var q = Context.DoIt(0);
var x=1; var y=2;
q.Completed += (a,b) => DoMore(x,y);
My 2 questions are
1) has DoIt already been activated by the time I attach q.Completed, and
2) does the return type (void) enter into the timing at all?
Now, I know there's another way to call DoIt, namely:
var q = Context.DoIt(0,myCallback);
This leads me to think the two ways of making the call are mutually exclusive.
Although DoIt() is executed on a remote computer, it is best to attach Completed event handler immediately. Otherwise, when the process completes, you might miss out on the callback.
You are correct. The two ways of calling DoIt are mutually exclusive.
If you have complicated logic, you may want to consider using the Bcl Async library. See this blog post.
Using async, your code will look like this:
// Note: you will need the OperationExtensions helper
public async void CallDoItAndDosomething()
{
this.BusyIndicator.IsBusy = true;
await context.DoIt(0).AsTask();
this.BusyIndicator.IsBusy = false;
}
public static class OperationExtensions
{
public static Task<T> AsTask<T>(this T operation)
where T : OperationBase
{
TaskCompletionSource<T> tcs =
new TaskCompletionSource<T>(operation.UserState);
operation.Completed += (sender, e) =>
{
if (operation.HasError && !operation.IsErrorHandled)
{
tcs.TrySetException(operation.Error);
operation.MarkErrorAsHandled();
}
else if (operation.IsCanceled)
{
tcs.TrySetCanceled();
}
else
{
tcs.TrySetResult(operation);
}
};
return tcs.Task;
}
}

Best practices for converting WCF calls to async WCF calls

I am running into issues when trying to convert all my normal WCF calls to async WCF calls. I'm finding I have a refactor a lot of code and not sure exactly how to do it. I have used the method that I found here but running into issues where I need things to happen in order.
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
foreach(Item i in itemList)
{
DoSomeWork(i);
if(i.SomeID == 0)
{
DoSomeMoreWork(i);
}
UpdateRecord(i) // this can't execute until the above code is complete
}
}
private void DoSomeWork(Item i)
{
// call async method
}
private void DoSomeMoreWork(i)
{
// call async method
}
private void UpdateRecord(item i)
{
// call async method
}
What is the best way to refactor code to work in an asyncronous way, or do I need to completely rethink my logic? Do I really have to insert counters and switches everywhere to make sure certain things are done before other things execute?
EDIT: The reason I'm doing this is in the next couple months, we are converting this WPF application to Silverlight, which requires async calls. So I'm trying to convert our regular WCF calls to async in preparation. I'm finding it requires a different way of thinking.
For what you're doing, I'd say the real place to handle things is to make a single call to the service per item, not 3.
Preferably, if the list of items is not huge, make a single call to the service with the whole list...
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
foreach(Item i in itemList)
{
DoAllTheWorkAndUpdate(i);
}
}
or...
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
foreach(Item i in itemList)
{
if(i.Id == 0)
{
DoLotsOfWorkAndUpdate(i);
}
else
{
DoSomeWorkAndUpdate(i);
}
}
}
or...
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
DoTheWorkOnTheWholeList(itemList);
}
In other words, it feels like some of your responsibilities may be misplaced - I generally prefer to make services where I can make a single call to them. Then, the asynchronous nature is irrelevant, because you're not performing a sequence of events.
Take a look at Juval Lowy's (author of Programming WCF Services) website for examples of how to achieve asynchronous programming in WCF. The downloads are free; you just have to provide your email address.
I am perhaps a bit puzzled as to why you need to use asynchronous WCF operations when you need things to be synchronous inside the loop.
If you are just using the async methods to help keep the UI from hanging, then you could just use a BackgroundWorker that supports progress updates to keep the UI up to date, and not use Async WCF calls.
You should also be able to call your various functions from the Completed events for the Async methods.
Just hook up event handlers to the completed events and then pass your Item object as the userState parameter when you start the async WCF call. This way you will have it as a parameter when each of the Completed events fires. That way you will only be doing the next step in your processing as the previous async call completes.
I don't know if this really is answering your question though.
Try using this
http://ayende.com/Blog/archive/2008/03/29/WCF-Async-without-proxies.aspx
the approach that definitely works.
If you're not using Silverlight, you can block your thread in one method until the other methods complete, using, say, a ManualResetEvent. But that won't work in Silverlight, since all WCF calls happen on the main UI thread, so if you block that thread, everything blocks. A better approach is to do something like this, using callbacks:
public delegate void OperationCallback();
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
foreach (Item i in itemList)
{
DoSomeWork(i, () =>
{
if (i.SomeID == 0)
{
DoSomeMoreWork(i, () =>
{
UpdateRecord(i);
});
}
else
{
UpdateRecord(i);
}
});
}
}
private void DoSomeWork(Item i, OperationCallback callback)
{
// call async method then callback when it completes.
callback();
}
private void DoSomeMoreWork(Item i, OperationCallback callback)
{
// call async method, then callback when it completes.
callback();
}
private void UpdateRecord(Item i)
{
// call async method
}
It's certainly not as clear as the synchronous version, but if you use lambda expressions as much as possible, it's still possible to keep the control flow fairly readable.
Add 2 properties to Item called SomeWorkDone and SomeMoreWorkDone both as booleans. Create methods to handle both DoSomeWorkCompleted and DoSomeMoreWorkCompleted. In those methods, set the respective boolean properties to true and call UpdateRecord. Within UpdateRecord, ensure that both Done properties are true and then complete the calls.
You'll have some possible contention issues but this should get you going.

How do you wait/join on a WCF Web Service called from Silverlight?

If you call a web service from Silverlight like this:
MyServiceClient serviceClient = new MyServiceClient();
void MyMethod()
{
serviceClient.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(serviceClient_GetDataCompleted);
serviceClient.GetDataAsync();
// HOW DO I WAIT/JOIN HERE ON THE ASYNC CALL, RATHER THAN BEING FORCE TO LEAVE THIS METHOD?
}
I would rather wait/join with the asych service thread inside "MyMethod" rather than leaving "MyMethod" after calling "GetDataAsync", what is the best way to do this?
Thanks,
Jeff
No you cannot do this way. You will end up in a deadlock. GetDataCompleted is called by the mainthreed. The same threed thait is waiting in WaitOne.
I have to ask; why? The point is to provide your user with a fluid experience and waiting on a web service call will not necessarily do that. I suppose you want the full block of content to load before the Silverlight control loads. In that case, I would turn to caching the content rather than forcing the client to wait indefinitely.
To do this you would use a ManualResetEvent in your class (class level variable) and then wait on it.
void MyMethod()
{
wait = new ManualResetEvent(false);
// call your service
wait.WaitOne();
// finish working
}
and in your event handler code
void serviceClient_GetDataCompleted(...)
{
// Set values you need from service
wait.Set();
}
You could also use a lambda and closure to get similar behavior:
serviceClient.GetDataCompleted += (s,e) =>
{
// Your code here
};
serviceClient.GetDataAsync();
If you had a base class provide the mechanics of building a WCF channel, it could then be used to build the BeginX / EndX methods for a async call.
public class ServiceFooCoordinator : CoordinatorBase<IServiceFoo>
{
public IAsyncResult BeginMethodFoo ()
{
IAsyncResult ar = null;
IServiceFoo channel = null;
channel = _factory.GetChannel();
Begin( channel, () => ar = channel.BeginMethodFoo( null, channel ) );
return ar;
}
public Bar[] EndMethodFoo ( IAsyncResult ar )
{
IServiceFoo channel = null;
channel = _factory.GetChannel();
return channel.EndMethodFoo( ar );
}
}
Which can then be used in a method:
ServiceFooCoordinator _coordinator;
var asyncResult = _coordinator.BeginMethodFoo();
try
{
var result = _coordinator.EndMethodFoo( asyncResult );
}
catch ( Exception )
{ }
Which gets you your asynchronous call in a sychronous manner.