Routing and ASP.NET MVC woes !!!
So you have created a MVC application and worked on it a bit, and now your Global.asax contains calls to a setup of your RouteCollection that has got complex logic inside it and now you need to understand your routing better and perhaps fix that particular scenario where routing does not seem to work (keep in mind for instance that the first match algorithm is used when using your MVC routing table). How to understand those routes in a better way without staring at your code. How about interpreting it at realtime using a runtime debugger for just that case. First off, download the
ASP.NET MVC Routing Debugger Visualizer tool.
Go to the following url:
http://visualstudiogallery.msdn.microsoft.com/2993e666-4534-49c8-807f-e8bffcaee7e0
Keep in mind that this should be easily installed in Visual Studio 2010 using the Tools => Extension Manager dialog in DevEnv.
Now we need to "patch" your system to allow this tool to work.
First off edit the devenv.exe.config file to allow loading remote sources:
Open the file
C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe.config
Inside the runtime xml element node add the following:
<loadFromRemoteSources enabled="true" />
Just to double check, check that the dll is added to the following folder:
C:\Program Files\Microsoft Visual Studio 10.0\Common7\Packages\Debugger\Visualizers
There should now be a file called MvcRouteVisualizer.dll in this folder, this is the library which constitutes the ASP.NET MVC Route debugger visualizer tool.
Start the MVC application with debugging turned on and add a breakpoint in a MVC controller action, I tested this tool out with the HomeController About action in my basic templated ASP.NET MVC application for instance. Hit Ctrl+D+Q (quickwatch) and add a watch to the System.Web.Routing.RouteTable.Routes object (which is a collection of the routes to monitor for our app) and hit the available magnify icon button to the right of the value column of our watch window in our debugger.
If all now went well, you should have this nifty tool to display the routes in our MVC app. This way, if the routing seem to have gone berserk and you cant understand why your nice routing table is not correctly set up, MVC Route visualizer routing tool comes to your rescue.
Here is a screenshot of this great tool, happy coding!
Saturday, 31 December 2011
Thursday, 29 December 2011
Creating custom ActionResult
It is possible to inherit the ActionResult class and create a custom ActionResult.
The following class creates a new kind of ActionResult for spewing out the serialized string of an inputted data contract instance.
You will need to add a reference to the System.Runtime.Serialization assembly and namespace. We use DataContractSerializer to serialize the object to a string value. The stream in use is the context.HttpContext.Response.OutputStream, where context is the ControllerContext (current).
It is required to set the ContentType to "text/xml" to output xml.
Usage, adding a test method to homecontroller (ignore Hungarian notation, this is for demonstration purposes..) :
Then we get the xml outputted of the data contract passed in:
The morale of the story, to create a new kind of ActionResult:
- inherit from ActionResult
- implement abstract method ExecuteResult
The following class creates a new kind of ActionResult for spewing out the serialized string of an inputted data contract instance.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Runtime.Serialization;
namespace TestActionMethodSelectorAttribute.ActionResult
{
public class DataContractSerializedResult : System.Web.Mvc.ActionResult
{
private object data;
public DataContractSerializedResult(object data)
{
this.data = data;
}
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.Response;
response.ContentType = "text/xml";
DataContractSerializer serializer = new DataContractSerializer(data.GetType());
serializer.WriteObject(response.OutputStream, data);
}
}
}
You will need to add a reference to the System.Runtime.Serialization assembly and namespace. We use DataContractSerializer to serialize the object to a string value. The stream in use is the context.HttpContext.Response.OutputStream, where context is the ControllerContext (current).
It is required to set the ContentType to "text/xml" to output xml.
Usage, adding a test method to homecontroller (ignore Hungarian notation, this is for demonstration purposes..) :
public DataContractSerializedResult About2()
{
return new DataContractSerializedResult(
new AgeNameDataContract
{
Age = 93,
Name = "Gamla Olga"
});
}
Then we get the xml outputted of the data contract passed in:
The morale of the story, to create a new kind of ActionResult:
- inherit from ActionResult
- implement abstract method ExecuteResult
Timing your MVC Actions
Add the following attribute to your MVC actions to view the timing of your mvc actions using System.Diagnostics.Stopwatch class.
This is another filter attribute example.
Usage (homecontroller):
It is nice to output the elapsed time in millisecond in the http headers, since we then easily can monitor the values outside Visual Studio, in our browser:
This is another filter attribute example.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Diagnostics;
namespace TestActionMethodSelectorAttribute.Attributes
{
public class StopwatchAttribute : ActionFilterAttribute
{
private Stopwatch _stopWatch;
public StopwatchAttribute()
{
_stopWatch = new Stopwatch();
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
_stopWatch.Start();
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
_stopWatch.Stop();
var response = filterContext.HttpContext.Response;
response.AddHeader("X-elapsed-milliseconds", _stopWatch.ElapsedMilliseconds.ToString());
}
}
}
Usage (homecontroller):
[Stopwatch]
public ActionResult About()
{
return View();
}
It is nice to output the elapsed time in millisecond in the http headers, since we then easily can monitor the values outside Visual Studio, in our browser:
Using ActionMethodSelectorAttribute in MVC
If you want an MVC controller action to be only available for Ajax methods, use theAjaxMethodSelectorAttribute. Inherit this abstract class to create the attribute AjaxOnlyAttribute below and tag this attribute with your method:
Usage (testing the attribute out in HomeController):
If the current request is not an AjaxRequest, a Http 404 is returned. The attribute [HttpPost] and [HttpGet]is inherited from the ActionMethodSelectorAttribute. They also implement the abstract method IsValidForRequest.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace TestActionMethodSelectorAttribute.Attributes
{
public class AjaxOnlyAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
return controllerContext.HttpContext.Request.IsAjaxRequest();
}
}
}
Usage (testing the attribute out in HomeController):
[AjaxOnly]
public ActionResult About()
{
return View();
}
If the current request is not an AjaxRequest, a Http 404 is returned. The attribute [HttpPost] and [HttpGet]is inherited from the ActionMethodSelectorAttribute. They also implement the abstract method IsValidForRequest.
Monday, 26 December 2011
Asynchronous MVC controllers end to end example
=== PREAMBLE ===
My intended audience:
1) You are a programmer or articial being understanding code (probably the former)
2) You work with ASP.NET MVC
3) You must take in use asynchronous processing to handle a slow and time consuming
MVC action and want to learn how to implement an AsyncController.
If this is the case, please read on!
== PREAMBLE ===
I guess many of you know how to create an ordinary MVC controller inheriting from System.Web.Mvc.Controller class, but what about creating an Asynchronous MVC controller?
It is possible to opt-in asynchronous controllers in MVC out of the box of the MVC framework. This will be a code sample of how this is possible. The goal of the asynchronous controller will be to provide better scalability, especially for complex calculations that take long which are accessed by many simultaneous users. Beware though, the standard synchronous design is easier to relate to and will be suitable in many standard scenarios. Asynchronous controllers should only be applied where there is a good reason to expect bottlenecks to be present in the code and in a real production environment.
Moving on to the asynchronous controller. Instead of inheriting from the controller class, inherit from the System.Web.Mvc.AsyncController class in MVC. The following code shows how to create an asynchronous controller.
Code sample follows:
The class in this example is called TestAsyncController. It inherits from the AsyncController class. The class contains two action methods which is called IndexAsync and IndexCompleted. In general, for every asynchronoous MVC action, there must be two method suffixed with Async and Completed, just like every controller must be suffixed with Controller (part of the design by contract conventions in MVC).
I put the attribute [AsyncTimeout(60000)] here, it is possible to specify in milliseconds how long an async timeout should be allowed to execute before timing out. It is also possible to use the attribute [NoAsynctimeout] instead.
Further on, I use the static method ThreadPool.QueueUserWorkItem to add an asynchronous call in the current Thread Pool. I use the AsyncManager.OutstandingOperations.Increment() and corresponding Decrement() methods to keep track of the pending asynchronous calls. AsyncManager is part of System.Web.Mvc.Async namespace. This book keeping is required for correctly arriving at the Complete method that will receive the asynchronous result. For convenience, I move the result to the TempData dictionary. This will be available for me in the Complete method in my controller. Since the data I get is a string, I just copy it to the ViewBag (dynamic object) and this is then just displayed in the MVC view Index.cshtml in the folder TestAsync.
Here is the service contract for the NewsService used (WCF service):
As you can see, the WCF service tags the operation BeginGetSomeNews with the AsyncPattern equals set to true to allow asynchronous execution. Not only will the IIS service not receive a blocking call, the service itself is also run asynchronous in this case. The WCF service also got a pair of methods this time prefixed with Begin and End. Only the Begin method is attributed with [AsyncPattern=true], the end method is not even attributed with OperationItem attribute without any overloads. This is because the end method is just a callback for the Begin method. As in asynchronous programming, the Begin method starts by receiving its parameters, followed by AsyncCallback callback, object asyncState paramteters. The End method returns string in this case and also receives such an object.
The service implementation looks like this:
I use a class called CompletedAsyncResult, this looks like this (MSDN is the source):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace TestServices
{
public class CompletedAsyncResult : IAsyncResult
{
T data;
public CompletedAsyncResult(T data)
{ this.data = data; }
public T Data
{ get { return data; } }
#region IAsyncResult Members
public object AsyncState
{ get { return (object)data; } }
public WaitHandle AsyncWaitHandle
{ get { throw new Exception("The method or operation is not implemented."); } }
public bool CompletedSynchronously
{ get { return true; } }
public bool IsCompleted
{ get { return true; } }
#endregion
}
}
Then, I just added a Service Reference to the WCF class library containing my service to generate a proxy or service agent to access my WCF service in my controller, as seen in the first code.
Important GOTCHAS about asynchronous MVC controllers:
My intended audience:
1) You are a programmer or articial being understanding code (probably the former)
2) You work with ASP.NET MVC
3) You must take in use asynchronous processing to handle a slow and time consuming
MVC action and want to learn how to implement an AsyncController.
If this is the case, please read on!
== PREAMBLE ===
I guess many of you know how to create an ordinary MVC controller inheriting from System.Web.Mvc.Controller class, but what about creating an Asynchronous MVC controller?
It is possible to opt-in asynchronous controllers in MVC out of the box of the MVC framework. This will be a code sample of how this is possible. The goal of the asynchronous controller will be to provide better scalability, especially for complex calculations that take long which are accessed by many simultaneous users. Beware though, the standard synchronous design is easier to relate to and will be suitable in many standard scenarios. Asynchronous controllers should only be applied where there is a good reason to expect bottlenecks to be present in the code and in a real production environment.
Moving on to the asynchronous controller. Instead of inheriting from the controller class, inherit from the System.Web.Mvc.AsyncController class in MVC. The following code shows how to create an asynchronous controller.
Code sample follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Threading;
namespace SubstitutePartInCompositionContainer.Controllers
{
public class TestAsyncController : AsyncController
{
[AsyncTimeout(60000)]
public ActionResult IndexAsync()
{
AsyncManager.OutstandingOperations.Increment();
ThreadPool.QueueUserWorkItem((s) =>
{
ServiceReference1.NewsServiceClient client =
new ServiceReference1.NewsServiceClient();
TempData["news"] = client.GetSomeNews("Steinkjer");
AsyncManager.OutstandingOperations.Decrement();
}, null);
return View();
}
public ActionResult IndexCompleted()
{
ViewBag.DateStamp = DateTime.Now;
ViewBag.News = TempData["news"] as string;
return View();
}
}
}
The class in this example is called TestAsyncController. It inherits from the AsyncController class. The class contains two action methods which is called IndexAsync and IndexCompleted. In general, for every asynchronoous MVC action, there must be two method suffixed with Async and Completed, just like every controller must be suffixed with Controller (part of the design by contract conventions in MVC).
I put the attribute [AsyncTimeout(60000)] here, it is possible to specify in milliseconds how long an async timeout should be allowed to execute before timing out. It is also possible to use the attribute [NoAsynctimeout] instead.
Further on, I use the static method ThreadPool.QueueUserWorkItem to add an asynchronous call in the current Thread Pool. I use the AsyncManager.OutstandingOperations.Increment() and corresponding Decrement() methods to keep track of the pending asynchronous calls. AsyncManager is part of System.Web.Mvc.Async namespace. This book keeping is required for correctly arriving at the Complete method that will receive the asynchronous result. For convenience, I move the result to the TempData dictionary. This will be available for me in the Complete method in my controller. Since the data I get is a string, I just copy it to the ViewBag (dynamic object) and this is then just displayed in the MVC view Index.cshtml in the folder TestAsync.
Here is the service contract for the NewsService used (WCF service):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace TestServices
{
[ServiceContract]
public interface INewsService
{
[OperationContract(AsyncPattern=true)]
IAsyncResult BeginGetSomeNews(string city, AsyncCallback callback,
object asyncState);
string EndGetSomeNews(IAsyncResult result);
}
}
As you can see, the WCF service tags the operation BeginGetSomeNews with the AsyncPattern equals set to true to allow asynchronous execution. Not only will the IIS service not receive a blocking call, the service itself is also run asynchronous in this case. The WCF service also got a pair of methods this time prefixed with Begin and End. Only the Begin method is attributed with [AsyncPattern=true], the end method is not even attributed with OperationItem attribute without any overloads. This is because the end method is just a callback for the Begin method. As in asynchronous programming, the Begin method starts by receiving its parameters, followed by AsyncCallback callback, object asyncState paramteters. The End method returns string in this case and also receives such an object.
The service implementation looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Threading;
namespace TestServices
{
public class NewsService : INewsService
{
public IAsyncResult BeginGetSomeNews(string city, AsyncCallback callback,
object asyncState)
{
Thread.Sleep(3000); //simulate some sleep
return new
CompletedAsyncResult("Here are some news for " + city);
}
public string EndGetSomeNews(IAsyncResult result)
{
var resultFromAsync = result as CompletedAsyncResult;
return resultFromAsync.Data;
}
}
}
I use a class called CompletedAsyncResult, this looks like this (MSDN is the source):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace TestServices
{
public class CompletedAsyncResult
{
T data;
public CompletedAsyncResult(T data)
{ this.data = data; }
public T Data
{ get { return data; } }
#region IAsyncResult Members
public object AsyncState
{ get { return (object)data; } }
public WaitHandle AsyncWaitHandle
{ get { throw new Exception("The method or operation is not implemented."); } }
public bool CompletedSynchronously
{ get { return true; } }
public bool IsCompleted
{ get { return true; } }
#endregion
}
}
Then, I just added a Service Reference to the WCF class library containing my service to generate a proxy or service agent to access my WCF service in my controller, as seen in the first code.
Important GOTCHAS about asynchronous MVC controllers:
- There is no explicit call between the Async and Completed method in the MVC controller inheriting from AsyncController. This is code by design or contract.
- We must "help" MVC keep track of the outstandingoperations for the AsyncManager in our code. When the counter turns to zero again, the async operation decrementing the value last will call its Complete method.. Use AsyncManager throughout.
- Google blogger does not handle generic arguments well, but the CompletedAsyncResult object takes string as a generic type argument in my demo code here. It could be a complex type such as a data contract.
- There are many more methods of achieving this, this is just one example.