Monday, May 14, 2012

Using TPL to access Async WCF Endpoints in ASP.net MVC

Using TPL to access Async WCF Endpoints in ASP.net MVC:
I am in the process of building out a internal portal/dashboard for our company which will allow us to get a status of what is going on behind the scenes in our application.  I want this site to utilize our existing WCF endpoint and as much existing code as possible.  When doing this I realized pretty quickly that I needed to create Async Controller actions to hit our async endpoints which was a first for me.  Of course the first thing I did was a quick Bing search to see if I could find some existing examples to help me a long.  However, every example I found assumed that we were using the automatically generated proxy to access our endpoints rather than spinning up the connection manually via ChannelFactory and the service interface.  Because I struggled to get this working I thought I would share my experiances in case others are having the same issue.
Our WCF Endpoint Definition
[ServiceContract]
public interface IScheduledEventsService
{
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginScheduledEvents(ScheduledEventsRequest request, AsyncCallback callback, object state);
Result<IList<ScheduledEvent>> EndScheduledEvents(IAsyncResult result);

}


One thing to point out about the code above, the actual return value from our endpoint is a Result<T>.  The result class is a simple container envelope which provides us back some metadata, this is not something to worry about or to try to find online, you can simply ignore this for your needs

My MVC controller definition


public class ScheduledActivitiesController : AsyncController
{
public Task<PartialViewResult> Listing()
{
return Task.Factory
.StartNew(() => GetScheduleActivitiesAsync())
.ContinueWith(x => PartialView("_Listing", x.Result.ToList()));
}

private IList GetScheduleActivitiesAsync()
{
var baseUrl = ConfigurationManager.AppSettings["BaseWcfServerUrl"];

var channel = ChannelHelper.CreateFor<IScheduledEventsService>(baseUrl);

var myTask = Task.Factory
.FromAsync(channel.BeginScheduledEvents,
new Func<IAsyncResult, Result<IList<ScheduledEvent>>>(channel.EndScheduledEvents),
new ScheduledEventsRequest(),
null,
TaskCreationOptions.None);

var taskResult = myTask.Result;

return taskResult.ResultItem;
}
}


The above code is our entire controller (well at least the important parts her).  Please take note of 3 things


  1. Our controller inherits off of AsyncController which is required to do async controller actions in MVC

  2. My return type is a Task<PartialView> for the action, this is required

  3. In the .ContinueWith I am returning the correct PartialView w/ the data



One thing I want to point out here is that when trying to get the .FromAsync logic to work I keep getting compiler warnings telling me about a mismatch.  This was because at first I was NOT declaring my two Func<T> and just assumed the compiler knew what I meant (guess not).  As soon as I actually defined my 2 Func<T> signatures (I have removed the first one as R# told me it was not needed and sure enough it was not) the compiler was happy.

As you can see, once you make the compiler happy (pesky compiler) this is pretty straight forward.  Hope this helps someone.

Till next time,




ICT4PE&D

No comments:

Post a Comment

Thank's!