[英]ASP.NET Core MVC - Binding to model at runtime
我有以下視圖模型:
public class FormViewModel {
[Required, StringLength(100)]
public string Name { get; set; }
private object _parameters = null;
public object Parameters {
get {
if (_parameters == null)
_parameters = Activator.CreateInstance(Type.GetType("CustomParameters"));
return _parameters;
}
set {
_parameters = value;
}
}
}
CustomParameters如下所示:
public class CustomParameters {
[Required]
public string Text { get; set; }
}
現在,如果我發布以下表單數據:
"Name" => "Foo"
"Parameters.Text" => "Bar"
正確設置了“名稱”屬性,但是“ Parameters.Text”屬性設置為null。
請注意,上面的場景已經簡化,參數需要支持綁定到多個自定義類型。
編輯-我添加了以下我在ASP.NET MVC中使用的代碼,但是ASP.NET Core的模型綁定似乎已被重寫,而我看不到需要做什么:
public class IRuntimeBindableModelBinder : DefaultModelBinder {
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
var newBindingContext = new ModelBindingContext() {
// In the original method you have:
// ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => bindingContext.Model, typeof(TModel)),
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => bindingContext.Model, bindingContext.Model.GetType()),
ModelName = bindingContext.ModelName,
ModelState = bindingContext.ModelState,
PropertyFilter = bindingContext.PropertyFilter,
ValueProvider = bindingContext.ValueProvider
};
return base.BindModel(controllerContext, newBindingContext);
}
}
如果有人可以提供幫助,我將不勝感激。
謝謝
這可以通過自定義ModelBinder完成。 這里的問題是.NET不知道哪種類型存儲在對象Property中,因此默認情況下為null。
您需要知道目標類型(通過Name或其他Type屬性),然后可以創建一個ModelBinder,如下所示:
public class MyModelBinder : IModelBinder
{
private readonly IModelMetadataProvider _modelMetadataProvider;
private readonly IModelBinderFactory _modelBinderFactory;
public MyModelBinder(IModelMetadataProvider modelMetadataProvider, IModelBinderFactory modelBinderFactory)
{
_modelMetadataProvider = modelMetadataProvider;
_modelBinderFactory = modelBinderFactory;
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var typeValue = bindingContext.ValueProvider.GetValue(nameof(ComplexModel.Type)).Values;
var nameValue = bindingContext.ValueProvider.GetValue(nameof(ComplexModel.Name)).Values;
var finalModel = new ComplexModel
{
Name = nameValue,
Type = typeValue
};
var innerType = LookupType(typeValue);
if (innerType != null)
{
finalModel.Parameters = Activator.CreateInstance(innerType);
var modelMetadata = _modelMetadataProvider.GetMetadataForType(innerType);
var modelBinder = _modelBinderFactory.CreateBinder(new ModelBinderFactoryContext
{
Metadata = modelMetadata,
CacheToken = modelMetadata
});
var modelName = bindingContext.BinderModelName == null ? "Parameters" : $"{bindingContext.BinderModelName}.Parameters";
using (var scope = bindingContext.EnterNestedScope(modelMetadata, modelName, modelName, finalModel.Parameters))
{
await modelBinder.BindModelAsync(bindingContext);
}
}
bindingContext.Result = ModelBindingResult.Success(finalModel);
return;
}
//NOTE: this maps a type string to a Type.
//DO NOT transmit a type FullName and use reflection to activate, this could cause a RCE vulnerability.
private Type LookupType(string type)
{
switch (type)
{
case "text":
return typeof(TextParam);
case "int":
return typeof(IntParam);
}
return null;
}
}
//Sample of ComplexModel classes
[ModelBinder(typeof(MyModelBinder))]
public class ComplexModel
{
public string Name { get; set; }
public string Type { get; set; }
public object Parameters { get; set; }
}
public class TextParam
{
public string Text { get; set; }
}
public class IntParam
{
public int Number { get; set; }
}
注意:使用類型進行自定義反序列化時,限制要反序列化的允許類型列表很重要。 如果您接受類型的全名並使用反射來激活,則可能會導致RCE漏洞,因為.NET中有些類型在設置屬性時會執行代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.