Reputation: 188
I actually migrate a silverlight application to a blazor server app (actualli in .NET 5 RC2). Originally, the silverlight accessed data through wcf services, and we keep this architecture (and wcf server in .NET 4.0) for the new app.
The way we call the services are however completely different between the silverlight and the blazor app
Silverlight
var myService = new Service(url);
myService.Method1Completed += myServiceMethod1Completed;
myService.Method1Async();//its not async at all, it was generate like that
....
void myServiceMethod1Completed(object sender, Method1CompletedCompletedEventArgs e)
{
//working with e.Result
Blazor App
var myService = new Service(url);
var result = await myService.Method1Async();//this time, its real async Task
//working with result
at this point, it work perfectly
Problem, in some scenario, the app need to make really long treatment, and the user continue his life on the app, call others services, etc
In the silverlight app no problems, during the "long treatment", the app can call others services without problems
But in my blazor app, when a service is already called, calling another service seem blocked in the await of the second service (i don't know exactly at which step, i just know the service is not called on the server
var myService = new Service(url);
var result = await myService.LongTreatmentAsync();
//working with result
...somewhere else in the app
var myService = new Service(url);
var result = await myService.OtherServiceAsync();//I never reach OtherService on the server until LongTreatmentAsync is finished
//working with result
Its a big deal on my side because it block all the app. I don't know if its a "normal behavior" of await pattern, a bug, a configuration problem in my side, but im stuck with it. I even don't know if its the server which blocked or if its on the client side.
I don't have specific configuration for my wcf client in my blazor app.
What i try :
Some precisions about my wcf calling on the blazor app I use a Custom Behavior in order to add a sessionId in the httpHeader because my wcf services are subject to authentification so my real implementation is like this
var myService= new Service(urlService);
myService.Endpoint.EndpointBehaviors.Add(new CustomBehavior(mySessionId));
//working with service
...
public class CustomBehavior : IEndpointBehavior
{
private string _sessionId;
public CustomBehavior(string pSessionId)
{
_sessionId = pSessionId;
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(new SessionInterceptor(_sessionId));
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
public class SessionInterceptor : IClientMessageInspector
{
private string _sessionId;
public SessionInterceptor(string pSessionId)
{
_sessionId = pSessionId;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
if (!string.IsNullOrEmpty(_sessionId))
{
HttpRequestMessageProperty reqProps = null;
if (request.Properties.ContainsKey(HttpRequestMessageProperty.Name))
{
reqProps = request.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
}
else
{
reqProps = new HttpRequestMessageProperty();
request.Properties.Add(HttpRequestMessageProperty.Name, reqProps);
}
reqProps.Headers[HttpRequestHeader.Cookie] = $"ASP.NET_SessionId={_sessionId}";
}
return null;
}
}
I don't know if make this can have a side effect precision : on the second call (the one never reached until the long treatment is finish), the BeforeSendRequest is called, I don't know if it can help you.
so i wait for your suggestions and your help to understand whats happen and make my call asynchronous like the silverlight app
Thanks for your help !
Julien
EDIT : It seem the problem come from the wcf server
The wcf server seem blocking the request if the other one with same sessionId (set by cookie in my wcf client) are not finished. If no sessionId by cookie is set then wcf server handle the call asynchronously.
I read lot of stuff of this problem on internet but no one was able to solve our problems, we can't deactivate session on the wcf server because everything is based on it. The more surprising is the silverlight app don't have this problem without specific configuration.
In fiddler i don't see specific difference between the silvelight request and the aspnetcore request, but one is blocked (waiting) and the other not.
We are pretty desesperate, do you have some tips/advices i don't try for now ?
Upvotes: 1
Views: 599
Reputation: 3974
WebAssembly does not support multithreading yet and this means that Blazor has only one thread available. It does not report itself as a thread-pool thread, but it is called that and fortunately it behaves like it. If you had only UI thread and an empty threadpool in your application, you would not have much fun with asynchronous functions because they have nowhere to run. Therefore, you can use asynchronous functions in Blazor, but you can't wait for them synchronously (which might be just fine - at least you find out where your libraries have issues with async calls) because you simply don't have the two threads available where one could wait while the other is running. Consequently, all synchronous waits for async methods cause a deadlock.
In the server-side Blazor, the situation is a bit different. There, of course, you have no problem with the thread pool, but something else is returning from the times of ASP .NET - synchronization context. Blazor needs it to guarantee working DOM synchronization, and it has the same limitations as in ASP .NET - one thread at a time. Therefore, if you are performing an operation in a thread with this synchronization context, you cannot wait for another that needs it. I mean you can, but it will deadlock.
The above content comes from this blog.
Upvotes: 2