Всем привет!
MVC Default Model Binding сам разбирает входные значения полей и подсовывает под указанную модель, т.е.
есть модель:
class Person {
public string Name {get;set;}
public string Age {get;set;}
}
действие:
[HttpPost]
public ActionResult SaveData(Person model) {
...
}
и вьюха с
@Html.BeginForm("SaveData", "Home", FormMethod.Post) {
@Html.EditorFor(model.Name, ...)
@Html.EditorFor(model.Age,...)
<input type="submit" text="Save"/>
}
при сабмите значения из Request.Form транслируются в объект типа Person.
У меня другая ситуация — у меня нет ни Request.Form, ни Request.QueryString
Допустим, имя класса (полное), например, "Front.Models.Person" и словарь Поле/Значение, например, ["Name"]/["Serg"]; ["Age"]/[28] я получил из базы.
Нужно точно так же, средствами MVC Default Model Binding (DMB), получить на выходе объект этого класса.
Именно НЕ руками через рефлекшн, а средствами DMB!
Можно ли осуществить задуманное?
Здравствуйте, curt_russel, Вы писали:
_>У меня другая ситуация — у меня нет ни Request.Form, ни Request.QueryString
_>Допустим, имя класса (полное), например, "Front.Models.Person" и словарь Поле/Значение, например, ["Name"]/["Serg"]; ["Age"]/[28] я получил из базы.
_>Нужно точно так же, средствами MVC Default Model Binding (DMB), получить на выходе объект этого класса.
_>Именно НЕ руками через рефлекшн, а средствами DMB!
А почему бы не использовать ControllerFactory для этого?
Ну а серьезно — у Model Binder вполне конкретная цель, а у DMB еще и конкретная реализация. Чисто теоретически, можно попробовать сэмулировать Web запрос из словаря создать QueryString и правда без рефлекшена не получится по имени класса (строке) получить его экземпляр. Но IMHO лучше уж тогда написать свой биндер.
Здравствуйте, pavel783, Вы писали:
P> или еще в утилите Reflector есть плагин filedisasembler — можно исходники dmb выдрать и заменить в них httpcontext и иже с ним входные данные на более абстрактные данные, dmb тогда будет более универсальным...
А можно не заниматься ерундой и сделать декоратор. Ну а если сильно хочется сорцы, то опять же не возиться с Reflector. ASP.NET уже давно OpenSource. Вот этот биндер (и прочие сорцы там же на
http://aspnetwebstack.codeplex.com)
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/DefaultModelBinder.cs
Здравствуйте, Doc, Вы писали:
Doc>Здравствуйте, pavel783, Вы писали:
P>> или еще в утилите Reflector есть плагин filedisasembler — можно исходники dmb выдрать и заменить в них httpcontext и иже с ним входные данные на более абстрактные данные, dmb тогда будет более универсальным...
Doc>А можно не заниматься ерундой и сделать декоратор. Ну а если сильно хочется сорцы, то опять же не возиться с Reflector. ASP.NET уже давно OpenSource. Вот этот биндер (и прочие сорцы там же на http://aspnetwebstack.codeplex.com)
Doc>http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/DefaultModelBinder.cs
Спасибо большое за советы!
Кому интересно, решение этой задачи:
private void Run()
{
var dictionary = {параметры из БД}.ToDictionary(vmv => vmv.ParameterName,vmv => vmv => vmv.ParameterValue);
var dictionaryValueProvider = new DictionaryValueProvider<object>(dictionary, CultureInfo.CurrentCulture);
GenerateModel(ctrl.ModelName, dictionaryValueProvider);
}
private object GenerateModel(string modelName, DictionaryValueProvider<object> dictionaryValueProvider)
{
var type = Type.GetType(modelName, false, true);
var model = Activator.CreateInstance(type);
CmsTryUpdateModel(model, dictionaryValueProvider);
return model;
}
protected internal bool CmsTryUpdateModel<TModel>( TModel model, IValueProvider valueProvider ) where TModel : class
{
if (model == null)
{
throw new ArgumentNullException("model");
}
if (valueProvider == null)
{
throw new ArgumentNullException("valueProvider");
}
Predicate<string> propertyFilter = propertyName => new BindAttribute().IsPropertyAllowed(propertyName);
IModelBinder binder = Binders.GetBinder(typeof(TModel));
var bindingContext = new ModelBindingContext() {
// in the original method you have:
// ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(TModel)),
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()), // нужно GetType, т.к. тип известен только в runtime
ModelName = null,
ModelState = ModelState,
PropertyFilter = propertyFilter,
ValueProvider = valueProvider
};
binder.BindModel(ControllerContext, bindingContext);
return ModelState.IsValid;
}