MVC: возможно ли иметь один пользовательский ModelBinder и ИД по умолчанию для одной модели? - PullRequest
0 голосов
/ 23 сентября 2011

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

Edit: пользовательский, конечно, запускается первым.

Ответы [ 3 ]

1 голос
/ 25 сентября 2011

Мо ответ правильный.Унаследуйте от DefaultModelBinder, затем переопределите CreateModel.Я просто отправляю, чтобы предоставить примеры кодов.

Подшивка:

public class RegistrationViewModelBinder : DefaultModelBinder 
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        return new RegistrationViewModel(Guid.NewGuid());
    }
}

Модель:

public class RegistrationViewModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }    
    public Guid Id { get; private set; }

    public RegistrationViewModel(Guid id)
    {
        Id = id;
    }
}

Если ваша собственность будет настраиваемой (В этом случаеэто идентификатор), вам нужно исключить его из привязки:

[Bind(Exclude = "Id")]
public class RegistrationViewModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }

    public Guid Id { get; set; }
}
1 голос
/ 26 сентября 2011

Спасибо, ребята, я думаю, что нашел решение, а именно, переопределить метод createmodel в defaultmodelbinder.Отсюда у меня была дополнительная помощь: http://noahblu.wordpress.com/2009/06/15/modelbinder-for-objects-without-default-constructors/

Требовалось обновление, чтобы использовать метаданные модели вместо установки типа модели, как показано в этой ссылке, из-за изменений, внесенных в mvc.Вот что я закончил в качестве первой попытки, которая, кажется, работает:

namespace NorthwindMVCApp.CustomBinders{

   public class NewShipperBinder<T> : DefaultModelBinder
{

    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        Type type1 = typeof(T);
        ConstructorInfo[] constructors = type1.GetConstructors();
        ConstructorInfo largestConstructor = constructors.OrderByDescending(x => x.GetParameters().Count()).First();
        ParameterInfo[] parameters = largestConstructor.GetParameters();
        List<object> paramValues = new List<object>();
        IModelBinder binder;
        string oldModelName = bindingContext.ModelName;
        foreach (ParameterInfo param in parameters)
        {
            string name = CreateSubPropertyName(oldModelName, param.Name);
            //bindingContext.ModelType = param.ParameterType;
            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, param.ParameterType);
            bindingContext.ModelName = name;
            if (!System.Web.Mvc.ModelBinders.Binders.TryGetValue(param.ParameterType, out binder))
                binder = System.Web.Mvc.ModelBinders.Binders.DefaultBinder;
            object model = binder.BindModel(controllerContext, bindingContext);
            paramValues.Add(model);
        }
       // bindingContext.ModelType = typeof(T);
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(T));
        bindingContext.ModelName = oldModelName;
        Debug.WriteLine(Environment.StackTrace); 
        object obj = Activator.CreateInstance(type1, paramValues.ToArray());
        return obj;
    }
}

}

Связываемый класс выглядит следующим образом.Причина всего этого заключается в том, что у него нет конструктора по умолчанию (чтобы убедиться, что в нем нет ненулевых значений):

namespace Core.Entities{

[EntityAttribute()]
public class Shipper 
{

    protected Shipper() : this("Undefined")
    {

    }

    public Shipper(string CompanyName)
    {
        this.CompanyName = CompanyName;
        Orders = new List<Order>();
    }

    public virtual int ShipperID { get; set; }
    public virtual IList<Order> Orders { get; set; }
    public virtual string CompanyName { get; set; }
    public virtual string Phone { get; set; }

    public override bool Equals(object obj)
    {
        Shipper obj_Shipper;
        obj_Shipper = obj as Shipper;
        if (obj_Shipper == null)
        {
            return false;
        }
        if (obj_Shipper.CompanyName != this.CompanyName)
        {
            return false;
        }
        return true;
    }

    public override int GetHashCode()
    {
        return CompanyName.GetHashCode();
    }
}
}

И, кстати, связыватель включен в global.asax следующим образом:

            ModelBinders.Binders.Add(typeof(Shipper), new CustomBinders.NewShipperBinder<Shipper>());

Так что будет легко добавить всю серию классов сущностей (циклически проходя), так как я веду список типов сущностей.

Таким образом, я смог обновить этообъект в базу данных.

Редактирование: немного заморозки, вот трассировка стека:

at NorthwindMVCApp.CustomBinders.NewShipperBinder`1.CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) in C:\Users\####\Documents\Visual Studio 2010\Projects\TestFluentNHibernate\NorthwindMVC\NorthwindMVCApp\CustomBinders\NewShipperBinder.cs:line 37
   at System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
   at System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
   at System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
0 голосов
/ 24 сентября 2011

Вы уже унаследовали от DefaultModelBinder? Я не думаю, что можно делать то, что вы намерены - если вы создаете связыватель модели клиента и он реализует IModelBinder, класс должен выполнить все необходимые действия.

...