简体   繁体   English

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

[英]Base controller implementation in ASP.NET MVC 2

I'm using ASP.NET MVC 2. I got the sample application from Darin (the guy that seems to answer all the MVC questions). 我正在使用ASP.NET MVC2。我从Darin(似乎可以回答所有MVC问题的人)那里获得了示例应用程序。 I'm not sure if any one else has this sample project that he created? 我不确定他是否创建了这个示例项目? He has a base controller in his application, and the code looks like this: 他的应用程序中有一个基本控制器,代码如下所示:

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; }
}

The questions that I have regarding this code is what does BaseController mean? 我对这段代码的疑问是BaseController是什么意思?

If I need to specify more than one repository how would the BaseController constructor code look like? 如果需要指定多个存储库,BaseController构造函数代码将如何显示?

Is it best practices to have only one repository per controller? 每个控制器只有一个存储库是最佳实践吗? The reason why I ask is because in my ApplicationController class I make use of a Create() action method to populate my view from custom view model. 我问的原因是因为在我的ApplicationController类中,我使用Create()动作方法从自定义视图模型填充视图。 In this view model I need to populate 2 different drop down lists. 在此视图模型中,我需要填充2个不同的下拉列表。 Bank names and account types. 银行名称和帐户类型。 Each has their own repository. 每个都有自己的存储库。 BankRepository has a method called GetBanks() and AccountTypeRepository has a method called GetAccountTpes(). BankRepository有一个名为GetBanks()的方法,而AccountTypeRepository有一个名为GetAccountTpes()的方法。 So in my Application controller I have to call these 2 methods to populate the drop downs. 因此,在我的应用程序控制器中,我必须调用这两个方法来填充下拉列表。 So the Application controllers implements Base controller. 因此,应用程序控制器实现了基本控制器。 How would base controller look like if I have to pass it more than one repository? 如果我必须传递多个存储库,基本控制器会是什么样子?

Please can someone shed some light regarding this. 请有人对此有所帮助。

@Darin: Thanks for the sample application, I am learning a lot from it already. @Darin:感谢您的示例应用程序,我已经从中学到了很多。

so each of your controllers could point to a different repo. 因此您的每个控制器都可以指向不同的存储库。 something like this: 像这样的东西:

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));
    }
}

UPDATED for Addresses 地址更新

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

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

UPDATED for Factory 工厂更新

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 */

Now rather than even using a BaseController you could just write this: 现在,您甚至无需编写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);

    }
}

I'm not sure if I'll answer all of your questions, but here goes... 我不确定是否会回答您所有的问题,但是这里...

I use a BaseController as well, but I don't do what your example does. 我也使用BaseController ,但是我不执行您的示例所执行的操作。 Here's how my code looks like (my application also uses DI for the constructors...): 这是我的代码的样子(我的应用程序还将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;
    }
}

And here's my AdministrationController which inherits from BaseController : 这是我的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;
    }
}

My AdministrationController only cares about CustomerProvider and EmployeeProvider and it passes AddressProvider , EmailProvider and PhoneProvider to the BaseController . 我的AdministrationController只关心CustomerProviderEmployeeProvider ,并将AddressProviderEmailProviderPhoneProvider传递给BaseController

AddressProvider , EmailProvider and PhoneProvider are in the BaseController because I consider Address , Email and Phone to be low-level objects. AddressProviderEmailProviderPhoneProviderBaseController因为我认为AddressEmailPhone低级对象。 My reason for that is because they can be linked to Customer , Employee or anything else as far as the database is concerned. 我这样做的原因是,就数据库而言,它们可以链接到CustomerEmployee或其他任何东西。 So, instead of having multiple methods for Customer or Employee to interact with each of their objects, I just have one. 因此,我没有让CustomerEmployee与他们的每个对象交互的多种方法,而是只有一种。 For example: 例如:

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);
    }
}

And with that I take care of my low-level objects. 这样,我就可以照顾我的低级对象。 Keep in mind, in my application I have additional methods to further manipulate those objects as needed. 请记住,在我的应用程序中,我还有其他方法可以根据需要进一步操作那些对象。

Now, in my AdministrationController I'm working with CustomerProvider and EmployeeProvider . 现在,在我的AdministrationController我正在使用CustomerProviderEmployeeProvider These are more specialized because I consider Customer and Employee to be high-level objects. 这些是更专业的,因为我认为“ Customer和“ Employee高级对象。 That being said, their providers do a bit more work than Delete . 话虽如此,他们的提供者比Delete要做更多的工作。 For example they also provide the view models used by the views (durp...): 例如,它们还提供了视图使用的视图模型(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
        });
    }
}

Is it best practices to have only one repository per controller? 每个控制器只有一个存储库是最佳实践吗?

I'm going to say no because your repositories will only work for the object they're instanced for. 我要说不,因为您的存储库仅适用于为其实例化的对象。 You can't have (well, you can, but that's just bad...) a repository that handles an Address , Email and Phone all at once because you'll have to specialize it just for it to work the way you need it. 您可能没有(很好,但是可以,但这很糟糕...)同时处理AddressEmailPhone的存储库,因为您必须对其进行专门化处理才能按照所需的方式工作。

My AddressProvider , EmailProvider and PhoneProvider are all essentially the same because they implement IProvider , however they each instance a generic repository ( Repository<T> ) for the object they're working with. 我的AddressProviderEmailProviderPhoneProvider本质上是相同的,因为它们实现了IProvider ,但是它们各自为要使用的对象实例化一个通用存储库( Repository<T> )。

Furthermore, you're controller shouldn't be interacting with the repositories directly, but indirectly through the providers. 此外,您的控制者不应直接与存储库进行交互,而应通过提供程序进行间接交互。

My CustomerProvider and EmployeeProvider each instance specialized repositories for Customer and Employee ( CustomerRepository , EmployeeRepository ), but they also instance other repositories they'll need when they for example construct the view models. 我的CustomerProviderEmployeeProvider分别为CustomerEmployee实例化专用存储库( CustomerRepositoryEmployeeRepository ),但是它们还实例化了它们在构造视图模型时所需的其他存储库。 For example, they'll instance a StateRepository which is Repository<State> or PhoneTypesRepository which is Repository<PhoneType> , and they'll use those repositories to pass additional objects/collections to the view to build up forms with drop downs or whatever. 例如,他们将实例的StateRepository其是Repository<State>PhoneTypesRepository其是Repository<PhoneType>他们将利用这些信息库传递额外的对象/集合到视图建立与下拉菜单或任何形式。 They'll also instance other providers to further help with building the view model such as CookieProvider which they use to get the currently active Cookie and pass it to the view model. 他们还将实例化其他提供者,以进一步帮助构建视图模型,例如CookieProvider ,它们用于获取当前活动的Cookie并将其传递给视图模型。

All in all it's a mesh of independent/generic providers or repositories which are combined to accomplish a specialized task. 总而言之,它是由独立/通用提供程序或存储库组成的网格,这些提供程序或存储库结合起来可以完成一项专门的任务。

I hope this sheds some light for you through an alternative way of writing code, or at the least I hope it just helps you understand a little bit better. 我希望这可以通过另一种编写代码的方式为您提供启发,或者至少希望它可以帮助您更好地理解。

PS In case you're wondering what Provider is, most all other people choose to call them Service , but to me that word is misused, so I just call them Provider s because they provide the controller with specialized functions or data as needed. PS如果您想知道Provider是什么,大多数其他人都选择将它们称为Service ,但是对我来说,这个词被滥用了,所以我称它们为Provider因为它们根据需要控制器提供了专门的功能或数据。

Well, it seems like the sample mentioned is somewhat special case or its authors taste. 好吧,似乎所提到的样本有点特殊情况或其作者的口味。

I'd advise to not comlicate things around and avoid such a layer supertype as a Base Controller unless it is clearly necessary. 我建议不要使周围的事情复杂化,除非明确有必要,否则避免使用诸如Base Controller的层超类型。 This approach lets you define as much Repositories (and other dependencies) per Controller as you like without forcing you to use special-case BaseController supertype. 这种方法使您可以根据需要为每个Controller定义尽可能多的存储库(和其他依赖项),而不必强制您使用特殊情况的BaseController超类型。

The other advice is when you need some common logic between your Controllers prefer Composition over Inheritance . 另一个建议是,当您需要控制器之间的一些通用逻辑时,更喜欢使用组合而不是继承

So, to summarize - yes, it is normal to have different repositories injected in your Controller if that is your case and for me it seems as the better approach than some kind of unnecessary BaseController. 因此,总而言之-是的,如果您的情况如此,在您的Controller中注入不同的存储库是正常的,对我而言,这似乎是比某种不必要的BaseController更好的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM