patterncsharpMinor
Old-way of asynchronous programming in ASP.NET MVC 3
Viewed 0 times
mvcasynchronousprogrammingwaynetoldasp
Problem
On ASP.NET MVC, I try to write an async Controller action with the old asynchronous programming model (actually, it is the current one, new one is still a CTP).
Here, I am trying to run 4 operations in parallel and it worked great. Here is the complete code:
```
public class SampleController : AsyncController {
public void IndexAsync() {
AsyncManager.OutstandingOperations.Increment(4);
var task1 = Task.Factory.StartNew(() => {
return GetReponse1();
});
var task2 = Task.Factory.StartNew(() => {
return GetResponse2();
});
var task3 = Task.Factory.StartNew(() => {
return GetResponse3();
});
var task4 = Task.Factory.StartNew(() => {
return GetResponse4();
});
task1.ContinueWith(t => {
AsyncManager.Parameters["headers1"] = t.Result;
AsyncManager.OutstandingOperations.Decrement();
});
task2.ContinueWith(t => {
AsyncManager.Parameters["headers2"] = t.Result;
AsyncManager.OutstandingOperations.Decrement();
});
task3.ContinueWith(t => {
AsyncManager.Parameters["headers3"] = t.Result;
AsyncManager.OutstandingOperations.Decrement();
});
task4.ContinueWith(t => {
AsyncManager.Parameters["headers4"] = t.Result;
AsyncManager.OutstandingOperations.Decrement();
});
task3.ContinueWith(t => {
AsyncManager.OutstandingOperations.Decrement();
}, TaskContinuationOptions.OnlyOnFaulted);
}
public ActionResult IndexCompleted(string headers1, string headers2, string headers3, string headers4) {
ViewBag.Headers = string.Join("", headers1, headers2, headers3, headers4);
return View();
}
public ActionResult Index2() {
ViewBag.Headers = string.Join("", GetReponse1(), GetResponse2(), GetResponse3(), GetResponse4());
Here, I am trying to run 4 operations in parallel and it worked great. Here is the complete code:
```
public class SampleController : AsyncController {
public void IndexAsync() {
AsyncManager.OutstandingOperations.Increment(4);
var task1 = Task.Factory.StartNew(() => {
return GetReponse1();
});
var task2 = Task.Factory.StartNew(() => {
return GetResponse2();
});
var task3 = Task.Factory.StartNew(() => {
return GetResponse3();
});
var task4 = Task.Factory.StartNew(() => {
return GetResponse4();
});
task1.ContinueWith(t => {
AsyncManager.Parameters["headers1"] = t.Result;
AsyncManager.OutstandingOperations.Decrement();
});
task2.ContinueWith(t => {
AsyncManager.Parameters["headers2"] = t.Result;
AsyncManager.OutstandingOperations.Decrement();
});
task3.ContinueWith(t => {
AsyncManager.Parameters["headers3"] = t.Result;
AsyncManager.OutstandingOperations.Decrement();
});
task4.ContinueWith(t => {
AsyncManager.Parameters["headers4"] = t.Result;
AsyncManager.OutstandingOperations.Decrement();
});
task3.ContinueWith(t => {
AsyncManager.OutstandingOperations.Decrement();
}, TaskContinuationOptions.OnlyOnFaulted);
}
public ActionResult IndexCompleted(string headers1, string headers2, string headers3, string headers4) {
ViewBag.Headers = string.Join("", headers1, headers2, headers3, headers4);
return View();
}
public ActionResult Index2() {
ViewBag.Headers = string.Join("", GetReponse1(), GetResponse2(), GetResponse3(), GetResponse4());
Solution
There is a lot of code repetition. I would create a custom class that inherits from Task and make it generic enough so you can have an array of your custom class and just loop through that array to do what you need to do.
I would also have
and finally I would use it like this
It is much less code, you can reuse it later, you can very easily add a new TaskController if you want to work with another URL, and it's a lot more readable.
To use this you will need to just edit
class TaskController : Task
{
public TaskController(AsyncManager asyncManager, string asyncManagerParameter, Func callback) : base(callback)
{
this.ContinueWith(t =>
{
//just for demonstration
Console.WriteLine(t.Result);
// Do some work with your asyncManager
asyncManager.Parameters[asyncManagerParameter] = t.Result.ToString();
});
}
}I would also have
GetResponse take a string uri as parameter instead of making a new GetResponse for each url that you want to use. public static string GetResponse(string uri)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
req.Method = "HEAD";
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
return resp.Headers.ToString(); // just changed this for demonstration purposes
}and finally I would use it like this
AsyncManager asyncManager = new AsyncManager();
TaskController[] taskControllers = {
new TaskController(asyncManager, "header1", () => GetResponse("http://google.com")),
new TaskController(asyncManager, "header3", () => GetResponse("http://www.twitter.com"))
};
foreach (TaskController tc in taskControllers)
{
tc.Start();
}It is much less code, you can reuse it later, you can very easily add a new TaskController if you want to work with another URL, and it's a lot more readable.
To use this you will need to just edit
this.ContinueWith inside TaskController and have it do whatever you want (decrement, etc)Code Snippets
class TaskController<T> : Task<T>
{
public TaskController(AsyncManager asyncManager, string asyncManagerParameter, Func<T> callback) : base(callback)
{
this.ContinueWith(t =>
{
//just for demonstration
Console.WriteLine(t.Result);
// Do some work with your asyncManager
asyncManager.Parameters[asyncManagerParameter] = t.Result.ToString();
});
}
}public static string GetResponse(string uri)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
req.Method = "HEAD";
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
return resp.Headers.ToString(); // just changed this for demonstration purposes
}AsyncManager asyncManager = new AsyncManager();
TaskController<string>[] taskControllers = {
new TaskController<string>(asyncManager, "header1", () => GetResponse("http://google.com")),
new TaskController<string>(asyncManager, "header3", () => GetResponse("http://www.twitter.com"))
};
foreach (TaskController<string> tc in taskControllers)
{
tc.Start();
}Context
StackExchange Code Review Q#7380, answer score: 2
Revisions (0)
No revisions yet.