patterncsharpMinor
.NET WCF Activator for sync and async calls
Viewed 0 times
callsasyncactivatornetforandwcfsync
Problem
I decided to re-write my code responsible for WCF calls, as all of my methods had
I am not sure about the code used for async. My doubts are based on this article.
Note - some code removed for brevity.
Here is the code for activators:
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Threading.Tasks;
using System.Web;
namespace MyProject.Concrete
{
public class SvcActivator
{
public delegate void ServiceMethod(T proxy);
private BasicHttpBinding binding
{
get
{
return new BasicHttpBinding
{
MaxReceivedMessageSize = int.MaxValue,
MaxBufferPoolSize = int.MaxValue
};
}
}
public static void Use(ServiceMethod method, string url)
{
var channelFactory = new ChannelFactory(binding);
var endpoit = new EndpointAddress(url);
IClientChannel proxy = (IClientChannel)channelFactory.CreateChannel(endpoit);
bool success = false;
try
{
method((T)proxy);
proxy.Close();
success = true;
}
catch (Exception)
{
throw;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
public static Task UseAsync(ServiceMethod method, string url, HttpBindingBase binding)
{
var channelFactory = new ChannelFactory(binding);
var endpoit = new End
try-catch-finally blocks. I read that it is bad idea to use a using() statement as it does not close the WCF connection. After digging around, I found a solution based on delegates. Yesterday I decided to add an activator for calls that are made by async controllers in my MVC Web API app.I am not sure about the code used for async. My doubts are based on this article.
Note - some code removed for brevity.
Here is the code for activators:
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Threading.Tasks;
using System.Web;
namespace MyProject.Concrete
{
public class SvcActivator
{
public delegate void ServiceMethod(T proxy);
private BasicHttpBinding binding
{
get
{
return new BasicHttpBinding
{
MaxReceivedMessageSize = int.MaxValue,
MaxBufferPoolSize = int.MaxValue
};
}
}
public static void Use(ServiceMethod method, string url)
{
var channelFactory = new ChannelFactory(binding);
var endpoit = new EndpointAddress(url);
IClientChannel proxy = (IClientChannel)channelFactory.CreateChannel(endpoit);
bool success = false;
try
{
method((T)proxy);
proxy.Close();
success = true;
}
catch (Exception)
{
throw;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
public static Task UseAsync(ServiceMethod method, string url, HttpBindingBase binding)
{
var channelFactory = new ChannelFactory(binding);
var endpoit = new End
Solution
You don't want to use
Instead, use the naturally-asynchronous methods that are available in your WCF client proxy. (Side note: if the proxy is from a very old Visual Studio version, you may need to recreate it).
Then you can look at making your
Next, your
Your DAL can use it as such:
The end result is that you are using
Task.Run from WebAPI (or other service frameworks) because that interferes with the ASP.NET thread pool heuristics.Instead, use the naturally-asynchronous methods that are available in your WCF client proxy. (Side note: if the proxy is from a very old Visual Studio version, you may need to recreate it).
Then you can look at making your
SvcActivator truly asynchronous. First, you'll need an asynchronous delegate type:public delegate Task ServiceMethodAsync(T proxy);Next, your
UseAsync method:public static async Task UseAsync(ServiceMethodAsync method, string url)
{
var channelFactory = new ChannelFactory(binding);
var endpoit = new EndpointAddress(url);
IClientChannel proxy = (IClientChannel)channelFactory.CreateChannel(endpoit);
bool success = false;
try
{
await method((T)proxy);
proxy.Close();
success = true;
}
catch (Exception)
{
throw;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}Your DAL can use it as such:
public async Task GetOrderAsync(int id)
{
Order order = null;
await SvcActivator.UseAsync(async svc =>
{
order = await svc.GetOrderAsync(id);
}, "url_goes_here");
return order;
}The end result is that you are using
async all the way, rather than wrapping a synchronous WCF call (GetOrder) within a Task.Run.Code Snippets
public delegate Task ServiceMethodAsync(T proxy);public static async Task UseAsync(ServiceMethodAsync method, string url)
{
var channelFactory = new ChannelFactory<T>(binding);
var endpoit = new EndpointAddress(url);
IClientChannel proxy = (IClientChannel)channelFactory.CreateChannel(endpoit);
bool success = false;
try
{
await method((T)proxy);
proxy.Close();
success = true;
}
catch (Exception)
{
throw;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}public async Task<Order> GetOrderAsync(int id)
{
Order order = null;
await SvcActivator<IOrdersService>.UseAsync(async svc =>
{
order = await svc.GetOrderAsync(id);
}, "url_goes_here");
return order;
}Context
StackExchange Code Review Q#57656, answer score: 2
Revisions (0)
No revisions yet.