Click here to Skip to main content
15,885,771 members
Articles / Web Development / ASP.NET / ASP.NETvNext

Using the Facade Pattern to Reduce Controller Dependencies

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
5 Jan 2016CPOL3 min read 11.8K   5   1
In an earlier article, I wrote about reducing controller dependencies with generic factories. One criticism of this approach, which I agree with, is that it hides those dependencies. This article looks at an alternate approach - using facades.

In an earlier article, I wrote about reducing Controller dependencies with generic factories. One criticism of this approach, which I agree with, is that it hides those dependencies. It uses service location, a well-known anti-pattern. I had reasoned that some service location was acceptable in this instance. I wasn't injecting the container around everywhere. I was using the container in one place, to resolve the specific factories that I needed. This was to avoid injecting many generic factories into a single controller. Instead, I would inject in a non-generic factory. I would then use the service locator pattern to call the correct factory. I've thought about this a bit more since. A better approach would be to group the factories together somehow. In this article, I’d like to discuss my approach to doing that. The façade pattern.

The Theory

So what’s the façade pattern all about? Well, it’s a way of grouping classes together. It provides a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use. This means we can group dependencies together behind a façade. We then inject the façade into the Controller. This reduces the number of interfaces we need to worry about.

That’s the theory out of the way. Let’s see some code!

A Practical Example

Let’s start by looking at an example Controller. Our ProductController has GET and POST methods for adding products, amongst others. It uses a factory to create the ViewModel for the GET operation. The POST operation accepts a command and uses a handler to process that command. It also displays a success or failure message in the view via a notifier. If you missed the articles on using commands/handlers or the notifier, you can read those here:

Now, back to the controller. Here's what it looks like before we introduce the façade:

C#
public class ProductController : Controller
{
    private readonly IViewModelFactory<ProductAddViewModel> productAddViewModelFactory;
    private readonly ICommandHandler<ProductAddCommand, int> productAddCommandHandler;
    private readonly INotifier notifier;

    public ProductController(IViewModelFactory<ProductAddViewModel> productAddViewModelFactory, 
        ICommandHandler<ProductAddCommand, int> productAddCommandHandler,
        INotifier notifier)
    {
        this.productAddViewModelFactory = productAddViewModelFactory;
        this.productAddCommandHandler = productAddCommandHandler;
        this.notifier = notifier;
    }

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

    [HttpPost]
    public ActionResult Add(ProductAddCommand command)
    {
        if (!ModelState.IsValid)
        {
            var viewModel = productAddViewModelFactory.Create();
            return View(viewModel);
        }

        var id = productAddCommandHandler.Execute(command);
        if (id > 0)
        {
            notifier.Success("The product was added successfully.");
        }
        else
        {
            notifier.Error("There was an error adding the product. Please try again.");
        }

        return RedirectToAction("Add");
    }
}

We're only looking at one operation here, but we now have 3 dependencies in the Controller. If we keep following this pattern, we'll add a factory and handler for each subsequent operation. Just adding edit and delete, and we're up to 7. That's getting a bit busy. Let's introduce our façade and bring that number down again:

C#
public interface IProductAddFacade
{
    ProductAddViewModel GetProductAddViewModel();
    int PostProductAddCommand(ProductAddCommand command);
    void ShowMessage(int productId);
}

public class ProductAddFacade : IProductAddFacade
{
    private readonly IViewModelFactory<ProductAddViewModel> productAddViewModelFactory;
    private readonly ICommandHandler<ProductAddCommand, int> productAddCommandHandler;
    private readonly INotifier notifier;

    public ProductAddFacade(IViewModelFactory<ProductAddViewModel> productAddViewModelFactory,
        ICommandHandler<ProductAddCommand, int> productAddCommandHandler,
        INotifier notifier)
    {
        this.productAddViewModelFactory = productAddViewModelFactory;
        this.productAddCommandHandler = productAddCommandHandler;
        this.notifier = notifier;
    }

    public ProductAddViewModel GetProductAddViewModel()
    {
        return productAddViewModelFactory.Create();
    }

    public int PostProductAddCommand(ProductAddCommand command)
    {
        return productAddCommandHandler.Execute(command);
    }

    public void ShowMessage(int productId)
    {
        if (productId > 0)
        {
            notifier.Success("The product was added successfully.");
        }
        else
        {
            notifier.Error("There was an error adding the product. Please try again.");
        }
    }
}

We can now replace our 3 dependencies in the controller with a single façade dependency.

C#
public class ProductController : Controller
{
    private readonly IProductAddFacade productAddFacade;

    public ProductController(IProductAddFacade productAddFacade)
    {
        this.productAddFacade = productAddFacade;
    }

    public ActionResult Add()
    {
        var model = productAddFacade.GetProductAddViewModel();
        return View(model);
    }

    [HttpPost]
    public ActionResult Add(ProductAddCommand command)
    {
        if (!ModelState.IsValid)
        {
            var viewModel = productAddFacade.GetProductAddViewModel();
            return View(viewModel);
        }

        var id = productAddFacade.PostProductAddCommand(command);
        productAddFacade.ShowMessage(id);
        return RedirectToAction("Add");
    }
}

We've simplified the Controller logic a little and reduced its dependencies. We can add façades for editing or deleting products without getting overrun with dependencies. This pattern has the added advantage that all our logic for adding products is in one place.

Wrapping Up

So what did we do here? Let's recap:

  • We wrapped calls relating to adding products behind a single façade.
  • We injected the façade into the Controller, reducing the complexity of the Controller
  • We moved the logic concerning which message to show into the façade, simplifying the Controller

View the original article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead Levelnis Ltd
United Kingdom United Kingdom
Follow along my journey as I create a newsletter about launching websites. Just message me with "I'm in" and I'll add you

Comments and Discussions

 
QuestionThis is not the facade pattern. This is the aggregate interface pattern. Pin
Timothee Howland9-Dec-20 11:11
Timothee Howland9-Dec-20 11:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.