Showing posts with label patterns. Show all posts
Showing posts with label patterns. Show all posts

Monday, November 7, 2011

PRG Pattern - How to Keep MVC ModelState

According to the definition of the HTTP POST and GET verbs:

  1. HTTP GET is used for non-changing (idempotent) data to your model.

  2. HTTP POST is used for changing data to your model.


Given this clear delineation, when receiving form data in your post back action method, return RedirectToAction(), which will result in a HTTP 302 (temporary redirect) and will generate a GET on the. This results in Post-Redirect-Get pattern.

One of the issue with this pattern, when using Asp .Net MVC, is that when validation fails or any exception occurs you have to copy the ModelState into TempData. Kazi Mansur has a great solution posted here under the sub section "13. Use PRG Pattern for Data Modification".

The examples he shows is:

[sourcecode language="csharp"]
public abstract class ModelStateTempDataTransfer : ActionFilterAttribute
{
protected static readonly string Key = typeof(ModelStateTempDataTransfer).FullName;
}

[AcceptVerbs(HttpVerbs.Get), OutputCache(CacheProfile = "Dashboard"), StoryListFilter, ImportModelStateFromTempData]
public ActionResult Dashboard(string userName, StoryListTab tab, OrderBy orderBy, int? page)
{
//Other Codes
return View();
}

[AcceptVerbs(HttpVerbs.Post), ExportModelStateToTempData]
public ActionResult Submit(string userName, string url)
{
if (ValidateSubmit(url))
{
try
{
_storyService.Submit(userName, url);
}
catch (Exception e)
{
ModelState.AddModelError(ModelStateException, e);
}
}

return Redirect(Url.Dashboard());
}
[/sourcecode]

and for the Action Filter itself

[sourcecode language="csharp"]
public class ExportModelStateToTempData : ModelStateTempDataTransfer
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Only export when ModelState is not valid
if (!filterContext.Controller.ViewData.ModelState.IsValid)
{
//Export if we are redirecting
if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
{
filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
}
}

base.OnActionExecuted(filterContext);
}
}

public class ImportModelStateFromTempData : ModelStateTempDataTransfer
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary;

if (modelState != null)
{
//Only Import if we are viewing
if (filterContext.Result is ViewResult)
{
filterContext.Controller.ViewData.ModelState.Merge(modelState);
}
else
{
//Otherwise remove it.
filterContext.Controller.TempData.Remove(Key);
}
}

base.OnActionExecuted(filterContext);
}
}
[/sourcecode]


I like the way this has been handled but because I like to learn from other people's ideas I also like to use the workflow for HTTP POSTs as described by Jimmy Bogard in his post, Cleaning up POSTs in ASP.NET MVC.

In short each action that requires a POST using the following ActionResult:

[sourcecode language="csharp"]
public class FormActionResult<T> : ActionResult
{
public ViewResult Failure { get; private set; }
public ActionResult Success { get; private set; }
public T Form { get; private set; }

public FormActionResult(T form, ActionResult success, ViewResult failure)
{
Form = form;
Success = success;
Failure = failure;
}

public override void ExecuteResult(ControllerContext context)
{
if (!context.Controller.ViewData.ModelState.IsValid)
{
Failure.ExecuteResult(context);

return;
}

var handler = ObjectFactory.GetInstance<IFormHandler<T>>();

handler.Handle(Form);

Success.ExecuteResult(context);
}
}[/sourcecode]

Which not only cleans up the POST workflow and makes testing so much easier but it also helps separate application concerns. In the original Action Filter there is a guard clause to ensure that the Filter Context result is either a RedirectResult or a RedirectToRouteResult

[sourcecode language="csharp"]
if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
[/sourcecode]

So how do we add the clause so that the result can be of the Generic type of FormActionResult? By using reflection.
[sourcecode language="csharp"]
if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult) || (filterContext.Result.IsTypeOfGeneric(typeof(FormActionResult<>))))
[/sourcecode]

where the signature IsTypeOfGeneric is an extension method which looks like the following:
[sourcecode language="csharp"]
public static bool IsTypeOfGeneric<T>(this T source, Type genericTypeToCompare)
{
if (!genericTypeToCompare.IsGenericType)
throw new ApplicationException(@"Compare type needs to be generic");

if (!source.GetType().IsGenericType)
throw new ApplicationException(@"Base type needs to be generic");

return source.GetType().GetGenericTypeDefinition()==genericTypeToCompare;
}
[/sourcecode]

The msdn definition of the method GetGenericTypeDefinition is here

Now we can use FormActionResult within our code and the ModelState will be saved from the POST to the GET.

Wednesday, January 19, 2011

Using StructureMap Automocker To Make Writing Tests fun.

I have for a period of time been a big fan of Jeremy Miller’s StructureMap library for Dependency Injection/Inversion Of Control. I particularly enjoy the Auto Registration and Type Scanning features of the library.

For instance within the Data Layer a registry such as:
[sourcecode language="csharp"]
public class DataRegistry : Registry
{
public DataRegistry()
{
Scan(x =&gt; { x.AddAllTypesOf(); x.ConnectImplementationsToTypesClosing(typeof(IRepository)); x.TheCallingAssembly(); });
}
}
[/sourcecode]

This class, which inherits from StructureMap.Configuration.DSLRegistry, will scan the types in the assembly that contains the Data Registry class, adds all implementations of IQuery to the the container and connects all implementation to the open generic IRepository.

I have recently discovered another feature that makes StructureMap one of my essential tools in my Development Toolkit. The aforementioned feature is Automocker, which comes in flavours such as RhinoAutoMocker and MoqAutoMocker. Automocker repurposes an IoC container to automate the creation and attachment of mock objects to a concrete class within unit tests. Certainly is a mouthful but hopefully an example will shed some light on the some of the advantages.

Let’s say you are writing Unit Tests for a Child Sponsorship website for Worldvision (something that happens quite a bit to me) and you have a class whose responsibility is to lock a user chosen child so that the child cannot be sponsored by another user of the site.

The class could look something like this:
[sourcecode language="csharp"]
public class ChildChosenForSponsorshipCommandHandler : ICommandHandler
{
private readonly IRepository _childRepository;
private readonly IChildOnHoldTimer _childOnHoldTimer;

public ChildChosenForSponsorshipCommandHandler(IRepository childRepository, IChildOnHoldTimer childOnHoldTimer)
{
_childRepository = childRepository;_
childOnHoldTimer = childOnHoldTimer;
}

public void Handle(Child child)
{
_childRepository.PlaceChildOnHold(child);
_childOnHoldTimer.Start();
}
}
[/sourcecode]

One test which could be written for this user story is
[sourcecode language="csharp"]
[Test]
public void ShouldPlaceChildOnHoldWhenChildIsChosenForSponsorship()
{
//arrangevar mockChildRepostory = MockRepository.GenerateMock();
var mockChildOnHoldTimer = MockRepository.GenerateMock();
var childChosenForSponsorshipCommandHandler = new ChildChosenForSponsorshipCommandHandler(mockChildRepostory,mockChildOnHoldTimer);

var child = new Core.Handlers.Child();

//actchildChosenForSponsorshipCommandHandler.Handle(child);

//assertmockChildRepostory.AssertWasCalled(x =&gt; x.PlaceChildOnHold(child));
}
[/sourcecode]

The way in which can be written using StructureMap’s AutoMocker assembly is:
[sourcecode language="csharp"]
[Test]
public void ShouldPlaceChildOnHoldWhenChildIsChosenForSponsorship()
{
//arrangevar childChosenForSponsorshipCommandHandler = new RhinoAutoMocker();

var child = new Core.Handlers.Child();

var classUnderTest = childChosenForSponsorshipCommandHandler.ClassUnderTest;

//actclassUnderTest.Handle(child);

//assertchildChosenForSponsorshipCommandHandler.Get().AssertWasCalled(x=&gt;x.PlaceChildOnHold(child));
}
[/sourcecode]

A whole ONE line less code, I’ll have that new feature out before lunch! On the surface in may not look like much but if the class under test (CUT) has three, four or more dependencies you’ve made the arranging of the Unit Test much easier. The greatest benefit of the AutoMocker that I can see is that it helps keep the content of your tests focused on what needs to be tested, the functionality of your system. It also helps to keep your tests less brittle as your objects evolve. That is, if you add another dependency as your code evolves and you’ve got 15 tests under this Test Fixture you won’t have 15 tests to fix so that you can get the green light. In other words you can concentrate on what is important the context of the next test.