Dynamic Proxy vs Static Proxy in WitRPC
Published on: 1/11/2025
By default, Castle DynamicProxy serves as the primary tool in WitRPC for creating proxy objects based on interface contracts. This allows developers to seamlessly interact with remote services as if they were local objects. DynamicProxy supports intercepting function calls, property access, and event subscriptions, making it an incredibly versatile solution for .NET development. Moreover, it effortlessly handles generic methods, where parameter types are undefined at the interface declaration stage.
However, DynamicProxy is not universally applicable. For instance, it does not work in Ahead-of-Time (AoT) compilation environments, such as Blazor WebAssembly or .NET Native AOT, where runtime code generation is unsupported.
For such scenarios, WitRPC introduces a static proxy implementation based on Source Generation using Roslyn APIs.
How to Use Static Proxy
To utilize the static proxy in WitRPC, follow these steps:
1. Add the OutWit.Common.Proxy Package to Your Contract Project
Install the OutWit.Common.Proxy package, which provides the necessary base classes and attributes for static proxy generation:
dotnet add package OutWit.Common.Proxy2. Mark Your Interface with the GenerateProxy Attribute
Apply the GenerateProxy attribute to the interface representing your contract:
using OutWit.Common.Proxy.Attributes;
[GenerateProxy]public interface IExampleService{ event ExampleServiceEventHandler ProcessingStarted; event ExampleServiceProgressEventHandler ProgressChanged; event ExampleServiceProcessingEventHandler ProcessingCompleted;
bool StartProcessing(); void StopProcessing();}By default, this generates a proxy class named IExampleServiceProxy.
To specify a custom name for the generated proxy class, pass the desired name as a parameter to the attribute:
[GenerateProxy("ServiceProxy")]public interface IExampleService{ event ExampleServiceEventHandler ProcessingStarted; event ExampleServiceProgressEventHandler ProgressChanged; event ExampleServiceProcessingEventHandler ProcessingCompleted;
bool StartProcessing(); void StopProcessing();}In this case, a proxy class named ServiceProxy will be generated.
Note: Generic methods are not supported in static proxy generation. Including generic methods in your interface will result in a compilation error.
3. Add the OutWit.Common.Proxy.Generator Package to Your Client Project
To enable proxy generation, add the OutWit.Common.Proxy.Generator package to your client project:
dotnet add package OutWit.Common.Proxy.GeneratorBuild the project, and the proxy class will be generated automatically.
Using the Static Proxy with WitRPC
Once the client is initialized:
var client = WitClientBuilder.Build(options =>{ options.WithWebSocket("ws://localhost:5000"); options.WithJson(); options.WithEncryption();});
await client.ConnectAsync(TimeSpan.FromSeconds(5), CancellationToken.None);Instead of creating a dynamic proxy:
var service = client.GetService<IExampleService>();Use the static proxy:
var service = client.GetService<IExampleService>(interceptor => new ServiceProxy(interceptor));Beyond this change, the rest of the workflow with WitRPC remains unchanged.
Advantages of Static Proxy
-
Compatibility with AoT: Static proxies work seamlessly in Ahead-of-Time (AoT) compilation environments, such as Blazor WebAssembly and .NET Native AOT.
-
Improved Startup Performance: Since the proxy code is generated at compile time, runtime reflection overhead is eliminated, resulting in faster application startup.
-
No Dependency on Reflection.Emit: Unlike DynamicProxy, static proxies do not rely on Reflection.Emit, making them suitable for platforms restricting dynamic IL generation.
Disadvantages of Static Proxy
-
Less Flexible: Static proxies require explicit setup at compile time, making them less adaptable for scenarios where runtime behavior needs dynamic adjustment.
-
Increased Build Complexity: Using source generators introduces additional build steps and dependencies, complicating the development process.
The choice between DynamicProxy and Static Proxy ultimately depends on your application’s requirements. For AoT environments or scenarios without dynamic IL generation, static proxies offer a powerful alternative. However, DynamicProxy remains an excellent choice for maximum flexibility and ease of use in runtime environments.
Explore more about WitCom and its static proxy implementation: Static Proxy Example