Is there any way to validate the lifetime in DI? - c#

I'm looking for some way to enforce the checking (runtime, of course) of the proper lifetime registration of dependency-injection services, in .Net Core or higher.
Let's say I have a stateful service like this one:
public class MyStatefulService
{
private object _state;
}
However, by mistake, I could register it with the wrong lifetime:
services.AddTransient<MyStatefulService>();
So, I won't be alerted, but the actual behavior is not what I'd expect: the service is created at every request, and the state won't be preserved.
I wonder if there is a way to reinforce this pattern. For instance, it would be nice if I could decorate the class with an attribute like this:
[Singleton]
public class MyStatefulService
{
private object _state;
}
at this point, possibily at startup or at the very first request, the framework should throw if the registration is different than AddSingleton (along its overloads).
Similarly, the subject could apply for transient-only services, which shouldn't registered as singletons.
The only solution came in my mind is rather naive, and I don't like so much:
//line of principle code
public static class MySingletonChecker
{
private static HashSet<Type> _set = new HashSet<Type>();
public static void Validate(Type type)
{
if (_set.Contains(type))
{
throw new Exception();
}
else
{
_set.Add(type);
}
}
}
public class MyStatefulService
{
public MyStatefulService()
{
MySingletonChecker.Validate(this.GetType());
}
private object _state;
}
Is there any better solution, hack or anything that helps to prevent errors?

If you want to idiot-proof your code, you can provide an extension method to IServiceCollection that registers your service exactly the way it should be.
public static void AddMyStatefulService(this IServiceCollection services)
{
services.AddSingleton<MyStatefulService>();
}
Then in your services configuration section, the developer would type:
services.AddMyStatefulService();

Here's a way like I was pointing out in the comments
Let's have some empty types:
public class ScopedService {}
public class TransientService {}
Let's have a real service that derives from one of the empty types:
public class RealService: ScopedService, IRealService {
//impl
}
And a generic registration method helper:
static void MyAddScoped<TService, TImplementation>(IServiceCollection services)
where TService : class
where TImplementation : ScopedService, TService
{
services.AddScoped<TService, TImplementation>();
}
Let's register our realservice using the helper:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
MyAddScoped<IRealService, RealService>(services);
}
RealService is a ScopedService - think of this as "how you decorate a service to insist it be added as scoped"
Suppose the developer changes the service to be a transient:
class RealService: TransientService, IRealService {
Now you get a compiler error from the helper method:
The type 'YourApplication.RealService' cannot be used as type parameter 'TImplementation' in the generic type or method 'Startup.MyAddScoped<TService, TImplementation>(IServiceCollection)'. There is no implicit reference conversion from 'WebApplication1.RealService' to 'WebApplication1.ScopedService'.
Your "one person who looks after registration" can know that the developer is indicating the service is no longer registerable as Scoped and can change it (and the build will be broken until it is changed, which is a good way of preventing accidental release of incorrect code)

Another way to validate lifetimes, is by inspecting the entire DI container in the ConfigureServices clause.
Each member of a IServiceCollection has a LifeTime property which gives you the information you're looking for: https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicedescriptor.lifetime?view=dotnet-plat-ext-5.0#Microsoft_Extensions_DependencyInjection_ServiceDescriptor_Lifetime

To move DI composition to the declaration of a class you could work with some self-made marker interfaces like IRegisterTransientServiceAs<T>and add it to your class like this:
public class MyStatefulService : IMyStatefulService, IRegisterSingletonServiceAs<IMyStatefulService>
Within your composition you have your own extension method that iterates through all loaded types within the application domain, searches for the given generic interface and register them with the declarated lifetime from the given interface.
Maybe this is not real DI, but as you already mentioned, mostly the lifetime of a service is baked into the code of the service itself and it happens very rarely that a specific service will be used in different project with different lifetimes. So IMHO it is okay to bake the desired lifetime into the class itself, instead of making the decision outside.

Related

Injecting dependencies with runtime dependencies

I'm building an application that performs actions initiated by a user and one particular class has dependencies on things I can wire up in DI such as an ILogger instance as well as an HttpClient in addition to runtime arguments that identify the user and the instance of the action (mostly to be used while logging to help with debugging).
The trouble I have is that I'm not entirely sure how to inject this class into the other classes that need it as a result of the runtime dependencies.
Here's a simplified example of one of my classes:
public class Dependency : IDependency
{
private readonly HttpClient httpClient;
private readonly ILogger<Dependency> logger;
private readonly RuntimeDeps runtimeDeps
public Dependency(
ILogger<Dependency> logger,
HttpClient httpClient,
RuntimeDeps runtimeDeps)
{
// set private fields
}
public Result DoStuff()
{
// use Http client to talk to external API
// something fails so log the failure and some helpful info
logger.log($"{runtimeDeps.InstanceId} failed. " +
"Initiated by {runtimeDeps.UserName}");
}
}
This feels like it requires a factory to create but then is it best to request the HttpClient and Logger in the factory method or declare it as a dependency of the factory? If the latter, I presume the factory would have to be registered as a transient or as a scoped resource since registering it as a singleton would result in a captive dependency (I think).
Any suggestions on redesigns are also welcome if this is a symptom of a poor design. I'd love to implement Mark Seeman's Pure DI to get some more assistance from the compiler but I don't know if that's possible in Azure functions.
A transient factory with the transient dependencies injected into the constructor and the runtime dependencies as parameters of the Create method will work fine.
DI is baked into the Azure Functions library in the sense that parameters are injected into the trigger methods, but beyond these you should be able to use Pure DI to manage your own dependencies by calling into some composition root helper class from the trigger function which knows how to build your dependency graph in a pure manner.
Instead of requiring runtime data during the construction of a component, it's better to let runtime data flow through method calls on an initialized object graph by either:
passing runtime data through method calls of the API or
retrieving runtime data from specific abstractions that allow resolving runtime data.
I formalized this in 2015 in this blog post, which I referred to in the comments.
After reading your additional comments, I came to the conclusion that in your case option 2 is most suited, as the data you are sending is likely an implementation detail to the component, and should not be part of the public API.
In that case, you can redesign your component as follows:
public class Dependency : IDependency
{
public Dependency(
ILogger<Dependency> logger,
HttpClient httpClient,
IRuntimeDepsProvider provider) ...
public Result DoStuff()
{
// use Http client to talk to external API
// something fails so log the failure and some helpful info
logger.log($"{provider.InstanceId} failed. " +
$"Initiated by {provider.UserName}");
}
}
IRuntimeDepsProvider is an abstraction that hides the retrieval and storage of runtime data. This gives you the ability to postpone the decision to either use a Closure Composition Model or an Ambient Composition Model until the Last Responsible Moment.
Using the IRuntimeDepsProvider abstraction, you can chose to set the incoming runtime values after the object graph is constructed. For instance:
public class MyFunction
{
// Notice the different abstraction here
public MyFunction(
IRuntimeDepsInitializer initializer,
IHandler<Something> handler) ...
public void TheFunction(Guid instanceId, string userName, Something cmd)
{
// Setting the runtime data *after* the object graph is constructed,
initializer.SetData(instanceId, userName);
// but before the graph's public methods are invoked.
handler.Handle(cmd);
}
}
Here, a second abstraction is introduced, namely IRuntimeDepsInitializer. Now you can have one class implementing both interfaces:
public class RuntimeDepsStorage : IRuntimeDepsInitializer, IRuntimeDepsProvider
{
public Guid InstanceId { get; private set; }
public string UserName { get; private set; }
public void SetData(Guid id, string name)
{
InstanceId = id;
UserName = name;
}
}
TIP: Instead of using two interfaces, you can also use only IRuntimeDepsProvider and let MyFunction depend on the concrete RuntimeDepsStorage. Which solution is best depends on the context.
Now the main trick here is to make sure that RuntimeDepsStorage becomes a Scoped dependency, because you want to reuse it throughout a request, but not shared by multiple requests.
When applying Pure DI, this would look like this:
var storage = new RuntimeDepsStorage();
new MyFuncion(
initializer: storage,
handler: new SomethingHandler(
stuffDoer: new Dependency(
httpClient: client, // Did you notice this is a runtime dep as well?
logger: new Logger<Dependency>(),
provider: storage)))
If, on the other hand, you would be using MS.DI as your DI Container, registration would be similar to the following:
services.AddScoped(_ => new RuntimeDepsStorage());
services.AddScoped<IRuntimeDepsProvider>(
c => c.GetRequiredService<RuntimeDepsStorage>());
services.AddScoped<IRuntimeDepsInitializer>(
c => c.GetRequiredService<RuntimeDepsStorage>());
// etc, your usual registrations here

.NET Core DI without constructor arguments

Until now, I have used the Unity IOC container to resolve dependencies, which works just fine. With the Unity DI, I normally resolve instances in the following way:
Public class TestClass {
public TestClass()
{
var instance = IOC.resolve<InterfaceClassToResolve>();
}
}
This works great, but seeing that .net core now provides me with an out of the box DI container, I would much rather like to use that - There is just one problem compared to the Unity IOC, namely that it is injected as a constructor argument, and not resolved like the example above.
In most cases, I figured that it forces me to chain my dependencies throughout multiple classes, instead of just resolving my dependency in the classes that actually needs them.
I have been looking at ways to solve this, and as far as I can see, the only option is to do something like this:
Public class TestClass {
public TestClass(IServiceProvider serviceProvider)
{
var instance = serviceProvider.GetService<InterfaceClassToResolve>();
}
}
And then we are back to square one again...
Therefore, am I missing some of the functionality behind the .net core IOC, or is there some secret sauce to why most examples wants me use the .net core IOC via constructor arguments?
You can use DI without constructors like:
On the ConfigureServices
services.AddSingleton<YourClass>()
Then inject it like this:
private YourClass YourClass
{
get
{
return this.serviceProvider.GetRequiredService<YourClass>();
}
}
As already commented, Service Locator pattern is not the best method and considered an anti-pattern.
I understand the necessity, though, of finding a way to easily convert existing code to the out-of-the-box DI system without going mad.
I therefore suggest you to do something like this:
1) Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DatabaseContext>(
options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
// other services configuration here
// IMPORTANT: This should be the last line of ConfigureServices!
IOC.CurrentProvider = services.BuildServiceProvider();
}
...
2) IOC.cs
public class IOC
{
public static IServiceProvider CurrentProvider { get; internal set; }
public static T resolve<T>()
{
return CurrentProvider.GetService<T>();
}
}
This should allow you to use dotnet core DI with existing service locator code based on Unity, with minimal fixes (basically just some using declarations to be fixed), as long as you solemnly promise to refactor your code as soon as possible to get rid of all that Service Locator code :D

Use same implementation for two services with ASP.NET Dependency Injection

I have a ServiceLifetime.Scoped dependency that I only want created once per web request, but it needs to fulfill the request for two services. One of them is an interface that an implementation fulfills, the other is the implementation itself. Right now I'm essentially doing this:
public interface IService {}
public class ServiceImplementation : IService {
public Object ImplementationSpecificState;
}
public void ConfigureServices(IServiceCollection services) {
services.AddScoped<IService, ServiceImplementation>();
services.AddScoped<ServiceImplementation>();
}
Unfortunately, this is giving me two distinct objects with every web request. One in the code that depends on ServiceImplementation, and a different one in the code that depends on IService.
How do I make requests for IService and ServiceImplementation provide the same underlying object?
By using the implementationFactory-based extension method, you can dive back into the IServiceProvider's dependency graph to get the implementation when asked for the interface, and you don't even lose compile-time type checking.
public void ConfigureServices(IServiceCollection services) {
services.AddScoped<ServiceImplementation>();
services.AddScoped<IService>(
provider => provider.GetService<ServiceImplementation>()
);
}
Fancy.

Castle Windsor intercept method call from within the class

We have components registrations in Castle Windsor container like so
void RegisterComponent<TInterface, TImplementation>() {
var component = Component.For<TInterface>().ImplementedBy<TImplementation>();
component.Interceptors<SomeInterceptor>();
container.Register(component);
}
However we got to the problem that when we do a method call from within the class it does not get intercepted. For example we have component like
ServiceA : IService {
public void MethodA1() {
// do some stuff
}
public void MethodA2() {
MethodA1();
}
}
And if we call MethodA2 or MethodA1 methods from some other class it is intercepted, but MethodA1 apparently not intercepted when called from MethodA2 since the call is from within the class.
We have found similar case with the solution Castle Dynamic Proxy not intercepting method calls when invoked from within the class
However the solution features component and proxy creation using new operator which is not suitable in our case since we are using container. Can we use this solution with component registration like above? Or are there other approaches to solve the problem?
For interception to work on MethodA1 when invoked from MethodA2 you need to be using inheritance based interception (it's because you are using this reference to make the invocation).
To make inheritance based interception possible first you need to make MethodA1 and MethodA2 virtual.
Then you can make container registration like this:
container.Register(Component.For<ServiceA>().Interceptors<SomeInterceptor>());
container.Register(Component.For<IService>().UsingFactoryMethod(c => c.Resolve<ServiceA>()));
First register your service as itself applying interceptors (this will add inheritance based interception over the service). Then you can register the interface which will use service registered earlier.
Change your registration to the following and Windsor should switch to class proxies - i.e. using inheritance for interception, instead of composition.
void RegisterComponent<TInterface, TImplementation>() {
container.Register(Component.For<TInterface,TImplementation>().ImplementedBy<TImplementation>().Interceptors<SomeInterceptor>());
}
We use CreateClassProxy method to create the proxy for the service as it was proposed in an answer to the question Castle Dynamic Proxy not intercepting method calls when invoked from within the class.
Then we register the obtained proxy as an implementation for the interface.
So our custom RegisterComponent method looks like this
private void RegisterComponent<TInterface, TImplementation>()
where TInterface : class
where TImplementation : class, TInterface
{
var proxyType = new ProxyGenerator().CreateClassProxy<TImplementation>().GetType();
Container.Register(Component.For<TInterface>().ImplementedBy(proxyType));
}
The full component registration is
Container = new WindsorContainer();
Container.Kernel.Resolver.AddSubResolver(new CollectionResolver(Container.Kernel));
// Interceptor
Container.Register(Component.For<IInterceptor>().ImplementedBy<SomeInterceptor>().LifestyleTransient());
// Component registrations
RegisterComponent<ISomeService, SomeService>();
And, of course, all methods you need to intercept should be virtual since inheritance based proxy is used.
However a drawback of this solution is that you could not use constructor injection when creating a proxy object.
Notice that you are creating "dummy" proxy object with new operator only to get a type of the proxy. Therefore you are unable to use constructor injection only when constructing a dummy proxy, but when you resolve your service via container, injection would work just fine. So this drawback is critical only for components with construction logic being more complex than just assigment of dependencies. If you need only dependency assigments you can try to resolve all dependencies from container manually before creating dummy proxy
private object[] ResolveConstructorParameters<TType>()
{
return typeof(TType).GetConstructors()
.Single(c => c.IsPublic)
.GetParameters()
.Select(p => _container.Resolve(p.ParameterType))
.ToArray();
}
and then RegisterComponent would become
private void RegisterComponent<TInterface, TImplementation>()
where TInterface : class
where TImplementation : class, TInterface
{
var constructorParameters = ResolveConstructorParameters<TImplementation>();
var proxyType = new ProxyGenerator().CreateClassProxy(typeof(TImplementation), constructorParameters).GetType();
_container.Register(Component.For<TInterface>().ImplementedBy(proxyType));
}
You can also just fill arguments with null.
#NikolayKondratyev I've looked into https://github.com/castleproject/Windsor/blob/master/src/Castle.Windsor/Windsor/Proxy/DefaultProxyFactory.cs#L110
and I've done the registration the easy way:
container.Register(Classes.FromThisAssembly().BasedOn(typeof(IRepositoryBase<,>))
.WithServiceAllInterfaces().WithServiceSelf()
.LifestyleTransient());
Note .WithServiceSelf() call, this actually switches class-based proxying
I know this is an old thread, but I just came across it while getting Castle interceptors working in Blazor WASM (which they actually do, but beware...Mono can't seem to support proxying any class that has any generic methods...).
Anyway, to get around this issue in my case, I simply injected the container into my class, and in the method that needed to call a "sibling method" via this I simply resolved a fresh instance of my interface and called the method on that. It won't work for scenarios with shared context/transient states, but the interceptor indeed does its thing.
In Blazor's client WASM app's Program.cs:
public static async Task Main(string[] args)
{
WebAssemblyHostBuilder builder = WebAssemblyHostBuilder.CreateDefault(args);
...
builder.ConfigureContainer<IWindsorContainer>(new WindsorServiceProviderFactory(), container =>
{
container.Register(Component.For<IInterceptor>()
.ImplementedBy<BlazorInterceptor>()
.Named("BlazorInterceptor").LifestyleTransient());
});
...
builder.Services.AddScoped<IService, Service>();
...
await builder.Build().RunAsync();
}
Example service and interface implementation:
public Interface IService
{
MethodA(int arg);
MethodB(int arg);
}
[Interceptor("BlazorInterceptor")]
public class Service : IService
{
private readonly IServiceProvider _container;
public Service(IServiceProvider container)
{
this._container = container;
}
public MethodA(int arg)
{
IService service = this._container.GetRequiredService<IService>();
service.MethodB(arg);
}
public MethodB(int arg)
{
//should be intercepted...just in a different instance of the service unless you're using singletons...
}
}
Pros: Doesn't require virtualizing methods or complicating your DI configuration.
Cons: Kind of gross (useful for stateless repositories, but would probably give something like EF a heart attack).

Structuremap IContainer Implementation

I am currently trying to get my head around structuremap now that the ObjectFactory static function has been marked as obsolete.
In the long run I have to use this in a MVC and WebApi application. When previously used, a line to a static method was placed in the the global.asax to initialise everything using the ObjectFactory.
ObjectFactory.Initialize{
container.For .....
}
Trying to convert this to the new IContainer approach I have come up with the following however am wondering if I have actually inadvertently implemented this often mentioned Anti-Pattern in my approach.
Static method to return container:
public class StructureMapConfig
{
public static IContainer GetContainer()
{
return new Container(container =>
{
container.For<IUserService>().Use<UserService>();
container.For<IStringService>().Use<StringService>();
container.For<IUserRepository>().Use<UserRepository>();
});
}
}
Userservice's contstructor looks like this:
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
private readonly IStringService _stringService;
public UserService(IUserRepository userRepository, IStringService stringService)
{
_userRepository = userRepository;
_stringService = stringService;
}
Finally the initialise (this instance in a console app) looks somthing like this:
private static IUserService _userService;
private static IContainer _container;
static void Main(string[] args)
{
_container = StructureMapConfig.GetContainer();
_userService = _container.GetInstance<IUserService>();
}
So to my questions.
Am I doing anything seriously wrong here
In the UserService, should I be passing the IContainer in and using the object factory to get the instance or should I leave as is.
Is returning the IContainer from the static method the best approach
If this was a MVC app, is it best practice to build this once in the Global.asax or should the controller constructor call the static method every time.
Thanks for any advice.
To go through your questions in order:
Am I doing anything seriously wrong here
No, I don't see anything seriously wrong here. There are a few improvements you could make that I'll talk about shortly.
In the UserService, should I be passing the IContainer in and using
the object factory to get the instance or should I leave as is.
You're correct in injecting UserService over an instance of IContainer. If your controller only requires the UserService then why inject the entire container. Really you only want to inject the bare minimum of what you need to reduce unnecessary coupling and dependencies.
Is returning the IContainer from the static method the best approach
Within the removal of the ObjectFactory then yes, returning an instance of the container via a static method is a common approach for those classes whose creation is not managed via MVC's Dependency Resolution.
If this was a MVC app, is it best practice to build this once in the
Global.asax or should the controller constructor call the static
method every time.
Creating the container in Global.asax.cs is your best approach as it's done once on Application_Start, however see below for my recommendation of using a nested container per http request.
Improvements:-
Take advantage of StructureMap's registries:
Instead of referencing the dependencies directly like this:
public static IContainer GetContainer()
{
return new Container(container =>
{
container.For<IUserService>().Use<UserService>();
container.For<IStringService>().Use<StringService>();
container.For<IUserRepository>().Use<UserRepository>();
});
}
Opt to use StructureMap's registries instead. This way you can group your dependencies (such as MVC specific dependencies or WebAPI specific dependencies, like so:
public class WebsiteRegistry : Registry
{
public WebsiteRegistry()
{
this.For<IUserService>().Use<UserService>();
this.For<IStringService>().Use<StringService>();
this.For<IUserRepository>().Use<UserRepository>();
}
}
Then load your registries like this:
container.Configure(c => {
c.IncludeRegistry<WebsiteRegistry>();
c.IncludeRegistry<TaskRegistry>();
});
HTTP Context bound containers:
Another recommended pattern when using StructureMap with ASP.NET MVC or WebApi (or any HTTP based application) is to use nested containers that are bound to each HTTP request. This basically involves creating a new nested container on each HTTP request and then disposing it at the end of the request. This ensures that dependencies such as session objects, database connections, or UoW contexts are disposed of as soon as the HTTP request is over.
I would recommend taking a look over this article which goes into more detail on the matter and talks about how this can be set up.
This is exactly the same technique that's used in the StructureMap.MVC5 package that's often recommended by StructureMap's creator, Jeremy Miller.
Auto registering dependencies
Instead of registering every dependency with StructureMap manually you can take advantage of StructureMap's auto-registration. You can also specify your own scanning conventions.

Categories

Resources