ASP.NET MVC 2中的基本控制器实现

时间:2010-12-03 14:06:26

标签: c# asp.net-mvc asp.net-mvc-2 dependency-injection autofac

我正在使用ASP.NET MVC 2.我从Darin(那个似乎回答所有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()的方法。所以在我的Application控制器中,我必须调用这两个方法来填充下拉列表。因此Application控制器实现了Base控制器。如果我必须将多个存储库传递给它,那么基本控制器将如何显示?

请有人对此有所了解。

@Darin:感谢您的示例应用程序,我已经从中学到了很多东西。

3 个答案:

答案 0 :(得分:4)

所以你的每个控制器都可以指向不同的仓库。像这样的东西:

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 :(得分:1)

我不确定我是否会回答你的所有问题,但这里有......

我也使用了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仅关注CustomerProviderEmployeeProvider,并将AddressProviderEmailProviderPhoneProvider传递给BaseController

AddressProviderEmailProviderPhoneProvider位于BaseController,因为我认为AddressEmailPhoneCustomer 低级对象。我的理由是因为就数据库而言,它们可以链接到EmployeeCustomer或其他任何内容。因此,我只需要一个方法,而不是让Employeepublic 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我正在使用EmployeeProviderCustomer。这些更专业,因为我认为Employeepublic 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 }); } } 高级对象。话虽这么说,他们的提供商比删除做了更多的工作。例如,它们还提供视图使用的视图模型(durp ...):

Address

每个控制器只有一个存储库是最佳做法吗?

我要说不,因为你的存储库只适用于他们实例化的对象。你不能拥有(好吧,你可以,但那只是坏......)一个处理EmailPhoneAddressProvider的存储库,因为你必须专门它只是为了让它以你需要的方式工作。

我的EmailProviderPhoneProviderIProvider基本相同,因为它们实现了Repository<T>,但每个实例都是一个通用存储库(CustomerProvider)他们正在使用的对象。

此外,您的控制器不应直接与存储库交互,而应通过提供程序间接交互。

我的EmployeeProviderCustomer每个实例专门用于EmployeeCustomerRepositoryEmployeeRepositoryStateRepository)的存储库,但它们也是其他实例他们在构建视图模型时需要的存储库。例如,他们将实例Repository<State> PhoneTypesRepositoryRepository<PhoneType> CookieProvider,他们将使用这些存储库将其他对象/集合传递给视图建立有下拉或其他形式的表格。他们还会对其他提供商进行实例化,以进一步帮助构建视图模型,例如Cookie,用于获取当前活动的Provider并将其传递给视图模型。

总而言之,它是一个独立/通用的提供者或存储库的网格,它们被组合起来完成一项专门的任务。

我希望通过另一种编写代码的方式为您提供一些启示,或者至少我希望它能帮助您更好地理解。

P.S。如果你想知道Service是什么,大多数其他人选择称呼他们Provider,但对我来说这个词被滥用了,所以我只称他们为{{1}}因为他们< em>根据需要为控制器提供专门的功能或数据。

答案 2 :(得分:0)

嗯,看起来提到的样本有些特殊情况或作者的品味。

除非明显有必要,否则我建议不要对周围事物进行复制并避免使用这种图层超类型作为基本控制器。这种方法允许您根据需要为每个Controller定义尽可能多的存储库(和其他依赖项),而不必强制使用特殊情况的BaseController超类型。

另一个建议是当您需要控制器之间的某些通用逻辑时更喜欢Composition over Inheritance

所以,总结一下 - 是的,在你的控制器中注入不同的存储库是正常的,如果这是你的情况,对我来说它似乎比某种不必要的BaseController更好的方法。