【问题标题】:In ASP.NET MVC 5, how can I deserialize a complex object from a FormCollection?在 ASP.NET MVC 5 中,如何从 FormCollection 反序列化复杂对象?
【发布时间】:2019-04-13 02:21:56
【问题描述】:

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 时自动为我们执行此操作,因此我们肯定可以使用这样的工具作为单行调用?

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

【问题讨论】:

  • 这些类是否共享一个基类?或者你可以让动作的参数成为一个对象,然后从那里检查它的类型以做出决定? MVC 使用模型绑定器将各种输入反序列化到模型中。您可以制作一个自定义模型绑定器来确定类型,然后通过其中一个标准绑定器运行它以自动进行反序列化。
  • “这些类是否共享一个基类?”这些类(不一定)共享一个基类;它们的属性可能完全不同和/或不兼容。 “MVC 使用模型绑定器来反序列化......您可以制作自定义模型绑定器”感谢指针/方向 :)
  • 不幸的是,我发现的每个“自定义模型绑定器”教程都明确说明要进行逐个属性、逐个字段的手动传播。老实说,我只是在寻找像 Json 的 DeserializeObject 这样简单的东西,但对于 FormCollection,为什么这么难找到?微软的代码中肯定有一些东西。
  • 我过去所做的是制作一个自定义模型绑定器,该绑定器检查表单集合中的某些类型指示符,然后通过为它们提供应该反序列化的类型来调用其他模型绑定器。看看这个让你知道你可以做什么https://stackoverflow.com/questions/36504824/how-to-call-default-model-binding-from-custom-binder-in-webapi

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


【解决方案1】:

由于我一直在寻找一种简单的单行代码来将 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
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-20
    相关资源
    最近更新 更多