Saturday, November 20, 2010

An extendable MVC2 ModelMetaDataProvider (OCP baby!)

So, last blog I mentioned that my ModelMetaDataProvider smelled like an OCP violation to me.  While technically it's only doing one thing right now, when I read Brad Wilsons blog on what he's doing, I decided I wanted that, but didn't want that big honking class doing all that stuff, so I figured I'd do a little refactoring. I started with this.
   1:  public class MetadataProvider : DataAnnotationsModelMetadataProvider
   2:      {
   3:          protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
   4:          {
   5:              var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
   6:              var linkText = attributes.OfType<LinkText>().FirstOrDefault();
   7:              if(linkText != null)
   8:                  metadata.AdditionalValues.Add("LinkText",linkText);
   9:   
  10:              return metadata;
  11:          }
  12:   
  13:      }

I just wanna have some interface that builds up a ModelMetaData. For simplicity sake, I'll just give it the same signature as DataAnnotationsModelMetadataProvider, but just allow you to send in the ModelMetaData that's already built.


   1:     public interface IModelMetaBuilder
   2:      {
   3:          ModelMetadata BuildUp(ModelMetadata metaData, IEnumerable<Attribute> attributes, Type containerType,
   4:                                Func<object> modelAccessor, Type modelType, string propertyName);
   5:      }


Then I'll make the MetadataProvider just get all instances of those from the container, loop through em all, and build up. That way we can add new behavior without opening it back up (yeah, that's OCP).

First, lets make my LinkText stuff from my last blog and move it into one of these,

   1:  public class LinkTextModelMetadataBuilder : IModelMetaBuilder
   2:      {
   3:          public ModelMetadata BuildUp(ModelMetadata metadata, IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
   4:          {
   5:              var linkText = attributes.OfType<LinkText>().FirstOrDefault();
   6:              if (linkText != null)
   7:                  metadata.AdditionalValues.Add("LinkText", linkText);
   8:              return metadata;
   9:          }
  10:      }

Now... Lets go fix my MetaDataProvider to use my IOC container of choice (StructureMap). To be honest, this is so simple, I'm kinda embarrased that I'm making a blog out of it - but hey, I've got no pride (yeah right).

   1:   public class MetadataProvider : DataAnnotationsModelMetadataProvider
   2:      {
   3:          private readonly IContainer _container;
   4:   
   5:          public MetadataProvider(IContainer container)
   6:          {
   7:              _container = container;
   8:          }
   9:   
  10:          protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
  11:          {
  12:              var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
  13:              var allBuilders = _container.GetAllInstances<IModelMetadataBuilder>();
  14:              foreach (var builder in allBuilders)
  15:              {
  16:                  builder.BuildUp(metadata, attributes, containerType, modelAccessor, modelType, propertyName);
  17:              }
  18:              return metadata;
  19:          }
  20:   
  21:      }

Next up, lets write a cute little registry for StructureMap that'll go get em all. Oh yeah, I renamed that interface to IModelMetadataBuilder. Here it is.

   1:   public class ModelMetadataProviderRegistry : Registry
   2:      {
   3:          public ModelMetadataProviderRegistry()
   4:          {
   5:              Scan(scanner =>
   6:                       {
   7:                           scanner.AssemblyContainingType(GetType());
   8:                           scanner.AddAllTypesOf<IModelMetadataBuilder>();
   9:                       });
  10:          }
  11:      }

And there we go...  Now we just gotta change the App_Start stuff that wired up the ModelMetadataProvider to inject the Container, or better yet, just go get the instance from the container. Like so (well like the last line here - line 13).

   1:   protected void Application_Start()
   2:          {
   3:   
   4:              StructureMapInitilizer.Initilize();
   5:   
   6:              new Bootstrapper(ObjectFactory.Container).BootstrapApplication();
   7:              //TODO: make this stuff bootstrap classes
   8:              AreaRegistration.RegisterAllAreas();
   9:              RegisterGlobalFilters(GlobalFilters.Filters);
  10:              RegisterRoutes(RouteTable.Routes);
  11:              Db = OpenDatabase();
  12:              ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory(ObjectFactory.Container));
  13:              ModelMetadataProviders.Current = ObjectFactory.Container.GetInstance<MetadataProvider>();
  14:   
  15:          }

Cool... and everything is still passing! Next up... I'm gunna go steal all the cool ModelMetaData stuff from everyone, but implement them in their own builders. First up is Brad Wilsons, because it's a whole lot of awesome.

All I need to do is to instead of inheriting the DataAnnotationsModelMetaDataProvider, I'll implement IModelMetadataBuilder. Since the signatures are almost exactly the same this is really easy. Here's what I ended up with.

   1:   public class WilsonModelMetadataBuilder : IModelMetadataBuilder
   2:      {
   3:          public ModelMetadata BuildUp(ModelMetadata metadata,IEnumerable<Attribute> attributes,
   4:                                                          Type containerType,
   5:                                                          Func<object> modelAccessor,
   6:                                                          Type modelType,
   7:                                                          string propertyName)
   8:          {
   9:   
  10:            
  11:   
  12:              // Prefer [Display(Name="")] to [DisplayName]
  13:              DisplayAttribute display = attributes.OfType<DisplayAttribute>().FirstOrDefault();
  14:              if (display != null)
  15:              {
  16:                  string name = display.GetName();
  17:                  if (name != null)
  18:                  {
  19:                      metadata.DisplayName = name;
  20:                  }
  21:   
  22:                  // There was no 3.5 way to set these values
  23:                  metadata.Description = display.GetDescription();
  24:                  metadata.ShortDisplayName = display.GetShortName();
  25:                  metadata.Watermark = display.GetPrompt();
  26:              }
  27:   
  28:              // Prefer [Editable] to [ReadOnly]
  29:              EditableAttribute editable = attributes.OfType<EditableAttribute>().FirstOrDefault();
  30:              if (editable != null)
  31:              {
  32:                  metadata.IsReadOnly = !editable.AllowEdit;
  33:              }
  34:   
  35:              // If [DisplayFormat(HtmlEncode=false)], set a data type name of "Html"
  36:              // (if they didn't already set a data type)
  37:              DisplayFormatAttribute displayFormat = attributes.OfType<DisplayFormatAttribute>().FirstOrDefault();
  38:              if (displayFormat != null
  39:                      && !displayFormat.HtmlEncode
  40:                      && String.IsNullOrWhiteSpace(metadata.DataTypeName))
  41:              {
  42:                  metadata.DataTypeName = DataType.Html.ToString();
  43:              }
  44:   
  45:              return metadata;
  46:          }
  47:      }

There ya go folks... Have fun with it.
If you pull down my code, just look in myDojo.Infrastructure.Web. It's all there.

Peace out!


E

MVC templating, LinkTextAttribute and List templates (Razor and MVC3)

So, while this isn't bad code.

   1:  <ul>
   2:      @foreach (var item in Model)
   3:      {
   4:          <li><a href='Details/@Model.id' title='@Model.Name'>@Model.Name</a></li>
   5:      }
   6:  </ul>

 


Frankly, I'm sick of writing it. How often do we write stuff like this? Just about one for every controller. This just isn't using the MVC stack to it's full potential - plus, I've been doing a lot of reading on templating on MVC2/3 and figured I'd give it a shot.

So, first thing I did was write a quick little template that'll work for any IEnumerable. For first pass, I didn't even worry about the links... just get a generic template for a UL. I added a new partial view in ~/Views/Shared/DisplayTemplates and named it UL.cshtml. Sheesh, I love Razor! Anyway it's pretty simple..


   1:  @model  System.Collections.IEnumerable
   2:  <ul>
   3:      @foreach(var item in Model){
   4:          <li>@Html.DisplayFor(m => item)</li>
   5:      }
   6:  </ul>

Note that I'm using Html.DisplayFor... If you're just pumping out values to the client like so @Model.SomePropery, you're really not using the MVC stack like you can be. Display templates give you free hooks to alter the html if the need arises for REALLY cheap, plus it gives you a central place to generate the html for a specific data type, no matter how complex or simple.


When I sent this model through it.


   1:   [DefaultProperty("Name")]
   2:      public class DojoDetails : ObjectWithIdentity 
   3:      {
   4:          
   5:          public virtual string Name { get; set; }
   6:          public virtual Address Address { get; set; }
   7:      }

It just generated a list of Names for Dojos. So now, what I wanna do is be able to mark the ViewModel with some Attribute that says "Hey, this is the Text and Here is the format and here is the value for the link". So I made this little attribute.


   1:   public class LinkText : Attribute
   2:      {
   3:          public string LinkFormatProperty { get; set; }
   4:          public string LinkFormatString { get; set; }
   5:      }

And I went and marked up my DojoDetails with it.


   1:   public class DojoDetails : ObjectWithIdentity 
   2:      {
   3:          [LinkText(LinkFormatProperty = "Id",LinkFormatString = "~/Dojos/Details/{0}")]
   4:          public virtual string Name { get; set; }
   5:          public virtual Address Address { get; set; }
   6:      }

Next task is to make sure we actually get that data down into the metadata for the view model. To do this, we need to write an implementation of DataAnnotationsModelMetadataProvider. It's got one method that we need to override (CreateMetadata). Not too difficult. The MVC stack put an AdditionalProperties Dictionary on ModelMetaData, so we'll just pump in the attribute right there so we can get to it in our templates. Here's how I did it.


   1:   public class MetadataProvider : DataAnnotationsModelMetadataProvider
   2:      {
   3:          protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
   4:          {
   5:              var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
   6:              var linkText = attributes.OfType<LinkText>().FirstOrDefault();
   7:              if(linkText != null)
   8:                  metadata.AdditionalValues.Add("LinkText",linkText);
   9:              return metadata;
  10:          }
  11:   
  12:      }
 
Simple enough, just see if the attribute is there, if so, add it. This code smells like a OCP violation, but I'm gunna leave it alone for now, since I wanna stay on task. 
 
Next up, I'm gunna go write a new template that'll grab that linktext attribute and create an anchor tag. I created a little ViewModel for the link so I can write a template for it - it's silly simple.

   1:   public class ModelLinkViewModel
   2:      {
   3:          public ModelLinkViewModel()
   4:          {
   5:   
   6:          }
   7:          public ModelLinkViewModel(string link, string text)
   8:          {
   9:              Url = link;
  10:              Text = text;
  11:          }
  12:   
  13:          public string Text { get; set; }
  14:          public string Url { get; set; }
  15:      }

 

Lets go mark up our view model now.

 

   1:    public class DojoDetails : ObjectWithIdentity 
   2:      {
   3:          [LinkText(LinkFormatProperty = "Id",LinkFormatString = "~/Dojos/Details/{0}")]
   4:          public virtual string Name { get; set; }
   5:          public virtual Address Address { get; set; }
   6:      }

 

Id is on ObjectWithIdentity, and we're just giving a virtual url to the details page. Now I'll create a little helper method that'll a ModelLinkViewModel from the DojoDetails.

 

   1:  public static class ModelMetaDataExtensions
   2:      {
   3:          public static ModelLinkViewModel LinkToModelDetails<TModel>(this HtmlHelper<TModel> helper)
   4:          {
   5:              var displayProperty = helper.ViewData.ModelMetadata.Properties.First(p => p.AdditionalValues.ContainsKey("LinkText"));
   6:              var linkTextAttribute = (ModelMetaData.LinkText)displayProperty.AdditionalValues["LinkText"];
   7:              var linkFormat = linkTextAttribute.LinkFormatString;
   8:              var linkProperty = helper.ViewData.ModelMetadata.Properties.First(p => p.PropertyName == linkTextAttribute.LinkFormatProperty);
   9:              var request = ServiceLocation.CurrentContainer.GetInstance<HttpRequestBase>();
  10:   
  11:              var link = request.Resolve(String.Format(linkFormat, linkProperty.Model));
  12:              if(! (displayProperty.Model is string))
  13:                  throw new InvalidOperationException(String.Format("[LinkText] can only be used on String properties. {0} is a {1}",displayProperty.PropertyName, displayProperty.ContainerType.Name));
  14:              var text = (String)displayProperty.Model;
  15:              return new ModelLinkViewModel(link, text);
  16:   
  17:          }
  18:      }
 
So, on link 5, I just go find the property marked with LinkText attribute. Once we have it, we pull all the data out of it. On Line 8, I'm going and getting the property mentioned in the LinkTextAttribute as the propery that has the value to format. Line 11 is just an extension I made that Resolves virtual url's and we just format up the link.
 
So now that that works, lets go make a template for the list item.
 

   1:  @model object
   2:  @using myDojo.Infrastructure.Web.HtmlHelpers;
   3:  @if (Model == null) {
   4:      <text>@ViewData.ModelMetadata.NullDisplayText</text>
   5:  }
   6:   
   7:  else if(ViewData.ModelMetadata.Properties.FirstOrDefault(p => p.AdditionalValues.ContainsKey("LinkText")) != null)
   8:  {
   9:    var x = Html.LinkToModelDetails();
  10:    <text>@Html.DisplayFor(m => x)</text>
  11:      
  12:  }else if (ViewData.TemplateInfo.TemplateDepth > 1)
  13:  {
  14:      <text>@ViewData.ModelMetadata.SimpleDisplayText</text>
  15:  }
 
Ok, so this has way too much defensive code, but whatever... really all we care about is line 7. We just go grab the LinkText property from the Model, and use the extension method to get a ModelLinkViewModel, then use our old friend DisplayFor. If there isn't a LinkText propery, it'll just display the DefaultPropery. 
 
For now, this is just gunna display .ToString() on ModelLinkViewModel - and I doubt our users wanna see the type of ModelLinkViewModel, so lets go write a template for that type.
 
Once again, I go add another view to ~/Views/Shared/DisplayTemplates, and I name it the Type that I wanna template.
 
Here it is. Really couldn't be much simpler.
 

   1:  @model myDojo.Infrastructure.Web.HtmlHelpers.ModelLinkViewModel
   2:  <a href='@Model.Url' title='@Model.Text'>@Model.Text</a>
 
There we go! 
So now, we go change the original list page to this.
 

   1:  @inherits System.Web.Mvc.WebViewPage<IEnumerable<MyDojo.Query.ViewModels.Dojos.DojoDetails>>
   2:   
   3:  @{
   4:      View.Title = "List";
   5:      Layout = "~/Views/Shared/_Layout.cshtml";
   6:  }
   7:   
   8:      <h2>All our Schools</h2>
   9:      
  10:      @Html.ActionLink("Create new school", "Create")
  11:   
  12:      @Html.DisplayForModel("UL")
  13:      
 
Note that I just tell it the template name (file minus extension name in ~Views/Shared/DisplayTemplates) and there we go... It all works.
 
There's a WHOLE lot I could do to clean this up... and I will, but I really wanted to see if I could get this to work. Lots and lots of goodies in the MVC stack, we really need to use them more!
 
If you wanna see it you can Git the code.
 
Have fun!
 

Tuesday, November 16, 2010

Contextual View - graceful degrading put still wizbangy!

Ok, So in my MyDojo project my I've got a really simple view to create a new school. Controller method looks like so.
   1:   public ActionResult Create()
   2:         {
   3:             var model = new CreateSchoolForm();
   4:             return View(model);
   5:         }



Really really simple... I typically start with UIs like this, then our UI engineers at work come and say "Oh, we wanna do this via ajax! Can you just change that to a Json method? Then we end up with 2 methods.

   1:   public ActionResult CreateAjax()
   2:         {
   3:             var model = new CreateSchoolForm();
   4:             return Json(model,JsonRequestBehavior.AllowGet);
   5:         }

So on the actual view, they'll actually set the url on a link to the Create action on the controller, but use Jquery to override the onclick on to just make an Ajax get to Create Ajax.

Something like this...


   1:   <script>
   2:          $(document).ready(function () {
   3:              $('#makeAjaxRequest').click(function (ev) {
   4:                  $.get(this.href.replace('Create','CreateAjax'), null, function (data) { alert(data); });
   5:                  ev.returnVal = false;
   6:                  return false;
   7:              });
   8:          });
   9:      </script>



I hate having 2 methods that do the exact same thing, and that the url that I gave them won't work (they've gotta replace the url for ajax). So sometimes I'll do this.

   1:   public ActionResult Create()
   2:         {
   3:             var model = new CreateSchoolForm();
   4:              return _request.IsAjaxRequest() ? (ActionResult)Json(model) : (ActionResult)View(model);
   5:         }

Ok, whatever... Simple enough, but I'm sick of forking code like that all the darn time. So I just added this to my abstract base controller.

   1:  protected ActionResult ContextualView(object model, string viewName=null)
   2:          {
   3:              if(Request.IsAjaxRequest())
   4:              {
   5:                  return Json(model, JsonRequestBehavior.AllowGet);    
   6:              }
   7:              return String.IsNullOrEmpty(viewName) ? View(model) : View(viewName, model);
   8:          }
 
Works like a charm!
 
Need to get this puppy encapsulated into it's own ActionResult class, that way we could use it with without inheriting the base controller class. Yeah, one day I'll do that. It just won't be today.

Friday, November 12, 2010

But you can't do that! Command Validators in the MVC stack

 

 

So, yeah, DataAnnotations are great.  I use them for Required, StringLength, Regex, and such. I use them, and you should too. In a CQRS system, you want to avoid issuing commands that won't succeed at all costs (uhhhh... duhhhhh).  I keep hearing Greg and Udi talk about how a shared library that can used that checks rules to check the validity of a command before issuing it. I can't find one, so I'm gunna do it. I'm thinking we just need a simple interface,  like so.
   1:  using myDojo.Infrastructure.CQRS.Commands;
   2:   
   3:  namespace myDojo.Infrastructure.CQRS.Validation
   4:  {
   5:      public interface IValidate<TCommand> where TCommand : ICommand
   6:      {
   7:          bool IsValid(TCommand command);
   8:      }
   9:  }

What I'm thinking is that I'll just use my IOC container to go get all these, execute each of them for a command. If any of them fails, we don't issue the command, and by checking what IValidate failed, we know why, and can communicate that to the user.

I think something like this...

   1:  using System.Collections.Generic;
   2:  using myDojo.Infrastructure.CQRS.Commands;
   3:   
   4:  namespace myDojo.Infrastructure.CQRS.Validation
   5:  {
   6:      public interface ICommandValidator<TCommand> where TCommand : ICommand
   7:      {
   8:          bool IsValid<TCommand>(TCommand command);
   9:          IEnumerable<IValidate<TCommand>> FailedRules { get; set; }
  10:      }
  11:  }



I guess that looks good... Lets try and make an implementation.  Test first.

   1:  using myDojo.Infrastructure.CQRS.Commands;
   2:  using myDojo.Infrastructure.CQRS.Validation;
   3:  using NUnit.Framework;
   4:  using Rhino.Mocks;
   5:  using StructureMap;
   6:   
   7:  namespace myDojo.Domain.UnitTests.Infrastructure
   8:  {
   9:      [TestFixture]
  10:      public class when_using_the_command_validator
  11:      {
  12:          
  13:          [Test]
  14:          public void if_a_validator_fails_is_valid_will_return_false()
  15:          {
  16:              if_the_command_is_not_valid();
  17:              when_Validate_Command_is_called();
  18:              _isValid.ShouldBeFalse();
  19:          }
  20:          
  21:          private void if_the_command_is_not_valid()
  22:          {
  23:              var validatorThatWillReturnFalse = MockRepository.GenerateMock<IValidate<SomeTestCommand>>();
  24:              validatorThatWillReturnFalse.Stub(v => v.IsValid(_command)).Return(false);
  25:              ObjectFactory.Inject(validatorThatWillReturnFalse);
  26:          }
  27:   
  28:          private CommandValidator<SomeTestCommand> _validator;
  29:          private SomeTestCommand _command;
  30:          private bool _isValid;
  31:   
  32:   
  33:          public void when_Validate_Command_is_called()
  34:          {
  35:              _validator = new CommandValidator<SomeTestCommand>(ObjectFactory.Container);
  36:              _isValid = _validator.IsValid(_command);
  37:          }
  38:          [SetUp]
  39:          public void establish_context()
  40:          {
  41:              ObjectFactory.Initialize(a => { });
  42:              _command = new SomeTestCommand();
  43:              
  44:          }
  45:      }
  46:      public class SomeTestCommand : ICommand
  47:      {
  48:          
  49:      }
  50:  }

Ok, so I'm just mocking up a validator that will fail, and making sure IsValid returns false. Here's what I did to make it pass.

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using myDojo.Infrastructure.CQRS.Commands;
   5:  using StructureMap;
   6:   
   7:  namespace myDojo.Infrastructure.CQRS.Validation
   8:  {
   9:      public class CommandValidator<TCommand> : ICommandValidator<TCommand> where TCommand : ICommand
  10:      {
  11:          private readonly IContainer _container;
  12:   
  13:          public CommandValidator(IContainer container)
  14:          {
  15:              _container = container;
  16:          }
  17:   
  18:          public bool IsValid(TCommand command)
  19:          {
  20:              foreach(var validator in _container.GetAllInstances<IValidate<TCommand>>())
  21:              {
  22:                  if (!validator.IsValid(command))
  23:                      return false;
  24:              }
  25:              return true;
  26:          }
  27:   
  28:          public IEnumerable<IValidate<TCommand>> FailedRules
  29:          {
  30:              get { throw new NotImplementedException(); }
  31:              set { throw new NotImplementedException(); }
  32:          }
  33:      }
  34:  }
So, that one is good. Lets go add a test to make sure the positive is good (when there's only valid commands). Here she is.
 

   1:  [Test]
   2:          public void if_the_validator_passes_is_valid_will_return_false()
   3:          {
   4:              if_the_command_is_valid();
   5:              when_Validate_Command_is_called();
   6:              _isValid.ShouldBeTrue();
   7:          }
   8:          private void if_the_command_is_valid()
   9:          {
  10:              var validatorThatWillReturnFalse = MockRepository.GenerateMock<IValidate<SomeTestCommand>>();
  11:              validatorThatWillReturnFalse.Stub(v => v.IsValid(_command)).Return(true);
  12:              ObjectFactory.Inject(validatorThatWillReturnFalse);
  13:          }



Next up, lets get the failed command.

   1:    [Test]
   2:          public void failed_rules_will_contain_the_failed_validator()
   3:          {
   4:              if_the_command_is_not_valid();
   5:              when_Validate_Command_is_called();
   6:              _validator.FailedRules.ShouldContain(ObjectFactory.GetInstance<IValidate<SomeTestCommand>>());
   7:          }



We just go inject a failing command, then go make sure it gets added to FaildRules. Fails now (because we didn't write the code)... Lets go fix it.

Couple changes here, but pretty simple.

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using myDojo.Infrastructure.CQRS.Commands;
   5:  using StructureMap;
   6:   
   7:  namespace myDojo.Infrastructure.CQRS.Validation
   8:  {
   9:      public class CommandValidator<TCommand> : ICommandValidator<TCommand> where TCommand : ICommand
  10:      {
  11:          private readonly IContainer _container;
  12:          private List<IValidate<TCommand>> _failedRules;
  13:   
  14:          public CommandValidator(IContainer container)
  15:          {
  16:              _container = container;
  17:              _failedRules = new List<IValidate<TCommand>>();
  18:          }
  19:   
  20:          public bool IsValid(TCommand command)
  21:          {
  22:              foreach(var validator in _container.GetAllInstances<IValidate<TCommand>>())
  23:              {
  24:                  if (!validator.IsValid(command))
  25:                      _failedRules.Add(validator);
  26:              }
  27:              return _failedRules.Count() == 0;
  28:          }
  29:   
  30:          public IEnumerable<IValidate<TCommand>> FailedRules { get { return _failedRules; } }
  31:      }
  32:  }
 
Instead of just short-circuiting the check for failed validators in the loop, now I just add each failed one to the collection, and then just return that true if the collection count is 0. Oh yeah, I removed the setter on FailedRules from the interface, since we won't need that.
 
And she passes!
 
Ok, let's go use it now. What I'm thinking is that (for now), I'll just plug it into my CommandActionResult. I probably could get prettier, but lets just make it work first.
 
Here's what CommandActionResult.ExecuteResult looks like now.
 

   1:   public override void ExecuteResult(ControllerContext context)
   2:          {
   3:              
   4:              if (!context.Controller.ViewData.ModelState.IsValid)
   5:              {
   6:                  ValidationFailedResult().ExecuteResult(context);
   7:                  return;
   8:              }
   9:              ICommandHandlerResult result = null;
  10:             
  11:              var handler = Container.GetInstance<ICommandHandler<TCommand>>();
  12:              result = handler.Handle(Command);
  13:              if(result is Success)
  14:              {
  15:                  Success().ExecuteResult(context);
  16:                  return;
  17:              }
  18:              CommandFailedResult(result).ExecuteResult(context);
  19:          }


So, before we even get the handler (line 11), lets just go get the CommandValidator and check it first.


Here's what I got now.

   1:  public override void ExecuteResult(ControllerContext context)
   2:          {
   3:   
   4:              if (!context.Controller.ViewData.ModelState.IsValid)
   5:              {
   6:                  ValidationFailedResult().ExecuteResult(context);
   7:                  return;
   8:              }
   9:   
  10:              var validator = Container.GetInstance<ICommandValidator<TCommand>>();
  11:   
  12:              if (!validator.IsValid(Command))
  13:              {
  14:                  ValidationFailedResult().ExecuteResult(context);
  15:                  return;
  16:              }
  17:   
  18:              ICommandHandlerResult result = null;
  19:             
  20:              var handler = Container.GetInstance<ICommandHandler<TCommand>>();
  21:              result = handler.Handle(Command);
  22:              if(result is Success)
  23:              {
  24:                  Success().ExecuteResult(context);
  25:                  return;
  26:              }
  27:              CommandFailedResult(result).ExecuteResult(context);
  28:          }
 
Kinda ugly... We've got 2 places where we're executing that ValidationFailedResult. That kinda smells, but I'd hate to go get the validator if I don't need it right? Screw it... I'm gunna go try this puppy out, then try to clean it up. 
 
Lets go make a validator to make sure we don't create dupe email addresses. So, I'm actually making a new assembly for my validators because validation will use both Commands and Queries - and I don't want either of those having a ref to each other. 
 
Here's my validator.
 

   1:  using myDojo.Infrastructure;
   2:  using myDojo.Infrastructure.CQRS.Validation;
   3:  using MyDojo.Query.ViewModels;
   4:   
   5:  namespace myDojo.Commands.Users.Validation
   6:  {
   7:      public class EmailAddressMustBeUnique : IValidate<RegisterUser>
   8:      {
   9:          private readonly IReadModelRepository<MartialArtistDetails> _readModelRepository;
  10:   
  11:          public EmailAddressMustBeUnique(IReadModelRepository<MartialArtistDetails> readModelRepository)
  12:          {
  13:              _readModelRepository = readModelRepository;
  14:          }
  15:   
  16:          public bool IsValid(RegisterUser command)
  17:          {
  18:              return _readModelRepository.GetSingle(m => m.EmailAddress == command.EmailAddress) == null;
  19:          }
  20:      }
  21:  }
 
 
Give it a shot..
 

Server Error in '/' Application.



StructureMap Exception Code:  202
No Default Instance defined for PluginFamily myDojo.Infrastructure.CQRS.Validation.ICommandValidator`1[[myDojo.Commands.Users.RegisterUser, myDojo.Commands, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], myDojo.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

 
I actually knew that was gunna happen, but I wanted my blog to be a bit longer so I could show off about structure map. Gotta go tell SM to add all those validators. Simple enough....
 
Here's my quick integration test for my registry.
 

   1:   [Test]
   2:          public void get_a_EmailIsUnique_validator()
   3:          {
   4:              _container.GetAllInstances<IValidate<RegisterUser>>()
   5:                  .FirstOrDefault(v => v is EmailAddressMustBeUnique).ShouldNotBeNull();
   6:          }
 
Registry to make it pass looks like so.
 

   1:   
   2:   
   3:  using myDojo.Infrastructure.CQRS.Validation;
   4:  using StructureMap.Configuration.DSL;
   5:   
   6:  namespace myDojo.Commands.Users.Validation
   7:  {
   8:      public class CommandValidationRegistry : Registry 
   9:      {
  10:          public CommandValidationRegistry()
  11:          {
  12:              Scan(s =>
  13:                       {
  14:                           s.AssemblyContainingType(GetType());
  15:                           s.ConnectImplementationsToTypesClosing(typeof (IValidate<>));
  16:                           s.ConnectImplementationsToTypesClosing(typeof (ICommandValidator<>));
  17:                       });
  18:          }
  19:      }
  20:  }


Lets try the web again (that's what I get for not TDDing, huh?)...


Same freeking thing?! Oh yeah, that's because I've been working all day and my brain is fried. I forgot to add ref to the new assembly to my web project. Ok... add it, and...

What the??! Same thing... Time to go look at that test again. I'm missing something


Duh! I only tested that we could get a IValidate<RegisterUser>, not an ICommandValidator. New test looks like so.

   1:   [Test]
   2:          public void get_a_RegisterUser_CommandValidator()
   3:          {
   4:              _container.GetInstance<ICommandValidator<RegisterUser>>().ShouldNotBeNull();
   5:          }


Yeah, there, got the error. Now lets go fix it. Something to do with open generics. I think this'll fix it.


   1:   

   2:   

   3:  using myDojo.Infrastructure.CQRS.Validation;

   4:  using StructureMap.Configuration.DSL;

   5:   

   6:  namespace myDojo.Commands.Users.Validation

   7:  {

   8:      public class CommandValidationRegistry : Registry 

   9:      {

  10:          public CommandValidationRegistry()

  11:          {

  12:              Scan(s =>

  13:                       {

  14:                           s.AssemblyContainingType(GetType());

  15:                           s.ConnectImplementationsToTypesClosing(typeof (IValidate<>));

  16:                           s.ConnectImplementationsToTypesClosing(typeof (ICommandValidator<>));

  17:   

  18:                       });

  19:              For(typeof (ICommandValidator<>)).Use(typeof(CommandValidator<>));

  20:          }

  21:      }

  22:  }

 

Finally! Actually we don't need line 16. Why? You know, I'm gunna email the SM user group and find out, cause I ain't quite sure. Remove it and re-run test... Yep, I'm good.
Ok, lets hit website again.

 

And we're good!

 

We're not yet communicating to the user why the hell the command failed though. Lets see what we can do there.

   1:  public override void ExecuteResult(ControllerContext context)
   2:          {
   3:   
   4:              if (!context.Controller.ViewData.ModelState.IsValid)
   5:              {
   6:                  ValidationFailedResult().ExecuteResult(context);
   7:                  return;
   8:              }
   9:   
  10:              var validator = Container.GetInstance<ICommandValidator<TCommand>>();
  11:   
  12:              if (!validator.IsValid(Command))
  13:              {
  14:                  foreach (var failedRule in validator.FailedRules)
  15:                  {
  16:                      context.Controller.ViewData.ModelState.AddModelError(failedRule.GetType().Name,failedRule.ToString());
  17:                  }
  18:                  ValidationFailedResult().ExecuteResult(context);
  19:   
  20:                  return;
  21:              }
  22:   
  23:              ICommandHandlerResult result = null;
  24:             
  25:              var handler = Container.GetInstance<ICommandHandler<TCommand>>();
  26:              result = handler.Handle(Command);
  27:              if(result is Success)
  28:              {
  29:                  Success().ExecuteResult(context);
  30:                  return;
  31:              }
  32:              CommandFailedResult(result).ExecuteResult(context);
  33:          }

 

Now we just override ToString() on the validation message, and they get added to the Model Errors. Here's what my view looks like - oh yeah, it's Razor.


 

   1:  @inherits System.Web.Mvc.WebViewPage<myDojo.Web.Models.RegisterUserForm>
   2:   
   3:  @{
   4:      View.Title = "Register";
   5:      LayoutPage = "~/Views/Shared/_Layout.cshtml";
   6:  }
   7:   
   8:      <h2>Create your account</h2>
   9:      <form action='@Url.Action("Register","User")' method='POST'>
  10:              @Html.ValidationSummary()
  11:          <div>
  12:              @Html.LabelFor(m => m.EmailAddress)
  13:              @Html.TextBoxFor(m => m.EmailAddress)
  14:              @Html.ValidationMessageFor(m => m.EmailAddress)
  15:          </div>
  16:          <div>
  17:              <input type="submit" value="ok" />
  18:          </div>
  19:      </form>

 

And when I try to register with a pre-existing email address I see this.

 
blog
 
I think we can clean up that CommandActionResult a lot, and I probably will - just not tonight.
 
I like having my command validation in it's own assembly. This gives me some DRY around my validation, not sure how much I'll reuse it yet, but we'll find out, huh?
 
Have fun with it, tell me why it sucks, or why it doesn't.



 
 

Tuesday, November 9, 2010

When just a query don't work - MappedQueryActionResult

So in my last post I made a Query action result. This works great for list and details screens. What about edit screens though? If you're posting back your actual entity as your viewmodel this works fine. However, I've gotten to where I make nice little small view models that represent just the form I'm wanting to post. Like this method
   1:   public ActionResult Edit(string email)
   2:          {
   3:              var readModel = _detailsReadModelRepository.GetSingle(d=>d.EmailAddress == email);
   4:              var viewModel = new EditMartialArtistForm(readModel);
   5:              return View(viewModel);
   6:   
   7:          }

Nothing wrong with this method. Can't be - because I wrote it. *snicker. But, I think I can make it better. So, since I'm not big on solving my own problems, I went and looked at some of Jimmy Bogard's stuff. Jimmy wrote AutoMapper, and is an all round genius. In fact, the only reason you should be reading this blog is because you've read all his blogs and you're not geek full yet. I pulled down the code from his mvcConf at http://headspringlabs.codeplex.com/ and found this little gem.



   1:  using System;
   2:  using System.Web.Mvc;
   3:  using AutoMapper;
   4:   
   5:  namespace HeadspringExample.UI.Helpers
   6:  {
   7:      public class AutoMapViewResult : ActionResult
   8:      {
   9:          public Type SourceType { get; private set; }
  10:          public Type DestinationType { get; private set; }
  11:          public ViewResult View { get; private set; }
  12:   
  13:          public AutoMapViewResult(Type sourceType, Type destinationType, ViewResult view)
  14:          {
  15:              SourceType = sourceType;
  16:              DestinationType = destinationType;
  17:              View = view;
  18:          }
  19:   
  20:          public override void ExecuteResult(ControllerContext context)
  21:          {
  22:              var model = Mapper.Map(View.ViewData.Model, SourceType, DestinationType);
  23:   
  24:              View.ViewData.Model = model;
  25:   
  26:              View.ExecuteResult(context);
  27:          }
  28:      }
  29:  }

If you don't know what AutoMapper is, well, that's not the point of this blog, but basically, it maps an instance of one type to an instance of another based on conventions. Saves LOTS and lots of boilerplate code that we used to hire interns to write before Bush drove the Economy in a ditch and Obama backed a tow truck over it trying to fix it. Now we just go steal Jimmy's stuff and it gets done for free and interns work at McDonalds and McDonalds workers go beg on the street corner and panhandlers are just SOL.  What the heck was that all about???  God I love Dos Equis!

Back on track. Yeah, it's a good beer!

Ok, so I wanna send a Query off to an AutoMapper then send that off to a view. Want my consumers to look something like this.


   1:   public ActionResult Edit(string email)
   2:          {
   3:              return MappedQueryView<GetMartialArtistDetailsByEmail,EditMartialArtistForm>(s =>s.EmailAddress = email);
   4:          }

Uhh... I don't know if that's even possible, since IQuery.Execute is object... But hey, lets see what we can come up with.  25 minutes (and 2 more Dos Equis) later... Duhhh... Look at Jimmy's AutoMapViewResult. He made overloads for IMappingEngine.Map that take source, source type and destination type (not the generics).. We're in business! So I wrote this.

   1:  using System;
   2:   
   3:  using System.Web.Mvc;
   4:  using AutoMapper;
   5:  using myDojo.Infrastructure.CQRS.Query;
   6:  using StructureMap;
   7:   
   8:  namespace myDojo.Infrastructure.Web
   9:  {
  10:      public class MappedQueryViewResult<TQuery,TDestination> : ViewResult where TQuery:IQuery
  11:      {
  12:          private static IMappingEngine Mapper { get { return Container.GetInstance<IMappingEngine>(); } }
  13:          private static IContainer Container { get { return ServiceLocation.CurrentContainer; } }
  14:   
  15:          public MappedQueryViewResult(Action<TQuery> buildUpQuery)
  16:          {
  17:              BuildUpQuery = buildUpQuery;
  18:          }
  19:   
  20:          protected Action<TQuery> BuildUpQuery { get; set; }
  21:   
  22:          public override void ExecuteResult(ControllerContext context)
  23:          {
  24:              var query = Container.GetInstance<TQuery>();
  25:              if (BuildUpQuery != null)
  26:                  BuildUpQuery(query);
  27:              var source = query.Execute();
  28:              var viewModel = Mapper.Map(source,source.GetType(), typeof (TDestination));
  29:              ViewData.Model = viewModel;
  30:              base.ExecuteResult(context);
  31:          }
  32:          
  33:      }
  34:  }


Not much to it really. I just use go get the Query from StructureMap, build it up (exactly the same way QueryActionResult does) but instead of setting the Model to the query results, I pump it through the IMappingEngine. Add a nice little Convenience method to our base controller.

   1:  public ActionResult MappedQuery<TQuery,TDestination>(Action<TQuery> buildUpQuery=null) where TQuery:IQuery
   2:          {
   3:              return new MappedQueryViewResult<TQuery, TDestination>(buildUpQuery);
   4:          }
 
And there we go! The method now looks like this.
 

   1:  public ActionResult Edit(string email)
   2:          {
   3:              return MappedQuery<GetMartialArtistDetailsByEmail,EditMartialArtistForm>(s =>s.EmailAddress = email);
   4:          }
A nice little side effect to not depending on the repositories directly is that we no longer have ANY direct dependencies in the controller now. Default ctor is fine. All the service location stuff happens in the ActionResult. Personally, I think this is a good thing. I can test my Queries in isolation and have the infrastructure wrapped up well and we know it works. 
Here's what the controller looks like now.


   1:  using System;
   2:  using System.Web.Mvc;
   3:  using myDojo.Commands.Users;
   4:  using myDojo.Infrastructure.Web;
   5:  using MyDojo.Query.Queries;
   6:  using myDojo.Web.Models;
   7:   
   8:  namespace myDojo.Web.Controllers
   9:  {
  10:      public class UserController : DefaultController
  11:      {
  12:          public ActionResult Register()
  13:          {
  14:              return View(new RegisterUserForm());
  15:          }
  16:          [HttpPost]
  17:          public CommandActionResult<RegisterUser> Register(RegisterUserForm form)
  18:          {
  19:              return Command(new RegisterUser(form.EmailAddress, null), () => RedirectToAction("Edit", new {email = form.EmailAddress}));
  20:          }
  21:          public ActionResult Edit(string email)
  22:          {
  23:              return MappedQuery<GetMartialArtistDetailsByEmail,EditMartialArtistForm>(s =>s.EmailAddress = email);
  24:          }
  25:          public ActionResult Details(Guid id)
  26:          {
  27:              return Query<MartialArtistDetailsById>(q => q.Id = id);
  28:          }
  29:          [HttpPost]
  30:          public CommandActionResult<EditMartialArtistInfo> Edit(EditMartialArtistForm model)
  31:          {
  32:              return Command(new EditMartialArtistInfo(model.Id, model.Name, model.Biography), () => RedirectToAction("List"));
  33:          }
  34:          public ActionResult List()
  35:          {
  36:              return Query<AllMatialArtists>();
  37:          }
  38:   
  39:      }
  40:   
  41:     
  42:  }
 

Monday, November 8, 2010

The Journey to thinner controllers - MVC QueryActionResult

In the endless drive to smaller and smaller controllers, I'm gunna see if I can't make an ActionResult for query results. Basically, while this code doesn't suck at all.
   1:  public ActionResult Details(Guid id)
   2:          {
   3:              var details = _detailsReadModelRepository.GetById(id);
   4:              return View(details);
   5:          }



I think we can make it even better. I really wanna call out that a method is a Query. So I'm gunna make a QueryActionResult. So I just create the class and inherit ActionResult. It has one abstract on it, ExecuteResults(ControllerContext). Lets start really simple first. I'm thinking we just take in a Func<Object> that will execute the query to get the viewmodel, then send that off to the the rendering engine.

   1:  using System;
   2:  using System.Web.Mvc;
   3:   
   4:  namespace myDojo.Infrastructure.Web
   5:  {
   6:      public class QueryActionResult : ViewResult
   7:      {
   8:          public Func<object> Query { get; set; }
   9:          
  10:          public override void ExecuteResult(ControllerContext context)
  11:          {
  12:              QueryMustBeSet();
  13:              ViewData.Model = Query();
  14:              base.ExecuteResult(context);
  15:          }
  16:   
  17:          private void QueryMustBeSet()
  18:          {
  19:              if(Query == null)
  20:                  throw new ArgumentNullException("Query");
  21:          }
  22:      }
  23:  }

Ok, simple enough, but we really didn't accomplish much. The consumer code now looks like this.



   1:  public ActionResult Details(Guid id)
   2:          {
   3:              return new QueryActionResult
   4:                         {
   5:                             Query = () => _detailsReadModelRepository.GetById(id)
   6:                         };
   7:          }

Yeah, that's probably worse than when we started. To be fair though, the only reason View(object) is convenient is because of the convenience method on Controller that sets the ViewData.Model. So, since I'm all about being fair, I'll go add a convenience method to our base controller.

   1:    public QueryActionResult Query(Func<object> query)
   2:          {
   3:              return new QueryActionResult
   4:                         {
   5:                             Query = query
   6:                         };
   7:          }

Now the consumer looks like this.

   1:  public QueryActionResult Details(Guid id)
   2:          {
   3:              return Query(() => _detailsReadModelRepository.GetById(id));
   4:          }

I like that. Pretty nice huh? Of course we can add overloads to the Query method that'll let you send to different Views (just like View() has on Controller).

But I think I can make it a little better. I think I want it to look like this.

   1:   public ActionResult Details(Guid id)
   2:          {
   3:              return Query(new GetDetailsForMartialArtist(id));
   4:          }

To do that, I'm gunna create a little Query interface. Essentially, I'll just be using the command pattern. Here's the interface.

   1:  namespace myDojo.Infrastructure.CQRS.Query
   2:  {
   3:      public interface IQuery
   4:      {
   5:          object Execute();
   6:      }
   7:  }

Next, I just go make a Query that gets details by id. Uh oh! Wait... dependencies. I have to specify the params for the query somewhere, and I don't want to constructor inject them, because that just smells (even though that's what I just wrote - that happens to me a lot.). I'd rather just write the query like this.

   1:   
   2:   
   3:  using System;
   4:  using myDojo.Infrastructure;
   5:  using myDojo.Infrastructure.CQRS.Query;
   6:  using MyDojo.Query.ViewModels;
   7:   
   8:  namespace MyDojo.Query.Queries
   9:  {
  10:      public class MartialArtistDetailsById : IQuery
  11:      {
  12:          private readonly IReadModelRepository<MartialArtistDetails> _repository;
  13:   
  14:          public MartialArtistDetailsById(IReadModelRepository<MartialArtistDetails> repository)
  15:          {
  16:              _repository = repository;
  17:          }
  18:   
  19:          public Guid Id { get; set; }
  20:   
  21:          public MartialArtistDetails Execute()
  22:          {
  23:              IdMustBeSet();
  24:              return _repository.GetById(Id);
  25:          }
  26:   
  27:          private void IdMustBeSet()
  28:          {
  29:              if(Id.Equals(Guid.Empty))
  30:                  throw new ArgumentException("Id","Id must be set");
  31:          }
  32:      }
  33:  }

This looks pretty good, but how to make it work??? I really don't want to have to new that Query object up, because that means I'll have to DI every dependency for every query on a controller. That just seems counterproductive to me. Let's see what we can do.

Instead of injecting Func<object>, we'll take an Action<TQuery> that we'll use to build up the query properties so that the params for the queries are properly set. Like so.

   1:  using System;
   2:  using System.Web.Mvc;
   3:  using myDojo.Infrastructure.CQRS.Query;
   4:   
   5:  namespace myDojo.Infrastructure.Web
   6:  {
   7:      public class QueryActionResult<TQuery> : ViewResult where TQuery:IQuery
   8:      {
   9:          public Action<TQuery> BuildUpQuery { get; set; }
  10:          public override void ExecuteResult(ControllerContext context)
  11:          {
  12:              var query = ServiceLocation.CurrentContainer.GetInstance<TQuery>();
  13:              BuildUpQuery(query);
  14:              ViewData.Model = query.Execute();
  15:              base.ExecuteResult(context);
  16:          }
  17:      }
  18:  }

So we change the convenience method to look like this.

   1:   public QueryActionResult<TQuery> Query<TQuery>(Action<TQuery> buildUpQuery) where TQuery: IQuery
   2:          {
   3:              return new QueryActionResult<TQuery>
   4:                         {
   5:                            BuildUpQuery = buildUpQuery,
   6:                         };
   7:          }

Now the controller looks like this.

   1:   public QueryActionResult<MartialArtistDetailsById> Details(Guid id)
   2:          {
   3:              return Query<MartialArtistDetailsById>(q => q.Id = id);
   4:          }
 
Ok... let's use some optional parameters to make this more usable.
 

   1:  public QueryActionResult<TQuery> Query<TQuery>(Action<TQuery> buildUpQuery=null,string viewName=null) where TQuery: IQuery
   2:          {
   3:              var result = new QueryActionResult<TQuery>
   4:                         {
   5:                            BuildUpQuery = buildUpQuery,
   6:                            
   7:                         };
   8:              if (!String.IsNullOrEmpty(viewName))
   9:                  result.ViewName = viewName;
  10:              return result;
  11:          }
 
Don't want a null ref for BuildUpQuery in QueryActionResult, so let's just not execute it if it's null.

   1:  using System;
   2:  using System.Web.Mvc;
   3:  using myDojo.Infrastructure.CQRS.Query;
   4:   
   5:  namespace myDojo.Infrastructure.Web
   6:  {
   7:      public class QueryActionResult<TQuery> : ViewResult where TQuery:IQuery
   8:      {
   9:          public Action<TQuery> BuildUpQuery { get; set; }
  10:          public override void ExecuteResult(ControllerContext context)
  11:          {
  12:              var query = ServiceLocation.CurrentContainer.GetInstance<TQuery>();
  13:              if(BuildUpQuery!=null)
  14:                  BuildUpQuery(query);
  15:              ViewData.Model = query.Execute();
  16:              base.ExecuteResult(context);
  17:          }
  18:      }
  19:  }

Let's go fix our List() method on the UserController now.

Before:

   1:  public ActionResult List()
   2:          {
   3:              var users = _detailsReadModelRepository.GetAll().AsEnumerable();
   4:              return View(users);
   5:          }

After:

   1:  public ActionResult List()
   2:          {
   3:              return Query<AllMatialArtists>();
   4:          }

I like it. Do you?

Code is up on github.