How to make WCF RESTful service work async? - c#

I'm building WCF rest service and it's client. I plan, that client does not know much about the service, just right URL's to call methods and expected results.
My service contract is:
[WebInvoke(Method="POST", UriTemplate="/tasks")]
[OperationContract]
void SubmitTask(Transaction task);
[WebGet(UriTemplate = "/tasks/{taskId}")]
[OperationContract]
[XmlSerializerFormat]
Transaction GetTask(string taskId);
SubmitTask is realized like:
SubmitTask(Transaction task)
{
DoSomethingWithTask(task);
task.Status = "SomeStatus";
DoSomethingElseWithTaks(task);
task.Status = "SomeOtherStatus";
}
What I expect on client:
ButtonClick()
{
SubmitTask(task);
while(true)
{
string status = Transaction GetTask(task.taskId).Status;
Textbox.Text+= status;
if(status==ok)
break;
Thread.Sleep(1000);
}
}
The problem is - GetTask is not performed on service side, while all SubmitTask operations are completed, so I get only last task status on client side. How to realize asynchronos operation performing in this situation?
Thanks in advance!

Have you read this interesting little article? Tweaking WCF to build highly scalable async REST API and the following article that is very good and which will hopefully provide the answer you desire Fixing WCF to build highly scalable async REST API

Related

Is CallbackContract a good strategy for one-to-one communication?

The Background
I have a WCF client and service with a one-to-one relationship (i.e. one service host per client). I use a callback contract to pass messages from the service to the client.
[ServiceContract(CallbackContract = typeof(IMessageTarget)]
public interface IMessageService
{
[OperationContract]
void StartMessages();
}
public interface IMessageTarget
{
[OperationContract]
Task SendAsync(Message message);
[OperationContract(IsOneWay = true)]
void Complete();
[OperationContract(IsOneWay = true)]
void Fault(ExceptionDetail exception);
}
On the client, I set up a duplex connection to begin communication. MessageTarget.Completion completes when the Complete() or Fault(ExceptionDetail) methods are called.
IMessageTarget target = new MessageTarget();
var channelFactory = new DuplexChannelFactory<IMessageService>(target, new NetNamedPipeBinding());
IMessageService service = channelFactory.CreateChannel(new EndpointAddress(EndpointUri));
service.StartMessages();
await target.Completion;
The service sends messages to the client as soon as they become available. The client is able to delay further messages by making SendAsync() take a long time to return.
IMessageTarget client = OperationContext.Current.GetCallbackChannel<IMessageTarget>();
// later, whenever a message is created
await client.SendAsync(message);
// finally
client.Complete();
The Problem
I discovered that the client hangs if the service crashes. Unfortunately, WCF provides no reliable way to detect if the service is still up, other than calling a service method and catching CommunicationException. Therefore, I added a new operation
[OperationContract]
Task PingAsync();
so the client can monitor if the service goes down.
service.StartMessages();
while (!target.Completion.IsCompleted)
{
await service.PingAsync();
await Task.Delay(TimeSpan.FromSeconds(0.5));
}
await target.Completion;
The Question
Doesn't this defeat the purpose of using callbacks? I'm struggling to see how this "listen for callbacks while constantly pinging" strategy is better than simply polling for the latest messages (with no duplex required). Did I over-engineer this, or is there some other benefit to callbacks?
Most WCF related exceptions are derived from CommunicationsException, so what you did is good in that sense. As you noted, pinging / polling defeats the purpose of the callback implementation. Bottom line, you need to just call the service and be ready to deal with any exceptions that happen during the service invocation. There's really no reliable way to see if the service is available.
If you are not already doing so, you can also look at the IClientChannel events to monitor what happens with the connection.
client.InnerChannel.Closed += OnChannelClosed;
client.InnerChannel.Opening += OnChannelOpening;
client.InnerChannel.Opened += OnChannelOpened;
client.InnerChannel.Closing += OnChannelClosing;
client.InnerChannel.Faulted += OnChannelFaulted;
client.InnerChannel.UnknownMessageReceived += OnChannelUnknownMessageReceived;

Understanding WCF IsOneWay, CalbackContracts and Duplex - Are my assumptions correct?

I have been reading and experimenting with WCF and trying to understand the workings in simple terms. So my questions are for verification and validation of what I believe to be correct but I need to be sure:
In a typical Publish-Subscribe Duplex service.
1: Service Contract - this is the communication path that clients must make to the service.
2: Callback contract - this is the communication methods back to the client.
3: Setting the IsOneWay = true property on a callback contract means the Client will not get anything back from the server.
4: setting IsOneWay = true on the ServiceContract means the server will not get anything back from the client.
5: void return methods still send a reply back, if IsOneWay=true, the reply is is ignored, if false error and soap info can be obtained. ^
for brevity I have looked at the following and then Some^ⁿ:
Understanding WCF
WCF issue with using IsOneWay attribute
Understanding WCF Client to Server
https://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontractattribute.isoneway(v=vs.110).aspx
Take a look at this tutorial for WCF, and this MSDN Article on duplex services.
You're almost there with your definitions, I would define the above myself as:
Service Contract - The interface that defines the operations a web service exposes to clients.
Callback Contract - Similar to a service contract, but as you note, for the client side. This is defines how a web service can communicate to client as a separate call. (As opposed to simply returning data from the calls in the service contract). These are often used for returning values from long-running web service calls, or event signaling.
IsOneWay = true on the service contract - This specifies that the service operation is returns no value, and hence the client will simply "fire and forget". The call to the webservice will not block the client until it completes, but instead return immediately. For this reason, operations with IsOneWay = true can only return void.
IsOneWay = true on the callback contract - This is much the same as it is on the service contract. When the server calls the operation on the callback contract, it will return immediately and not block until the operation completes.
Void returns - If IsOneWay is not set to true, the call will still block until the operation completes, a SOAP message will still be returned, but with no data (unless you are passing back faults). If you wish to actually return values, you can either do so exactly as you would with normal methods, setting the return type of the operation i.e
[ServiceContract]
public interface IService
{
[OperationContract]
DateTime GetDateTime();
}
public class Service : IService
{
public DateTime GetDateTime()
{
return DateTime.Now;
}
}
Alternatively, you could create a duplex service, with a callback contract, and IsOneWay = true
[ServiceContract(CallbackContract = typeof(ICallbackService))]
public interface IService
{
[OperationContract(IsOneWay = true)]
void GetDateTime();
}
public interface ICallbackService
{
[OperationContract(IsOneWay = true)]
void GetDateTimeCompleted(DateTime dateTime);
}
public class Service : IService
{
public void GetDateTime()
{
// Do long action here.
...
Callback.GetDateTimeCompleted(DateTime.Now);
}
ICallbackService Callback
{
return OperationContext.Current.GetCallbackChannel<ICallbackService>();
}
}
Using this method:
The call to the webservice GetDateTime() operation would return immediately
The "Very long operation" would execute on the server
The GetDateTimeCompleted(DateTime dateTime) on the client would get triggered when the server completes.
Please note that the above duplex example is not complete, you'll need to ensure you're handling things like sessions correctly.
You're definitely on the right track. I'd recommend following the tutorials linked above, (along with any others you find) and experimenting. You'll soon get a good feel for what is possible.

Why to Implement Asynchronous Service if Asynchronous Proxies on client does the exact same thing

Initially I have my Service Contract :
[ServiceContract]
interface IDataRetrieve
{
[OperationContract]
List<OrderDetails> GetOrderDetails(string FilterValue);
}
And Implemented the Service as :
public List<OrderDetails> GetOrderDetails(string filterValue)
{
//My Operation
}
Now After following the article from MSDN , I updated my Service Contract
[ServiceContract]
interface IDataRetrieve
{
[OperationContractAttribute(AsyncPattern = true)]
IAsyncResult BeginGetOrderDetails(string filterValue, AsyncCallback callback, object asyncState);
List<OrderDetails> EndGetOrderDetails(IAsyncResult result);
}
And the Implementation:
public IAsyncResult BeginGetOrderDetails(string filterValue, AsyncCallback callback, object asyncState)
{
this.FilterValue = filterValue;
var task = Task<List<OrderDetails>>.Factory.StartNew(this.WorkerFunction, asyncState);
return task.ContinueWith(res => callback(task));
}
public List<OrderDetails> EndGetOrderDetails(IAsyncResult result)
{
return ((Task<List<OrderDetails>>)result).Result;
}
public List<OrderDetails> WorkerFunction(object state)
{
//My Operation
}
But While using both the implementation in ASP.NET observed the same result being returned in same fashion.
So , Why should I take the extra step to implement asynchronously while the same can be accomplished just by creating proxies in client side? I think using Task is not the only benefit here?
Am I missing something important !!
Over the past few years, our team has received a good deal of sound WCF assistance from Wenlong Dong’s blog, so we generally value his thoughts. As such, I recommend the following article on WCF asynchronous programming.
http://blogs.msdn.com/b/wenlong/archive/2009/02/09/scale-wcf-application-better-with-asynchronous-programming.aspx
"For blocking calls such as I/O operations or remote calls, you should always thinking about using asynchronous patterns. In those cases, you would be able to reduce number of threads used in the system while waiting for operations to complete. Here are a few cases where you would like to use asynchronous patterns:
A WCF service operation is waiting for a database operation
to complete.
A WCF service operation calls into another WCF client proxy of a backend WCF service.
A UI thread waits for data from WCF client calls."
Regards,

Question regarding appropriate use for Task in C#

I have a question regarding Task. I have a WCF app which has a method ReceiveEmpInfo which will be called from a client app.
WCF Server app:
public void ReceiveEmpInfo(string EmpName, string EmpId)
{
DifferentClass.SaveEmpToDB(string EmpName, string EmpId);
return;
}
My requirement is I want to return this method call (ReceiveEmpInfo()) once I call the method SaveEmpToDB(), I don’t want to hold the client call until the SaveEmpToDB() method saves the data to the database. I’m thinking of using Task, but I’m not sure whether it will solve my requirement.
Please give me your suggestions.
Thanks,
Joe
Yes, it will. Once you call Task.Start() your WCF method can return and the task will run in the "background". You have to be very careful, especially if you're running this WCF service inside of IIS. If these tasks are very long running and the IIS application pool shuts down (or gets restarted) your task is going to get whacked [potentially] in the middle of its work.
BTW: I'm assuming you're referring to: System.Threading.Tasks.Task
Use callbacks, and do async calls to db or whatever,
see example http://msdn.microsoft.com/en-us/library/ca56w9se.aspx
This is a lot like this post:
How to make a call to my WCF service asynchronous?
I think the links in the popular answer should help.
If this is a one-way fire-and-forget operation you can simply make the operation one-way. This will not block the client for the duration of the method execution.
[ServiceContract]
interface ISomeContract
{
[OperationContract(IsOneWay = true)]
void ReceiveEmpInfo(string EmpName, string EmpId)
}

Async CTP - How can I use async/await to call a wcf service?

If I call a WCF service method I would do something like this:
proxy.DoSomethingAsync();
proxy.DoSomethingAsyncCompleted += OnDoSomethingAsyncCompleted;
How could I do the same using the new async ctp?
I guess I would need something like proxy.DoSomethingTaskAsync or proxy.DoSomethingAsync().ToTask()? The web service call needs to return a Task<T> to be able to use the await keyword, but how??
In the CTP there are factory methods that do the work of turning regular APM functions (Begin/End) into ones that are compatible with the new async keyword, for instance:
Stream s = new FileStream("C:\test.txt", FileMode.CreateNew);
byte []buffer = new byte[100];
int numBytesRead = await Task<int>.Factory.FromAsync(s.BeginRead, s.EndRead, buffer, 0, buffer.Length, null);
So in your case you can do the equivalent and then you'd then call it like so:
async proxy.DoSomethingTaskAsync()
See this thread on the CTP discussion group for more info
An asynchronous service using async-await is very responsive as it can interleave many client calls and execute them in parallel (2).
Despite this, the service can run fully thread-safe on one thread (3) and can be a singleton service (1) or a service object created by the framework for a session or a call only.
When implementing the service, please note the ServiceBehaviourAttributes (1)...(3) :
[ServiceContract( Namespace="X", Name="TheContract" )]
public interface IAsyncContractForClientAndService
{
[OperationContract]
Task<TResponse> SendReceiveAsync( TRequest req );
}
[ServiceBehavior (InstanceContextMode = InstanceContextMode.Single, // (1)
// also works with InstanceContextMode.PerSession or PerCall
ConcurrencyMode = ConcurrencyMode.Multiple, // (2)
UseSynchronizationContext = true)] // (3)
public MyService : IAsyncContractForClientAndService
{
public async Task<TResponse> SendReceiveAsync( TRequest req )
{
DoSomethingSynchronous();
await SomethingAsynchronous();
// await lets other clients call the service here or at any await in
// subfunctions. Calls from clients execute 'interleaved'.
return new TResponse( ... );
}
}
To run every call on one thread, a System.Threading.SynchronizationContext.Current != null must be present at the moment you Open() the ServiceHost.
Using the SynchronizationContext, you need not to care about locks. Atomic, non interruptable code sections stretch roughly from one await to the next.
Take care that shared service data is in a consistent state at every await and be aware that successive requests from one client may be responded not in the order they where sent.
On client side, the asynchronous service operation is awaitable:
var response = await client.Channel.SendReceiveAsync( request );
It is not possible to use out or ref parameters in the operation contract. All response data must be passed by the returned value Task(T).
I use this interface in AsyncWcfLib, it supports a Actor based programming model.
There is a WCF sample in the Async CTP that will show you how to use the async/await model in WCF.
In terms of plans for supporting this model in WCF, you can take a look at the following post:
Link
Hope this helps.
Amadeo
As mentioned by Matt, there is a TaskFactory.FromAsync method that allows you to create a Task from a Begin/End pair. You need to enable asynchronous endpoints when you add your WCF reference, and then you can wrap them up yourself using extension methods.
As mentioned by Amadeo, there is a sample of this in the Async CTP, under the (C# WCF) Stock Quotes directory.
Also in that directory, there is a TaskWsdlImportExtension project. Add a reference to that dll and modify your .config as such:
<configuration>
<system.serviceModel>
<client>
<metadata>
<wsdlImporters>
<extension type="TaskWsdlImportExtension.TaskAsyncWsdlImportExtension, TaskWsdlImportExtension" />
</wsdlImporters>
</metadata>
</client>
</system.serviceModel>
</configuration>
Then you don't have to do your own wrapping at all; the TaskWsdlImportExtension will do it for you.
It is quite common to have asynchronous clients calling a synchronous service.
The following client and service contracts match (a bit magic used behind the scenes):
[ServiceContract( Namespace="X", Name="TheContract" )]
public interface IClientContractAsynchronous
{
[OperationContract]
Task<TResponse> SendReceiveAsync( TRequest req );
}
[ServiceContract( Namespace="X", Name="TheContract" )]
public interface IServiceContractSynchronous
{
[OperationContract]
TResponse SendReceive( TRequest req );
}
The client interface is directly awaitable:
var response = await client.Channel.SendReceiveAsync( request );
It is not possible to use out or ref parameters in the operaton contract. All response data must be passed in the return value. This actually was a breaking change for me.
I use this interface in AsyncWcfLib, it supports a Actor based programming model.
You rightly point out that async/await are built around methods returning Task and Task (for a great explanation of the working of async/await, see here). Here's how to generate Task based methods for a WCF service:
Visual Studio 2012 RC has an additional check-box in the "Configure Service Reference" dialog box: "Generate task based operations". While I don't see that option documented in the MSDN, I expect it exists specifically to allow seamless async/await on WCF calls.
For earlier versions, take a look at this post, describing an extension which allows generating Task<> based methods on WCF even with the CTP.

Categories