Пользовательская модель Binder, наследующая от DefaultModelBinder - программирование
Подтвердить что ты не робот

Пользовательская модель Binder, наследующая от DefaultModelBinder

Я пытаюсь создать собственное связующее устройство для MVC 4, которое наследует от DefaultModelBinder. Я бы хотел, чтобы он перехватывал любые интерфейсы на любом уровне привязки и пытался загрузить желаемый тип из скрытого поля под названием AssemblyQualifiedName.

Вот что я до сих пор (упрощен):

public class MyWebApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ModelBinders.Binders.DefaultBinder = new InterfaceModelBinder();
    }
}

public class InterfaceModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, 
        ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType.IsInterface 
            && controllerContext.RequestContext.HttpContext.Request.Form.AllKeys.Contains("AssemblyQualifiedName"))
        {
            ModelBindingContext context = new ModelBindingContext(bindingContext);

            var item = Activator.CreateInstance(
                Type.GetType(controllerContext.RequestContext.HttpContext.Request.Form["AssemblyQualifiedName"]));

            Func<object> modelAccessor = () => item;
            context.ModelMetadata = new ModelMetadata(new DataAnnotationsModelMetadataProvider(),
                bindingContext.ModelMetadata.ContainerType, modelAccessor, item.GetType(), bindingContext.ModelName);

            return base.BindModel(controllerContext, context);
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}

Пример файла Create.cshtml(упрощенного):

@model Models.ScheduledJob

@* Begin Form *@
@Html.Hidden("AssemblyQualifiedName", Model.Job.GetType().AssemblyQualifiedName)

@Html.Partial("_JobParameters")
@* End Form *@

Вышеуказанный частичный _JobParameters.cshtml рассматривает свойства Model.Job и строит элементы управления редактирования, похожие на @Html.EditorFor(), но с некоторой дополнительной разметкой. Свойство ScheduledJob.Job имеет тип IJob (интерфейс).

Пример ScheduledJobsController.cs(упрощенный):

[HttpPost]
public ActionResult Create(ScheduledJob scheduledJob)
{
    //scheduledJob.Job here is not null, but has only default values
}

Когда я сохраняю форму, она правильно интерпретирует тип объекта и получает новый экземпляр, но свойства объекта не устанавливаются в соответствующие значения.

Что еще мне нужно сделать, чтобы сообщить связующему по умолчанию взять на себя привязку свойства указанного типа?

4b9b3361

Ответ 1

В этой статье я показал, что я слишком усложняю модельное связующее. Работает следующий код:

public class InterfaceModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType.IsInterface)
        {
            Type desiredType = Type.GetType(
                EncryptionService.Decrypt(
                    (string)bindingContext.ValueProvider.GetValue("AssemblyQualifiedName").ConvertTo(typeof(string))));
            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, desiredType);
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}

Ответ 2

С MVC 4 легко переопределить сообщения, если это все, что вам может понадобиться в настраиваемом связующем устройстве:

    protected void Application_Start(object sender, EventArgs e)
    {
        //set mvc default messages, or language specifc
        ClientDataTypeModelValidatorProvider.ResourceClassKey = "ValidationMessages";
        DefaultModelBinder.ResourceClassKey = "ValidationMessages";
    }

Затем создайте файл ресурсов с именем ValidationMessages с такими элементами:

NAME: FieldMustBeDate 
VALUE: The field {0} must be a date. 
NAME: FieldMustBeNumeric 
VALUE: The field {0} must be a number

.

Мы сделали это для сбоя соблюдения. Наше сканирование безопасности не понравилось, что инъекция javascript вернется и появится в сообщениях проверки и будет выполнена. Используя эту реализацию, мы переопределяем сообщения по умолчанию, которые возвращают предоставленное пользователем значение.