首页 > 解决方案 > 在 ASP.NET MVC 5 中,如何从 FormCollection 反序列化复杂对象?

问题描述

ASP.NET MVC 5 中是否有可访问的工具来从[HttpPost]操作中获取 FormCollection 参数并将其反序列化为给定类型?像,MyModelType myModel = SOMEHOWDSERIALIZE<MyModelType>(formCollection);

我们有一个复杂的对象,我们在 ASP.NET MVC 5 中使用通常的 EditorFor 绑定来处理,而帖子过去看起来像这样:

[HttpPost]
public ActionResult MyModelAction(MyModelV1 myModel)
{
    // .. process the model here
}

现在,我们有了新版本的模型,我们不会创建新的路由/URL来发布新的模型版本有效负载。模型的属性有足够的元数据供我们推断其反序列化类型,因此我们可以使用表单字段中的元数据来破译要反序列化和执行的模型类型。所以现在它看起来像这样:

[HttpPost]
public ActionResult MyModelAction(FormCollection parameters)
{
    switch (parameters["OurVersionDisambiguator"])
    {
        case "V1":
            var myModel_V1 = SOMEHOW_DESERIALIZE<MyModel_V1>(parameters);
            return MyModelAction(myModel_V1);
        case "V2":
            var myModel_V2 = SOMEHOW_DESERIALIZE<MyModel_V2>(parameters);
            return MyModelAction(myModel_V2);
        default: throw new NotImplementedException();
    }
}

[NonAction]
public ActionResult MyModelAction(MyModelV1 myModelV1) 
{
    // process the model
}

[NonAction]
public ActionResult MyModelAction(MyModelV2 myModelV2) 
{
    // process the model
}

在上面的示例中,我推断创建类似以下方法的东西,但我不确定如何处理它......

T SOMEHOW_DESERIALIZE<T>(FormCollection parameters)

我知道我可以使用 Activator 和 Reflection 并“手动”手动输入反序列化,但是由于 ASP.NET MVC 通常会在我们不使用时自动为我们执行此操作FormCollection,因此肯定有这样的工具可以作为单线调用?

请注意,在上述示例中,处理必须继续有权访问请求上下文,因为在同一个请求中可能存在要处理的文件上传流。

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

解决方案


由于我一直在寻找一种简单的单行方法来将 FormCollection 绑定到运行时已知类型的模型,因此拥有自定义模型绑定器并不是一个很好的解决方案。幸运的是,我正在寻找的内置功能是TryUpdateModel(..).

[HttpPost]
public ActionResult MyModelAction(FormCollection parameters)
{
    switch (parameters["OurVersionDisambiguator"])
    {
        case "V1":
            var myModel_V1 = new MyModel_V1();
            var hasModelStateError /* ignoring */ =
                TryUpdateModel(myModel_V1, parameters.ToValueProvider());
            return MyModelAction(myModel_V1);
        case "V2":
            var myModel_V2 = new MyModel_V2();
            var hasModelStateError /* ignoring */ =
                TryUpdateModel(myModel_V2, parameters.ToValueProvider());
            return MyModelAction(myModel_V2);
        default: throw new NotImplementedException();
    }
}

[NonAction]
public ActionResult MyModelAction(MyModelV1 myModelV1) 
{
    // process the model
}

[NonAction]
public ActionResult MyModelAction(MyModelV2 myModelV2) 
{
    // process the model
}

推荐阅读