Decide implementation at runtime using dependency injection - c#

I have a scenario where I need to get an implementation not known until runtime.
My approach so far is by creating a service class (to abstract the logic from the classes that use them).
The clients and the service is registered with DI. The calling classes only requests Service.
Below are two different approaches (simplified):
public class Service
{
private readonly IClient client1;
private readonly IClient client2;
public Service(Client1 client1, Client2 client2)
{
this.client1 = client1;
this.client2 = client2;
}
public Data GetData(string client, string something)
{
if (client == "client1")
return this.client1.GetData(something);
return this.client2.GetData(something);
}
}
And:
public class Service
{
private readonly IServiceProvider serviceProvider;
public Service(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public Data GetData(string client, string something)
{
if (client == "client1")
return this.serviceProvider.GetRequiredService<Client1>().GetData(something);
return this.serviceProvider.GetRequiredService<Client2>().GetData(something);
}
}
And then this is used by calling:
service.GetData("client1", ...)
Are any of these alternatives a good approach for doing this? Is one preferable over the other?

In all cases, option 2 is a bad one.
The service locator pattern is widely considered to be an antipattern. It may solve the problem at hand but it creates many other problems down the line.
You're letting your consumer decide which client to use, which effectively negates the idea of letting the service define its own dependency using the constructor.
Magic strings are never desirable. If your consumer is deciding the client anyway, then it makes no sense for them to have to use some magic string to select the correct client. It's considerably less error prone to let them pass the client itself - but then Service isn't relying on the DI framework for the client object, which may defeat the purpose of your setup.
IF the choice of client is made dynamically every time GetData() is called, then option 1 is a valid approach.
Though I would suggest using more descriptive names than "client1" and "client2" where possible.
IF the choice of client is dynamic, but remains fixed after application start, meaning that all calls to GetData() during the same runtime will be handled by the same client, then it's better to choose this client when registering your dependencies:
// Startup.cs
if( /* selection criteria */)
{
services.AddScoped<IClient, Client1>();
}
else
{
services.AddScoped<IClient, Client2>();
}
// Service.cs
public class Service
{
private readonly IClient client;
public Service(IClient client)
{
this.client = client;
}
public Data GetData(string something)
{
return this.client.GetData(something);
}
}
Though I would suggest using more descriptive names than "client1" and "client2" where possible.
Note that your selection criteria can be whatever you want them to be, e.g. an app config value, database value, environment value, compilation type (debug/release), ... The world is your oyster.
Also evaluate whether you'd be better off implementing an additional abstraction that can decide which client to redirect to (e.g. a ClientFactory or ClientRouter). This isn't always necessary, but if your requirements are less-than-trivial the abstraction may help keep things simple.

Both have drawbacks:
Version #1 always gets two instantiated clients. If instantiation is a heavy process, this is not good.
Version #2 hides it's dependencies. That is a well-known anti-pattern.
The perfect solution would be to inject an IClient1Factory and an IClient2Factory and call their factory create methods when needed. That means you still instantiate only one, not both, but you do not hide the dependencies.
As always there is no perfect solution, you now obviously need to write and maintain those two factories. Make sure it's worth it. If Client1/Client2 class instantiation is just a simple new with nothing happening in the constructor, you may want to opt for the simpler Version #1 approach. If it's simple and it works, don't wrap it in too many pattern layers. Only use them if you need them.

what you can do, is to inject ClientX trought an interface for more flexibility as shown in code below :
public class Service<T> where T : IClient
{
private readonly IServiceProvider serviceProvider;
public Service(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public Data GetData<T>(string something)
{
return this.serviceProvider.GetRequiredService<T>().GetData(something);
}
}

Related

Constructor Injection Only When Needed

I am looking for a way to inject an interface into a class only when it needs to be used.
For context I am trying to set up publish/subscribe messaging between two different projects, and to do this I am using both RabbitMQ and Azure Service Bus to suit different needs. To determine which one I want to use I use a boolean value which is set in app settings, like so:
if (AppSettingsProvider.MessagingEnabled)
{
if (AppSettingsProvider.AzureServiceBusEnabled)
{
services.AddSingleton<IEventBus, EventBusServiceBus>(
sp =>
{
var serviceBusPersistentConnection = sp.GetRequiredService<IServiceBusPersistentConnection>();
var scope = sp.CreateScope();
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionManager>();
var subscriptionClientName = AppSettingsProvider.SubscriptionName;
return new EventBusServiceBus(serviceBusPersistentConnection, logger, eventBusSubcriptionsManager, subscriptionClientName, scope);
});
}
else
{
services.AddSingleton<IEventBus, EventBusRabbitMQ>(
...
}
}
I have an if statement that wraps all of this checking MessagingEnabled. Ideally I don't want either implementation to be set up if messaging is turned off.
My issue here is that IEventBus is injected in different event publishing classes, however if I have messaging turned off I get exceptions that there is no instantiation of the injected IEventBus. As an example:
public class EventBusPublisher : IEventBusPublisher
{
private readonly IEventBus _eventBus;
private readonly IMapper _mapper;
public EventBusPublisher(IMapper mapper, IEventBus eventBus)
{
_mapper = mapper;
_eventBus = eventBus;
}
I thought maybe if I made the IEventBus nullable it may solve this issue however it has not.
This class will never be used if messaging is turned off, so there should be no problems with there not being an event bus implementation available in this case. Is there a way to, I guess tell the class its okay that there is no implementation for it?
Thanks.
It's common practice to provide a null implementation that does nothing, a common example being the NullLogger.
You can register that implementation for IEventBus, if messaging is disabled.
Depending on your use case, the class could either just do nothing, if methods are called, or possibly throw an InvalidOperationException.
Of course, it would technically be possible to register null like this:
services.AddSingleton<IEventBus>(factory => null);
But I would strongly advise against that, because now you would have to check your dependency for null everywhere and kind of defeats the purpose of DI.

Should EF6 DbContext be injected as Scoped or Transient if transactions need to be executed both in batches and asynchronously individually?

About 2 years ago, we made the change from ADO.net over to Entity Framework 6. Initially, we simply instantiated our DbContexts where we needed them. However, at some point we started down the path of prepping for implementing Dependency Injection in the solution. As such, our DbContexts were injected into our MVC controller constructors, and then the necessary logic classes were instantiated directly using the DbContexts. For awhile, this worked great as we had certain IRepository implementations that allowed us to manipulate dozens of entities across multiple repositories, and save them all with a single SaveChanges call.
However, over time, we've started to adapt a more purist DI approach where all our new classes are being injected (rather than instantiated). As a side-effect, we've started moving away from repositories and towards using EF as just a core repository across our solution. This has lead to us building modules in our application that perform their unit of work and save their changes. So rather than having dozens of repositories being used and accessed to perform an operation, we simply use the DbContext.
Initially, this worked out alright as we were injecting our DbContexts as scoped, and the functionality was unchanged. However, with the move towards more self-contained, self-saving modules, we've encountered concurrency errors with our new functionality. We managed to solve the concurrency issues by switching the DI configuration for our DbContexts over to transient. This presented each self-contained module with a new DbContext and they were able to execute and save without caring what the other modules were doing.
However, switching the DbContexts over to transient had the unfortunate side-effect of making it impossible to switch our legacy modules over to our DI container as they relied on a singular shared DbContext across all of their injected dependencies.
So my main conundrum is whether we should make our DbContexts Scoped or Transient. And if we do settle on scoped, how do we write our new modules so that they can execute in a parallel way? And if we settle on transient, how can we preserve the functionality in our dozens of legacy classes that are still developed and used?
Scoped
Pros
Single DbContext per request. No worries about entities being tracked in different contexts, and saves can be done wholesale.
Legacy Code does not need any major changes to be switched to DI.
Cons
Unrelated tasks can't execute concurrently using the same context.
Developers must constantly be aware of the state of the current context. They need to be wary of any side-effects from other classes utilizing the same context.
System.NotSupportedException: 'A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe.' thrown during concurrent operations.
Transient
Pros
New DbContext per class. No worries about locking context while performing most operations on the context.
Modules become self-contained and you don't need to worry about side-effects from other classes.
Cons
Receiving an entity from one context and attempting to use it in a different context instance can cause errors.
No ability to perform batch operations across multiple different classes sharing the same context.
Here is a demo algorithm to force a concurrency error for a scoped context. It presents a possible use-case for the transient injection.
// Logic Class
public class DemoEmrSaver
{
private readonly DbContext_dbContext;
public DemoEmrSaver(DbContext dbContext)
{
_dbContext = dbContext;
}
public Task CreateEmrs(int number)
{
Contract.Assert(number > 0);
for (var i = 0; i < number; i++)
CreateEmr();
return _dbContext.SaveChangesAsync();
}
private void CreateEmr()
{
var emr = new EMR
{
Name = Guid.NewGuid().ToString()
};
_dbContext.EMRs.Add(emr);
}
}
// In a controller
public async Task<IActionResult> TestAsync()
{
// in reality, this would be two different services.
var emrSaver1 = new DemoEmrSaver(_dbContext);
var emrSaver2 = new DemoEmrSaver(_dbContext);
await Task.WhenAll(emrSaver1.CreateEmrs(5), emrSaver2.CreateEmrs(5));
return Json(true);
}
And here is a demo of how the older services often functioned
public class DemoEmrSaver
{
private readonly DbContext _dbContext;
public DemoEmrSaver(DbContext dbContext)
{
_dbContext = dbContext;
}
public void CreateEmrs(int number)
{
Contract.Assert(number > 0);
for (var i = 0; i < number; i++)
CreateEmr();
}
private void CreateEmr()
{
var emr = new EMR
{
Name = Guid.NewGuid().ToString()
};
_dbContext.EMRs.Add(emr);
}
}
// controller action
public async Task<IActionResult> TestAsync()
{
var emrSaver1 = new DemoEmrSaver(_dbContext);
var emrSaver2 = new DemoEmrSaver(_dbContext);
emrSaver1.CreateEmrs(5);
emrSaver2.CreateEmrs(5);
await _catcContext.SaveChangesAsync();
return Json(true);
}
Is there some sort of middle ground that won't require massive overhauls to the old code, but that still enables my new modules to be defined and utilized in a simple way (e.g. avoiding having to pass a Func of some sort into each constructor to get a new instance, and avoid having to specifically a request a fresh DbContext everywhere I need one?
Also probably important, I'm using the .Net Core DI Container from the Microsoft.Extensions.DependencyInjection namespace.
Why not to use an artificial scopes were you have this difficulties?
For example, we have some background services in our codebase, when they are used inside a normal AspNet core web app, as you say, the context are bounded to the requests, but for our console apps, we do not have the concept of scoped, so we have to define it ourselves.
To create an artificial scope, simply inject an IServiceScopeFactory, then, everything inside will utilize the new, separated context.
public class SchedulerService
{
private readonly IServiceScopeFactory _scopeService;
public SchedulerService(IServiceScopeFactory scopeService)
{
_scopeService = scopeService;
}
public void EnqueueOrder(Guid? recurrentId)
{
// Everything you ask here will be created as if was a new scope,
// like a request in aspnet core web apps
using (var scope = _scopeService.CreateScope())
{
var recurrencyService = scope.ServiceProvider.GetRequiredService<IRecurrencyService>();
// This service, and their injected services (like the context)
// will be created as if was the same scope
recurrencyService.ProcessScheduledOrder(recurrentId);
}
}
}
This way you can control the lifetime of the scoped services, helping you to share the same context inside that block.
I would recommend to create just one service this way, and then inside the service program everything as normal, this way your code will be keep clean and easier to read, so, do like the example:
using (var scope = _scopeService.CreateScope())
{
var recurrencyService = scope.ServiceProvider.GetRequiredService<IRecurrencyService>();
// In this service you can do everything and is
// contained in the same service
recurrencyService.ProcessScheduledOrder(recurrentId);
}
Please do not add complex code inside the using, something like
using (var scope = _scopeService.CreateScope())
{
var recurrencyService = scope.ServiceProvider.GetRequiredService<IRecurrencyService>();
var otherService= scope.ServiceProvider.GetRequiredService<OtherService>();
var moreServices = scope.ServiceProvider.GetRequiredService<MoreServices>();
var something = recurrencyService.SomeCall();
var pleaseDoNotMakeComplexLogicInsideTheUsing = otherService.OtherMethod(something);
...
}
EDIT
My fear with this approach is that it's applying a Service Locator
pattern, and I've often seen that dismissed as an anti-pattern where
DI is concerned
An anti-pattern would be to use this as normal work, but I am suggesting to introduce it in just one part, there are limits and constraints to what DI can do and can help you with your problems.
For example, property injection (no constructor injection) are also a code smell, but it is not banned or deleted of the framework, because in some cases is the only solution, or the most simple, and keeping things simple is more important than keep all the good practices (even best practices are not white or black, sometimes you will have to do trade-offs between follow one or other principle).
My solution should be in one part of your program, not for everything, that is why I recommend to create just one service, and from there make all the services, you can not use constructor injection to break the scoped life cycle, so IServiceScopeFactory exists just for that.
And sure, it is not for general use, but to help with lifecycle problems like you have.
If you are worried about calling GetService<SomeClass> you can create an abstraction to keep your code clean, for example, I created this general service:
public class ScopedExecutor
{
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly ILogger<ScopedExecutor> _logger;
public ScopedExecutor(
IServiceScopeFactory serviceScopeFactory,
ILogger<ScopedExecutor> logger)
{
_serviceScopeFactory = serviceScopeFactory;
_logger = logger;
}
public async Task<T> ScopedAction<T>(Func<IServiceProvider, Task<T>> action)
{
using (var scope = _serviceScopeFactory.CreateScope())
{
return await action(scope.ServiceProvider);
}
}
public async Task ScopedAction(Func<IServiceProvider, Task> action)
{
using (var scope = _serviceScopeFactory.CreateScope())
{
await action(scope.ServiceProvider);
}
}
}
Then i have this extra layer (you could make this in the same class as the previous)
public class ScopedExecutorService<TService>
{
private readonly ScopedExecutor _scopedExecutor;
public ScopedExecutorService(
ScopedExecutor scopedExecutor)
{
_scopedExecutor = scopedExecutor;
}
public Task<T> ScopedActionService<T>(Func<TService, Task<T>> action)
{
return _scopedExecutor.ScopedAction(serviceProvider =>
action(
serviceProvider
.GetRequiredService<TService>()
)
);
}
}
Now, where you need your services as a separated context, you can use it something like this
public class IvrRetrieveBillHistoryListFinancingGrpcImpl : IvrRetrieveBillHistoryListFinancingService.IvrRetrieveBillHistoryListFinancingServiceBase
{
private readonly GrpcExecutorService<IvrRetrieveBillHistoryListFinancingHttpClient> _grpcExecutorService;
public IvrRetrieveBillHistoryListFinancingGrpcImpl(GrpcExecutorService<IvrRetrieveBillHistoryListFinancingHttpClient> grpcExecutorService)
{
_grpcExecutorService = grpcExecutorService;
}
public override async Task<RetrieveBillHistoryListFinancingResponse> RetrieveBillHistoryListFinancing(RetrieveBillHistoryListFinancingRequest retrieveBillHistoryListFinancingRequest, ServerCallContext context)
{
return await _grpcExecutorService
.ScopedLoggingExceptionHttpActionService(async ivrRetrieveBillHistoryListFinancingHttpClient =>
await ivrRetrieveBillHistoryListFinancingHttpClient
.RetrieveBillHistoryListFinancing(retrieveBillHistoryListFinancingRequest)
);
}
}
As you see, no service.GetService is called in the business code, just in one place in our toolkit

What is the best approach to define an HttpClient instance in a base class of a class library project?

There is an application which has 3 interfaces and whoever wants to use this app needs to implement these interfaces. I have created a class library project which has these interface implementations that I have inherited all from the same base class to be able to have a single HttpClient. Here is what I have done so far:
public class BaseProxy
{
protected static readonly HttpClient Client;
static BaseProxy()
{
Client = new HttpClient();
}
}
and I have used this Client in all derived classes to make GetAsync and PostAsync requests as follows:
public class XProxyImplementation
{
var response = Client.GetAsync(BaseUrl + "XXXApi/GetClientSettings/").Result;
response.EnsureSuccessStatusCode();
}
None of the methods in Web API are async by the way and I chose singleton solution because I don't want to use using block for each request. My question is should I go for a DI solution or is this code enough for an app which will be used internally? All suggestions for improvement are welcome.
I have read many answers regarding to using DI containers but this is just a class library with proxy implementations.
My other concern is even if I want to use DI, currently I am not able to introduce DI in my constructor classes because the other application that uses my implementations is looking for an empty constructor. When I try to pass HttpClient parameter to the constructor I get the following error:
The current type, System.Net.Http.HttpMessageHandler, is an abstract
class and cannot be constructed
The application which uses my dlls doesn't allow me to pass any parameters to constructor that uses any abstract classes. I guess this application uses Unity to make the handshake and in some way it looks for an empty constructor. Once I try to do the following changes I am getting the error:
public BaseProxy() : this(Service.HttpClient)
{
}
public XProxyImplementation(HttpClient client) : base(client)
{
}
That's why I actually prefered singleton instance to DI implementation.
DI? Yes
DI will enable testability of your proxy classes, whereas your current implementation cannot be unit-tested. It will also improve separation of concerns: remove the responsibility of controlling HttpClient lifetime from the proxy.
Typically, you would do something like this:
public abstract class BaseProxy
{
protected readonly HttpClient Client;
protected BaseProxy(HttpClient client)
{
Client = client;
}
// ... other members
}
public class XProxyImplementation : BaseProxy
{
public XProxyImplementation(HttpClient client) : base(client)
{
}
// ... other members
public Task SendRequest() // for example
{
return Client.GetAsync("....");
}
}
During the tests, you would initialize a different instance of HttpClient, injecting a test-friendly implementation of HttpMessageHandler:
// you implement TestHttpMessageHandler that aids your tests
var httpClient = new HttpClient(new TestHttpMessageHandler());
var proxyUnderTest = new XProxyImplementation(httpClient);
See this blog post for explanation of unit testing with HttpClient and HttpMessageHandler.
DI container? No
Now that we introduced dependency injection into your code, next question is, what injection mechanism should be used.
In your specific case, I would vote against coupling to any specific DI container, because you want your library to be consumed by many different applications, and you don't want to bloat their dependencies (an application might already be using a different DI container).
Moreover, since the code you posted is very simple, a full-blown DI container would be an overkill. In production code, you can just move your singleton HttpClient to a "service locator":
public static class SingletonServices
{
public static readonly HttpClient HttpClient;
static SingletonServices()
{
HttpClient = new HttpClient();
}
}
So that when you instantiate a proxy in production code, you do this:
var proxy = new XProxyImplementation(SingletonServices.HttpClient);
I would definitely go with a DI solution for this using the Microsoft.Extensions.DependencyInjection package.
https://dzone.com/articles/dependency-injection-in-net-core-console-applicati
And you should also be very aware how you use your async methods like GetAsync.
Using .Result almost never gives the desired result and you would be better off making the method async and using an await keyword like so:
var response = await Client.GetAsync(BaseUrl + "XXXApi/GetClientSettings/");
https://montemagno.com/c-sharp-developers-stop-calling-dot-result/
is a good resource for the whys and hows of this best practice
DI is the answer. If you do not want to use ID there is an HttpClientFactory that you can implement.
You can read more here
https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests

Logging as a decorator vs. Dependency Injection - what if I need to log inside the class?

(I originally asked this question in this comment, but Mark Seemann asked me to create a new question instead.)
I'm starting a new app (.NET Core, if that matters), and right now I'm trying to decide how exactly to do logging.
The general consensus seems to be that logging is a cross-cutting concern, so the logger shouldn't be injected directly into the class that is supposed to log.
Often, there's an example like the following class how not to do it:
public class BadExample : IExample
{
private readonly ILogger logger;
public BadExample(ILogger logger)
{
this.logger = logger;
}
public void DoStuff()
{
try
{
// do the important stuff here
}
catch (Exception e)
{
this.logger.Error(e.ToString());
}
}
}
Instead, the class with the business logic shouldn't know about the logger (SRP) and there should be a separate class which does the logging:
public class BetterExample : IExample
{
public void DoStuff()
{
// do the important stuff here
}
}
public class LoggingBetterExample : IExample
{
private readonly IExample betterExample;
private readonly ILogger logger;
public LoggingBetterExample(IExample betterExample, ILogger logger)
{
this.betterExample = betterExample;
this.logger = logger;
}
public void DoStuff()
{
try
{
this.betterExample.DoStuff();
}
catch (Exception e)
{
this.logger.Error(e.ToString());
}
}
}
Whenever an IExample is needed, the DI container returns an instance of LoggingBetterExample, which uses BetterExample (which contains the actual business logic) under the hood.
Some sources for this approach:
Blog posts by Mark Seemann:
Instrumentation with Decorators and Interceptors
Dependency Injection is Loose Coupling
Blog post and SO answer by Steven:
Meanwhile... on the command side of my architecture
Windsor - pulling Transient objects from the container
My question:
Obviously, the LoggingBetterExample approach only works as long as the logging can be done outside the actual class.
(like in the example above: catch any exceptions thrown by BetterExample from outside)
My problem is that I'd like to log other things inside the actual class.
Mark Seemann suspected here that if someone needs to do this, maybe the method in question is doing too much.
As I said before, I'm in the planning phase for a new application, so I don't have much code to show, but the use case I'm thinking right now is something like this:
My app will have a config file with some optional values.
The user may decide to omit the optional values, but it's an important decision to do this.
So I'd like to log a warning when some of the optional values are missing, just in case it happened by error.
(omitting the values is perfectly fine though, so I can't just throw an exception and stop)
This means that I will have a class which reads config values and needs to do something like this (pseudocode):
var config = ReadConfigValues("path/to/config.file");
if (config.OptionalValue == null)
{
logger.Warn("Optional value not set!");
}
No matter if ReadConfigValues is in this class or a different one, I don't think this class would violate the SRP.
When I'm not able to log outside the actual class by using a decorator, is there a better solution than to inject the logger?
I know I could read the config file in the inner class, but check the values (and log the warning) in the decorator. But IMO checking the value is business logic and not infrastructure, so to me it belongs in the same class where the config file is read.
checking the value is business logic and not intfastructure, so to me it belongs in the same class where the config file is read.
Obviously, I don't know your domain well enough to dispute the truth of that assertion, but that logging is part of the domain model sounds strange to me. Anyway, for the sake of argument, let's assume that this is the case.
What ought not to be the case, though, is that reading a configuration file is domain logic. While reading and manipulating the data from a file could easily be domain logic, reading a file is I/O.
The most common approach to Inversion of Control in application architecture is to employ the Ports & Adapters architecture. The entire point of such an architecture is to decouple the domain model from I/O, and other sources of non-determinism. The poster example is to show how to decouple the domain model from its database access, but file access falls squarely in that category as well.
What this ought to imply in this particular case is that you're going to need some IConfigurationReader interface anyway. This means that you can apply a Decorator:
public class ValidatingConfigurationReader : IConfigurationReader
{
private readonly IConfigurationReader reader;
private readonly ILogger logger;
public ValidatingConfigurationReader(IConfigurationReader reader, ILogger logger)
{
this.reader = reader;
this.logger = logger;
}
public MyConfiguration ReadConfigValues(string filePath)
{
var config = this.reader.ReadConfigValues(filePath);
if (config.OptionalValue == null)
{
this.logger.Warn("Optional value not set!");
}
return config;
}
}
This ValidatingConfigurationReader class can be implemented in the domain model, even if the underlying, file-reading IConfigurationReader implementation belongs in some I/O layer.
Don't take SRP so seriously, otherwise you'll end up with functional programming. If you afraid of getting your class cluttered by putting log statements inside it, then you have two options. The first one you already mentioned which is using a Decorator class but you can't access/log the private stuff. The second option is using partial classes and putting the logging statements in a separate class.

What really interceptors do with my c# class?

I was asked to implement castle dynamic proxy in my asp.net web application and i was going through couple of articles which i got from Castle Project and Code Project about castle dynamic proxy in asp.net web application....
Both articles delt with creating interceptors but i can't get the idea why interceptors are used with classes.... Why should i intercept my class which is behaving properly?
Let's say that your class needs to do 3 things for a certain operation:
Perform a security check;
Log the method call;
Cache the result.
Let's further assume that your class doesn't know anything about the specific way you've configured your security, logging, or caching. You need to depend on abstractions of these things.
There are a few ways to go about it. One way would be to set up a bunch of interfaces and use constructor injection:
public class OrderService : IOrderService
{
private readonly IAuthorizationService auth;
private readonly ILogger logger;
private readonly ICache cache;
public OrderService(IAuthorizationService auth, ILogger logger,
ICache cache)
{
if (auth == null)
throw new ArgumentNullException("auth");
if (logger == null)
throw new ArgumentNullException("logger");
if (cache == null)
throw new ArgumentNullException("cache");
this.auth = auth;
this.logger = logger;
this.cache = cache;
}
public Order GetOrder(int orderID)
{
auth.AssertPermission("GetOrder");
logger.LogInfo("GetOrder:{0}", orderID);
string cacheKey = string.Format("GetOrder-{0}", orderID);
if (cache.Contains(cacheKey))
return (Order)cache[cacheKey];
Order order = LookupOrderInDatabase(orderID);
cache[cacheKey] = order;
return order;
}
}
This isn't horrible code, but think of the problems we're introducing:
The OrderService class can't function without all three dependencies. If we want to make it so it can, we need to start peppering the code with null checks everywhere.
We're writing a ton of extra code to perform a relatively simple operation (looking up an order).
All this boilerplate code has to be repeated in every method, making for a very large, ugly, bug-prone implementation.
Here's a class which is much easier to maintain:
public class OrderService : IOrderService
{
[Authorize]
[Log]
[Cache("GetOrder-{0}")]
public virtual Order GetOrder(int orderID)
{
return LookupOrderInDatabase(orderID);
}
}
In Aspect Oriented Programming, these attributes are called Join Points, the complete set of which is called a Point Cut.
Instead of actually writing dependency code, over and over again, we leave "hints" that some additional operations are supposed to be performed for this method.
Of course, these attributes have to get turned into code sometime, but you can defer that all the way up to your main application code, by creating a proxy for the OrderService (note that the GetOrder method has been made virtual because it needs to be overridden for the service), and intercepting the GetOrder method.
Writing the interceptor might be as simple as this:
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
if (Attribute.IsDefined(invocation.Method, typeof(LogAttribute))
{
Console.Writeline("Method called: "+ invocation.Method.Name);
}
invocation.Proceed();
}
}
And creating the proxy would be:
var generator = new ProxyGenerator();
var orderService = (IOrderService)generator.CreateClassProxy(typeof(OrderService),
new LoggingInterceptor());
This is not only a lot less repetitive code, but it completely removes the actual dependency, because look what we've done - we don't even have an authorization or caching system yet, but the system still runs. We can just insert the authorization and caching logic later by registering another interceptor and checking for AuthorizeAttribute or CacheAttribute.
Hopefully this explains the "why."
Sidebar: As Krzysztof Koźmic comments, it's not a DP "best practice" to use a dynamic interceptor like this. In production code, you don't want to have the interceptor running for unnecessary methods, so use an IInterceptorSelector instead.
The reason you would use Castle-DynamicProxy is for what's called Aspect Orientated Programming. It lets you interject code into the standard operation flow of your code without the need to become dependent on the code itself.
A simple example is as always, logging. That you would create a DynamicProxy around a class that you have errors from that it logs the data going into the method and catches any exceptions and then logs the exception.
Using the intercepter your current code has no idea it exists (assuming you have your software built in a decoupled way with interfaces correctly) and you can change the registration of your classes with an inversion of control container to use the proxied class instead without having to change a single line else where in code. Then when you solve the bug you can turn off the proxying.
More advanced usage of proxying can be seen with NHibernate where all of the lazy loading is handled through proxies.

Categories