Asp.net Razor Web Pages Binding Values To Object

708 views Asked by At

I am just wondering is there a way to bind coming request values to an object like we do in MVC in Web Pages.

Web pages has a simpler way to develop smaller websites than mvc. So I want to use razor web pages to develop websites now.

I used MVC for long time and there was automatic model binding based on conventions. And in any Action you can use TryUpdateModel() method to bind request values on complex object for extra cool job.

There is a ModelBinders.Binders.DefaultBinder.BindModel() method I can see in page but it needs two long parameters.

I am wondering is there a simple fast way for bind Request Parameters to C# object :)

Thx for help.

1

There are 1 answers

0
Mike Brind On

There is no Model Binding in the Web Pages framework. The framework was developed with novice developers primarily in mind and from the comments I saw from members of the project team at the time, they didn't think their target audience would understand or use strongly typed containers for data (business objects).

I needed something like this for a project I worked on, so I built my own very simple model binder. It's rough code that only handles simple types and hasn't been put through any kind of wringer, but it serves my purpose. You can use it for the basis of something more robust:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;

public static class RequestBinder
{
    /// <summary>
    /// Generates entity instances from Request values
    /// </summary>
    /// <typeparam name="TEntity">The Type to be generated</typeparam>
    /// <param name="request"></param>
    /// <returns>TEntity</returns>
    public static TEntity Bind<TEntity>(this HttpRequestBase request) where TEntity : class, new()
    {
        var entity = (TEntity)Activator.CreateInstance(typeof(TEntity));
        var properties = typeof(TEntity).GetProperties();
        foreach (var property in properties)
        {
            object safeValue;
            Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
            try
            {
                if (t == typeof(String))
                {
                    safeValue = string.IsNullOrEmpty(request[property.Name]) ? null : request[property.Name];
                }
                else if (t.IsEnum)
                {
                    safeValue = (request[property.Name] == null) ? null : Enum.Parse(t, request[property.Name]);
                }
                else
                {
                    Type tColl = typeof(ICollection<>);
                    if (t.IsGenericType && tColl.IsAssignableFrom(t.GetGenericTypeDefinition()) || t.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == tColl))
                    {
                        continue;
                    }
                    safeValue = (request[property.Name] == null) ? null : Convert.ChangeType(request[property.Name], t);
                }
                property.SetValue(entity, safeValue, null);
            }
            catch (Exception)
            {

            }
        }
        return entity;
    }

    /// <summary>
    /// Populates an existing entity's properties from the Request.Form collection
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="request"></param>
    /// <param name="entity"></param>
    /// <returns></returns>
    public static TEntity Bind<TEntity>(this HttpRequestBase request, TEntity entity) where TEntity : class, new()
    {
        foreach (string item in request.Form)
        {
            var property = entity.GetType().GetProperty(item);
            if (property != null)
            {
                object safeValue;
                Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
                try
                {
                    if (t == typeof(String))
                    {
                        safeValue = string.IsNullOrEmpty(request[property.Name]) ? null : request[property.Name];
                    }
                    else if (t.IsEnum)
                    {
                        safeValue = (request[property.Name] == null) ? null : Enum.Parse(t, request[property.Name]);
                    }
                    else
                    {
                        Type tColl = typeof(ICollection<>);
                        if (t.IsGenericType && tColl.IsAssignableFrom(t.GetGenericTypeDefinition()) || t.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == tColl))
                        {
                            continue;
                        }
                        safeValue = (request[property.Name] == null) ? null : Convert.ChangeType(request[property.Name], t);
                    }
                    property.SetValue(entity, safeValue, null);
                }
                catch (Exception)
                {

                }
            }
        }
        return entity;
    }
}

You would use it like this:

var person = Request.Bind<Person>();

It's unclear at the moment how Web Pages will be incorporated into ASP.NET vNext. The ASP.NET team have talked about eliminating duplication across Web Pages, MVC and Web API, so hopefully that will result in Web Pages including Model Binding.