WCF Async operations not really async - wpf

wonder if anyone can tell me where i'm going wrong.
i've added a service reference in my wpf application VS2012
however my wait on the Async call is blocking, i'm not doing anything with it at the moment.
The Async call I got for free when I added the Service reference...
Yet when I await ma.searchModelsAsync I'm blocked...
can anyone shed some light on this??
first I call the function like this:
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
button1.IsEnabled = false;
var cnt = await GetDataFromWcf();
button1.IsEnabled = true;
}
here is the actual function I call
public async Task<List<ViewModels.ModelInfo>> GetDataFromWcf()
{
using (var ma = new DataGenic.ModelActionsServiceTypeClient())
{
var modelInfos = await ma.searchModelsAsync(new ModelSearchCriteria { Category = "ECB" }, 1, 50);
return modelInfos.Select(mi => new ViewModels.ModelInfo { Id = mi.Id, Name = mi.Name, Uri = mi.Uri }).ToList();
}
}
btw: if I put the function in a Task.Run(() => ... then it behaves as I expcect...
Not sure if WCF is really giving me what I want.. ideas anyone?

Based on the comment thread thus far, it sounds like there's enough work happening before the WCF task starts up such that you'd like to have GetDataFromWcf return to the caller sooner than that. That's a somewhat common issue with async methods (IMHO) - the 'gotcha' that they run synchronously up until that first 'await' call, so they can still cause noticeable UI delays if too much is happening before the first 'await' :)
Because of that, a simple change would be to use Task.Yield (by adding await Task.Yield(); as the first line in GetDataFromWcf) which changes the behavior to have the async method return back to the caller immediately. As the MSDN doc mentions, you can use await Task.Yield(); in an asynchronous method to force the method to complete asynchronously. That sentence alone (and how silly it sounds on the surface) helps show the 'gotcha' IMHO :)

Related

Entity Framework async call blocking UI thread

I have been slowly trying to convert my code from using action delegates to the new Tasks in my WPF application. I like the fact that an await operation can run in the same method, greatly reducing the number of methods I need, enhancing readability, and reducing maintenance. That being said, I am having a problem with my code when calling EF6 async methods. They all seem to run synchronously and are blocking my UI thread. I use the following technologies/frameworks in my code:
.NET Framework 4.5
WPF
MVVM Light 5.2
Generic Unit Of Work/Repository Framework v3.3.5
https://genericunitofworkandrepositories.codeplex.com/
Entity Framework 6.1.1
SQL Server 2008 R2 Express
As an example, I have a LogInViewModel, with a command that executes after a button is clicked on my WPF application. Here is the command as initialized in the constructor:
LogInCommand = new RelayCommand(() => ExecuteLogInCommand());
Here is the command body:
private async void ExecuteLogInCommand()
{
// Some code to validate user input
var user = await _userService.LogIn(username, password);
// Some code to confirm log in
}
The user service uses a generic repository object that is created using MVVM Light's SimpleIoC container. The LogIn method looks like this:
public async Task<User> LogIn(string username, string password)
{
User user = await _repository.FindUser(username);
if (user != null && user.IsActive)
{
// Some code to verify passwords
return user;
}
return null;
}
And my repository code to log in:
public static async Task<User> FindUser(this IRepositoryAsync<User> repository, string username)
{
return await repository.Queryable().Where(u => u.Username == username).SingleOrDefaultAsync();
}
The SingleOrDefaultAsync() call is Entity Framework's async call. This code is blocking my UI thread. I have read multiple articles from Stephen Cleary and others about async await and proper use. I have tried using ConfigureAwait(false) all the way down, with no luck. I have made my RelayCommand call use the async await keywords with no luck. I have analyzed the code and the line that takes the longest to return is the SingleOrDefaultAsync() line. Everything else happens almost instantaneously. I have the same problem when making other async calls to the DB in my code. The only thing that fixes it right away is the following:
User user = await Task.Run(() =>
{
return _userService.LogIn(Username, p.Password);
});
But I understand this should not be necessary since the call I am making to the database is IO bound and not CPU bound. So, what is wrong with my application and why is it blocking my UI thread?
Your RelayCommand is not async.
LogInCommand = new RelayCommand(() => ExecuteLogInCommand());
Because there is no async/await your ExecuteLogInCommand will be called synchronously.
You got to change it to
LogInCommand = new RelayCommand(async () => await ExecuteLogInCommand());
so that the RelayCommand is called async too.
Your LogIn and FindUser (which, according to the guidelines, should be called LogInAsync and FindUserAsync) which are not supposed to work with the UI should use ConfigureAwait(false) on all awaits.
However all calls are synchronous until something really asynchronous is called. I suppose that would be SingleOrDefaultAsync.
If wrapping it in Task.Run makes such a difference, then, for some reason, SingleOrDefaultAsync must be running synchronously.

async await not waiting

Tried to find something similar and read all the answers given but couldn`t find something that will explain it to me.
Here is a sample code for opening a dialog popup (WPF). I want after the ShowOverlayView turns to True, that the UI will be accessible (this is why the async-await) and the program to wait until it is finished when the user clicks "Close".
Small clarification:
ShowOverlayViewModel sets a boolean to true/false for the Visibility property of a ContentControl. Since this is the case then I have nothing to wait for "the regular way".
Currently when the view is being "visible" the MessageBox is immediately shown.
Seems like it doesn`t wait for the AutoResetEvent.
Small update: It seems to be relevant specific to the MessageBox. I tried to change the Message property after the await code line and it occurred only after the are.Set(). I would still love to know why did the MessageBox act as it did.
private void CommandAction()
{
ShowOptionsDialog();
MessageBox.Show("");
}
private async void ShowOptionsDialog()
{
var are = new AutoResetEvent(false);
var viewmodel = new DialogPopupViewModel();
viewmodel.Intialize("some title", "some message", DialogPopupViewModel.YesNoCancelButtons);
SetOverlayViewModel(viewmodel);
viewmodel.SetCloseViewAction(() =>
{
HideOverlayView();
are.Set();
});
ShowOverlayView = true;
await Task.Factory.StartNew(() =>
{
are.WaitOne();
//return viewmodel.DialogResult;
});
//return DialogResultEnum.Cancel;
}
Thanks for the help
Classic async-void bug. Research what async void does and why it's bad practice. Since ShowOptionsDialog() does not return a task that is awaited execution continues immediately. Change the return type to Task and await the result of the method call.
You can replace the event with a TaskCompletionSource<object> and say await myTcs.Task. A TCS is a more TPL-friendly event.

How to ensure wcf service client finishs his works in silverlight?

I use wcf service client to submit changes of data for a silverlight project. The correlative codes like this:
public class DispatcherCollection : UpdatableCollection<DocumentDispatcher>
{
public override void SubmitChanges()
{
DocumentServiceClient client = new DocumentServiceClient();
client.NewDocumentCompleted += (s, e) =>
{
// (s as DocumentServiceClient).CloseAsync();
// do something
};
client.UpdateColumnCompleted += (s, e) =>
{
// (s as DocumentServiceClient).CloseAsync();
// do something
};
client.RemoveDocumentCompleted += (s, e) =>
{
// (s as DocumentServiceClient).CloseAsync();
// do something
};
foreach (DocumentDispatcher d in this)
{
if (d.IsNew)
{
// d=>object[] data
client.NewDocumentAsync(data);
d.IsNew=false;
}
else
{
foreach (string propertyName in d.modifiedProperties)
{
client.UpdateColumnAsync(d.ID, GetPropertyValue(propertyName));
}
dd.ClearModifications();
}
}
foreach (DocumentDispatcher dd in removedItems)
{
client.RemoveDocumentAsync(dd.ID);
}
removedItems.Clear();
}
}
Class UpdatableCollection derives from ObserableCollection, and I implemtent logics in class DocumentDispatcher and UpdatableCollection to buffer the changes of data such as new created, property modified and removed. I use SubmitChanges method to submit all changes to server.
Now I am stuck:
1. I am at a loss when to close the client after a bunlde fo async calls. I don't know which callback is the last one.
2. What will happen when a user closes the IE immediately right after clicking the save button (it seems to be done because it runs async but in fact the updating threads are industriously running.)?
You can keep a counter or use an isbusy function to monitor the callbacks from your Async calls - to make sure they all finished.
If the user fires off a request to the WCF service, the WCF service will complete but there will be no call back - as the application will be closed.
I think that there is no wait handle for silverlight asynchornized call brings inconvenience. Here is my experence. I want to check and submit modifications of data which are not expicitly submitted when browser is closing. I have implemented codes in App_Exit like this:
private void Application_Exit(object sender, EventArgs e)
{
Document doc = EDPViewModel.CurrentViewModel.Document;
if (doc != null) new ServiceClient().SubmitChangesAsync(doc);
}
provided that in the SubmitChangesAsync method, not submitted modifications of doc are found out and submitted. Therefore, because of the asynchronized running features, while the service invoking is being sent, the application is yet immediately closed. And that will dispose related resouces of the application, including Service Invoking Tasks. So the codes above work not. I hope so eagerly that somewhere exists a mechanism, which can export a wait handle from silverlight asynchronized call, so that I can update the above codes whith this:
private void Application_Exit(object sender, EventArgs e)
{
Document doc = EDPViewModel.CurrentViewModel.Document;
if (doc != null)
{
Task t = new TaskFactory().StartNew(() => new ServiceClient().SubmitChangesAsync(doc));
t.Wait();
}
}
With wait operation I can really be sure that all modifications are really definitely submitted. So is there any similar pattern that can be used in silverlight?
It's for me a good news, as you put it, that calls could work like the mode "requesting and forgetting". So I needn' to worry too much about data losing during submitting.
To ensure all service calls are sent out before application is closed, I think, counter is a simple and effient idea. I will try to implement it in my project.
Thank you for your help!

WP7 HttpWebRequest check if file exists (synchronously)

I need to check if a file exists and I need to do it from several places in code.
Some of the places I can handle it with a callback (kinda ugly but it will work). But the one I don't know how to handle seems to require that it be Synchronous.
I need to call the method to check if it exist from a RelayCommand as the "canExecute" method.
Any ideas on how to handle this?
This is what I currently have but calling the .WaitOne on the UI thread is blocking the background worker so it completely locks the app.
private bool FileExists(Uri file)
{
var exists = false;
ManualResetEvent resetEvent = new ManualResetEvent(false);
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (s, e) =>{
WebRequest request = HttpWebRequest.Create(file);
request.Method = "HEAD"; //only request the head so its quick
request.BeginGetResponse(result =>
{
try
{
//var response = request.EndGetResponse(result);
var req = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
exists = (response.StatusCode.ToString() == "OK");
}
catch
{
exists = false;
}
resetEvent.Set();
}
, request);
};
worker.RunWorkerAsync();
resetEvent.WaitOne();
return exists;
}
You should never make HTTPWebRequest's synchronous on the UI thread - this could block the UI for seconds or minutes...
If you really want to make an HTTPWebRequest appear to be synchronous on a background thread then simply use a ManualResetEvent inside a callback - e.g. something like:
var resetEvent = new ManualResetEvent();
theHttpWebRequest.BeginGetResponse((result) => {
var response = theHttpWebRequest.EndGetResponse(result);
// use response.StatusCode to check for 404?
resetEvent.Set();
});
resetEvent.WaitOne();
Also, please note that checking if a file exists over HTTP might be better done by calling a small webservice which does the check - it depends on the size of the file you are checking.
AFAIK this is not possible. You can never make synchronous calls to web services in Silverlight.
You have to leave canExecute method empty (to always execute the command), and make async call to check if file exists in handler for the command. The real code for the command has to execute in handler for that async call.
I think it is only way you can manage it.
btw-you can use lambda expressions to make it look more like synchronous code. Or maybe Reactive Extensions may help with better looking code (jesse's tutorial).
The way I would approach this problem is to create some kind of flag ( i.e IsFileExists) and return that flag from CanExecute method. Flag shold be set to false initially and your button disabled under assumption that untill we know that file does exits we consider it doesn't. Next I would fire HTTPWebRequest or wcf call or any other async method to check if file exists. Once callback confirms that file exists set flag to true and fire CanExecuteChanged event. If you want to be fancy you can add some visual feedback while waiting for responce. In general user experienc would be much better than locking up screen for duration of the web request.

Silverlight Async Design Pattern Issue

I'm in the middle of a Silverlight application and I have a function which needs to call a webservice and using the result complete the rest of the function.
My issue is that I would have normally done a synchronous web service call got the result and using that carried on with the function. As Silverlight doesn't support synchronous web service calls without additional custom classes to mimic it, I figure it would be best to go with the flow of async rather than fight it. So my question relates around whats the best design pattern for working with async calls in program flow.
In the following example I want to use the myFunction TypeId parameter depending on the return value of the web service call. But I don't want to call the web service until this function is called. How can I alter my code design to allow for the async call?
string _myPath;
bool myFunction(Guid TypeId)
{
WS_WebService1.WS_WebService1SoapClient proxy = new WS_WebService1.WS_WebService1SoapClient();
proxy.GetPathByTypeIdCompleted += new System.EventHandler<WS_WebService1.GetPathByTypeIdCompleted>(proxy_GetPathByTypeIdCompleted);
proxy.GetPathByTypeIdAsync(TypeId);
// Get return value
if (myPath == "\\Server1")
{
//Use the TypeId parameter in here
}
}
void proxy_GetPathByTypeIdCompleted(object sender, WS_WebService1.GetPathByTypeIdCompletedEventArgs e)
{
string server = e.Result.Server;
myPath = '\\' + server;
}
Thanks in advance,
Mike
The best would be to use Reactive Extensions. Then (assuming you'd create an extension method IObservable<string> GetPathByTypeId(string typeId) on WS_WebService1SoapClient you can do this:
proxy
.GetPathByTypeId(TypeId)
.Subscribe(server =>
{
//Here you can do stuff with the returned value
});
As close to having synchronous call as it gets :)
Given the asynch nature of Silverlight you cannot return values from myFunction. Instead you can pass an Action which is executed once the service call is complete. See the example code below. I am not sure if it is considered best practice, but I use this "pattern" a lot and it has always worked fine for me.
EDIT
Updated the code below to include multiple arguments in the callback action.
void DoSomething(Guid TypeId, Action<int, bool> Callback)
{
WS_WebService1.WS_WebService1SoapClient proxy = new WS_WebService1.WS_WebService1SoapClient();
proxy.GetPathByTypeIdCompleted += (s, e) =>
{
string server = e.Result.Server;
myPath = '\\' + server;
//
if (myPath == "\\Server1")
{
Callback(888, true);
}
else
{
Callback(999, false);
}
};
proxy.GetPathByTypeIdAsync(TypeId);
}
void CallDoSomething()
{
DoSomething(Guid.NewGuid(), (returnValue1, returnValue2) =>
{
//Here you can do stuff with the returned value(s)
});
}
Put the processing of the GetPathByTypeId result into the GetPathByTypeIdCompleted callback. Assign mypath there. Make mypath a property and implement the INotifyPropertyChanged interface to notify dependents of Mypath that Mypath has changed.
Observer depends on mypath
Observer sets a notification event for mypath
Get Mypath by asynchronous invocation of GetPathByTypeId
Mypath is set, invokes notifiaction of Observer
Observer works with Mypath

Resources