gpt4 book ai didi

c# - 如何使用相同的 MVC Controller 方法处理数组或单个对象?

转载 作者:太空狗 更新时间:2023-10-30 01:20:36 24 4
gpt4 key购买 nike

我有一个接受列表作为参数的 ActionResult 方法:

[HttpPost]
public ActionResult MyMethod (List<ClassA> json)
{
...
}

这会将传入的 json 字符串绑定(bind)到已填充的 ClassA 对象的通用列表中。

问题是有时传入的 json 只是一个 json 对象,而不是一个 json 对象数组。

有什么方法可以抢占它,以便我可以直接绑定(bind)到 ClassA 和 List?或者我可以使用其他一些技术吗?

以下是 JSON 的发送方式(作为数组):

var myjsonarray = [{
"ID": "1",
"FirstName": "John",
"LastName": "Doe",
}, {
"ID": "2",
"FirstName": "Jane",
"LastName": "Doe",
}];

$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "/Home/MyPage",
data: JSON.stringify(myjsonarray),
dataType: 'json'
});

以上过程没问题。这也有效:

var myjsonarray = [{
"ID": "1",
"FirstName": "John",
"LastName": "Doe",
}];

但是当我作为一个未包装在数组中的单个对象发送时:

var myjsonarray = {
"ID": "1",
"FirstName": "John",
"LastName": "Doe",
};

我的 ActionResult 方法参数为空:

json == null

最佳答案

虽然您的问题并不清楚,但从其他答案的评论来看,您似乎无法控制向您发送此 JSON 的客户端代码。 (如果你这样做了,最简单的解决方案是在发送之前将你的单个对象包装在一个数组中,正如其他人已经建议的那样。)

如果 MVC 允许我们在 Controller 中添加方法重载来处理这种情况,那就太好了,例如:

[HttpPost]
public ActionResult MyMethod (List<ClassA> list)
{
...
}

[HttpPost]
public ActionResult MyMethod (ClassA single)
{
...
}

虽然这可以很好地编译,但不幸的是,当您在运行时点击该方法时,它会导致 System.Reflection.AmbiguousMatchException

因此,看起来您需要创建自定义 IModelBinder解决问题。虽然我之前没有实现过自定义模型绑定(bind)器,但我将其视为挑战并提出了以下建议。您显然必须根据自己的需要对其进行调整,但它似乎适用于您的示例。

代码如下:

public class CustomModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
IValueProvider provider = bindingContext.ValueProvider;

// Check whether we have a list or a single object. If we have a list
// then all the properties will be prefixed with an index in square brackets.
if (provider.ContainsPrefix("[0]"))
{
// We have a list. Since that is what the controller method is
// expecting, just use the default model binder to do the work for us.
return ModelBinders.Binders.DefaultBinder.BindModel(controllerContext, bindingContext);
}
else
{
// We have a single object.
// Bind it manually and return it in a list.
ClassA a = new ClassA();
a.ID = GetValue<int>(provider, "ID");
a.FirstName = GetValue<string>(provider, "FirstName");
a.LastName = GetValue<string>(provider, "LastName");
return new List<ClassA> { a };
}
}

private T GetValue<T>(IValueProvider provider, string key)
{
ValueProviderResult result = provider.GetValue(key);
return (result != null ? (T)result.ConvertTo(typeof(T)) : default(T));
}
}

要将此自定义绑定(bind)器插入 MVC 管道,请将此行添加到 Global.asax.cs 中的 Application_Start() 方法。

ModelBinders.Binders.Add(typeof(List<ClassA>), new CustomModelBinder());

现在,显然这不是一个通用的解决方案;它是专门为处理 ClassA 而定制的。我必须相信,有可能制定一个通用解决方案来处理任何类型列表的这种“单一或列表”情况,但这要复杂得多,超出了这个答案的范围。为此,您可能还需要创建自定义 IModelBinderProvider .如果你想达到那个水平,你需要自己调查。这是一个 MSDN article这可能会让您更深入地了解绑定(bind)在幕后的工作原理。

关于c# - 如何使用相同的 MVC Controller 方法处理数组或单个对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18642879/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com