我有一个将使用可选的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
答案 0 :(得分:0)
您可以尝试结合使用这两个类:
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
答案 1 :(得分:0)
我最终致力于创建自己的自定义模型活页夹,该活页夹可以进行递归绑定。只要不重复使用属性名(无论如何在我的模型中都不会发生这种情况),就可以解决我不公开嵌套模型类的属性名的问题。
所以现在我有以下类结构:
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
当然,我还没有对此进行广泛的测试,所以我不知道会出现什么问题,但是现在所有嵌套模型都正确地填充了来自查询字符串的数据,并且可以将模型类易于重复使用:)
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;
}
}
答案 2 :(得分:-1)
据我所知,默认模型绑定程序无法做到这一点。我们必须实现以下自定义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);
}
}
在Action控制器中,我们可以按照以下方式使用Binder
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