I want to call asynchronous methods from a WCF service, something like:
[ServiceContract]
interface IService
{
[OperationContract]
int SomeMethod(int data);
}
int SomeMethod(int data)
{
var query = ... build LINQ query;
var response = await query.ToListAsync();
return response.Length;
}
I don't want to add async to the IService interface or SomeMethod method. Using asynchronous methods is an internal issue that shouldn't be reflected in the interface.
How can I do that?
CLARIFICATION:
My problem here is using await in a non-async method. I don't want the service contract to change (the client doesn't necessarily know what async is), and I don't want to split the method into BeginSomeMethod and EndSomeMethod. I want one method that uses await internally.
Whether the server is using sync or async code does not matter for the client. Client and server are separated by a well-specified wire-protocol (often SOAP). SOAP has no notion of asynchronous completion.
You can have a sync server and an async client, or vice versa. The client cannot even detect whether the server is sync or async. This is an implementation detail. The server could be a wrist watch running Linux and you still couldn't tell.
The style of IO you use is an implementation detail and does not influence the bytes that go over the network.
So pick what you like. The client can still use async IO to access the server.
I'm not sure why this is such a surprise to people. In other contexts this seems very intuitive: You can have a asynchronous TCP server and a synchronous client. I can say new WebClient().DownloadString(url) and download a string synchronously from a web-server that is implemented in an asynchronous way. I cannot even tell what server software is running.
Use Fiddler to look at what goes over the wire when you make a WCF call. There is no notion of synchronous or asynchronous calls.
Under the hood, when you invoke a service asynchronously, the WCF client library using TCP sockets in an asynchronous way. When you invoke synchronously, TCP sockets are being used with blocking calls. That's the entire difference.
WCF generated clients can be made to have asynchronous methods in addition to the synchronous methods. Select the "Generate asynchronous operations" option in the UI. Now you have both versions. Both fully functional.
Here's how you can convince yourself of this with an experiment: Write a sync server, and call it both sync and async from the same .NET client. Now write a 2nd server asynchronously (in any style you like) and use the exact same client code to call it.
Task and IAsyncResult are not serializable over SOAP anyway so it cannot possibly be the case that a Task is transmitted to the client.
Related
I’m currently in the process of migrating a client application over to .NET 4.5 to make use of async/await. The application is a client for a WCF service which currently offers only synchronous services. I am wondering now, how should I asynchronously consume this synchronous service?
I am using channel factories to connect to the WCF service, utilizing a service contract that is shared between both server and client. As such, I cannot use the auto-generation from VisualStudio or svcutil to generate asynchronous client proxies.
I have read this related question which is about whether to wrap the synchronous call on the client-side using Task.Run, or whether to extend the service contract with async methods instead. The answer suggests that having “real” asynchronous methods offered by the server is better for the client performance as no thread will have to actively wait for the service call to finish. This does make a lot of sense to me, and it would mean that the synchronous calls should be wrapped on the server-side.
On the other hand, Stephen Toub discorages doing this in general in this blog post. Now, he does not mention WCF there, so I am not sure if this just applies to libraries that run on the same machine, or if it also applies to things that run remotely, but where the introduction of asynchronicity has an actual impact on the connection/transfer.
And after all, as the server does not actually work asynchronously anyway (and likely won’t for another while), some threads will always have to wait: Either on the client or on the server. And that does also apply when consuming the services synchronously (currently, the client waits on a background thread to keep the UI responsive).
Example
To make the problem more clear, I have prepared an example. The full project is available for download here.
The server offers a synchronous service GetTest. This is the one that currently exists, and where the work happens—synchronously. One option would be to wrap this in an asynchronous method, for example using Task.Run, and offer that method as an additional service in the contract (requiring the contract interface to be expanded).
// currently available, synchronous service
public string GetTest() {
Thread.Sleep(2000);
return "foo";
}
// possible asynchronous wrapper around existing service
public Task<string> GetTestAsync() {
return Task.Run<string>(() => this.GetTest());
}
// ideal asynchronous service; not applicable as work is done synchronously
public async Task<string> GetTestRealAsync() {
await Task.Delay(2000);
return "foo";
}
Now, on the client-side, this service is created using a channel factory. That means I only have access to the methods as defined by the service contract, and I especially don’t have access to asynchronous service methods unless I explicitely define and implement them.
Depending on which methods are now available, I have two options:
I can asynchronously call the synchronous service by wrapping the call:
await Task.Run<string>(() => svc.GetTest());
I can asynchronously call the asynchronous service directly, which is provided by the server:
await svc.GetTestAsync();
Both works fine, and will not block the client. Both methods involve busy waiting on some end: Option 1 waits on the client, which is equivalent to what has been done before in a background thread. Option 2 waits on the server by wrapping the synchronous method there.
What would be the recommended way to make a synchronous WCF service async-aware? Where should I perform the wrapping, on the client or on the server? Or are there better options to do this without having to wait anywhere, i.e. by introducing “real” asynchronicity on the connection—like the generated proxies do?
The client side and server side are totally separate from an async standpoint, they do not care about each other at all. You should have your sync function on your sever and only the sync function on your server.
If you want to do it "right", on the client you will not be able to reuse the same interface for your generating your channel factory as the interface that is used to generate the server.
So your server side would look like this
using System.ServiceModel;
using System.Threading;
namespace WcfService
{
[ServiceContract]
public interface IService
{
[OperationContract]
string GetTest();
}
public class Service1 : IService
{
public string GetTest()
{
Thread.Sleep(2000);
return "foo";
}
}
}
and your client side would look like this
using System;
using System.Diagnostics;
using System.ServiceModel;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SandboxForm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var button = new Button();
this.Controls.Add(button);
button.Click += button_Click;
}
private async void button_Click(object sender, EventArgs e)
{
var factory = new ChannelFactory<IService>("SandboxForm.IService"); //Configured in app.config
IService proxy = factory.CreateChannel();
string result = await proxy.GetTestAsync();
MessageBox.Show(result);
}
}
[ServiceContract]
public interface IService
{
[OperationContract(Action = "http://tempuri.org/IService/GetTest", ReplyAction = "http://tempuri.org/IService/GetTestResponse")]
Task<string> GetTestAsync();
}
}
If your server-side API can be naturally async (like your Task.Delay example, rather than the Task.Run wrapper), declare it as Task-based in the contract interface. Otherwise, just leave it synchronous (but don't use Task.Run). Do not create multiple endpoints for the sync and async versions of the same method.
The generated WSDL remains the same for async and sync contract APIs, I just found out that myself: Different forms of the WCF service contract interface. Your clients will keep running unchanged. By making your server-side WCF method asynchronous, all you do is improve the service scalability. Which is a great thing to do, of course, but wrapping a synchronous method with Task.Run would rather hurt the scalability than improve it.
Now, the client of your WCF service doesn't know if the method is implemented as synchronous or asynchronous on the server, and it doesn't need to know that. The client can call your method synchronously (and block the client's thread) or it can call it asynchronously (without blocking the client's thread). In either case, it won't change the fact that the SOAP response message will be sent to the client only when the method has fully completed on the server.
In your test project, you're trying to exposes different versions of the same API under different contract names:
[ServiceContract]
public interface IExampleService
{
[OperationContract(Name = "GetTest")]
string GetTest();
[OperationContract(Name = "GetTestAsync")]
Task<string> GetTestAsync();
[OperationContract(Name = "GetTestRealAsync")]
Task<string> GetTestRealAsync();
}
This doesn't really make sense, unless you want to give your client an option to control if the method runs synchronously or asynchronously on the server. I cannot see why you would want this, but even if you have your reason, you'd be better off controlling this via a method argument and a single version of the API:
[ServiceContract]
public interface IExampleService
{
[OperationContract]
Task<string> GetTestAsync(bool runSynchronously);
}
Then, in the implementation your could do:
Task<string> GetTestAsync(bool runSynchronously)
{
if (runSynchronously)
return GetTest(); // or return GetTestAsyncImpl().Result;
else
return await GetTestAsyncImpl();
}
#usr explains this in great details here. To sum up, it is not like the WCF service calls back your client to notify about the completion of the async operation. Rather, it simply sends back the full SOAP response using the underlying network protocol when it's done. If you need more than that, you could use WCF callbacks for any server-to-client notifications, but that would span the boundaries of a single SOAP message.
This isn't horrible: https://stackoverflow.com/a/23148549/177333. You just wrap your return values with Task.FromResult(). You have to change the service side, but it's still synchronous and you're not using an extra thread. That changes your server-side interface which can still be shared with the client so it can wait asynchronously. Otherwise it looks like you have to maintain separate contracts on server and client somehow.
I have a web service that I want to call from one of my asp.net classes.
I can call my web service successfully.But now I need to call this service asynchronously. I need to call it and NOT wait for the service to complete execution. I don't need to process a response from the service and don't need to verify if the service executed successfully. All I want is to be able to call the service and be free to do other things.
You need to consume web service asynchronously.
Goto and check
AddServiceReference -> Advance -> generate asynchronous operations.
after this async callback events will be available to you for every method
Suppose you have ABC method in you service when you will consume it by as sync these methods will be available to you in your application
1>ABC (fire and wait for output)
2>ABCAsync(fire and forget)
3>ABC callback event(get fired <if ABCAsync is called> when data available in your application)
One way to implement a fire-and-forget approach is to use the IsOneWay property on the OperationContract attribute, like this:
[OperationContract(IsOneWay=true)]
public void SomeMethod(string someValue);
When set to true, the operation won't return a message. Note that methods marked as one-way cannot have return types or ref or out parameters (which makes sense). It also should not be confused with asynchronous calls, because it's not the same thing (in fact, a one-way call can block on the client if it takes a while to get a connection, for example).
See OperationContractAttribute.IsOneWay Property for more information.
Have you tried this:?
http://msdn.microsoft.com/en-us/library/bb885132(v=vs.110).aspx
this is another way to do it, check it out.
I'm very new to Web API and I have an unusual pattern that I need to implement. In the Post method of my controller, it is to take an object which includes a CallbackURL. It will then immediately return an HTTP response to the caller. Afterwards, it will use a 3rd party, off-site API to perform some work with the object. Once that work is done, the controller is to post the results of that work to the CallbackURL.
However, I do not know how to implement this in Web API. Once I return the HTTP response, the controller's lifecycle is over, correct? If so, how do I perform the work I need to do after I return the response?
If you only need to post results to a url and not to the client that initiated the call, you could possibly do something as easy as this:
public string MyAPIMethod(object input)
{
Task.Factory.StartNew(() =>
{
//call third-party service and post result to callback url here.
});
return "Success!";
}
The api call will return right away, and the Task you created will continue the processing in a different thread.
Creating a task to finish up the request (as suggested by Jason P above) will most likely solve the problem, thread-safety provided. However that approach might hurt the performance of your Web service if calls to the 3rd party API take a significant amount of time to complete and/or you are expecting many concurrent clients. If that was the case, your problem seems to be the perfect candidate for a service pattern called "Request/Acknowledge/Callback" (also "Request/Acknowledge/Relay"). Using that pattern, your Web API method will just store each request (including the callback URL) into a queue/database and return quickly. A separate module (possibly running on more than one machine, depending on the number and complexity of the tasks) will take care of completing the tasks, and subsequently notifying completion through the callback URL (please see http://servicedesignpatterns.com/ClientServiceInteractions/RequestAcknowledge).
This is presuming you want to return the results of your 3rd-party query to the caller.
You're correct, this is outside of what's possible with WebAPI. Once you return the HTTP Response, the client also has no connection to your server.
You should look into Asp.Net SignalR, which allows a persistent connection between the client and server, working in modern browsers, and even back to IE7 (though officially unsupported), as well as supporting non-browser clients.
You can then do a couple of things, all of which require the client to connect to SignalR first.
Option 1: You can call your WebApi controller, which can return, but not before launching a task. This task can query the 3rd party api, then invoke a function on the caller via SignalR with the results that you want to provide.
Option 2: You can call a SignalR Hub action, which can talk back to your client. You can tell your client the immediate response, query the 3rd-party api, then return the results you want to provide.
I am currently implementing an application protocol library relying on TCP/IP for transport (long lasting connection).
I am trying to achieve a nice asynchronous implementation relying on TAP pattern using C#5 async/await constructs, mainly to put into practice the concepts I have only seen in theory up until now.
The client can connect to a remote server and send requests to it.
client receives response from the server as well as requests (full duplex mode).
From the point of view of the client code, the asynchronous call to my library to send a request to the server and receive the associated response is as simple as :
var rsp = await session.SendRequestAsync(req);
From inside my protocol library, I am just buliding the request, converting it to bytes (to be sent on the network stream) and I call WriteAsync on the stream and I then await on a Task created just before sending the request, making use of a TaskCompletionSource object, which is basically waiting for the associated response to be received (and setting the result on the tcs), and then return the response to the client caller.
This part seems fine.
Now the "problem" concerns the part where server is sending requests to the client. There are different type of requests that the server can send to the client.
My protocol library is using an asynchronous loop to listen to the underlying stream (receiving incoming responses or requests from the server).
This loop is reading responses/requests asynchronously on the stream, then in case of a request from the server, it raises an event corresponding to the request type (such as ReceivedRequestTypeA). The client code can subscribe to these events to be notified when a specific request type is received from the server. The event args of these contains all the parameters associated with the request as well as a response object, to be set by the client, which will be asynchronously sent on the stream by library once event handler code is completed.
The code for the asynchronous listen loop is as follow. Please do not mind the while true, not very pretty (cancelation pattern should be used instead), but this is not the point !
private async Task ListenAsync()
{
while(true)
{
Request req = await ReadRequestAsync();
await OnReceivedRequest(req);
}
}
So the loop is calling the asynchronous method ReadRequestAsync which is just reading some bytes asynchronously in the stream until a complete request or response is available.
Then it forwards the request to the asynchronous method OnReceivedRequest which code can be seen below :
private async Task OnReceivedRequest(Request req)
{
var eventArgs = new ReceivedRequestEventArgs { Req = req };
if (req is RequestTypeA)
{ ReceivedRequestTypeA(this, eventArgs); }
[... Other request types ...]
await SendResponseAsync(eventArgs.Resp);
}
This asynchronous method raise the appropriate request type event.
The client code is subscribed to this event, so its appropriate event handler method is called ... the client code does whatever it needs with the request and then construct a response and set it in the EventArgs object -end of event handler method-. The code resumes in OnReceivedRequest in the library, and the response is sent asynchronously (calling WriteAsync on the underlying stream).
I don't think this is a good approach, as it can completely block the asynchronous loop in the library if the event handler code on client side is doing a lengthy blocking operation (bye bye fully asynchronous protocol library, you are now becoming somehow synchronous due to client code). The same would happened if I was using an asynchronous task based delegate for events and awaiting on it.
I was thinking that instead of using events, I could have an asynchronous method GetRequestTypeAAsync() which would be implemented using TaskCompletionSource object in library, and the tcs result being set with the request in OnReceivedRequest. And on client code side, instead of subscribing to ReceivedRequestTypeA event, the code would rather consist of a loop arround GetRequestTypeAAsync(). Still as the client code must somehow provide a response to the library to be sent to server, I don't know how this could work ...
My brain is completely fuzzy right now and can't really think clear. Any suggestion for a nice design will be greatly appreciated.
Thanks !
I'm also working on async/await TCP/IP sockets, and I strongly recommend you take a look at TPL Dataflow. It's pretty easy to make async-friendly endpoints using two BufferBlocks (one for reads and one for writes).
In my system, the TCP/IP socket wrapper exposes a simple ISourceBlock<ArraySegment<byte>> representing the raw reads. This is then linked to a TransformManyBlock which performs message framing, and from there it can be linked to a TransformBlock which parses the bytes into actual message instances.
This approach works best if you have a RequestType base class from which all your other message types inherit. Then you can have a single receiving task that just (asynchronously) receives RequestType message instances from the end of the dataflow pipeline.
I need to be able to cancel async calls made to my webservice. One solution I have is to use manage my own threads, and use synchronous methods from the SOAP client. This works fine and it needs some more fine grained thread management.
If I used any of these two patterns provided from adding a web service reference, say:
var Client = new ASL_WS.SvcSoapClient()
IAsyncResult result = Client.BeginAuthenticateUser(Email, Password, new AsyncCallback(AuthCompleted));
or
var Client = new ASL_WS.SvcSoapClient()
Client.AuthenticateUserCompleted += AuthCompleted;
Client.AuthenticateUserAsync(Email, Passsword);
do any of these two patterns give me a way of cancelling the request? One use case could be: a user logs in, but wants to cancel before the authenticate call completes.
Of course, I could implement this differently by modifying the asyncState passed to these calls, and setting it to disable UI update, but it's not what I'm looking for.
Could I just just cancel all outstanding operations. Does Client.Abort() cancel such operations. What if there are many async requests, are all cancelled? Are there any other API methods that can do this?
Yes, you can use Abort method but keep below notes in mind. You can also use CancelAsync.
Abort notes: http://msdn.microsoft.com/en-us/library/aa480512.aspx
When you call the Abort method, any outstanding requests will still complete, but they will complete with a fault. This means that if you are using callbacks, your callback function will still be called for each outstanding request . When the EndInvoke method is called, or in our case, the wrapper function EndDelayedResponse, then a fault will be generated indicating that the underlying connection has been closed.
CancelAsync example: http://www.codeproject.com/KB/cpp/wsasync.aspx