2009-07-03 4 views
2

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

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    
} 

Где SimpleThing это конкретный класс, который едва реализует IThing.

Однако я хотел бы, чтобы все мои методы имели дело с интерфейсом. У меня есть сборка данных, которая использует NHiberate и ее собственную реализацию IThing (назовем ее RealThing). Я не могу передать SimpleThing, потому что он будет жаловаться на «неизвестный объект».

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

Спасибо!

ответ

1

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

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

+0

Привет, пользователь10789, поставили ли вы эту стремительную награду? –

4

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

3

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

Первый добавить код в мой класс NHibernate Repository перевести простой тип POCO, используемый контроллером MVC (SimpleThing) к типу сущности, NHibernate хотел (RealThing):

/// <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), и он скопирует свойства элемента, который вы передаете, в тип, который хочет NHibernate. Очевидно, это было немного неуклюже, поэтому я посмотрел на пользовательские привязки моделей.


Во втором подходе, я создал пользовательские модели связующего, как это:

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.

+0

Я думаю, что второе решение - это очень простая автоматизация (с генерацией кода или с отражением). –

0

Это не относится к вашему вопросу.

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

 Смежные вопросы

  • Нет связанных вопросов^_^