Tag Archives: asp.net

Conditional Required Validation in ASP.NET MVC

using System.ComponentModel.DataAnnotations;
using System.Reflection;

public sealed class ConditionalRequiredAttribute : RequiredAttribute
{
    public override bool RequiresValidationContext
    {
        get { return true; }
    }

    public string ConditionalPropertyName { get; private set; }

    public ConditionalRequiredAttribute(string conditionalPropertyName)
    {
        ConditionalPropertyName = conditionalPropertyName;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        PropertyInfo conditionalProperty = validationContext.ObjectType.GetProperty(ConditionalPropertyName);
        bool conditionalValue = (bool)conditionalProperty.GetValue(validationContext.ObjectInstance);
        if (conditionalValue)
        {
            return base.IsValid(value, validationContext);
        }
        else
        {
            return ValidationResult.Success;
        }
    }
}

Nonempty Collection Validation in ASP.NET MVC

using System;
using System.Collections;
using System.ComponentModel.DataAnnotations;

[AttributeUsage(AttributeTargets.Property)]
public sealed class NotEmptyAttribute : RequiredAttribute
{
    public override bool IsValid(object value)
    {
        ICollection valueCollection = value as ICollection;
        return valueCollection != null && valueCollection.Count > 0;
    }
}

ASP.NET MVC HTML Helper: Once

public static HtmlString Once(this HtmlHelper @this, Func<dynamic, HelperResult> template)
{
    string key = "Once";
    ISet<string> cache;
    if (@this.ViewContext.HttpContext.Items.Contains(key))
    {
        cache = (ISet<string>)@this.ViewContext.HttpContext.Items[key];
    }
    else
    {
        cache = new HashSet<string>();
        @this.ViewContext.HttpContext.Items[key] = cache;
    }
    string html = template(null).ToString();
    if (!cache.Contains(html))
    {
        cache.Add(html);
        return new HtmlString(html);
    }
    else
    {
        return null;
    }
}

Usage:

@for (int i = 0; i < 10; i++)
{
    @Html.Once(
        @<script type="text/javascript">
            alert("You will only see this once.");
        </script>);
}

Programmatic View Rendering in ASP.NET MVC

using System.IO;
using System.Web.Mvc;

public class ControllerBase : Controller
{
    protected string RenderResult(ViewEngineResult result, object model)
    {
        ViewData.Model = model;
        using (StringWriter writer = new StringWriter())
        {
            ViewContext viewContext = new ViewContext(ControllerContext, result.View, ViewData, TempData, writer);
            result.View.Render(viewContext, writer);
            result.ViewEngine.ReleaseView(ControllerContext, result.View);
            return writer.ToString();
        }
    }

    protected string RenderPartialView(string viewName, object model)
    {
        return RenderResult(ViewEngines.Engines.FindPartialView(ControllerContext, viewName), model);
    }

    protected string RenderView(string viewName, string masterName, object model)
    {
        return RenderResult(ViewEngines.Engines.FindView(ControllerContext, viewName, masterName), model);
    }

    protected string RenderView(string viewName, object model)
    {
        return RenderView(viewName, null, model);
    }
}

Relative Date Validation in ASP.NET MVC

using System;
using System.ComponentModel.DataAnnotations;
using System.Reflection;

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public sealed class LaterThanAttribute : ValidationAttribute
{
    public override bool RequiresValidationContext
    {
        get { return true; }
    }

    public string ComparedPropertyName { get; private set; }
    public string ComparedPropertyDisplayName { get; set; }
    public bool AllowEqual { get; set; }
    public bool IgnoreTime { get; set; }

    public LaterThanAttribute(string comparedPropertyName)
    {
        ComparedPropertyName = comparedPropertyName;
        AllowEqual = false;
        IgnoreTime = false;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value == null)
        {
            return ValidationResult.Success;
        }
        DateTime dateTime = (DateTime)value;
        PropertyInfo comparedProperty = validationContext.ObjectType.GetProperty(ComparedPropertyName);
        object comparedValue = comparedProperty.GetValue(validationContext.ObjectInstance);
        if (comparedValue == null)
        {
            return ValidationResult.Success;
        }
        DateTime comparedDateTime = (DateTime)comparedValue;
        if (IgnoreTime)
        {
            dateTime = dateTime.Date;
            comparedDateTime = comparedDateTime.Date;
        }
        if (dateTime > comparedDateTime)
        {
            return ValidationResult.Success;
        }
        else
        {
            if (AllowEqual && dateTime == comparedDateTime)
            {
                return ValidationResult.Success;
            }
            else
            {
                return new ValidationResult(string.Format(
                    "The {0} field must be later than{1}the {2} field.",
                    validationContext.DisplayName,
                    AllowEqual ? " or equal to " : " ",
                    ComparedPropertyDisplayName ?? ComparedPropertyName));
            }
        }
    }
}

Custom Property Binding in ASP.NET MVC

IPropertyBinder.cs:

using System.ComponentModel;
using System.Web.Mvc;

public interface IPropertyBinder
{
    object BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor);
}

PropertyBinderAttribute.cs:

using System;
using System.Web.Mvc;

[AttributeUsage(AttributeTargets.Property)]
public sealed class PropertyBinderAttribute : Attribute
{
    public Type BinderType { get; private set; }

    public PropertyBinderAttribute(Type binderType)
    {
        BinderType = binderType;
    }

    public IPropertyBinder GetBinder()
    {
        return (IPropertyBinder)DependencyResolver.Current.GetService(BinderType);
    }
}

ModelBinderBase.cs:

using System.ComponentModel;
using System.Linq;
using System.Web.Mvc;

public class ModelBinderBase : DefaultModelBinder
{
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
    {
        PropertyBinderAttribute attribute = propertyDescriptor.Attributes
            .OfType<PropertyBinderAttribute>()
            .SingleOrDefault();
        if (attribute == null)
        {
            base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
        }
        else
        {
            propertyDescriptor.SetValue(bindingContext.Model, attribute.GetBinder().BindProperty(controllerContext, bindingContext, propertyDescriptor));
        }
    }
}

Global.asax.cs:

using System;
using System.Web;
using System.Web.Mvc;

public class Global : HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        ModelBinders.Binders.DefaultBinder = new ModelBinderBase();
    }
}

To make use of this code, write a custom property binder that implements IPropertyBinder and decorate the corresponding property in your view model with a PropertyBinderAttribute that references your binder’s type.

Trimmed String Binding in ASP.NET MVC

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;

public class TrimmingModelBinder : DefaultModelBinder
{
    protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
    {
        if (propertyDescriptor.PropertyType == typeof(string))
        {
            if (value != null)
            {
                value = ((string)value).Trim();
                if ((string)value == "")
                {
                    bool convertToNull = true;
                    DisplayFormatAttribute attribute = propertyDescriptor.Attributes
                        .OfType<DisplayFormatAttribute>()
                        .SingleOrDefault();
                    if (attribute != null)
                    {
                        convertToNull = attribute.ConvertEmptyStringToNull;
                    }
                    if (convertToNull)
                    {
                        value = null;
                    }
                }
            }
        }
        base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);
    }
}