MVC pattern differences

前端 未结 3 991
情深已故
情深已故 2021-02-04 11:26

I just need a few links to articles I can read up on or some basic explanations regarding the different patterns used in MVC (C#).

At present I tend to build my web apps

相关标签:
3条回答
  • 2021-02-04 11:42

    Controller:

    In theory your controller should be only handling "data". Moving pieces of information from one place to another.

    Little example:

    1. Controller receives request "GetMessage" with some parameter.
    2. Sends this data to service layer. In service layer you are accessing repository returning message.
    3. Cntroller receives this message (or if there were none null) and decides if it shoudl send received message back or maybe there was an error and user should be notified somehow.

    All the business logic "in theory" should be behind some service layer. That way you can easilly test everything. Logic in controller makes some tests more difficult.

    Interfaces:

    Interface based design is very popular now. Especially with all the IOC Containers handling dependancy injection. But if you are starting with this concept don't bother about these keywords. If you know the Repository pattern, then try at first with IRepository interface and instead of accesing repository by concrete class, use IRepository. (Just change field in controller from Repository to IRepository).

    Generaly about interfaces

    You will see the benefit of interfaces in more complex scenarios, but there is one technique that will show you all the glory of this approach. Unit Testing + Mocking.

    0 讨论(0)
  • 2021-02-04 11:44

    I can't say this is the best practice, but this is what I use, and why, and here we go:


    1. The repositories.

    They are structured this way:

    There are three basic interfaces, IRead<>, IReadCreate<> and IReadCreateDelete<>.

    interface IRead<T>
    { 
        T FindOne(int id);
        IQueryable<T> GetOne(int id);
        IQueryable<T> FindAll(Expression<Func<T, bool>> predicate);
    }
    
    interface IReadCreate<T> : IRead<T>
    { 
        T Create();
        void Create(T entity);
    }
    
    interface IReadCreateDelete<T> : IReadCreate<T>
    { 
        void Delete(int id);
        void Delete(T entity);
        void DeleteWhere(Expression<Func<T, bool>> predicate);
    }
    

    The all other interfaces look like this:

    interface ICategoriesRepository : IReadCreate<Category>
    {
        IQueryable<Category> GetAllActive();
    }
    

    And all of them provides additional usefull functionality on the data source they depend on. It means, I cannot reach other typed repositories in my implementation repository. That should be done on Services. (Look below.)

    The main goal of this approach is to show the calling code (from another assembly, because all my repositories, services and other contracts are defined (as interfaces) in separate DLL project) what it can do (like reading and creating items) and what it cannot do (like deleting items).


    2. Services

    Services and best way to implement your business logic. They should implement all your vital logic methods. To achive that kind of implementation they will need some repositories depency, and here it comes the Dependency Injector. I prefer to use Ninject, because it allows me to inject dependency properties like this:

    internal class CategoriesService : ICategoryService
    {
        public ICategoriesRepository CategoriesRepository { get; set; }
        public IWorkstationsRepository WorkstationsRepository { get; set; }
    
        // No constructor injection. I am too lazy for that, so the above properties 
        // are auto-injected with my custom ninject injection heuristic.
    
        public void ActivateCategory(int categoryId)
        {
            CategoriesRepository.FindOne(categoryId).IsActive = true;
        }
    }
    

    The goal of services is to eliminate business logic from controllers and from repositories.


    3. ViewModels

    Cool thing, as you told, but the reason is why are you building them up in theirselves is the thing I can't get. I am using the automapper for that (with its queryable extensions), which allows me to create views like this:

    Let's say I have a view which needs an IEnumerable<TicketViewModel> model. What I do is:

    public class FooController : Controller
    {
         public IMappingEngine Mapping { get; set; } // Thing from automapper.
         public ITicketsRepository TicketsRepository { get; set; }
    
         public ViewResult Tickes()
         { 
             return View(TicketsRepository.GetAllForToday().Project(Mapping)
                 .To<TicketViewModel>().ToArray();
         }
    }
    

    That's it. Simple call to repository, which makes calls to underlying data source (another pattern. I wont write about it, because its abstraction is needed only for testing.), which makes calls to database (or whatever you implement IDataSource<T>). Automapper automappically maps the Ticket to TicketViewModel and form database I retrive the only needed for my ViewModel columns, including the cross-table in a single request.


    Conclusion

    There are much to say more, but I hope this will give you some food for thought. All the patterns and programs I use are:

    1. Automapper (mapping);
    2. Ninject (dependency injection);
    3. Repositories (data access);
    4. Data Source (data reads from .. well.. from data source);
    5. Services (data interactivity);
    6. ViewModels (data transfer objects);
    7. Maybe something else I'll edit to add about.
    0 讨论(0)
  • 2021-02-04 11:49

    When I started reading your post I was thinking that maybe what you are looking for is an understanding of SOLID principles. And then you end by mentioning interfaces and service layers. Interesting.

    There are plenty of articles celebrating the holy grail of SOLID and DRY (Many without understanding what DRY advocates are really proposing). But the general idea in the .NET world, is NOT to go to the autogenerated Page_Load in an aspx and start typing away all willy nilly until a page does what it is supposed to do. MVC to the rescue.

    You say you have a model for each view. I would call that sound. Even if two models are identical, they are only equal, not the same. For example: A NewsItem is not an EventItem. If you want to expand on one, it should not effect the other.

    Then you continue with saying you are producing your models in the view model itself. That sounds backwards. But you say you do so in order to keep your controller clean. Good! What is missing in your mindset, is services.

    What you want to do is to move all code that actually perform any kind of work into services. A service can be based on an aspect, or on a feature or why not a control. Looking at one web project now, I see: VisitorService, NewsfeedService, CalendarService, CachingService, MainMenuService, HeaderService, FooterService etc etc ad infinitum.

    In this scenario, the controller is only responsible for asking a service (or services), that performs some work, for a model. And then forward that model to a view.

    Once you got 'business logic' into services you can easily apply IoC (Inversion of Control) to your projects if that makes you happy. I have not cast my vote on IoC yet. I have the eerie the benefits is not as great as advertized, and you can do without the code bloat for sure. But IoC do ask of you to think before you code.

    For a very easy going tutorial on IoC, I recommend Ninject. Not only does it feature Ninjas, but samurais, swords and shuriken as well. That's a lot cooler than cars and animals.

    https://github.com/ninject/ninject/wiki/Dependency-Injection-By-Hand

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