WCF Asynch pattern - Really required? - wcf

I have created one WCF service which performs a lengthy operation asynchronously using Asynch pattern. I have referred to below link to implement BeginAddNumbers and EndAddNumbers methods in the ServiceContract.
http://aspalliance.com/1335_Asynchronous_Pattern_in_Windows_Communication_Foundation.5
Everything is working fine. But I dont understand why we require this approach?
Even though its asynchronous operation on server, client will still blocked and we
have to invoke this operation asynchornously on client as well.
So instead of implementing operation asynchronously on server it's always
better to invoke operation asynchronously on client side to have responsive UI.
Can anyone help me to understand concept of implementing asynchronous operation on server side? Any practical example where I need to play around AsyncPattern=true in conjunction with OperationContract ?
Adding client code. Client is implemented using WPF application
private void button1_Click(object sender, RoutedEventArgs e)
{
MathOperationClient c = new MathOperationClient();
Task t = new Task(new Action(() =>
{
///Even if AddNumbers is is implemented as asynchronous operation
///second call to AddNumbers get chance only after completing below
///call.
///Note: AddNumbers method takes 10 sec to execute
int nResult = c.AddNumbers(2, 3);
this.Dispatcher.BeginInvoke(new Action(()=>{
label1.Content = nResult.ToString();
})
, null);
}));
t.Start();
Task t1 = new Task(new Action(() =>
{
///Below method is invoked only after executing first call ( above call with parameters 2 and 3 )
///in other words below call is blocked for 10 seconds.
///So what is advantage of implementing asynchronous AddNumbers method on server side?
int result = c.AddNumbers(5,5);
this.Dispatcher.BeginInvoke(new Action(() =>
{
label2.Content = result.ToString();
})
, null);
}));
t1.Start();
}
Thanks, Hemant

this post has some information.
in general:
In case of WCF, the realproxy is of type System.ServiceModel.Channels.ServiceChannelProxy. This proxy implementation calls service method synchronously even if we call it using BeginInvoke.
WCF only issues asynchronous calls if the method that is called on a proxy begins with BeginXXX() and is decorated with [OperationContract(AsyncPattern=true)] attribute.

I like the idea to implement this server side; and clearly indicate this by naming the operation accordingly. After all, if a call is asynchronous in nature, why give the client the choice?
Another reason is scalability: doing it server-side decouples the request from the WCF dispatcher thread. This means that WCF threads will not be blocked.
See here for an example.
You could even decide to make it a one way call; and have the client poll at regular intervals; which is, in fact, my favorite approach.

Related

ServiceStack: Reinstate pipeline when invoking a Service manually?

As a follow-up to this question, I wanted to understand how my invoking of a Service manually can be improved. This became longer than I wanted, but I feel the background info is needed.
When doing a pub/sub (broadcast), the normal sequence and flow in the Messaging API isn't used, and I instead get a callback when a pub/sub message is received, using IRedisClient, IRedisSubscription:
_subscription.OnMessage = (channel, msg) =>
{
onMessageReceived(ParseJsonMsgToPoco(msg));
};
The Action onMessageReceived will then, in turn, invoke a normal .NET/C# Event, like so:
protected override void OnMessageReceived(MyRequest request)
{
OnMyEvent?.Invoke(this, new RequestEventArgs(request));
}
This works, I get my request and all that, however, I would like it to be streamlined into the other flow, the flow in the Messaging API, meaning, the request finds its way into a Service class implementation, and that all normal boilerplate and dependency injection takes place as it would have using Messaging API.
So, in my Event handler, I manually invoke the Service:
private void Instance_OnMyEvent(object sender, RequestEventArgs e)
{
using (var myRequestService = HostContext.ResolveService<MyRequestService>(new BasicRequest()))
{
myRequestService.Any(e.Request);
}
}
and the MyRequestService is indeed found and Any called, and dependency injection works for the Service.
Question 1:
Methods such as OnBeforeExecute, OnAfterExecute etc, are not called, unless I manually call them, like: myRequestService.OnBeforeExecute(e) etc. What parts of the pipeline is lost? Can it be reinstated in some easy way, so I don't have to call each of them, in order, manually?
Question 2:
I think I am messing up the DI system when I do this:
using (var myRequestService = HostContext.ResolveService<MyRequestService>(new BasicRequest()))
{
myRequestService.OnBeforeExecute(e.Request);
myRequestService.Any(e.Request);
myRequestService.OnAfterExecute(e.Request);
}
The effect I see is that the injected dependencies that I have registered with container.AddScoped, isn't scoped, but seems static. I see this because I have a Guid inside the injected class, and that Guid is always the same in this case, when it should be different for each request.
container.AddScoped<IRedisCache, RedisCache>();
and the OnBeforeExecute (in a descendant to Service) is like:
public override void OnBeforeExecute(object requestDto)
{
base.OnBeforeExecute(requestDto);
IRedisCache cache = TryResolve<IRedisCache>();
cache?.SetGuid(Guid.NewGuid());
}
So, the IRedisCache Guid should be different each time, but it isn't. This however works fine when I use the Messaging API "from start to finish". It seems that if I call the TryResolve in the AppHostBase descendant, the AddScoped is ignored, and an instance is placed in the container, and then never removed.
What parts of the pipeline is lost?
None of the request pipeline is executed:
myRequestService.Any(e.Request);
Is physically only invoking the Any C# method of your MyRequestService class, it doesn't (nor cannot) do anything else.
The recommended way for invoking other Services during a Service Request is to use the Service Gateway.
But if you want to invoke a Service outside of a HTTP Request you can use the RPC Gateway for executing non-trusted services as it invokes the full Request Pipeline & converts HTTP Error responses into Typed Error Responses:
HostContext.AppHost.RpcGateway.ExecuteAsync()
For executing internal/trusted Services outside of a Service Request you can use HostContext.AppHost.ExecuteMessage as used by ServiceStack MQ which applies Message Request Request/Response Filters, Service Action Filters & Events.
I have registered with container.AddScoped
Do not use Request Scoped dependencies outside of a HTTP Request, use Singleton if the dependencies are ThreadSafe, otherwise register them as Transient. If you need to pass per-request storage pass them in IRequest.Items.

Using TAP progress reporting in a WCF service

I (new to WCF) am writing a WCF service that acquires and analyzes an X-ray spectrum - i.e. it is a long-running process, sometimes several minutes. Naturally, this begs for asynchronous calls so, using wsDualHttpBinding and defining the following in my ServiceContract
[ServiceContract(Namespace="--removed--",
SessionMode=SessionMode.Required, CallbackContract=typeof(IAnalysisSubscriber))]
public interface IAnalysisController
{
// Simplified - removed other declarations for clarity
[OperationContract]
Task<Measurement> StartMeasurement(MeasurementRequest request);
}
And the (simplified) implementation has
async public Task<Measurement> StartMeasurement(MeasurementRequest request)
{
m_meas = m_config.GetMeasurement(request);
Spectrum sp = await m_mca.Acquire(m_meas.AcquisitionTime, null);
UpdateSpectrum(m_meas, sp);
return m_meas;
}
private void McaProgress(Spectrum sp)
{
m_client.ReportProgress(sp);
}
Where m_client is the callback object obtained from m_client = OperationContext.Current.GetCallbackChannel(); in the "Connect" method - called when the WCF client first connects. This works as long as I don't use progress reporting, but as soon as I add progress reporting by changing the "null" in the m_mca.Acquire() method to "new Progress(McaProgress)", on the first progress report, the client generates an error "The server did not provide a meaningful reply; this might be caused by a contract mismatch..."
I understand the client is probably awaiting a particular reply of a Task rather than having a callback made into it, but how do I implement this type of progress reporting with WCF? I would like the client to be able to see the live spectrum as it is generated and get an estimate of the time remaining to complete the spectrum acquisition. Any help or pointers to where someone has implemented this type of progress reporting with WCF is much appreciated (I've been searching but find mostly references to EAP or APM and WCF and not much related to TAP).
Thanks, Dave
Progress<T> wasn't really meant for use in WCF. It was designed for UI apps, and may behave oddly depending on your host (e.g., ASP.NET vs self-hosted).
I would recommend writing a simple IProgress<T> implementation that just called IAnalysisSubscriber.ReportProgress directly. Also make sure that IAnalysisSubscriber.ReportProgress has OperationContract.IsOneWay set to true.

ASP.NET, WCF and per-operation static variables - how to use them safely?

I have a WCF service and I have the following (simplified) class:
public class PerOperationSingleton : IDisposable
{
private static bool _hasInstance = false;
public PerOperationSingleton()
{
if(_hasInstance)
throw new InvalidOperationException("Cannot have multiple instances during a single WCF operation");
_hasInstance = true;
}
public void Dispose()
{
_hasInstance = false;
}
}
I guess, it's pretty self explanatory piece of code. I don't need a singleton for entire WCF service but only during a single operation call. If one instance of the PerOperationSingleton is disposed, it should be safe to create a new instance during the same WCF operation.
The problem is that I don't know how to make the _hasInstance variable to be effective only for one WCF operation. I know about [ThreadStatic], but I've heard that ASP.NET and WCF do not guarantee that an operation will be executed on a single thread - it might be transferred to another thread.
I definitely don't want my _hasInstance = true to move to thread pool and get incorrectly detected if some other operation picks that thread from the pool.
If WCF operation moves to another thread, I would like the _hasInstance variable to keep the "true" value if it was set.
And I don't want to change some global settings for my WCF service to avoid affecting the performance or get into some problems which will be hard to debug and solve later (I don't feel proficient enough in advanced ASP.NET and WCF topics).
I cannot store _hasInstance in session either because my client requested to disable .NET sessions for various reasons.
I would like the class PerOperationSingleton actually to be environment agnostic. It shouldn't really know anything about WCF or ASP.NET.
How do I make _hasInstance variable static during entire call of my WCF operation and don't affect other WCF operations?
I would consider using OperationContext to make you data "static" during the operation call.
Here is a similar discussion Where to store data for current WCF call? Is ThreadStatic safe?

Calling WCF in async manner from client makes the WCF service also act in async manner?

When a WCF service is called in an async manner from a client, then we know that the client app is NOT blocked.
But is the thread on the WCF side blocked while executing the async method call OR the WCF releases the thread it uses to initiate the method call ?
For example, if I call the 'Add' method in an async manner from an ASP.Net app, as in code below, will the service instance in back-end wait till method completes? The WCF uses an InstanceContext of PerCall.
CalculatorClient client = new CalculatorClient();
// AddAsync
double value1 = 100.00D;
double value2 = 15.99D;
client.AddCompleted += new EventHandler<AddCompletedEventArgs>(AddCallback);
client.AddAsync(value1, value2);
WCF support for asynchronous calls are strictly a client-side feature only.
In-fact the service has no way (and should not have) of telling the difference between two clients, one making a synchronous call and the other making an asynchronous call.
This is true regardless of whether the client is making a call via an async proxy, or directly via async invocation.
It is easy to show this is true with a thought experiment; ANY wcf service can be called asynchronously, and additionally this is REGARDLESS of the binding selected - therefore this must be solely a client-side facility.

Asynchronous WCF

I am trying to create a WCF service that supports asynchronous calls. I followed all samples and tutorials I could find, and all of them have the customary pattern of one synchronous method, and the async Begin and End such as:
[OperationContract(AsyncPattern = false)]
string GetData(int value);
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetData(int value, AsyncCallback callback, object asyncState);
string EndGetData(IAsyncResult result);
However, only the synchronous GetData gets called, no matter what I do on the client side. Fiddler tells me that the message is always the same:
<s:Envelope
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><GetData
xmlns="http://tempuri.org/"><value>0</value></GetData></s:Body></s:Envelope>
When I remove the synchronous GetData interface, the async method now is properly called.
Is this normal behavior? Is there anything else I should do to support sync and async versions of a method?
This is a common misconception. You assume that you need to make the server asynchronous in order for the client to be able to make async calls. This is not true. Server and client are 100% independent. They are separated by a binary wire protocol.
The message that you see in Fiddler is always the same because SOAP does not know anything about sync or async. At the SOAP level your decision does not manifest itself. For that reason the client cannot observe your server-side decision, either.
This means you can just make the server synchronous in still have a truely async client, or the other way around.
In any case, you should only implement one pattern on the server: Either sync or async. Never both. Get rid of one of your implementations. From a functional standpoint it doesn't matter which one stays.
I'm pulling up important information from the comments here:
It is hard to fit an explanation about when to use server-side async
into this comment box. In short, don't use it on the server by
default. Use it if special circumstances make it attractive or
necessary.
On a meta-level let me point out that async IO has become
a fad that should not be followed lightly. The community is in a very
unfortunate state of misinformation about this right now.