Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Simplify Controller logic using factories

0.00/5 (No votes)
5 Jan 2016 1  
Article exploring how ViewModels fit in to the MVC ecosystem and how to use factories to create them.

Making the jump from WebForms to ASP.NET MVC presents many challenges. One of the more difficult concepts to grasp is knowing what you should put where. You understand that a View is equal to a Page. You’ve got your head around the fact that a View needs a Controller Action to create it. You get that routing comes into play to match URLs to your Controller Actions. So far so good. You’re even warming to the idea of using ViewModels to pass data to your Views.

Question is, how should you populate your ViewModel with data? Most applications these days involve some sort of database. To retrieve data from the database necessitates some kind of repository layer. But where do we call our repository from? We could call it within our View. We could keep our View simple and delegate this work to the Controller. If our Controller only has one or two Actions, that's fine. But what happens when that number starts creeping up? We now have 5 or 6 Views to serve from our Controller. Each View uses its own model. Each model needs populating from our repository. That's a lot of mapping for our Controller to deal with. Maybe there's a better way for us to handle this. In this article I’ll be discussing the idea of using factories to create our ViewModels.

Let's get SOLID. The Single Responsibility Principle.

You've no doubt heard of the Single Responsibility Principle. It's one of the SOLID principles that govern good software architectural practices. The Single Responsibility Principle states that a class should have one reason to change. In other words, it should be responsible for doing one thing. So our controller should only worry about returning the right response for each request. It shouldn't worry about creating the data for each view. It shouldn't care where that data comes from. It should be able to delegate that responsibility to something else. In other words, it should be able to ask another class to create that data for it.

Let’s get building. It’s time for a factory.

One approach I favour for this scenario is to introduce the concept of a factory. Each ViewModel that we need to create has its own factory. Every time a page loads, the controller asks the factory to create the model. The factory takes in any dependencies it needs to allow it to populate the model. It doesn't care about validation or anything else. It just creates a model every time it's asked to.

Let's illustrate this with an example. Say we are building a product catalogue. We might have a ProductController for this. Our catalogue has the ability to add and edit individual products. Our products are quite simple and just have an id, title, description and category. Here's our controller:

public class ProductController : Controller
{
    public ActionResult Add()
    {
        // add code goes here
        return View();
    }

    public ActionResult Edit(int productId)
    {
        // edit code goes here
        return View();
    }
}

Our Add method will use a factory to create a ProductAddViewModel. Our Edit method will use a different factory to create a ProductEditViewModel. Here are our view models:

public class ProductAddViewModel
{
    public string Title { get; set; }
    public string Description { get; set; }
    public int CategoryId { get; set; }
    public IEnumerable<SelectListItem> Categories { get; set; }
}

public class ProductEditViewModel : ProductAddViewModel
{
    public int ProductId { get; set; }
}

Here's what our add factory might look like:

public interface IProductAddViewModelFactory
{
    ProductAddViewModel Create();
}

public class ProductAddViewModelFactory : IProductAddViewModelFactory
{
    private readonly ICategoryRepository categoryRepository;

    public ProductAddViewModelFactory(ICategoryRepository categoryRepository)
    {
        this.categoryRepository = categoryRepository;
    }

    public ProductAddViewModel Create()
    {
        var categories = categoryRepository.FetchAll();
        var model = new ProductAddViewModel
        {
            Categories = categories.Select(x => new SelectListItem{Text = x.Name, Value = x.Id.ToString()})
        };
        return model;
    }
}

Now for the edit factory:

public interface IProductEditViewModelFactory
{
    ProductEditViewModel Create(int input);
}

public class ProductEditViewModelFactory : IProductEditViewModelFactory
{
    private readonly IProductRepository productRepository;
    private readonly ICategoryRepository categoryRepository;

    public ProductEditViewModelFactory(IProductRepository productRepository, ICategoryRepository categoryRepository)
    {
        this.productRepository = productRepository;
        this.categoryRepository = categoryRepository;
    }

    public ProductEditViewModel Create(int input)
    {
        var categories = categoryRepository.FetchAll();
        var product = productRepository.FetchById(input);
        var model = new ProductEditViewModel
        {
            ProductId = input,
            CategoryId = product.Category.Id,
            Title = product.Title,
            Description = product.Description,
            Categories = categories.Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() })
        };
        return model;
    }
}

The main difference in our edit factory is that we pass in the product id. This allows us to fetch the product from the repository and map it to our ViewModel. This all takes place within the factory. The controller has no knowledge of any of it.

Now that our factories are creating our ViewModels, we need to wire them up. Here's what our Controller now looks like:

public class ProductController : Controller
{
    private readonly IProductAddViewModelFactory productAddViewModelFactory;
    private readonly IProductEditViewModelFactory productEditViewModelFactory;

    public ProductController(IProductAddViewModelFactory productAddViewModelFactory, IProductEditViewModelFactory productEditViewModelFactory)
    {
        this.productAddViewModelFactory = productAddViewModelFactory;
        this.productEditViewModelFactory = productEditViewModelFactory;
    }

    public ActionResult Add()
    {
        var model = productAddViewModelFactory.Create();
        return View(model);
    }

    public ActionResult Edit(int productId)
    {
        var model = productEditViewModelFactory.Create(productId);
        return View(model);
    }
}

The only downside to this approach comes when we have many Controller actions. We will end up introducing quite a few dependencies into our Controller over time. Check out my other post for a way that we can deal with this issue: Reducing Controller dependencies with generic factories. It uses generics, so that we can use a single view model factory to create all our view models.

View original article

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here