Linq to Sql and ASP.NET MVC – DataContext Per Request

This is the first in a series of posts about using Linq to Sql with ASP.NET MVC.

Code for this series is available here.

When using an ORM tool within a web application, it’s often common to scope a unit of work to the lifetime of an HTTP Request. If you’re using Linq to Sql and ASP.NET MVC, you can achieve this by using an Inversion of Control container in conjunction with an ActionFilter.

For this example, I’m going to be using the StructureMap IoC container alongside a fictional “Blog” database.

Firstly, you’ll need to configure StructureMap by calling ObjectFactory.Configure inside your Global.asax passing in a custom Registry instance:

protected void Application_Start() {
	RegisterRoutes(RouteTable.Routes);
 
	ObjectFactory.Configure(cfg => {
		cfg.AddRegistry(new MyRegistry());
	});
}

The code for MyRegistry looks like this:

public class MyRegistry : Registry {
	public MyRegistry() {
		For<BlogDataContext>()
			.HttpContextScoped()
			.Use(c => new BlogDataContext());
 
		Scan(scan => {
			scan.AddAllTypesOf<Controller>();
		});
	}
}

Here I’m telling StructureMap to create one instance of my BlogDataContext per HTTP Request as well as registering each Controller instance with the container.

Next, we need to tell MVC to use StructureMap to instantiate our controllers. This can be done by creating a custom ControllerFactory:

public class StructureMapControllerFactory : DefaultControllerFactory {
	protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
		return (IController) ObjectFactory.GetInstance(controllerType);
	}
}

We can then replace the DefaultControllerFactory with the StructureMapControllerFactory in our Application_Start:

protected void Application_Start() {
	RegisterRoutes(RouteTable.Routes);
 
	ObjectFactory.Configure(cfg => {
		cfg.AddRegistry(new MyRegistry());
	});
 
	ControllerBuilder.Current.SetControllerFactory(
		new StructureMapControllerFactory());
}

Now, if we create a PostController (for creating and editing Posts in our fictional blog), we can now take a BlogDataContext in the constructor (for better testability, you’d probably want to hide the DataContext behind an interface):

public class PostController : Controller {
	private readonly BlogDataContext context;
 
	public PostController(BlogDataContext context) {
		this.context = context;
	}
 
	public ActionResult Edit(int id) {
		var post = context.Posts.Single(x => x.Id == id);
		return View(post);
	}
}

Now, visiting http://mysite/Post/Edit/1 would return a view to display a post with the Id of 1 (assuming the appropriate Post exists in the database).

Automatically Submitting Changes

We can take this a stage further by adding an ActionFilter to our application that will automatically call SubmitChanges on our DataContext at the end of the HTTP Request:

public class AutoCommitAttribute : ActionFilterAttribute {
	public override void OnActionExecuted(ActionExecutedContext filterContext) {
		if (filterContext.Controller.ViewData.ModelState.IsValid) {
			var currentDataContext = ObjectFactory.GetInstance<BlogDataContext>();
 
			using (var transaction = new TransactionScope()) {
				currentDataContext.SubmitChanges();
				transaction.Complete();
			}
		}
	}
}

Here we call into StructureMap to retrieve our current DataContext and commit any changes back to the database inside a transaction. Note that this will only happen if the ModelState is valid (ie there are no validation errors).

Another thing to keep in mind that using an IoC container as a Service Locator (as we’re doing in this filter) is generally considered bad practice. There are ways around this but these are outside the scope of this post.

Now, whenever we make a change to one of our entities the change will automatically be committed to the database provided the action is decorated with the AutoCommit attribute:

[AcceptVerbs(HttpVerbs.Post), AutoCommit]
public ActionResult Create(Post post) {
	context.Posts.InsertOnSubmit(post);
	return RedirectToAction("Index");
}

FluentValidation 1.2 beta 1 available

FluentValidation 1.2 beta 1 is now available to download.

This release contains several new features:

Setting the validator cascade mode

In v1.1, if you have multiple validators defined on a single property then all of those validators will be executed even if the first one fails. This can be changed by calling the Cascade method:

RuleFor(x => x.Surname)
  .Cascade().StopOnFirstFailure()
  .NotNull()
  .Length(1, 250);

In this case, the Length validator would not be run on the Surname property if the NotNull validator fails.

This is customisable globally by setting the static property ValidatorOptions.CascadeMode.

MVC2 Support

The FluentValidationModelBinder has been modified to work with ASP.NET MVC2 RC. Note that if you want to use FluentValidation with MVC1, you will need to use the older 1.1 release.

FluentValidation 1.2 Beta 1 does not currently include the custom ModelMetadataProvider and ModelValidatorProvider that I mentioned in this post.

In its current state, the MVC2 metadata API is not extensible enough to work well with FluentValidtion (see this post for details) so I’ve omitted them from this beta. If MVC2’s support for external frameworks is improved before RTM, then I will consider re-adding these features for the next release.

Custom user state

Custom user state can be stored alongside validation failures:

RuleFor(person => person.Surname).NotNull().WithState(person => "foo")

This state can then be retrieved from the ValidationFailure object if the rule fails:

var result = validator.Validate(model);
var error = result.Errors[0];
var customState= error.CustomState;

OnAnyFailure

Rules can define a callback method that will be invoked if any of the validators associated with a particular rule fail:

RuleFor(person => person.Surname).NotNull().OnAnyFailure(person => {
   Console.WriteLine("#fail");
});

WithPropertyName

The WithPropertyName method can be used to override the name of the property that will be used when associating an error message with a particular property:

public class PersonValidator : AbstractValidator<Person> {
  public PersonValidator() {
    RuleFor(person => person.Surname).NotNull().WithPropertyName("foo");
  }
}
var validator = new PersonValidator();
var result = validator.Validate(new Person());
//property name is 'foo' instead of 'Surname'
string propertyName = result.Errors.Single().PropertyName;

InlineValidator

The InlineValidator can be used to define rules without creating a dedicated validator class:

var validator = new InlineValidator<Person>() {
  v => v.RuleFor(x => x.Surname).NotNull();
  v => v.RuleFor(x => x.Age).GreaterThan(0);
}

ValidateAndThrow

The ValidateAndThrow extension method can be used to throw an exception when validation fails rather than returning a ValidationResult.

Experimental xVal integration

Thanks to Adam Schroder, FluentValidation now includes experimental support for generating xVal rules. I’ve labelled this as “Experimental” as there is currently no support for custom validation messages or some of the more complex FluentValidation rules. The future of the FluentValidation xVal integration also depends on what happens with MVC2’s validation providers and whether xVal will continue to be developed after the MVC2 release.

New PropertyValidator base class (potentially breaking change)

In FluentValidation 1.x, all property validators implemented the IPropertyValidator<T,TProperty> interface. As of v1.2 this has been deprecated in favour of the PropertyValidator base class. Note that property validators themselves are no longer generic, which makes them easier to work with if you need to gather metadata about a validator.

For example, in v1.1 the NotNullValidator looked like this:

[ValidationMessage(Key = "notnull_error")]
public class NotNullValidator<T, TProperty> : IPropertyValidator<T, TProperty> {
	public PropertyValidatorResult Validate(PropertyValidatorContext<T, TProperty> context) {
		if (context.PropertyValue == null) {
			var formatter = new MessageFormatter().AppendProperyName(context.PropertyDescription);
			string error = context.GetFormattedErrorMessage(typeof(NotNullValidator<T, TProperty>), formatter);
 
			return PropertyValidatorResult.Failure(error);
		}
		return PropertyValidatorResult.Success();
	}
}

…while in v1.2 it now looks like this:

public class NotNullValidator : PropertyValidator, INotNullValidator {
	public NotNullValidator() : base(() => Messages.notnull_error) {
		SupportsStandaloneValidation = true;
	}
 
	protected override bool IsValid(PropertyValidatorContext context) {
		if (context.PropertyValue == null) {
			return false;
		}
		return true;
	}
}

The use of a base class helps keep the validator definitions simple. Also note that the ValidationMessage attribute has been removed – localised error messages can now be specified either by passing a resource type and key to the base PropertyValidator constructor or by using a lambda expression.

If you have written any custom property validators, it is recommended that you change them to inherit from PropertyValidator. However, there is a backwards compatibility layer in place which should allow old-style property validators to continue working.

DefaultResourceManager has been removed (breaking change)

In order to add better localization support, the DefaultResourceManager has been removed in favour of Visual Studio’s default generated “Messages” class. If you need to replace this with your own Messages class, you can set the static ResourceProviderType property on the ValidatorOptions class.

Limitations of MVC2’s ModelValidatorProviders

One of the new features in ASP.NET MVC 2 is the ability the ability to define multiple validation providers. These are used by the DefaultModelBinder to automatically validate your model objects when they are passed to action parameters.

I wanted to try and write one of these for FluentValidation (see this post) but after trying this it has become quite clear that the ModelValidatorProvider API does have some limitations which have caused me some problems.

Problem 1: Property-level validation

To understand this problem, first we need to look at how different validation frameworks perform their work.

When using FluentValidation, the validators work against a pre-populated object. For example:

public class CustomerValidator : AbstractValidator<Customer{ 
  public CustomerValidator() {
     RuleFor(x => x.Surname).NotNull();
     RuleFor(x => x.CreditLimit).GreaterThanOrEqualTo(0);
  }
}
 
var customer = new Customer { CreditLimit = -1, Surname = null };
var validator = new CustomerValidator();
var results = validator.Validate(customer);

You cannot reliably validate individual properties by themselves because they may have dependencies on *other* properties being set. For example:

RuleFor(x => x.Surname).NotEqual(x => x.Forename);

This rule says tht the Surname and Forename properties must not be equal. In this case, you cannot validate the surname property by itself without having first set the value for the Forename property. Other validation frameworks (eg the Castle Project’s validation attributes) work in a similar way.

The MVC Framework’s DefaultModelBinder is primarily designed to work with the System.ComponentModel.DataAnnotations attributes. These work in a different way – they validate individual values, not the entire object. To support this, the DefaultModelBinder allows validating both the individual property values (in the OnPropertyValidated method) as well as validating the entire instance (in the OnModelUpdated method).

Here are the relevant methods from DefaultModelBinder:

//OnPropertyValidated - called for each property being bound.
protected virtual void OnPropertyValidated(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value) {
    ModelMetadata propertyMetadata = bindingContext.PropertyMetadata[propertyDescriptor.Name];
    propertyMetadata.Model = value;
    string modelStateKey = CreateSubPropertyName(bindingContext.ModelName, propertyMetadata.PropertyName);
 
    // run validation
    foreach (ModelValidator validator in propertyMetadata.GetValidators(controllerContext)) {
        foreach (ModelValidationResult validationResult in validator.Validate(bindingContext.Model)) {
            bindingContext.ModelState.AddModelError(CreateSubPropertyName(modelStateKey, validationResult.MemberName), validationResult.Message);
        }
    }
 
    // only add a "value was required" error message if there were no validation errors
    if (bindingContext.ModelState.IsValidField(modelStateKey)) {
        if (value == null && !TypeHelpers.TypeAllowsNullValue(propertyDescriptor.PropertyType)) {
            bindingContext.ModelState.AddModelError(modelStateKey, GetValueRequiredResource(controllerContext));
        }
    }
}
//OnModelUpdated - called once the entire object has been bound. 
protected virtual void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) {
    IDataErrorInfo errorProvider = bindingContext.Model as IDataErrorInfo;
    if (errorProvider != null) {
         string errorText = errorProvider.Error;
         if (!String.IsNullOrEmpty(errorText)) {
            bindingContext.ModelState.AddModelError(bindingContext.ModelName, errorText);
          }
    }
 
    if (!IsModelValid(bindingContext)) {
        return;
    }
 
    foreach (ModelValidator validator in bindingContext.ModelMetadata.GetValidators(controllerContext)) {
        foreach (ModelValidationResult validationResult in validator.Validate(null)) {
            bindingContext.ModelState.AddModelError(CreateSubPropertyName(bindingContext.ModelName, validationResult.MemberName), validationResult.Message);
        }
    }
}

On first glance, this looks like it will work. When OnPropertyValidated calls GetValidators, I can return an empty collection of validators and do all of my work in a single validator in OnModelUpdated. Unfortunately, this does not work.

See the end of OnPropertyValidated? Here, it checks if there have been any validation errors for the property and if not then it will go ahead and run its own built-in field validation anyway for non-nullable value types – it will put a message saying “A value was required” into ModelState. And you can’t turn this off. The *only way* to stop this built-in validation is to support property-level validation in your custom ValidatorProvider. Not very useful if the underlying framework does not support this.

To work around the above issue, I ended up adding property-level validation to FluentValidation, but this is not a completely reliable solution because of the issues related to cross-property validation I mentioned above.

Problem 2: The DataAnnotationsModelValidatorProvider is greedy

The next problem that I ran into is that the DataAnnotationsModelValidatorProvider will always run required field validation, even if you’re not using the DataAnnotations attributes!

Here is an example that uses FluentValidation to validate an object where a null value is being bound to a non-nullable value type:

[Validator(typeof(FooValidator))]
public class Foo {
	public int Id { get; set; }
}
 
public class FooValidator : AbstractValidator<Foo> {
	public FooValidator() {
		RuleFor(x => x.Id).NotEmpty();
	}
}
 
[Test]
public void AddsOneError() {
	var foo = new Foo();
 
	ModelValidatorProviders.Providers.Add(
		new FluentValidationModelValidatorProvider(new AttributedValidatorFactory())
	);
 
	var meta = ModelMetadataProviders.Current.GetMetadataForProperty(() => null, typeof(Foo), "Id");
	var validators = ModelValidatorProviders.Providers.GetValidators(meta, new ControllerContext());
 
	var results = validators.SelectMany(x => x.Validate(foo)).ToList();
 
	Assert.AreEqual(1, results.Count()); //fails - 2 instead of 1
}

This test fails because there are two error messages rather than one:

The Id field is required.
'Id' should not be empty.

…the first of these errors comes from the DataAnnotationsModelValidatorProvider even though I have NOT decorated the Id property with a [Required] attribute.

Why does this happen? The answer is in DataAnnotationsModelValidatorProvider’s GetValidators method:

 if (metadata.IsRequired && !attributes.Any(a => a is RequiredAttribute)) {
       attributes = attributes.Concat(new[] { new RequiredAttribute() });
 }

This checks to see if the property is a non-nullable type and it does not have a RequiredAttribute, then it assumes that the property should have a RequiredAttribute anyway!
You can work around this by removing the DataAnnotationsModelValidatorProvider:

ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(
	new FluentValidationModelValidatorProvider(new AttributedValidatorFactory())
);

…and the test now passes.

Unfortunately, this is far from ideal. This means you cannot use the DataAnnotations attributes to validate one model and a custom provider for a different model. You have to choose one or the other.

One way to work around this problem is to use a composite validator provider that wraps the underlying providers:

public class CompositeValidatorProvider : ModelValidatorProvider {
	public static void Bootstrap(ModelValidatorProviderCollection providerCollection, params ModelValidatorProvider[] customProviders) {
		var validators = customProviders.ToList();
		validators.AddRange(providerCollection);
		providerCollection.Clear();
		providerCollection.Add(new CompositeValidatorProvider(validators));
	}
 
	readonly IEnumerable<ModelValidatorProvider> innerInnerProviders;
 
	protected CompositeValidatorProvider(IEnumerable<ModelValidatorProvider> innerProviders) {
		this.innerInnerProviders = innerProviders;
	}
 
	public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context) {
		foreach(var provider in innerInnerProviders) {
			var validators = provider.GetValidators(metadata, context).ToList();
			if(validators.Count > 0) {
				return validators;	
			}
		}
 
		return Enumerable.Empty<ModelValidator>();
	}
}

This custom provider can be used to wrap the built-in providers (including the DataAnnotations provider) as well as your own custom providers. In its GetValidators method, it iterates over each of the inner providers and asks each one to create a collection of validators. It only returns validators from the first provider that returns a non-empty collection. This means that if your custom provider can validate the object then the DataAnnotations provider will not be executed.

Now, the following test passes:

[Test]
public void AddsOneError() {
	var foo = new Foo();
 
    	var fluentProvider = new FluentValidationModelValidatorProvider(new AttributedValidatorFactory());
 
	CompositeValidatorProvider.Bootstrap(ModelValidatorProviders.Providers, fluentProvider);
 
	var meta = ModelMetadataProviders.Current.GetMetadataForProperty(() => null, typeof(Foo), "Id");
	var validators = ModelValidatorProviders.Providers.GetValidators(meta, new ControllerContext());
 
	var results = validators.SelectMany(x => x.Validate(foo)).ToList();
 
	Assert.AreEqual(1, results.Count());
}

This raises the question: if you have to resort to doing this, what is the point in allowing multiple validation providers to be registered in the first place?

I am really hoping that the MVC team will fix this fairly significant problem before RTM, but as MVC2 is already at the RC stage I think this will be unlikely.

Phantom 0.2 Released

Phantom 0.2 is now available to download. A big thanks goes to Andrey Shchekin for this release who contributed the NAnt integration and the Runnable syntax.

For those not familiar with Phantom, this is a build system written in C# and Boo.

This release includes:

NAnt Integration

You can now execute NAnt tasks from within Phantom build scripts. In order for this to work, you’ll need to drop Phantom.Integration.Nant.dll and NAnt.Core.dll into the same directory as Phantom.exe. Once in place, you can import the NAnt tasks. This example executes the ‘echo’ task which is part of NAnt.Core.dll:

import tasks from NAnt.Core
target default:
   echo(message : "Hello from NAnt!")

Runnables

With v0.1 of Phantom, a lot of options were passed to helper methods via Hashes. For example, if you wanted tell msbuild to compile a project with a particular configuration and verbosity, you’d have to do the following:

msbuild("foo.sln", { "configuration": "release", "verbosity": "normal" })

With Phantom 0.2, most of these methods have been converted to classes that define regular properties. You can use Boo’s object initializer syntax they can still be declared on one line:

msbuild(file: "foo.sln", configuration: "release", verbosity: "normal")

This is called a ‘runnable’ as the msbuild class implements the IRunnable interface. When Phantom sees an instance of an IRunnable type being created, it will automatically call the ‘Run’ method (in this case, to kick off MSbuild). This syntax is equivalent to the following:

m = msbuild()
m.file = "foo.sln"
m.configuration = "release"
m.verbosity = "normal"
m.Run()

Runnables can also be used inside a with block:

with msbuild():
  .file = "foo.sln"
  .verbosity = "normal"
  .configuration = "release"

…and the ‘Run’ method will automatically be called at the end of the block. This is particularly useful if you have lots of properties that you want to set that cannot all fit on one line.

Improved FileList support

The 0.1 version of FileLists were rather limited. With 0.2 they now support exclusion patterns as well as recursively copying subdirectories:

with FileList("path/to/bin/debug"):
  .Include("**/*")
  .ForEach def(file):
    file.CopyToDirectory("directoryToPackage")

NCover Integration

Phantom 0.2 now includes runnables for executing NCover and NCoverExplorer. At present, these only work with the free Community Edition of NCover.

FluentValidation moved to GitHub and what’s coming in v1.2

After several months of increasing frustration with CodePlex’s svn integration, I have moved the source code for FluentValidation to GitHub.

Continuous builds can still be downloaded from my build server.

Documentation, discussions and the issue tracker will still remain on the CodePlex site, but if you want to play with the source code then you’ll need to head over to GitHub instead. If you have not used Git before then I recommend reading my Git Guide (the guide was written for the MvcContrib project, but all the concepts apply to FluentValidation too).

What’s coming with v1.2?

The upcoming release of FluentValidation (v1.2) will have several changes including the following:

A custom ModelMetadataProvider

The FluentValidationModelMetadataProvider will allow you to define ASP.NET MVC Metadata inside your validator classes, eg:

public CustomerValidator() {
   RuleFor(x => x.Surname)
      .NotNull() //regular validator
      .UIHint("Surname"); //MVC Metadata
 
}

The FluentValidationModelMetadataProvider will support the following metadata-related extension methods:

  • HiddenInput
  • UIHint
  • Scaffold
  • DataType
  • DisplayName
  • DisplayFormat
  • ReadOnly

A custom ModelValidatorProvider

Previous versions of FluentValidation had a custom IModelBinder implementation that allowed you to use FluentValidation to validate ASP.NET MVC action parameters. This will no longer be necessary in v1.2 as ASP.NET MVC 2’s ModelValidatorProvider infrastructure means FluentValidation can now be plugged in to MVC’s DefaultModelBinder:

public class MvcApplication : HttpApplication {
   public void Application_Start() {
      RegisterRoutes(RouteTable.Routes);
 
      ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(new AttributedValidatorFactory()));
   }
}

Note that the FluentValidationModelValidatorProvider will only support server-side validation, not client-side validation. FluentValidation’s validation mechanism is not compatible with how ASP.NET MVC 2 generates clientside validation rules.

Customisable Validator Cascade Mode

The validator cascade mode will be customisable in v1.2. Currently, if you have multiple validators defined on a single property then all of those validators will be executed even if the first one fails. This can be changed by calling the Cascade method:

RuleFor(x => x.Surname)
  .Cascade().StopOnFirstFailure()
  .NotNull()
  .Length(1, 250);

In this case, the Length validator would not be run on the Surname property if the NotNull validator fails.

This will also be customisable globally by setting the static property ValidatorOptions.CascadeMode.

I hope to release a first beta of v1.2 in the next couple of weeks. The final release should coincide with the release of ASP.NET MVC 2.