MVC5 - 如何为动作参数类型定义反序列化行为?

时间:2017-06-02 22:00:13

标签: c# asp.net-mvc asp.net-mvc-5

    public class LogsController : Controller
    {
        public async Task<ActionResult> User(string id, int? page)
        {
            return await User(id, (Page)page);
        }

        private async Task<ActionResult> User(string id, Page page)
        {
            var data = await Repo.GetData(id, page, 10);
            var model = new UserLogs
            {
                User = id,
                Events = data,
                Pager = new PagerInput(page, 10, data.TotalCount)
            };

            return View("UserGrid", model);
        }
    }

我的Page类提供了有用的功能,例如确保页面永远不会小于1,等等。但是,如果我的公共操作将Page作为参数,则它始终为null,无论表单或查询字符串中的值是什么,即使我已经在int中定义了隐式强制转换。

无论如何,我可以告诉MVC如何反序列化页面类型?这样提供某种方法/ ctor来转换为字符串?

我想在实际的页面类型上定义它,因为我将在多个控制器/操作中使用它。

我很高兴不需要双动作定义。

2 个答案:

答案 0 :(得分:1)

您必须创建自己的模型装订器。

Guid示例:

public class GuidModelBinder : DefaultModelBinder
{
    public override object BindModel(
            ControllerContext controllerContext,
            ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType == typeof(Guid) ||
            bindingContext.ModelType == typeof(Guid?))
        {
            Guid result;

            var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

            if (valueResult.AttemptedValue == null &&
                    bindingContext.ModelType == typeof(Guid))
                return Guid.Empty;

            if (valueResult.AttemptedValue == null &&
                    bindingContext.ModelType == typeof(Guid?))
                return null;

            if (Guid.TryParse(valueResult.AttemptedValue, out result))
                return result;
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}

创建绑定配置类后:

public class BindingConfig
{
    public static void RegisterBinders(ModelBinderDictionary binders)
    {
        binders.Add(typeof(Guid), new GuidModelBinder());
        binders.Add(typeof(Guid?), new GuidModelBinder());
    }
}

最后从Application_Start调用RegisterBinders:

protected void Application_Start()
{
    BindingConfig.RegisterBinders(ModelBinders.Binders);
}

答案 1 :(得分:0)

此自定义模型绑定器允许您通过简单地使用字符串参数定义构造函数来定义任何类型的反序列化行为:

public class CustomModelBinder : DefaultModelBinder
{
    static Assembly _assembly = typeof(CustomModelBinder).Assembly;
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {   
        if (_assembly.Equals(bindingContext.ModelType.Assembly))
        {
            var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            var ctor = bindingContext.ModelType.GetConstructor(new Type[] { typeof(string) });
            if (ctor != null && value != null)
                return ctor.Invoke(new object[] { value.AttemptedValue });
        }
        return base.BindModel(controllerContext, bindingContext);
    }
}

注册它......

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    ModelBinders.Binders.DefaultBinder = new CustomModelBinder();
}