ASP.NET MVC:избегайте тесной связи при привязке записи формы к параметру

StackOverflow https://stackoverflow.com/questions/1080925

Вопрос

Допустим, у меня есть интерфейс, подобный:

interface IThing {
   int Id { get; set; }
   string Title { get; set; }
}

И в ASP.NET MVC у меня есть форма, которая отправляет контроллеру действие, подобное этому:

 [AcceptVerbs(HttpVerbs.Post)]
 public ActionResult NewThing([Bind(Exclude = "Id")] SimpleThing thing) {

    // code to validate and persist the thing can go here            
 }

Где Что - то простое это конкретный класс, который едва ли реализует Все.

Однако я бы хотел, чтобы все мои методы работали с интерфейсом.У меня есть сборка данных, которая использует NHiberate и свой собственный Все реализация (давайте назовем это Реальное что - то).Я не могу передать ему SimpleThing, потому что он будет жаловаться на "неизвестный объект".

Есть ли у кого-нибудь какие-нибудь идеи о более чистом способе сделать это?Я думал о чем-то вроде использования заводского класса.Но как бы мне заставить MVC form binder использовать его?

Спасибо!

Это было полезно?

Решение 3

Здесь было несколько хороших предложений, и я действительно придумал решение, которое работает.Однако в итоге у меня получилось кое-что в целом.Я только что создал модели, специфичные для данных формы, которые я публиковал, и использовал привязку модели по умолчанию.

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

Другие советы

Вы можете использовать пользовательские модельные связующие.Однако статья о msdn совершенно бесполезна.Так что лучше воспользоваться поиском и найти что-нибудь получше.Доступно множество статей.

Я придумал два подхода к этому.

Первым было добавление кода в мой класс репозитория NHibernate для перевода простого типа POCO, используемого контроллером MVC (Что - то простое) к типу объекта , который хотел использовать NHibernate (Реальное что - то):

/// <summary>
/// A NHibernate generic repository.  Provides base of common 
/// methods to retrieve and update data.
/// </summary>
/// <typeparam name="T">The base type to expose 
/// repository methods for.</typeparam>
/// <typeparam name="K">The concrete type used by NHibernate</typeparam>
public class NHRepositoryBase<T, K> 
    : IRepository<T>
    where T : class
    where K : T, new()
{
    // repository methods ...

    /// <summary>
    /// Return T item as a type of K, converting it if necessary
    /// </summary>        
    protected static K GetKnownEntity(T item) {
        if (typeof(T) != typeof(K)) {
            K knownEntity = new K();

            foreach (var prop in typeof(T).GetProperties()) { 
                object value = prop.GetValue(item, null);
                prop.SetValue(knownEntity, value, null);
            }

            return knownEntity;
        } else {

            return (K)item;
        }            
    }

Таким образом, любой метод в репозитории может вызвать GetKnownEntity(T item), и он скопирует свойства передаваемого вами элемента в тип, который требуется NHibernate.Очевидно, это показалось немного неуклюжим, поэтому я заглянул в пользовательские папки для привязки моделей.


Во втором подходе я создал пользовательскую модель binder, подобную этой:

public class FactoryModelBinder<T> 
    : DefaultModelBinder 
    where T : new() 
{

    protected override object CreateModel(ControllerContext controllerContext, 
                                          ModelBindingContext bindingContext, 
                                          Type modelType) {

        return new T();                       
    }

}

Затем я зарегистрировал это в Global.asax.cs с помощью:

ModelBinders.Binders.Add(typeof(IThing), 
            new FactoryModelBinder<RealThing>());

И это прекрасно работает с действием контроллера, которое выглядит следующим образом:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult NewThing([Bind(Exclude = "Id")] IThing thing) {
    // code to process the thing goes here
}

Мне нравится второй подход, но большая часть моих материалов по внедрению зависимостей находится в классе Controller.Мне не нравится добавлять все эти сопоставления ModelBinder в Global.asax.cs.

Это не прямой ответ на ваш вопрос.

Мы используем несколько иной подход для решения той же проблемы, что и у вас.Наши контроллеры принимают DTO, которые соответствуют постоянному объекту поле за полем.Затем мы используем Автоматический преобразователь чтобы создать постоянные объекты, которые будут отправлены в базу данных.Это устраняет ненужные интерфейсы и блокирует общедоступный API (означает, что переименование поля объекта persistence не нарушит наш клиентский код).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top