我有一个工作正常的MVC 5项目,我需要将该项目迁移到带有.NET核心的MVC 6。在设法调整所有工作之后,我遇到了一个问题:我的许多操作都接受了多个对象作为参数。模型绑定器MVC 5正在使用没有问题,但MVC 6似乎在这些操作的所有参数中都为null,我猜它是MVC和WebAPI统一的一部分。我的问题是,如果它周围存在而不添加另一个请求包装器对象的模型库。
例如:
[HttpPost]
public ActionResult GetVersionData(OvlEnvironment environment, Pipeline pipeline)
{
BL.SetEnviromentVersion(pipeline, environment);
return PartialView("_Version", environment);
}
在mvc 5项目中,ajax请求包含
形式的json数据{ "environment" : {*Data...*},
"pipeline" : {*Data...*}
}
被接受了。在mvc 6中,响应同一请求的两个对象看起来都是空的 感谢
答案 0 :(得分:5)
您必须为ASP.NET Core MVC Framework提供提示,即在post请求的主体中找到要绑定到模型的数据。这是通过[FromBody] attribute完成的。
[FromBody]:使用配置的格式化程序绑定来自的数据 请求机构。格式化程序是根据内容类型选择的 请求。
按照设计,不可能将多个参数绑定到一个JSON源,如here所述。为了避免使用其他模型类,您可以使用这样的通用JObject:
[HttpPost]
public ActionResult GetVersionData([FromBody] JObject data)
{
var environment = data["environment"].ToObject<OvlEnvironment>();
var pipline = data["pipeline"].ToObject<Pipeline>();
BL.SetEnviromentVersion(pipeline, environment);
return PartialView("_Version", environment);
}
答案 1 :(得分:1)
我知道这篇文章很旧,但是我也遇到了这个问题。
我认为公认的答案是正确的,在ASP.NET MVC5中可以查找HttpRequest.InputStream,但是在ASP.NET Core 2中不再允许这样做。因此,解决方法是读取流一次并将解析的JObject存储在ModelState(https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.modelbinding.modelstatedictionary?view=aspnetcore-2.1)中。简单的测试表明,该方法可行。
这是这种方法的一个示例:
public class JsonMultiParameterModelBinder : IModelBinder
{
private static IModelBinder DefaultModelBinder;
private const string JSONKEY = "json_body";
public JsonMultiParameterModelBinder(IModelBinder defaultModelBinder)
{
DefaultModelBinder = defaultModelBinder;
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var httpContext = bindingContext.HttpContext;
var stream = bindingContext.HttpContext.Request.Body;
if (httpContext.Request.ContentType.Contains("application/json"))
{
JObject jobject = null;
ModelStateEntry entry = null;
bindingContext.ModelState.TryGetValue(JSONKEY, out entry);
if (entry == null)
{
using (var readStream = new StreamReader(stream, Encoding.UTF8))
using (var jsonReader = new JsonTextReader(readStream))
{
jobject = JObject.Load(jsonReader);
}
bindingContext.ModelState.SetModelValue(JSONKEY, jobject, null);
}
else
{
jobject = entry.RawValue as JObject;
}
var jobj = jobject[bindingContext.FieldName];
if (jobj == null)
{
httpContext.Response.StatusCode = 500; // error has occured
throw new JsonReaderException(string.Format("The rootnode '{0}' is not found in the Json message.", bindingContext.ModelName));
}
object obj = null;
var JSONSerializer = new JsonSerializer();
try
{
obj = jobj.ToObject(bindingContext.ModelType, JSONSerializer);
bindingContext.Model = obj;
bindingContext.Result = ModelBindingResult.Success(obj);
return Task.CompletedTask;
}
catch (Exception ex)
{
httpContext.Response.StatusCode = 500; // error has occured
throw ex;
}
}
return DefaultModelBinder.BindModelAsync(bindingContext);
}
}
以及此资料夹的提供者:
public class JsonMultiParameterModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
if (context.Metadata.IsComplexType)
{
ComplexTypeModelBinderProvider p = new ComplexTypeModelBinderProvider();
return new JsonMultiParameterModelBinder(p.GetBinder(context));
}
return null;
}
}
在Startup.cs中注册:
services.AddMvc(options =>
{
options.ModelBinderProviders.Insert(0, new JsonMultiParameterModelBinderProvider());
}