How to use ASP.NET MVC Generic Controller to populate the correct model

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

public abstract class GenericController<T> where T : class { public virtual ActionResult Details(int id) { var model = _repository.Set<T>().Find(id); return View(model); } } 

What can be implemented in this way.

 public class FooController : GenericController<Foo> { } 

Now, when someone asks for / Foo / Details / 42, entitiy is pulled from _repository Set<Foo>() , without having to write anything for this in FooController .

As he explains that this is good, but I think I want to develop a common controller for the product and the client, where I will not use EF to load the product and client models, rather use the MS data access application block.

 public abstract class GenericController<T> where T : class { public virtual ActionResult Details(int id) { //var model = _repository.Set<T>().Find(id); var model =customer.load(id); or var model =product.load(id); return View(model); } } 

So, when the request comes as /Customer/Details/42 or /product/Details/11 , then the general method of information about the controller will be called, but how can we detect that this request comes from which controller and, accordingly, creates an instance of the class right to load the right model.

If the request comes for the Client, then I need to download customer data from the detailed action method or if the request arrives for the product, then I need to download product information from the action method of the detailed controller.

How to use generics to get type T dataset with Entity Framework data block?

+6
source share
3 answers

You can create a set of repositories to work with your entities, such as CustomerRepository , ProductRepository from the base interface, for example

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

and then extend your base controller class with the repository type and its instance with any DI card

 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 is CustomerRepository:

 public class CustomerRepository : IBaseRepository { public T Get <T>(int id) { // load data from DB return new Customer(); } } 
+12
source

I donโ€™t think it is wise to place data and business logic like these in controllers when the size and complexity of your application exceeds a certain point. You must create repositories that handle data access and abstract technology (EF, plain ADO.NET, etc.) from consumers. You can use these repositories in your controller, but this will mean that your controllers still contain business logic that you do not want. Controllers must be thin.

What I did was create a service level between my repositories and controllers that contain business logic and delegate access to data in the repository. I use these services in my controllers to retrieve my domain models, where I map them to view models. You need the Inversion of Control container to "stick together" the layers together and provide a free connection between them.

A search for "C # mvc repository and service pattern" will lead to many examples. I found this post to be good, except for the fact that it returns view models from its services, not domain models.

These are just my 2 cents, please keep in mind that all of the above is only taken into account when you have a medium-range application, and not a regular training / trial website.

+7
source

Given my reservations in another question and my comments here explaining why this is not a final solution, I will try to give a more specific 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 the code that is required for /Customers/Details/42 to load the client with identifier 42 loaded from the Entity Framework context. The "common" part is solved by the Entity Framework method DbContext.Set<T>() , which returns the DbSet<TEntity> for the corresponding entity, in this case the DbSet<Customer> , which you can request.

However, there are many problems using this code:

  • You do not want your controller to know about your access to data. As you can see, the controller uses the YourEFContext property, which is closely related to the Entity Framework. You will want to distract this in the repository template.
  • You do not want your controller to create an instance of data access, this must be entered.
  • You do not want your controller to return database objects. You are looking for ViewModels and Mapper.
  • You do not want your controller to access data. Move data access to the service level, which also contains your business logic, draw it again using the repository template.

Now your question is actually: "Does the Enterprise Library data block have a method such as GetDataSet<T> ", so you donโ€™t need to refer to customer and product in your general controller, but unfortunately, t find this because I donโ€™t used EntLib for several years. This will help if you show the code that is currently used to access your database.

The ultimate goal you are looking for:

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

Your controller only talks to your service to create / read / update / delete business models and performs the mapping between ViewModels and BusinessModels (in <=> ). The service contains business logic and a business model (DataContacts when using WCF) and, in turn, maps ( <=> ) for and from DataModels and talks with your repository to save your models.

I understand that it can be a little difficult to understand right away, and probably why most ASP.NET MVC tutorials start at all three levels in one application. Check out ProDinner for a better approach.

+3
source

Source: https://habr.com/ru/post/958164/


All Articles