I decided to re-write my code responsible for WCF calls, as all of my methods had 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<T>
{
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<T>(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<T>(binding);
var endpoit = new EndpointAddress(url);
IClientChannel proxy = (IClientChannel)channelFactory.CreateChannel(endpoit);
bool success = false;
return Task.Run(() =>
{
try
{
method((T)proxy);
proxy.Close();
success = true;
}
catch (Exception)
{
throw;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
});
}
}
}
Here is sample DAL:
using System;
using System.Configuration;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using MyProject.OrdersService;
namespace MyProject.Concrete
{
public class OrdersDAL : CommonDAL
{
public Order GetOrder(int id)
{
Order order = null;
SvcActivator<IOrdersService>.Use(svc =>
{
order = svc.GetOrder(id);
}, "url_goes_here");
return order;
}
public async Task<Order> GetOrderAsync(int id)
{
Order order = null;
await SvcActivator<IOrdersService>.UseAsync(svc =>
{
order = svc.GetOrder(id);
}, "url_goes_here");
return order;
}
}
}
And finally, here is sample API controller:
namespace MyProject.Controllers
{
public class OrdersController : CommonController
{
private OrdersDAL ordersDAL;
public OrdersController()
{
ordersDAL = new OrdersDAL();
}
//sync call
[HttpGet, Route("orders/{id}")]
public HttpResponseMessage GetOrder(int id)
{
try
{
var order = ordersDAL.GetOrder(id);
if (order == null)
{
return RequestHelper.CreateResponse(Request, HttpStatusCode.NotFound, "Order not found.");
}
return RequestHelper.CreateResponse(Request, HttpStatusCode.OK, order);
}
catch (Exception ex)
{
//Error logging here
}
}
//async method call
[HttpGet, Route("orders/{id}")]
public async Task<HttpResponseMessage> GetOrder(string id)
{
try
{
var order = await ordersDAL.GetOrderAsync(id);
if (order == null)
{
return RequestHelper.CreateResponse(Request, HttpStatusCode.NotFound, "Order not found.");
}
return RequestHelper.CreateResponse(Request, HttpStatusCode.OK, order);
}
catch (Exception ex)
{
//Error logging here
}
}
}
}