Render Action Attribute

The purpose of this attribute is to be able to render action as an editor or display template for your form fields. First of all we will need the data structure which will hold options for the our editor template.

RenderActionOptions.cs

public class RenderActionOptions 
{
    public static string MetadataKey = "RenderActionOptions";

    public string Action { get; set; }
    public string Controller { get; set; }
    public string Area { get; set; }
}

Then we can use custom attribute, which implements IMetadataAware interface, to fill the options and pass them to a metadata.

RenderActionAttribute.cs

public class RenderActionAttribute : Attribute, IMetadataAware
{
    public RenderActionAttribute([AspMvcAction] string action)
    {
        Action = action;
    }

    public RenderActionAttribute([AspMvcAction] string action, [AspMvcController] string controller)
    {
        Action = action;
        Controller = controller;
    }

    public RenderActionAttribute([AspMvcAction] string action, [AspMvcController] string controller, [AspMvcController] string area)
    {
        Action = action;
        Controller = controller;
        Area = area;
    }

    public string Action { get; set; }
    public string Controller { get; set; }
    public string Area { get; set; }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.AdditionalValues[RenderActionOptions.MetadataKey] = new RenderActionOptions
        {
            Action = Action,
            Controller = Controller,
            Area = Area
        };
        metadata.TemplateHint = "RenderAction";
    }
}

And finally at our EditorTemplate we will retrieve the options from the metadata and use Html.RenderAction helper method to render our action. Please note, that Html.RenderAction nor Html.Action do not accept "area" as an argument, so we need to add the "area" key to our routes dictionary. Also, we pass data to the Html.RenderAction method to be able supply some additional information/metadata to the rendered action.

Shared/EditorTemplates/RenderAction.cshtml

@{
    var data = new RouteValueDictionary(ViewData);
    object o;
    ViewData.ModelMetadata.AdditionalValues.TryGetValue(RenderActionOptions.MetadataKey, out o);
    var options = o as RenderActionOptions;
    if (!string.IsNullOrEmpty(options.Area))
    {
        data["area"] = options.Area;
    }
    if (!string.IsNullOrEmpty(options.Controller))
    {
        Html.RenderAction(options.Action, options.Controller, data);
    }
    else
    {
        Html.RenderAction(options.Action, data);
    }
}

Example of Usage

MyModel.cs

public class MyModel 
{
    [Display(Name = "City"), RenderAction("ListCities", "Cities")]
    public int CityId { get; set; }
}

MyForm.cshtml

@model MyModel
// ...
@Html.EditorFor(m => m.CityId, new { htmlAttributes = new { @class = "my-editor" } } )
// ...
comments powered by Disqus