C# MVC5-如何定义动作参数类型的反序列化行为?
My Page类提供了一些有用的功能,例如确保页面不小于1等。但是,如果我的公共操作将Page作为参数,则无论表单或querystring中的值是多少,它都始终为null,即使我已经定义了int之间的隐式转换 我是否可以告诉MVC如何反序列化页面类型?这样一个函数是否提供某种方法/向量来从字符串转换 我想在实际页面类型上定义它,因为我将在多个控制器/操作中使用它C# MVC5-如何定义动作参数类型的反序列化行为?,c#,asp.net-mvc,asp.net-mvc-5,C#,Asp.net Mvc,Asp.net Mvc 5,My Page类提供了一些有用的功能,例如确保页面不小于1等。但是,如果我的公共操作将Page作为参数,则无论表单或querystring中的值是多少,它都始终为null,即使我已经定义了int之间的隐式转换 我是否可以告诉MVC如何反序列化页面类型?这样一个函数是否提供某种方法/向量来从字符串转换 我想在实际页面类型上定义它,因为我将在多个控制器/操作中使用它 我很高兴不需要双重动作定义。您必须创建自己的模型绑定器 Guid的示例: public class LogsControlle
我很高兴不需要双重动作定义。您必须创建自己的模型绑定器 Guid的示例:
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);
}
}
创建绑定配置类后:
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);
}
}
最后从应用程序启动调用RegisterBinder:
public class BindingConfig
{
public static void RegisterBinders(ModelBinderDictionary binders)
{
binders.Add(typeof(Guid), new GuidModelBinder());
binders.Add(typeof(Guid?), new GuidModelBinder());
}
}
此自定义模型绑定器允许您通过使用字符串参数定义构造函数来定义任何类型的反序列化行为:
protected void Application_Start()
{
BindingConfig.RegisterBinders(ModelBinders.Binders);
}
并注册它
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();
}