Part of the development process is constructing code to produce value to clients when the solution is delivered. To keep code clean, certain structures, or design patterns, should be embraced throughout the code base to aid with structure, maintainability, improve reuse and allow for easier team collaboration.
In this tutorial, I will look to explain one of the simpler patterns, how to implement it, and why it's still relevant in modern development in ASP.NET Core.
This tutorial is from the DotNetCurry(DNC) Magazine with in-depth tutorials and best practices in .NET and JavaScript. This magazine is aimed at Developers, Architects and Technical Managers and covers C#, Patterns, .NET Core, MVC, Azure, DevOps, ALM, TypeScript, Angular, React, and more. Subscribe to this magazine for FREE and receive all previous, current and upcoming editions, right in your Inbox. No Spam Policy.
What is a façade?
To get an understanding of what the façade pattern is, we first need to look at where the name comes from and how it can be used.
As with a number of design patterns, the façade design pattern takes its name from the construction industry and building architecture. A façade is defined as "the principle front of a building, that faces on to a street or open space" so it's the public face on multiple other parts of the building.
But what does this have to do with programming? Design patterns to the rescue!
Design patterns and well architected applications which follow development patterns and principles make life easier in the long run.
I've worked with a number of people in the past who have not seen the benefits of design patterns and just written code; it's usually worked but the code has been a bit of a mess!
I've also worked with several good developers who don't know what the patterns are called but if you describe them, they can relate and have seen/used them many times before.
Either way, design patterns will help you keep your code base readable and maintainable. The issue comes when to apply a pattern or just write the functionality directly and look to refactor in the future.
There will be times when you don't need a pattern or when you realise applying a design pattern earlier would have saved you time and headache. This unfortunately only comes with experience and working closely with more experienced developers.
There are also times when applying a design pattern because of what you "think" is going to change in the future and what you "expect" to come in the future is also detrimental to the quality of code as these events may not happen in your expected time scales or ever. This is where experience and refactoring come into the equation.
As with anything, when to apply a pattern or not comes with experience. When the need arises and if its beneficial to your codebase is a well-argued grey area. You have to decide for yourself.
Gang of Four
You can't talk about design patterns without a reference to “the” design patterns book. Often referred to as the "Gang of Four" book the full title is "Design Patterns - Elements of Reusable Object-Oriented Software". It is a highly recommended reference book. I'm still reading it, but I would say it's more reference material than a front to back page turner.
This book describes the façade pattern’s intent as:
"Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use"
What does a façade give me?
Like other design patterns, the façade pattern reduces tight coupling in your code to other parts of the system and the overall architecture as a whole.
Having a loosely coupled abstraction from the complexities of the subsystems allows for less complex testing and more maintainable code. The downside is that there are times when there will be more code files and lines of code which will feel like they should not be required.
It allows for a simplified interface on top of complex systems.
In the early development of a system this might not be an advantage as there are a number of moving parts especially with a multiple developer team working on the same code base. However, once the initial churn has settled, which with new code bases it will eventually happen, then additional functionality which needs to interact with the subsystems is usually easier and quicker as the consumer of the façade does not need to worry about the things "under the hood".
Not only do design patterns help with code quality but also with on-boarding new members of the team. Getting new members of a development team to be productive quickly is always a challenge, whether in a company setting or on an open source project. Keeping the complexities of the system initially abstracted away will allow for productivity to increase and avoid initial information overload.
So how do we implement it?
Façade Pattern - Simple Example
I hired a car on holiday recently and it had an interesting starting mechanism. From depressing the clutch and pushing the start button, it would execute a number of actions which would eventually lead to the car starting.
This is an example of a façade.
As a driver of the car, I would have to perform a couple of actions, but the car would have to do a lot more and interact with a number of subsystems to actually start the car. I have set out the functionality in a simple example below.
public class StartCarFacade : IStartCarFacade
{
/** constructor and dependencies snipped for brevity **/
public void Start()
{
// if the clutch is depressed then the sequence can start, if not then there is no point in continuing
if (_clutchSubSystem.ClutchDepressed())
{
if (_engineCheckSubSystem.EngineReady()
&& _fuelSubSystem.HasFuel())
{
// start the engine
_engineStartSystem.Start();
}
// and finally fold out the wing mirrors
_wingMirrorSystem.FoldOutWinMirrors();
}
}
}
In the simplified example you can see the driver wants to start the car by pressing the Start button. If the clutch subsystem does not indicate that the clutch peddle is depressed, it will not start the car. If it indicates the peddle is in the required state, then it will continue and check the other subsystems; such as is the engine ready to start and is there enough fuel in the car.
My rental car also folded out the wingmirrors once the car had started. This is an example of a subsystem which is not necessarily related but still required to be actioned. The driver does not want to manually have to initiate this functionality every time themselves.
This is a good example of the Single Responsibility Principle (SRP) in action. Its sole responsibility is to start the car and orchestrate out the responsibilities of the subsystems to the subsystems. If the logic gets too complex, then it could violate the principle and some further refactoring should be done.
Higher Abstraction Level Example
You can use the façade pattern at various levels in your architecture depending on how it is designed and what type of application or system you are building.
Another good example of using the façade pattern is when you are working with a fundamental object in your system and it is used a lot. Not only is it used for the underlying functionality but when it is saved or loaded, there are a number of actions which need to be done to make sure it is in a valid state to allow for this.
This could be combining a number of different database calls to construct the required instance, different types of data storage option calls or even be reliant on external systems such as Azure Search, Azure Functions, SignalR or a message queuing technology. This allows for multiple communication techniques to be used and intra-microservice event notifications to be fired if required.

However at a higher level, it can seem that a service or façade has more than one responsibility and violates the Single Responsibility Principle. This can be the case, however it comes down to the correct level of abstraction you are using in your application.
In this example the façade is abstracting the other service calls and as before works as an orchestrator for the functionality. These can be complex requirements and integration points, but the façade is there to hide these away from the regular callers of the code which only want to read and write an object.
public interface IExampleObjectFacade
{
Task<MyExampleObject> LoadAsync(Guid id,
CancellationToken cancellationToken = default);
Task<Guid> SaveAsync(MyExampleObject instance,
CancellationToken cancellationToken = default);
}
public class ExampleObjectFacade : IExampleObjectFacade
{
private readonly IMediator _mediator;
public ExampleObjectFacade(IMediator mediator)
{
_mediator = mediator;
}
public async Task<MyExampleObject> LoadAsync(Guid id,
CancellationToken cancellationToken = default)
{
return await _mediator.Send(
new LoadMyExampleObjectEvent(id), cancellationToken);
}
public async Task<Guid> SaveAsync(MyExampleObject instance,
CancellationToken cancellationToken = default)
{
return await _mediator.Send(
new SaveMyExampleObjectEvent(instance), cancellationToken);
}
}
The interface and implementation for the façade above defines high level Load and Save methods.
From the consuming code this is ideal as this is the right level of abstraction you want to use to read and write the instance your code flow is currently working on. Due to the complex nature of the actions required, the façade has the potential to become overloaded with dependencies and fall into the trap of becoming a "god" object.
In this example, I have used MediatR to delegate the processing to specific handlers for Loading or Saving. Please note that this could be seen as premature optimization, so be careful. Working with the methods on the façade then becomes straightforward. The consumer needs to know less about what is going on under the covers of the façade.
Note: MediatR is an open source project which aids with implementing the mediator pattern. More information can be found on the Github page - https://github.com/jbogard/mediatr and on Wikipedia - https://en.wikipedia.org/wiki/Mediator_pattern
Once the façade and its implementation have been created they will require registering with the ASP.Net Core DI mechanism. Like other services and library registrations this is done via the ConfigureServices method in the applications Startup class.
public void ConfigureServices(IServiceCollection services)
{
services.AddMediatR();
services.AddTransient<IExampleObjectFacade, ExampleObjectFacade>();
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
Like any dependency, now you can specify your controller, or service, to require it through constructor dependency injection. Due to the way the façade is setup, you only require one dependency at this point instead of multiple references.
public class MyExampleObjectController : ControllerBase
{
private readonly IExampleObjectFacade _facade;
public MyExampleObjectController(IExampleObjectFacade facade)
{
_facade = facade;
}
[HttpGet]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> GetById(Guid id,
CancellationToken cancellationToken = default)
{
var item = await _facade.LoadAsync(id, cancellationToken);
if (item == null)
{
return NotFound();
}
return Ok(item);
}
}
In the simple controller class definition above, you can see that there is only one dependency and one action. As this controller grows there may be additional actions added to allow for reading lists or saving an instance of MyExampleObject, however no further dependencies would be required as all would delegate to the façade to perform the required actions.
In a more complicated application the power of a façade can be more prevalent inside interconnected services. This is especially the case when multiple functionality points require access to the items which are abstracted behind the façade.
Related Design Patterns
Leading on from the examples, the façade pattern works really well with other design patterns. In the example, it is using the Mediator Pattern which can help reduce the dependency graphs for the façade implementation.
Other examples of using different patterns with the façade pattern are as follows:
- For validation of an instance, or parts of an instance, which is being saved it might make sense to use the Strategy Pattern. The façade can take a dependency on the Strategy but not need to worry about any of the processing requirements which will be run. This allows for the validation to be updated without changing the façade itself. More info - https://en.wikipedia.org/wiki/Strategy_pattern.
- Related items which need to be generated or specific types which are required and known at runtime can be created using the Abstract Factory Pattern. This allows for related items to be instantiated without the façade requiring further dependencies. More info - https://en.wikipedia.org/wiki/Abstract_factory_pattern.
What are the downsides of the façade pattern?
One of the downsides, as previously mentioned, is it can result in a “god object”.
So, what is a “god object”?
Like other services which evolve, the issue comes over time as the code base grows in functionality and complexity. As developers add small functionality points into the façade, additional dependencies are added without thinking about the bigger picture.
Initially it might be ok, but as typically developers’ mentality is “find the previous example and copy it”, this can balloon without care. Before long the dependency graph is huge, the method bodies are large and unwieldy and it generally becomes a mess.
There is also the potential risk that abstractions from different levels will leak across boundaries.
When adding in new functionality it needs to be made sure that it is being applied to the correct side of the façade. At the point of design, the functionality needs to be assessed with the potential for adjusting the level of abstraction. I've seen it done on both sides of the façade incorrectly and it can cause "leaks" which lead to developer headaches. It also diminishes the control which a façade can give you in your code base.
Making general sweeping comments about this topic is impossible, so make sure you discuss with your team, have peer reviews and pair programming sessions and talk it through to make sure it is applicable for your application.
So, is the façade pattern still relevant to ASP.NET Core?
In short; yes!
There are so many moving parts to applications in the modern world. Whether it is due to technology changes, data center location requirements for data storage or improved latency responses for customers or just complex processing, it makes the pattern applicable.
With the ever-increasing number of third-party services which are available, not to mention the new "serverless" wave which is currently being surfed, the potential is limitless. There will be new requirements for additional integrations, event sourcing, new caching techniques etc. All these can change and evolve over time however the consuming code of the façade will not care about them as long as the functionality it expects remains consistent and the abstraction level is the same.
With distributed processing systems and multiple microservices requiring parts of the information to continue to process I feel it is relevant even more than ever.
Conclusion
The façade design pattern is a great abstraction when used correctly.
It will likely be used in conjunction with other patterns and practices to aid in reducing complexity, improving readability and keeping your code maintainable.
When should the façade pattern be used? Like most things in software development "it depends".
If it feels right, then it most likely is. If, however, you feel like you're fighting a losing battle then it's probably not the right pattern, the right level of abstraction or you need to evaluate the current state of your code.
The ability to apply design patterns comes from identifying an issue and refactoring the code to make it better.
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Adam is a Technical Lead and Senior Software Developer with over 12 years of experience in various domain verticals primarily working with the Microsoft .NET stack. He enjoys investigating technical items and design patterns to aid with building scalable SaaS applications. Adam enjoys sharing what he has learnt in his blog -
adamstorr.co.uk; concentrating mainly on .NET and ASP.NET Core. Adam's posts have been featured on
ASP.NET as well as the
ASP.NET Community Stand up. Adam lives in the UK with his wife and two children. He enjoys running and playing disc golf. Follow Adam on Twitter at
@WestDiscGolf