Реализация базового контроллера в ASP.NET MVC 2 - PullRequest
1 голос
/ 03 декабря 2010

Я использую ASP.NET MVC 2. Я получил пример приложения от Дарина (парень, который, кажется, отвечает на все вопросы MVC). Я не уверен, есть ли у кого-то еще этот пример проекта, который он создал? В его приложении есть базовый контроллер, и код выглядит так:

public abstract class BaseController<TRepository> : Controller, IModelMapperController
{
   protected BaseController(TRepository repository, IMapper mapper)
   {
      Repository = repository;
      ModelMapper = mapper;
   }

   public TRepository Repository { get; private set; }
   public IMapper ModelMapper { get; private set; }
}

У меня есть вопросы относительно этого кода: что означает BaseController?

Если мне нужно указать несколько репозиториев, как будет выглядеть код конструктора BaseController?

Рекомендуется ли иметь только один репозиторий на контроллер? Причина, по которой я спрашиваю, заключается в том, что в моем классе ApplicationController я использую метод действия Create (), чтобы заполнить мое представление из пользовательской модели представления. В этой модели представления мне нужно заполнить 2 разных выпадающих списка. Названия банков и типы счетов. У каждого есть свой репозиторий. В BankRepository есть метод GetBanks (), а в AccountTypeRepository есть метод GetAccountTpes (). Таким образом, в моем контроллере приложений я должен вызвать эти 2 метода, чтобы заполнить выпадающие списки. Таким образом, Контроллеры приложений реализуют Базовый контроллер. Как будет выглядеть базовый контроллер, если мне придется передать его более чем в один репозиторий?

Пожалуйста, кто-нибудь может пролить свет на это.

@ Дарин: Спасибо за пример приложения, я уже многому у него учусь.

Ответы [ 3 ]

4 голосов
/ 03 декабря 2010

так что каждый из ваших контроллеров может указывать на разные репо.что-то вроде этого:

public class UsersController : BaseController<UserRepository>
{
    public UsersController() 
        : base(new UserRepository(), new UserModelMapper())
    {
        // do stuff
    }

    public ActionResult Index()
    {
        // now you can use syntax like, since "Repository" is type "UserRepository"
        return View(Respository.GetAllUsers());
    }

    public ActionResult Details(int id)
    {
        return View(Respository.GetUser(id));
    }
}

ОБНОВЛЕНО для адресов

public class AddressesController : BaseController<AddressRepository>
{
    public AddressesController() 
        : base(new AddressRepository(), new AddressModelMapper())
    {
    }

    public ActionResult Addresses(int id)
    {
        return View(Respository.GetAllByUserId(id));
    }
}

ОБНОВЛЕНО для фабрики

public static class RepositoryFactory
{
    internal static Hashtable Repositories = new Hashtable();

    internal static T GetRepository<T>() where T : class, new()
    {
        if (Repositories[typeof(T)] as T == null)
        {
            Repositories[typeof(T)] = new T();
        }
        return Repositories[typeof(T)] as T;
    }

    public static AccountTypeRepository AccountTypeRepository
    {
        get { return GetRepository<AccountTypeRepository>(); } 
    }

    public static BankRepository BankRepository
    {
        get { return GetRepository<BankRepository>(); } 
    }
    /* repeat as needed or change accessibility and call GetRepository<> directly */

Теперь вместо того, чтобы использовать BaseController, вы можете просто написать это

public class ApplicationModel
{
    public Application Application { get; set; }
    public IList<Bank> Banks { get; set; }
    public IList<AccountType> AccountTypes { get; set; }
}

public class ApplicationController : Controller
{
    public ActionResult Index()
    {
        ApplicationListModel model = new ApplicationListModel()
        {
            Applications = RespositoryFactory.ApplicationRepository.GetAll();
        }
        return View(model);
    }

    public ActionResult Details(int id)
    {
        ApplicationModel model = new ApplicationModel()
        {
            Application = RespositoryFactory.ApplicationRepository.Get(id),
            Banks = RespositoryFactory.BankRepository.GetAll(),
            AccountTypes = RespositoryFactory.AccountTypeRepository.GetAll()
        }
        return View(model);

    }
}
1 голос
/ 05 декабря 2010

Я не уверен, отвечу ли я на все ваши вопросы, но здесь идет ...

Я также использую BaseController, но я не делаю то, что делает ваш пример. Вот как выглядит мой код (мое приложение также использует DI для конструкторов ...):

public class BaseController : Controller {
    private readonly IProvider AddressProvider = null;
    private readonly IProvider EmailProvider = null;
    private readonly IProvider PhoneProvider = null;

    [Inject] // Using Ninject for DI
    public BaseController(
        AddressProvider AddressProvider,
        EmailProvider EmailProvider,
        PhoneProvider PhoneProvider) {
        this.AddressProvider = AddressProvider;
        this.EmailProvider = EmailProvider;
        this.PhoneProvider = PhoneProvider;
    }
}

А вот мой AdministrationController, который наследуется от BaseController:

public class AdministrationController : BaseController {
    private readonly CustomerProvider CustomerProvider = null;
    private readonly EmployeeProvider EmployeeProvider = null;

    [Inject]
    public AdministrationController(
        CustomerProvider CustomerProvider,
        EmployeeProvider EmployeeProvider,
        AddressProvider AddressProvider,
        EmailProvider EmailProvider,
        PhoneProvider PhoneProvider) : base(AddressProvider, EmailProvider, PhoneProvider) {
        this.CustomerProvider = CustomerProvider;
        this.EmployeeProvider = EmployeeProvider;
    }
}

Мой AdministrationController заботится только о CustomerProvider и EmployeeProvider, и он передает AddressProvider, EmailProvider и PhoneProvider в BaseController.

AddressProvider, EmailProvider и PhoneProvider находятся в BaseController, потому что я считаю Address, Email и Phone объектами низкого уровня . Моя причина в том, что они могут быть связаны с Customer, Employee или чем-то еще, что касается базы данных. Итак, вместо нескольких методов взаимодействия Customer или Employee с каждым из их объектов, у меня есть только один. Например:

public class BaseController : Controller {
    //  GET: /Addresses/{AddressId}/Delete
    public void DeleteAddress(
        int AddressId) {
        this.AddressProvider.DeleteAndSave(AddressId);

        Response.Redirect(Request.UrlReferrer.AbsoluteUri);
    }

    //  GET: /Emails/{EmailId}/Delete
    public void DeleteEmail(
        int EmaildId) {
        this.EmailProvider.DeleteAndSave(EmailId);

        Response.Redirect(Request.UrlReferrer.AbsoluteUri);
    }

    //  GET: /Phones/{PhoneId}/Delete
    public void DeletePhone(
        int PhoneId) {
        this.PhoneProvider.DeleteAndSave(PhoneId);

        Response.Redirect(Request.UrlReferrer.AbsoluteUri);
    }
}

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

Теперь в моем AdministrationController я работаю с CustomerProvider и EmployeeProvider. Они более специализированы, потому что я считаю Customer и Employee объектами высокого уровня . При этом их провайдеры выполняют немного больше работы, чем Delete . Например, они также предоставляют модели представлений, используемые представлениями (durp ...):

public class AdministrationController : BaseController {
    public ActionResult Customer(
        int CustomerId) {
        return this.View(this.CustomerProvider.GetView(CustomerId));
    }

    public AciontResult Customers() {
        return this.Veiw(this.CustomerProvider.GetAllView(CustomerId));
    }

    public ActionResult CustomerAddresses(
        int CustomerId,
        Address Address) {
        if (ModelState.IsValid) {
            this.CustomerProvider.AddAddressAndSave(CustomerId, Address);
        };

        return this.RedirectToAction("Customer", new {
            CustomerId = CustomerId
        });
    }

    public ActionResult Employee(
        int EmployeeId) {
        return this.View(this.EmployeeProvider.GetView(EmployeeId));
    }

    public ActionResult Employees() {
        return this.View(this.EmployeeProvider.GetAllView());
        //  OR
        //  return this.View(this.EmployeeProvider.GetActiveView());
        //  OR
        //  return this.Veiw(this.EmployeeProvider.GetInactiveView());
        //  ETC...
        //  All of these return the exact same object, just filled with different data
    }

    public RedirectToRouteResult EmployeeAddresses(
        int EmployeeId,
        Address Address) {
        if (ModelState.IsValid) {
            this.EmployeeProvider.AddAddressAndSave(EmployeeId, Address);
            //  I also have AddAddress in case I want to queue up a couple of tasks
            //  before I commit all changes to the data context.
        };

        return this.RedirectToAction("Employee", new {
            EmployeeId = EmployeeId
        });
    }
}

Рекомендуется ли иметь только один репозиторий на контроллер?

Я собираюсь сказать нет, потому что ваши репозитории будут работать только для объекта, для которого они созданы. Вы не можете иметь (ну, вы можете, но это просто плохо ...) хранилище, которое обрабатывает Address, Email и Phone одновременно, потому что вам нужно специализировать это просто для того, чтобы работать так, как вам нужно.

Мои AddressProvider, EmailProvider и PhoneProvider по сути одинаковы, поскольку они реализуют IProvider, однако каждый из них создает общий репозиторий (Repository<T>) для объекта, с которым они работают.

Кроме того, ваш контроллер должен взаимодействовать не с репозиториями напрямую, а косвенно через провайдеров.

My CustomerProvider и EmployeeProvider каждый экземпляр специализированных хранилищ для Customer и Employee (CustomerRepository, EmployeeRepository), но они также экземпляры других хранилищ, которые им понадобятся, когда они, например, конструируют представление моделей. Например, они будут создавать экземпляр StateRepository, равный Repository<State> или PhoneTypesRepository, равный Repository<PhoneType>, и использовать эти хранилища для передачи дополнительных объектов / коллекций в представление для создания форм с раскрывающимися списками или без разницы. Они также прикажут другим провайдерам помочь в построении модели представления, такой как CookieProvider, которую они используют, чтобы получить текущий активный Cookie и передать его модели представления.

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

Надеюсь, это поможет вам пролить свет на альтернативный способ написания кода или, по крайней мере, надеюсь, что это поможет вам немного лучше понять.

P.S. В случае, если вам интересно, что такое Provider, большинство других людей предпочитают называть их Service, но мне это слово неправильно используют, поэтому я просто называю их Provider s, потому что они предоставляют контроллер со специализированными функциями или данными при необходимости.

0 голосов
/ 17 декабря 2010

Что ж, похоже, что упомянутый образец - это особый случай или его авторский вкус.

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

Другой совет, когда вам нужна общая логика, которую предпочитают ваши контроллеры Композиция над наследованием .

Итак, подведем итог - да, это нормально, когда в ваш контроллер добавляются разные репозитории, если это ваш случай, и для меня это кажется лучшим подходом, чем какой-то ненужный BaseController.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...