Posts tagged with: asp.net-mvc

How to dynamically modify model meta data in ASP.NET MVC

Normally you just add the [Required] attribute to a view model to make it required. But I needed a way to configure whether a field to be required or not. The requirement was that it should be configured through web.config:

<appSettings>
    <add key="ticket-cat1-required" value="true" />
</appSettings>

Having to modify the view or the controller would not be very clean. Instead it’s much better to take advantage of the ModelValidatorProvider. I could have just done like this:

public class ConfigurableModelValidatorProvider : LocalizedModelValidatorProvider
{
    protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<System.Attribute> attributes)
    {
        bool isRequired = metadata.ContainerType == typeof (CreateViewModel)
                            && ConfigurationManager.AppSettings["ticket-cat1-required"] == "true";


        var theAttributes = attributes.ToList();
        if (!theAttributes.Any(x => x is RequiredAttribute) && isRequired)
            theAttributes.Add(new RequiredAttribute());

        return base.GetValidators(metaDataContext.Metadata, context, attributes);
    }
}

And then assigned it in global.asax:

protected void Application_Start()
{
    ModelValidatorProviders.Providers.Clear();
    ModelValidatorProviders.Providers.Add(new ConfigurableModelValidatorProvider());

    //...
}

But that would have created a tightly coupled provider.

The loosely coupled way

Instead I decided to take advantage of my inversion of control container and define some interfaces.

/// <summary>
/// Can adapt the generated metadata before it's sent to the view
/// </summary>
public interface IModelMetadataAdapter
{
    /// <summary>
    /// Adapt the meta data
    /// </summary>
    /// <param name="context">Context information</param>
    void Adapt(MetadataContext context);
}

The context used to modify the meta data:

/// <summary>
/// context for <see cref="IModelMetadataAdapter"/>
/// </summary>
public class MetadataContext
{
    /// <summary>
    /// Initializes a new instance of the <see cref="MetadataContext"/> class.
    /// </summary>
    /// <param name="metadata">The metadata.</param>
    public MetadataContext(ModelMetadata metadata)
    {
        if (metadata == null) throw new ArgumentNullException("metadata");
        Metadata = metadata;
    }

    /// <summary>
    /// See MSDN for info
    /// </summary>
    public ModelMetadata Metadata { get; set; }
}

Which allowed me to create this class (which is automatically registered in Griffin.Container):

[Component]
public class ToggleRequiredOnCreateModel : IModelMetadataAdapter
{
    public void Adapt(MetadataContext context)
    {
        if (context.Metadata.ContainerType != typeof(CreateViewModel))
            return;
        context.Metadata.IsRequired = false;
        if (context.Metadata.PropertyName != "Category1")
            return;

        context.Metadata.IsRequired = ConfigurationManager.AppSettings["ticket-cat1-required"] == "true";
    }
}

To make it all possible I’ve also have to modify the validator provider:

public class ConfigurableModelValidatorProvider : LocalizedModelValidatorProvider
{
    protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<System.Attribute> attributes)
    {
        var services = DependencyResolver.Current.GetServices<IModelMetadataAdapter>();

        var metaDataContext = new MetadataContext(metadata);
        foreach (var service in services)
        {
            service.Adapt(metaDataContext);
        }

        var theAttributes = attributes.ToList();
        if (!theAttributes.Any(x => x is RequiredAttribute) && metaDataContext.Metadata.IsRequired)
            theAttributes.Add(new RequiredAttribute());

        return base.GetValidators(metaDataContext.Metadata, context, attributes);
    }
}

In my case I’m using my Griffin.MvcContrib project to handle the localization, that’s why I inherit LocalizedModelValidatorProvider and not DataAnnotationsModelValidatorProvider.


Adding a required indicator in ASP.NET MVC3 using jQuery

You might want to indicate that fields in ASP.NET MVC3 is required visually.

Sample image

It’s easy thanks to the HTML attributes that the unobtrusive validation API generates.

Start by adding a new CSS class in your site.css called something like .required-indicator.

.required-indicator { color: red; font-size: 1.2em; font-weight: bold; }

Then add a small jQuery script somewhere (in the layout or an application.js):

$(function() {
    $('[data-val-required]').after('<span class="required-indicator">*</span>');
});

Done! Here is a sample fiddle.


How to handle transactions in ASP.NET MVC3

I got annoyed about having to repeat the transaction handling in every POST method of my controllers. First of all: I don’t want to have to take the unit of work in the constructor of each controller, since that implicitly says that all/most methods uses transactions. And I do not want to have to resolve a factory, since that says that all methods might use transactions. Finally using a singleton is the worst of solutions.

Before

The problem wasn’t that hard to solve thanks to the flexibility of ASP.NET MVC3. But let’s start by looking at a typical post method:

[HttpPost]
public virtual ActionResult Create(CreateModel model)
{
	if (!ModelState.IsValid)
		return View(model);

	var instruction = new Instruction(CurrentUser);
	Mapper.Map(model, instruction);

	using (var uow = _unitOfWorkFactory.Create())
	{
		_repository.Save(instruction);
		
		uow.SaveChanges();
	}
	
	return RedirectToAction("Details", new {id = instruction.Id});
}

After

What I did was to create a new action filter called TransactionalAttribute. It checks if the model state is valid and that no exceptions have been thrown. It uses the DependencyResolver to find a IUnitOfWork implementation if everything checks out OK. Since this is done in an action filter, the transaction will not be created unless it’s actually required. All you have to do is to register the UoW factory in your IoC container and tag your action:

[HttpPost, Transactional]
public virtual ActionResult Create(CreateModel model)
{
	if (!ModelState.IsValid)
		return View(model);

	var instruction = new Instruction(CurrentUser);
	Mapper.Map(model, instruction);
	_repository.Save(instruction);
	
	return RedirectToAction("Details", new {id = instruction.Id});
}

There is a small catch: You must add an error to the ModelState if you catch exceptions in your class. The transaction will otherwise get committed.

[HttpPost, Transactional]
public virtual ActionResult Create(CreateModel model)
{
	if (!ModelState.IsValid)
		return View(model);

	try
	{
		model.Category = model.Category ?? "Allmänt";

		var instruction = new Instruction(CurrentUser);
		Mapper.Map(model, instruction);
		_repository.Save(instruction);
		
		return RedirectToAction("Details", new {id = instruction.Id});
	}
	catch (Exception err)
	{
		// Adds an error to prevent commit.
		ModelState.AddModelError("", err.Message);
		Logger.Error("Failed to save instruction for app " + CurrentApplication, err);
		return View(model);
	}
}

Implementation

The attribute itself looks like this:

public class TransactionalAttribute : ActionFilterAttribute
{
	private IUnitOfWork _unitOfWork;

	public override void OnActionExecuting(ActionExecutingContext filterContext)
	{
		if (filterContext.Controller.ViewData.ModelState.IsValid && filterContext.HttpContext.Error == null)
			_unitOfWork = DependencyResolver.Current.GetService<IUnitOfWork>();

		base.OnActionExecuting(filterContext);
	}

	public override void OnActionExecuted(ActionExecutedContext filterContext)
	{
		if (filterContext.Controller.ViewData.ModelState.IsValid && filterContext.HttpContext.Error == null && _unitOfWork != null)
			_unitOfWork.SaveChanges();

		base.OnActionExecuted(filterContext);
	}
}

Simple, but effective! :)

Extras

The actual unit of work implementation depends on which kind of data layer you are using. You can use the following code snippet if you are using nhibernate and have successfully registered the ISession in your container:

public class NhibernateUnitOfWork : IUnitOfWork
{
	private readonly ISession _session;
	private ITransaction _transaction;

	public NhibernateUnitOfWork(ISession session)
	{
		_session = session;
		_transaction = session.BeginTransaction();
	}

	public void Dispose()
	{
		if (_transaction == null)
			return;

		if (!_transaction.WasCommitted)
			_transaction.Rollback();

		_transaction.Dispose();
		_transaction = null;
	}

	public void SaveChanges()
	{
		_transaction.Commit();
	}

}

The Unit of work interface is really simple:

public interface IUnitOfWork : IDisposable
{
	void SaveChanges();
}

Repositories, Unit Of Work and ASP.NET MVC

There are a lot of posts discussing repository implementations, unit of work and ASP.NET MVC. This post is an attempt to give you and answer which addresses all three issues.

Repositories

Do NOT create generic repositories. They look fine when you look at them. But as the application grow you’ll notice that you have to do some workarounds in them which will break open/closed principle.

It’s much better to create repositories that are specific for an entity and it’s aggregate since it’s much easier to show intent. And you’ll also only create methods that you really need, YAGNI.

Generic repositories also removes the whole idea with choosing an OR/M since you can’t use your favorite OR/Ms features.

Unit Of Work

Most OR/Ms available do already implement the UoW pattern. You simply just need to create an interface and make and adapter (google Adapter pattern) implementation for your OR/M.

Interface:

    public interface IUnitOfWork : IDisposable
    {
        void SaveChanges();
    }

NHibernate sample implemenetation:

    public class NHibernateUnitOfWork : IUnitOfWork
    {
        private readonly ITransaction _transaction;

        public NHibernateUnitOfWork(ISession session)
        {
            if (session == null) throw new ArgumentNullException("session");
            _transaction = session.BeginTransaction();
        }

        public void Dispose()
        {
            if (!_transaction.WasCommitted)
                _transaction.Rollback();

            _transaction.Dispose();
        }

        public void SaveChanges()
        {
            _transaction.Commit();
        }
    }

ASP.NET MVC

I prefer to use an attribute to handle transactions in MVC. It makes the action methods cleaner:

[HttpPost, Transactional]
public ActionResult Update(YourModel model)
{
    //your logic here
}

And the attribute implementation:

public class TransactionalAttribute : ActionFilterAttribute
{
    private IUnitOfWork _unitOfWork;

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        _unitOfWork = DependencyResolver.Current.GetService<IUnitOfWork>();

        base.OnActionExecuting(filterContext);
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // let the container dispose/rollback the UoW.
        if (filterContext.Exception == null)
            _unitOfWork.SaveChanges();

        base.OnActionExecuted(filterContext);
    }
}

Get an unique session in each browser tab

I got a lot to do at work, hence the silence. I got a lot to blog about, but so little time ;/ I found an interesting question at stackoverflow which this answer is for (also to show you that the blog is not forgotten).

A user wanted to store browser tab specific data which can be a problem since most browsers shares a session between different tabs. The solution is to create a new route which generates a GUID and then
use that guid to fetch and store session information. Keep in mind that you need to routes: One that works for users which just surfed into the site, and one that loads an existing guid.

Here is the route class:

public class GuidRoute : Route
{
	private readonly bool _isGuidRoute;

	public GuidRoute(string uri, object defaults)
		: base(uri, new RouteValueDictionary(defaults), new MvcRouteHandler())
	{
		_isGuidRoute = uri.Contains("guid");

		DataTokens = new RouteValueDictionary();
	}

	public override RouteData GetRouteData(HttpContextBase httpContext)
	{
		var routeData = base.GetRouteData(httpContext);
		if (routeData == null)
			return null;

		if (!routeData.Values.ContainsKey("guid") || routeData.Values["guid"].ToString() == "")
			routeData.Values["guid"] = Guid.NewGuid().ToString("N");

		return routeData;
	}

	public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
	{
		return !_isGuidRoute ? null : base.GetVirtualPath(requestContext, values);
	}
}

Replace the default route in global.asax with it:

/*routes.MapRoute(
	"Default", // Route name
	"{controller}/{action}/{id}", // URL with parameters
	new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);*/

routes.Add("Default", new GuidRoute(
	"{controller}/{action}/{id}", 
	new { controller = "Home", action = "Index", guid = "", id = UrlParameter.Optional }));

routes.Add("GuidRoute", new GuidRoute(
	"g/{guid}/{controller}/{action}/{id}", 
	new { controller = "Home", action = "Index", guid = "", id = UrlParameter.Optional }));

And finally some extension methods to make life easier in the controllers:

public static class ControllerExtensionMethods
{
	public static string GetGuid(this Controller controller)
	{
		return controller.RouteData.Values["guid"].ToString();
	}

	public static void SetGuidSession(this Controller controller, string name, object value)
	{
		controller.Session[controller.GetGuid() + "_" + name] = value;
	}

	public static object GetGuidSession(this Controller controller, string name)
	{
		return controller.Session[controller.GetGuid() + "_" + name];
	}
}

One thing left though: Any browser bookmarks will use an old GUID. Should not be a problem in most cases (unless the user opens the bookmark in multiple tabs = sharing the session between the tabs). Same
thing goes for opening a link in a new tab = shared.



First draft of my alternative HTML helpers

I’m getting closer to a first release of my ASP.NET MVC contribution project called Griffin.MvcContrib. I’ve just committed my first draft of the alternative HTML helpers. I’ve focused on helpers for Form tags in this commit. If you are wondering what’s wrong with the original helpers, please see my previous blog entry about using extension as an important part of a framework.

Here are some new features that my HTML providers add:

Extensible

By using extension methods there is no way to extend the functionality in them. I’ve solved this in two ways. First and foremost there aren’t any extension methods. My HtmlHelper class is just a facade that tries to use the DependencyResolver to find the proper generators. It will also create the default implementations if no extended ones are found.

To extend one of the helpers, simply derive it and make the changes you like. The following sample with add a “title” attribute to all text areas (which then can be picked up by a jquery script to create a nice tool tip)

    public class MyCustomTextAreaGenerator : TextAreaGenerator
    {
        public MyCustomTextAreaGenerator(ViewContext viewContext) : base(viewContext)
        {
        }

        protected override IEnumerable<NestedTagBuilder> GenerateTags()
        {
            var generatedTags = base.GenerateTags().ToArray();
            generatedTags[0].MergeAttribute("title", "You are so dirty!");
            return generatedTags;
        }
    }

and then register it in your current inversion of control container. Here is a sample for autofac:

containerBuilder
    .RegisterType<MyCustomTextAreaGenerator>()
    .AsImplementedInterfaces();

The following generators do currently exist:

  • CheckBoxGenerator
  • RadioButtonGenerator
  • SelectGenerator
  • TextAreaGenerator
  • TextBoxGenerator

Post processing generated HTML tags

You can also add more generic adapters which can be used to transform the generated HTML tags. The sample project which is included in github shows you how to:

  • create watermarks for textboxes
  • Add tooltips
  • Transform all age fields into UI sliders

Here is the watermark example:

    public class WatermarkAdapter : IFormItemAdapter
    {
        public void Process(FormItemAdapterContext context)
        {
            // there is a "Watermark" metadata but it cannot currently be set.
            // unless you are using a custom metadata provider like the one in the localization demo.
            if (string.IsNullOrEmpty(context.Metadata.Description) || !context.TagBuilder.Attributes.ContainsKey("class") || !context.TagBuilder.Attributes["class"].Contains("watermark"))
                return;

            context.TagBuilder.MergeAttribute("title", "Watermark:" + context.Metadata.Description);
        }
    }

And the jquery script creating the actual watermark (uses the jquery watermark plugin):

function watermark() {
    $('[title*="Watermark:"]').each(function () {
        $(this).watermark($(this).attr('title').substr(10));
        $(this).removeAttr('title');
    });
}

Enum galore

Are you using enums? Sure you do. The html helpers in Griffin.MvcContrib can generate lists, checkboxes and radio buttons automatically for them.

The following code:

@Html2.CheckBoxesFor(model => model.InputType) <br />
@Html2.RadioButtonsFor(model => model.InputType) <br />
@Html2.DropdownFor(model => model.InputType) <br />

Generates the following HTML:

HTML generated by enum html helpers

Lets format that dropdown

Dropdowns are something else that I’ve tried to improve. You can use formatters to determine how the select lists should be generated.

The following example are using a custom formatter which has been made to transform user objects:

@Html2.DropdownFor(model => model.CurrentUser, Select.From<UserFormatter>(Model.Users))

And the actual formatter:

    public class UserFormatter : ISelectItemFormatter
    {
        public SelectListItem Generate(object itm)
        {
            var item = (User)itm;
            return new SelectListItem
            {
                Text = string.Format("{0} {1}", item.FirstName, item.LastName),
                Value = item.Id.ToString()
            };
        }
    }

There are to formatters built into MvcContrib:

  • IdTitle
  • IdName

They uses reflection to find the proper properties.

Summary

All mentioned helpers should work without any problems. But I’m not done with the helpers yet. This post is most about me wanting feedback. Have I made any stupid mistakes? Do you have any suggestions how I can improve the code?

Please take a look at the sample project

The actual source code for all helpers can be found here


A more structured MembershipProvider.

If you take a look at the official documentation that tells you how to create your own custom MembershipProvider you’ll notice that the documentation is mostly about describing:

  • how you should throw exceptions and when
  • Which events you should invoke and when
  • How the logic in each method should work.

Let’s stop here for a moment. What are the most typical reason for creating a custom membership provider? Is it to change the behaviour(/contract) of the provider? Or maybe change the password handling? No. The most common reason is to add support for a custom data source.

Back to the MembershipProvider class. As I see it, it has four responsibilites:

  1. Be able to handle all members (login, register etc)
  2. Load/Store information from/in a data source
  3. Keep track of account/password policies and handle those.
  4. Handle passwords (encrypt/hash/compare)

And that’s why it’s such a tedious task to create a custom MembershipProvider: You need to implement all of those responsibilities.

Griffin.MvcContrib to the rescue!

With the MembershipProvider in Griffin.MvcContrib you do not need to know all of those details. Our MembershipProvider uses DependencyResolver (a built in
Service Locator in MVC3) to lookup the dependencies that it needs. You need to register the following services in your inversion of control container:

IAccountRepository

Used to retrieve/store membership accounts from/to a data source. It’s the only thing you need to implement to get support for a custom data source (like a database or a web service).

Source code

IPasswordStrategy

Used to handle passwords (comparing them, encrypting, decrypting). There are three strategies available in the framework:

  • ClearTextStrategy – Store passwords as clear text in the database
  • HashedPasswordStrategy – Hash passwords before they are stored.
  • TripleDesPasswordStrategy – Use TripleDes to encrypt/decrypt passwords.

Source code

IPasswordPolicy

Defines how passwords should be treated. For instance the minimum length, number of attempts before locking the account etc.

Two policy implementations exist. One who loads the policies from web.config and one “normal” class which you can create and assign the properties in.

Source code

How to use it

Disclaimer: You should know that Account Administration Tools won’t work since the provider has a dependency on DependencyResolver. Other than that, the provider works like any other provider.

Start by modifying your web.config to specify the new provider:

    <membership defaultProvider="GriffinMembershipProvider">
      <providers>
        <clear />
        <add name="GriffinMembershipProvider" type="Griffin.MvcContrib.Providers.Membership.MembershipProvider" applicationName="/" />
      </providers>
    </membership>

Then you need to register the dependencies in your inversion of control container. Here is a sample for Autofac:

protected void Application_Start()
{
	ContainerBuilder builder = new ContainerBuilder();
	builder.RegisterType<HashPasswordStrategy>().AsImplementedInterfaces();
	builder.RegisterType<RavenDbAccountRepository>().AsImplementedInterfaces();
	builder.RegisterInstance(new PasswordPolicy
		 {
			 IsPasswordQuestionRequired = false,
			 IsPasswordResetEnabled = true,
			 IsPasswordRetrievalEnabled = false,
			 MaxInvalidPasswordAttempts = 5,
			 MinRequiredNonAlphanumericCharacters = 0,
			 PasswordAttemptWindow = 10,
			 PasswordMinimumLength = 6,
			 PasswordStrengthRegularExpression = null
		 }).AsImplementedInterfaces();
								 
	// the rest of the initialization
}

If you like to switch from hashed passwords to encrypted passwords you just need to register TripleDesStrategy in the container instead. Or implement your own strategy.

Summary

The code is available at github and can be installed using nuget install-package griffin.mvccontrib.


Why extension methods should not be used as part of a framework.

Two of my favorite frameworks/libraries uses extension methods heavily. Autofac uses extension methods during registration and ASP.NET MVC3 for their HTML Helpers. Since extension methods are static, they are closed for extension. Which are one of the most important principles for object oriented programming.

For MVC I would like to be able to add a tooltip automatically for all editors and labels. It’s really simple, I just want to add a “title” attribute to all generated HTML elements where the ModelMetadata contains a “Description”. The source code for LabelFor looks like this:

    public static class LabelExtensions {
        public static MvcHtmlString Label(this HtmlHelper html, string expression) {
            return LabelHelper(html,
                               ModelMetadata.FromStringExpression(expression, html.ViewData),
                               expression);
        }

        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression) {
            return LabelHelper(html, 
                               ModelMetadata.FromLambdaExpression(expression, html.ViewData), 
                               ExpressionHelper.GetExpressionText(expression));
        }

        public static MvcHtmlString LabelForModel(this HtmlHelper html) {
            return LabelHelper(html, html.ViewData.ModelMetadata, String.Empty);
        }

        internal static MvcHtmlString LabelHelper(HtmlHelper html, ModelMetadata metadata, string htmlFieldName) {
            string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
            if (String.IsNullOrEmpty(labelText)) {
                return MvcHtmlString.Empty;
            }

            TagBuilder tag = new TagBuilder("label");
            tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
            tag.SetInnerText(labelText);
            return tag.ToMvcHtmlString(TagRenderMode.Normal);
        }
    }

Hence it’s impossible to do anything about the helper. I do understand why they use extension methods. It’s great since it’s very easy to find all available helpers. The problem is that you can’t do anything do modify the data that they generate.

The solution

Convert all extension methods to facades for the real implementation, and use DependencyResolver in the extension methods to find the proper classes. Create some interfaces and default implementations for all generators.

The new LabelHelper:

internal static MvcHtmlString LabelHelper(HtmlHelper html, ModelMetadata metadata, string htmlFieldName)
{

    var labelGenerator = DependencyResolver.Resolve<ILabelGenerator>();
    return labelGenerator.Create(html, metadata, htmlFieldName);
}

The default implementation (simplified example):

	public class LabelGenerator : ILabelGenerator
	{
	
		public virtual void Create(HtmlHelper html, ModelMetadata metadata, string htmlFieldName)
		{
            string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
            if (String.IsNullOrEmpty(labelText)) {
                return MvcHtmlString.Empty;
            }

            TagBuilder tag = new TagBuilder("label");
            tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
            tag.SetInnerText(labelText);
			ProcessTag(tag);
            return tag.ToMvcHtmlString(TagRenderMode.Normal);
		}
			
		protected virtual void ProcessTag(TagBuilder tag, ModelMetaData metaData)
		{
		}
	}

Which would allow me to create the following implementation:

	public class LabelWithTitlesGenerator : LabelGenerator
	{
		protected override void ProcessTag(TagBuilder tag, ModelMetaData metaData)
		{
			if (metaData.Description != null)
				tag.Attributes.Add("title", metaData.Description);
		}
	}

The only thing left is to inject it in my container and create a small jquery script which creates the actual tooltip using the “title” attribute.

Summary

Extension methods are closed for extension. Once declared you can not do anything to extend the functionality that they provide. It’s the same as if you would develop a framework where you put sealed on all your classes.

Extension methods were created to be able to make life easier by proving convenience methods for existing classes. The intention was not that you should use them as a part of your framework since you close down that part for extension if you do. The extension methods become locking out methods ;O


Pages:12