Asynchronously consume synchronous WCF service - c#

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.

Related

Show server counter on GUI while still in progress

My question is pretty simple, but I got lost somehow.
I have a project including ClientProject and ServerProject (WCF service application) contains my Service class and its interface.
The service runs method with few iterations.
All I need to do is to show on GUI the service's number of iteration on real time,
so that the user will be able to be aware to service activity state while running.
I've seen examples of declaring a delegate ServerEventHandler on service,
and registration to that event on client side.
For example:
ServiceProject:
public delegate void ServerEventHandler(object sender, EventArgs e);
public event ServerEventHandler ServerEvent; <br/><br/>
ClientProject:
public Client(Server s)
{
s.ServerEvent += new Server.ServerEventHandler(Subscribe);
}
But I can not figure out how can I implement it on my WCF project, since my client and server are separated projects so that the only way I can get my ServiceProject values on my ClientProject is through its ServiceReference.
I can't understand how can the client have the service instance, and how can it access the ServerEvent property through it.
What am I missing?
Do I have to mention anything on my contract? Or is there any other way to implement it?
I'd be thankful If you'll be able to help me..
you can implement WSDualHttpBinding which allows you to define callback contract
WCF comes with async variance for each operation..you can call async operation on Callback Operation so server process will keep running....Even callback will have DataContract so just create DataContract class which will hold all values which you want to show in UI..Imagine callback as Service exposed by client so that Server can notify client by calling appropriate operation.

Calling async methods from a WCF service

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.

How to call a web service in "fire and forget" way from ASP.Net

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.

WCF communicating between services on a server

I'm implementing an alert type system within my company LAN using WCF callbacks. It has a subscribe mechanism etc. I've used this tutorial as a starting point but I changed the binding to NetTcpBinding instead of wsDualHttpBinding and I'm self hosting in a Windows service.
That's working quite nicely but I have a question. Most of my clients do not need callback. They are various desktop applications that only need to send a one way alert to the server which will be passed on to those clients running the callback enabled "Notify" application and subscribed to that type of alert.
I might be concerned about nothing here but since my WCF service implements callback, all the clients need to implement a callback object whether they need callback or not. It would seem like a more tidy solution if the one way clients communicated with a service that does not do callback.
So ... I created another endpoint without callback in my WCF Service. It just has a simple one way method call. That works but my problem is that I can't quite figure out how to pass the received message to the callback enabled service.
My Windows Service has something like this:
internal static ServiceHost myNotifyHost;
internal static ServiceHost mySendingHost;
protected override void OnStart(string[] args)
{
// service with callback
myNotifyHost = new ServiceHost(typeof(NotifyService));
myNotifyHost.Open();
// service without callback
mySendingHost = new ServiceHost(typeof(SendingService));
mySendingHost.Open();
}
In my SendingService method that is called by the sendonly client, I thought I'd be able to do this:
var notify = (NotifyService)WindowsService.myNotifyHost.SingletonInstance;
notify.SendMessage("Message text");
SendMessage() sends the callback messages out to subscribed clients. Unfortunately, myNotifyHost.SingletonInstance is always null even when there is a client connected and waiting for callback. I guess I'm misunderstanding what that property means. NortifyService has these attributes
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
Is there a way that I can communicate between the two services? Should I give up and this and just stick to the one service and just live with implementing the meaningless callback class in those clients that don't need it. At this point it's not a big deal. It's more to do with my understanding of WCF.
Thanks
Try this,
public class NotifyService
{
public static NotifyService DefaultInstace;
public NotifyService()
{
DefaultInstace = this;
}
///.....SNIP......
}

How to make a call to my WCF service asynchronous?

I have a WCF service that I call from a windows service.
The WCF service runs a SSIS package, and that package can take a while to complete and I don't want my windows service to have to wait around for it to finish.
How can I make my WCF service call asynchronous? (or is it asynchronous by default?)
All your needs will be satisfied in the following articles from MSDN:
Implementing an Async Service Operation
Calling WCF Service Async
Designing Service Contracts
On Visual Studio 2010, on the Add Service Reference > click Advanced button > check the Generate Asynchronous Operations checkbox.
After doing so, the Async operations will be added and be available for your use.
Service side:
[ServiceContract]
public interface IMyService
{
[OperationContract]
bool DoWork(int i);
}
Client side:
[ServiceContract(Name = nameof(IMyService))]
public interface IMyServiceClient : IMyService
{
[OperationContract]
Task<bool> DoWorkAsync(int i);
}
the WCF Proxy inside of your client (Windows Service?) needs to be specified at creation that you wish to have Asynchronous operations available.
You can modify an existing WCF Proxy by right clicking on it and choosing 'Configure Service Reference' From here you just need to check the tick box next to 'Generate asynchronous operations'
Ok so that is the WCF Proxy side of things taken care of.
Now you need to use APM (Asynchronous Programming Model) with the Proxy inside of your client.

Categories