How to Master the Proxy Design Pattern in C#


When you’re building your next small to medium-sized project, you may need to add more layers of security.

For example, instead of allowing all users access to specific resources or functions, you want to ensure that only certain users can access those resources or functions at any given time. You can achieve the above functionality with the Proxy design pattern.

The Proxy is a structural design pattern where a proxy, in its most general form, is a class acting as a substitute for something else. The proxy could interface to anything: a network connection, a large object in memory, or some other resource that is expensive or impossible to duplicate.

In this article, you will discover the concept of the Proxy pattern, what it is, and how it can be applied to help solve real problems in software design.

What is the Proxy design pattern?

proxy pattern in a nutshell

Design patterns are a reusable solution to a recurring problem in software development. They describe how you should solve a programming problem in different situations. They play a vital role in SDLC (Software Development Life Cycle). As a software developer, you can use them to solve complex problems.

The Gang of Four originally introduced the design patterns in their book “Design Patterns: Elements of Reusable Object-Oriented Software“. They presented 23 design patterns in that book, one of which you will learn about in this article, i.e., the Proxy design pattern in C#.

The Proxy design pattern is a structural design pattern that allows one object to represent or substitute another object. It lets you provide a placeholder for another object. The Proxy design pattern provides an extra level of indirection for distributed, controlled, and intelligent access. Also known as a Surrogate or Placeholder design pattern, you can use it to hide the original object’s information. 

To understand how the Proxy pattern works, consider that you want to convey a message to someone you cannot talk to directly. To convey the message, you go to a third person with access to the second person. You tell your message to the third person, and he conveys it to the second person. So, the third person that conveys the message acts as a proxy of the second person and has a chance to filter your message before conveying it without your knowing.

The Proxy design pattern works the same. When a client requests a service, it hides the actual object and comes upfront to provide the requested service on behalf of the actual object.

When to use the Proxy design pattern?

Now that you know the Proxy design pattern interfaces the functionality of an original object with its proxy, you might be wondering where you should use it.

You can use the Proxy design pattern in the following ways:

  • Remote Proxy
  • Virtual Proxy
  • Protection Proxy
  • Logging Proxy
  • Caching Proxy
  • Smart Reference

Let’s go into more detail about each proxy type.

Remote Proxy

The remote proxy refers to representing an object that is present at a different location. It can be considered a stub in Remote Procedure Calls (RPC). You can also use it to provide the interface for remote resources, for example, a web service.

Virtual Proxy

You can use the proxy design pattern when you want to save the memory from being allocated to an object that you may not use in the future. Such a type of Proxy is called a virtual proxy.

The server creates the original object that consumes much memory only when the user requests or accesses it for the first time. After that, a proxy is created and used to refer to that original object.

Protection Proxy

An example of such a scenario could be a proxy server that restricts internet access in an office by allowing the valid content to be accessed and blocking the rest. The proxy pattern is also used to verify whether or not an actual user has access to the appropriate content. It serves as an authorization layer in this scenario and is called Protection Proxy.

Logging Proxy

A proxy that serves as an intermediary between the user’s web browser and website servers is called a logging proxy. You can log the sequence of calls and data transfer over a specific interface using a logging proxy.

Caching Proxy

A proxy design pattern is used as a caching proxy to increase the website’s speed. It is an internet caching technique that lets the Proxy server store recent and frequent webpage requests or data locally for quick access.

Smart Reference

The smart reference proxy design pattern is used to create a wrapper class that encapsulates a reference to an object. The wrapper class also contains logic to track how many references there are to the object. It automatically deletes the object when the last reference is removed.

This design pattern is used to improve the performance of applications by avoiding the need to constantly check if an object is no longer needed.

Who are the participants of the Proxy pattern? – Structural code in C#

The following UML diagram depicts the implementation of the Proxy design pattern:

The participants in this design pattern are:

  • Subject – Refers to the interface the actual object uses to represent its services. The Proxy should also implement this interface to be used anywhere in place of RealSubject.
  • Proxy – The Proxy is responsible for controlling the access to the RealSubject and its creation and deletion. It also maintains a reference to access the RealSubject. Implements the same interface as that of the RealSubject. 
  • RealSubject – Refers to the actual object that a proxy represents.

The client requests a service via an interface (Subject), and the interface provides it with reference to the Proxy. The client then handles the proxy same as the RealSubject (ActualObject) and invokes its methods.

The Proxy, at this point, can perform different tasks before calling the RealSubject’s methods. Meanwhile, the client may create the instances of the RealSubject, initialize and check permissions and perform different tasks. The Proxy prevents the client from directly accessing the RealSubject, adding an extra security layer.

Let’s see the sample code for the Proxy design pattern in C#.

//Creating the interface to be implemented by RealSubject and Proxy
interface ISubject
{
    void DoOperation();
}

//RealSubject implementing the interface
class RealSubject : ISubject
{
    public void DoOperation()
    {
        Console.WriteLine("Operation done by Real Subject!");
    }
}

//Proxy implementing the interface
class Proxy : ISubject
{
    private RealSubject _realSubject;
    public void DoOperation()
    {
        if (_realSubject == null)
        {
            _realSubject = new RealSubject();
        }
        Console.WriteLine("Proxy operation before Real Subject's operation.");
        _realSubject.DoOperation();
    }
}

//Client class that requests the service
class Client
{
    public void ClientCode(ISubject subject)
    {
        subject.DoOperation();
    }
}

And the usage:

Client client = new Client();
Console.WriteLine("Client Executing Via Real Object");
RealSubject realsubject = new RealSubject();
client.ClientCode(realsubject);

Console.WriteLine("Client executing via Proxy");

Proxy proxy = new Proxy();
client.ClientCode(proxy);
Console.ReadKey();

The above code produces the following output:

Client Executing Via Real Object
Operation done by Real Subject!
Client executing via Proxy
Proxy operation before Real Subject's operation.
Operation done by Real Subject!

Proxy pattern – Real World Example in C#

Here is a real-world implementation of the Proxy design pattern in C#. In this example, you will see how the proxy design pattern hides the actual object. The example shows a logging proxy. It logs the operation before RealSubject performs the math operation.

//Creating the Subject
public interface IMaths
{
    public int Add(int number1, int number2);
    public int Subtract(int number1, int number2);
    public int Multiply(int number1, int number2);
    public int Division(int number1, int number2);

}

//Creating the RealSubject
class Math : IMaths
{
    public int Add(int number1, int number2)
    {
        return number1 + number2;
    }
    public int Subtract(int number1, int number2)
    {
        return number1 - number2;
    }
    public int Multiply(int number1, int number2)
    {
        return number1 * number2;
    }

    public int Division(int number1, int number2)
    {
        return number1 / number2;
    }

}

//Creating Proxy
class MathLoggingProxy : IMaths
{
    Math math = new Math();

    public MathLoggingProxy()
    {
        Console.WriteLine("Calling the Math functions via Proxy");
    }
    public int Add(int number1, int number2)
    {
        Console.WriteLine("Log addition");
        return math.Add(number1, number2);
    }
    public int Subtract(int number1, int number2)
    {
        Console.WriteLine("Log substraction");
        return math.Subtract(number1, number2);
    }
    public int Multiply(int number1, int number2)
    {
        Console.WriteLine("Log multiplication");
        return math.Multiply(number1, number2);
    }

    public int Division(int number1, int number2)
    {
        Console.WriteLine("Log division");
        return math.Division(number1, number2);
    }
}

And the usage:

var proxy = new MathLoggingProxy();
Console.WriteLine("20 + 2 = " + proxy.Add(20, 2));
Console.WriteLine("20 - 2 = " + proxy.Subtract(20, 2));
Console.WriteLine("20 x 2 = " + proxy.Multiply(20, 2));
Console.WriteLine("20 / 2 = " + proxy.Division(20, 2));
Console.ReadKey();

The above example produces the following output.

Calling the Math functions via Proxy
Log addition
20 + 2 = 22
Log substraction
20 - 2 = 18
Log multiplication
20 x 2 = 40
Log division
20 / 2 = 10

Advantages of the Proxy design pattern

Here are some advantages of using the proxy design pattern:

  • The proxy design pattern helps you save memory by avoiding the duplication of objects that consume more memory.
  • It lets you control the service object without letting the client know about it.
  • You can provide service via Proxy even if the service object is not ready or available.
  • Proxy design pattern improves performance by caching the frequently used objects.
  • Easy to implement
  • Provides an additional layer of protection to the RealSubject

Disadvantages of the Proxy design pattern

The significant disadvantages of a proxy design pattern are:

What are the related patterns to the Proxy design pattern?

The related patterns to the proxy design pattern are Adapter and Decorator.

The Adapter pattern uses a different interface to wrap an object, whereas the Proxy uses the same.

The Adapter pattern changes the interface while preserving the behavior. Proxy changes the behavior while preserving the interface. The Adapter is used to adapt incompatible interfaces, and Proxy is used to cover the actual object.

The Decorator design pattern has a similar structure to the Proxy. This is because both are supposed to delegate the functionality of another object. The only difference is that the Proxy manages the life cycle of its object on its own, whereas the client controls the Decorator pattern.

You can find out the importance of the Decorator design pattern in the separate comprehensive article.

What is the Proxy pattern in microservices?

Microservices are a software engineering technique whereby an application is composed of small, independent processes that communicate with each other using language-agnostic APIs. These services are small, self-contained, and loosely coupled, and they can be deployed independently of each other.

The Proxy pattern in microservices involves creating a proxy service to act as an intermediary for communication between client and target services. The proxy may provide additional functionality, such as security or load balancing, or it may route requests to the underlying application or service.

The Proxy design pattern is used in microservices to hide the service a client calls.

When a client requests a service, the server invokes a different microservice altogether, and the client does not know which service is called. The proxy pattern in microservices is categorized as follows:

  1. Dumb Proxy: Delegates the request to another service.
  2. Smart Proxy: performs transformation, filtration, rejection, and logic before delegating the request to another service.

Is the AOP Proxy design pattern?

AOP (Aspect Oriented Programming) is a programming methodology that allows developers to modularize cross-cutting concerns, or aspects, of their applications. Aspects can be thought of as modules that implement specific functionality, such as logging, security, or data access.

Each aspect is implemented as a set of interrelated classes, which can be combined to form a complete application.

The AOP is based on the Proxy design pattern. You can create proxies that will handle the cross-cutting functionality.

Conclusion

Design patterns are essential to software design as they help solve a recurring problem. The Gang of Four introduced 23 design patterns, all having a different purpose and usage, one of which is the Proxy design pattern.

The Proxy design pattern, as stated earlier, is the alternate object used in place of an actual, large object. Its primary purpose is to save the memory from unnecessary allocation and speed up the website/ webpage by referencing the actual object without creating a new copy for each call by one or more clients.

Its structure is similar to the Adapter and Decorator patterns but differs in intent. Hope that you benefit from this article that defines the proxy design pattern in some real-world examples.

If you want to learn more about design patterns, check the separate in-depth article about design patterns in C#.

Recent Posts