How to use ASP.NET MVC Generic Controller to populate right model

后端 未结 3 872
醉话见心
醉话见心 2020-12-08 12:12

I asked a question about ASP.NET MVC Generic Controller and this answer shows a controller like this:

public abstract class GenericController<         


        
相关标签:
3条回答
  • 2020-12-08 12:48

    Given my disclaimers in the other question and my comments here explaining why this isn't an ultimate solution, I'll try to give a more concrete implementation:

    public abstract class GenericController<T> : Controller
        where T : class
    {
        protected YourEFContext _dataSource;
    
        public GenericController()
        {
            _dataSource = new YourEFContext();
        }
    
        public virtual ActionResult Details(int id)
        {
            var model = _dataSource.Set<T>().Find(id);
            return View(model);
        }
    }
    
    public class CustomerController : GenericController<Customer>
    {
    
    }
    

    This is all code that is needed to let /Customers/Details/42 load customer with ID 42 be loaded from the Entity Framework context. The "generic" part is solved by Entity Framework's DbContext.Set<T>() method, which returns the DbSet<TEntity> for the appropriate entity, in this case DbSet<Customer> which you can query.

    That being said, there are many problems with actually using this code:

    • You don't want to let your controller know about your data access. As you see, a YourEFContext property is used in the controller, tightly coupling it with Entity Framework. You'll want to abstract this away in a repository pattern.
    • You don't want your controller to instantiate its data access, this should be injected.
    • You don't want your controller to return database entities. You're looking for ViewModels and a Mapper.
    • You don't want your controller to do data access. Move the data access in a service layer that also contains your business logic, abstract it again through a repository pattern.

    Now your question actually is "Does the Enterprise Library Data Block have a method like GetDataSet<T>", so you don't have to refer to customer and product in your generic controller, but unfortunately I can't find that as I haven't used EntLib for a few years. It would help if you show the code you currently use to access your database.

    The ultimate goal you're looking for:

    [       MVC             ] <=> [         Service         ] <=> [   Repository   ]
    View ViewModel Controller     BusinessModel BusinessLogic     DataModel Database
    

    Your controller only talks to your service to Create/Read/Update/Delete BusinessModels, and performs the mapping between ViewModels and BusinessModels (at <=>). The service contains the business logic and business model (DataContacts when using WCF) and in turn maps (<=>) to and from DataModels and talks to your repository to persist your models.

    I understand this can be a bit much to grasp at once, and that's probably why most ASP.NET MVC tutorials start with all three tiers in one application. Take a look at ProDinner for a more proper approach.

    0 讨论(0)
  • 2020-12-08 12:52

    You may create a set of repositories for working with your entities, like CustomerRepository, ProductRepository from base interface like

    public interface IBaseRepository
    {
      T Get<T>(int id);
      void Save<T>(T entity);
    }
    

    and then extend your base controller class with repository type and its instance with any of DI frameworks

    public abstract class GenericController<T, TRepo> 
            where T : class
            where TRepo : IBaseRepository, new()
        {
            private IBaseRepository repository;
    
            public GenericController() 
            {
                repository = new TRepo();
            }
    
            public virtual ActionResult Details(int id)
            {
               var model =repository.Get<T>(id);
               return View(model);
            }
        }
    

    Example for CustomerController

    public class CustomerController : GenericController<Customer, CustomerRepository>
    {
    
    }
    

    where CustomerRepository:

    public class CustomerRepository : IBaseRepository
    {
      public T Get <T>(int id) 
      {
        // load data from DB
        return new Customer();
      }
    }
    
    0 讨论(0)
  • 2020-12-08 13:08

    I don't think it's wise to place data-access and business logic like this in controllers when your application's size and complexity grows beyond a certain point. You should create repositories which handle the data-access and abstract the technology (EF, plain ADO.NET, etc.) away from the consumers. You could use these repositories in your controller, but that would mean that your controllers still contain business logic which you don't want. Controllers should be thin.

    What I did was creating a service layer between my repositories and controllers which contain the business logic and delegate data-access to the repositories. I use these services in my controllers to fetch my domain models where I map them to view models. You're gonna want an Inversion of Control container to 'glue' the layers together and to provide loose coupling between them.

    A search for 'c# mvc repository and service pattern' will result in loads of examples. I found this post a good one, except for the fact that he returns view models from his services rather than domain models.

    This is just my 2 cents, please keep in mind that all of the above only counts when your have a 'mid-range' application and not a typical tutorial/try-out website.

    0 讨论(0)
提交回复
热议问题