我有一个动作,它将用可选的querystring参数调用。但是,这些参数包含在不同的视图模型中。当我尝试将这些模型添加到我的参数列表中时,只有一个模型被填充,其他的总是空的。除了一个空的查询字符串,所有的模型都是用默认值实例化的。
不能选择嵌套这些模型,因为我不希望嵌套的属性名称在querystring中可见。因此,除非能以某种方式绕过这一点,否则这也是一个可行的解决方案。
我注意到,在创建DefaultModelBuilder的快速覆盖时,所有模型都会被解析,但最终结果仍然是实际上只分配了一个模型。
这是我的场景:
public ActionResult Index(ModelA ma, ModelB ba)
{
return Content("ok");
}public class ModelA
{
public string Test { get; set; }
public string Name { get; set; }
}
public class ModelB
{
public int? SomeInteger { get; set; }
public int? TestInteger { get; set; }
}所需的查询字符串:
index?Test=Hi&SomeInteger=7
我想避免的是:
index?ModelA.Test=Hi&ModelB.SomeInteger=7
发布于 2019-06-10 21:38:58
您可以尝试创建一个将这两者结合在一起的类:
public class ModelPair
{
public ModelA A { get; set; }
public ModelB B { get; set; }
}然后用
public ActionResult Index(ModelPair mp)
{
return Content("ok");
}你可以做?A.Test=blah&B.SomeInteger=42
发布于 2019-06-11 09:12:30
我最终致力于创建自己的自定义模型绑定器来执行递归绑定。只要属性名不被重用,这在我的模型中就不会发生,这解决了我不公开嵌套模型类的属性名的问题。
所以现在我有了如下的类结构:
public class ModelA
{
public string Test { get; set; }
public string Name { get; set; }
}
public class ModelB
{
public int? SomeInteger { get; set; }
public int? TestInteger { get; set; }
}
public class ViewModel
{
public ModelA ModelA { get; set; }
public ModelB ModelB { get; set; }
}动作现在看起来是这样的
public ActionResult Index(ViewModel model)
{
return Content("ok");
}这样我就可以在不暴露丑陋的属性名称的情况下使用下面的查询字符串:
index?Test=Hi&SomeInteger=7&Name=Yep&TestInteger=72
当然,我还没有对此进行过长时间的测试,所以我不知道接下来会出现什么问题,但是所有的嵌套模型现在都正确地填充了来自querystring的数据,并且模型类可以很容易地重用:)
public class RecursiveModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var model = base.BindModel(controllerContext, bindingContext);
if (model != null)
{
var properties = bindingContext.ModelType.GetProperties().Where(x => x.PropertyType.IsClass && !x.PropertyType.Equals(typeof(string)) );
foreach(var property in properties)
{
var resursiveBindingContext = new ModelBindingContext(bindingContext)
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, property.PropertyType)
};
var recursiveModel = BindModel(controllerContext, resursiveBindingContext);
property.SetValue(model, recursiveModel);
}
}
return model;
}
}发布于 2019-06-10 14:58:45
据我所知,默认的Model Binder不能做到这一点。我们必须实现自定义模型绑定器如下所示。
public class CustomModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var query = bindingContext.HttpContext.Request.Query;
var modelb = new ModelB();
if (query.TryGetValue($"{bindingContext.ModelName}.{nameof(modelb.SomeInteger)}", out var someInteger))
{
modelb.SomeInteger = Convert.ToInt32(JsonConvert.DeserializeObject(someInteger).ToString());
}
if (query.TryGetValue($"{bindingContext.ModelName}.{nameof(modelb.TestInteger)}", out var testInteger))
{
modelb.TestInteger = Convert.ToInt32(JsonConvert.DeserializeObject(testInteger).ToString());
}
bindingContext.Result = ModelBindingResult.Success(modelb);
return Task.FromResult(modelb);
}
}在控制器操作中,我们可以使用绑定器,如下所示
public IActionResult Index(ModelA modelA, [ModelBinder(typeof(CustomModelBinder))]ModelB modelB)
{
return Json(new {modelA, modelB});
}在querystring中,我们可以使用前缀来区分每个模型。
?modelA.test="MATests"&modelA.Name="modelANameValue"&modelB.SomeInteger="5"请查找工作示例here on github
https://stackoverflow.com/questions/56520125
复制相似问题