RO EN

Proxy Pattern – access control to an object (lazy loading, security)

Proxy Pattern – access control to an object (lazy loading, security)
Doru Bulubasa
08 December 2025

Proxy Pattern is a structural design pattern that introduces an intermediary object — the proxy — to control access to a real object (Real Subject).

Its purpose is to provide an additional level of control without the rest of the application knowing that it is actually working with an “intermediary”.

This pattern is essential when:

  • the real object is expensive to create → lazy loading,

  • we need security or validations,

  • we want optimization of access to external resources,

  • we need to add cache, logging or monitoring.


1. Why do we need the Proxy Pattern?

Sometimes it is inefficient or unsafe to allow direct access to an object.

Classic examples:

  • ⏳ The object is hard to initialize (e.g., large image, database connection).

  • 🔐 The object must be protected by an access mechanism.

  • 🧮 The object is used frequently, but data doesn’t change → caching.

  • 📡 Access involves external calls, slow APIs, costly resources.

Proxy Pattern introduces a control layer that can decide:

  • when the object is created,

  • whether access is allowed,

  • whether data is returned from cache,

  • whether access should be logged or monitored.


2. What is the Proxy?

The proxy is an object with the same interface as the real object.

The client does not know the difference — everything is transparent.

Structure:

  • Subject – the common interface

  • RealSubject – the real implementation

  • Proxy – controls access and delegates to RealSubject


3. Common examples of proxies in .NET

✔ Virtual Proxy

Delays creation of the real object → lazy loading.

✔ Protection Proxy

Controls access → authorization / security.

✔ Cache Proxy

Stores results → performance.

✔ Remote Proxy

Access to remote resources → e.g., WCF, microservices.


4. Simple example in C# – Lazy Loading with Virtual Proxy

Purpose: load a large file (e.g., image) only when it is actually needed.

Subject

public interface IImage
{
    void Display();
}

Real Subject

public class RealImage : IImage
{
    private readonly string _fileName;

    public RealImage(string fileName)
    {
        _fileName = fileName;
        LoadFromDisk();
    }

    private void LoadFromDisk()
    {
        Console.WriteLine($"Loading image: {_fileName}");
    }

    public void Display()
    {
        Console.WriteLine($"Displaying image: {_fileName}");
    }
}

Proxy (Virtual Proxy)

public class ImageProxy : IImage
{
    private readonly string _fileName;
    private RealImage? _realImage;

    public ImageProxy(string fileName)
    {
        _fileName = fileName;
    }

    public void Display()
    {
        if (_realImage == null)
        {
            _realImage = new RealImage(_fileName);
        }

        _realImage.Display();
    }
}

Usage

IImage img = new ImageProxy("large_photo.png");

// the image is NOT loaded yet
Console.WriteLine("The image will be loaded only at Display.");

img.Display();   // load + display
img.Display();   // display only (no reload)

Result:

  • High efficiency

  • Delayed creation

  • Reduced memory consumption


5. Example: Proxy for security (Protection Proxy)

We control access to a service only for authorized users.

Subject

public interface IDocumentService
{
    void ReadDocument();
}

Real Subject

public class DocumentService : IDocumentService
{
    public void ReadDocument()
    {
        Console.WriteLine("Reading confidential document...");
    }
}

Secure Proxy

public class SecureDocumentProxy : IDocumentService
{
    private readonly DocumentService _documentService = new();
    private readonly string _userRole;

    public SecureDocumentProxy(string userRole)
    {
        _userRole = userRole;
    }

    public void ReadDocument()
    {
        if (_userRole != "Admin")
        {
            Console.WriteLine("Access denied!");
            return;
        }

        _documentService.ReadDocument();
    }
}

Usage

IDocumentService service = new SecureDocumentProxy("User");
service.ReadDocument(); // Access denied!

service = new SecureDocumentProxy("Admin");
service.ReadDocument(); // OK


6. Advantages

✔ Full control over access

Security, authentication, restrictions.

✔ Lazy loading

Creation only when needed.

✔ Caching and optimization

No duplicated effort for identical results.

✔ Flexible and extensible system

We can introduce logging, auditing, metrics without modifying the real object.


7. Disadvantages

✖ Increases architectural complexity

An additional layer.

✖ The proxy can become a bottleneck

If processing in the proxy is too heavy.


8. When to use Proxy Pattern in .NET?

  • Access to large files (images, documents).

  • Costly API calls → caching.

  • Objects with heavy initialization.

  • Services that require authorization.

  • Remote / distributed resources.

  • Logging / auditing for sensitive actions.