将多个对象作为参数传递给mvc 6 action

时间:2017-01-29 15:26:35

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

我有一个工作正常的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中,响应同一请求的两个对象看起来都是空的 感谢

2 个答案:

答案 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());
        }