Get Instance from Simple Injector without "GetInstance" method - c#

Following this answer I did this :
public class Log4netAdapter<T> : ILogger
{
private static readonly log4net.ILog logger = LogManager.GetLogger(typeof(T));
public void Log(LogEntry entry)
{
if(entry.LoggingEventType == LoggingEventType.Information)
logger.Info(entry.Message, entry.Exception);
else if(entry.LoggingEventType == LoggingEventType.Warning)
logger.Warn(entry.Message, entry.Exception);
else if(entry.LoggingEventType == LoggingEventType.Error)
logger.Error(entry.Message, entry.Exception);
else
logger.Fatal(entry.Message, entry.Exception);
}
}
And then on the Simple Injector :
container.RegisterConditional(
typeof(ILogger),
c => typeof(Log4netAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
This works great if I inject the ILogger on every class constructor I need. My problem is that I have some classes that I cannot use the constructor injection. For this cases I would tipically do :
var logger = SimpleInjectorInitializer.Container.GetInstance<ILogger>();
However the above method does not work, it throws an error on the simple injector class since the c.Consumer is null.
Here is one of the examples I need to resolve ILogger, this class is registered on the webapi startup class.
public class ExceptionWebApiHandlingAttribute : IExceptionFilter
{
public ExceptionWebApiHandlingAttribute()
{
}
}
Is there any alternative ?
Thanks

When working on the application boundary, it is sometimes hard or impossible to use constructor injection. Typical examples are MVC filter attributes or ASP.NET Web Form Page classes that require a default constructor.
A typical solution to these problems is to make such boundary class into a Humble Object, where all interesting logic is extracted from the boundary class into a component. The boundary class should only contain the call to the Service Locator and call one method on the resolved service. This minimizes the amount of untestable code in the application.
In all other cases, constructor injection should be preferred.
The fact however that you resolve an ILogger implies that your boundary class does too much. Instead this ILogger should be a constructor dependency of the component that you extracted from the boundary class to become a Humble Object.
Once you've done this, you won't be resolving ILogger directly anymore and this solves your problem; ILogger has become a dependency of a consumer and this ensures that Simple Injector is able to build the correct Logger<T> on your behalf.
When it comes to applying dependencies to exception filters in Web API (your particular case), a good solution is to create a proxy for your exception filters that will delegate the call to the real filter that gets resolved. This can be a bit of infrastructure and the concept is explained here.
If it is impossible to apply the above advise, for whatever reason, you can always request a Logger<T> directly from the container:
ILogger log = SimpleInjectorInitializer.Container.GetInstance<Logger<MyHumbleObject>>();

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

How do I get Type that Dependency is being injected into?

Im working with .net core 2.2 and using dependency injection. I have some custom infrastructure dependencies that manage logging, tracing, etc. that I inject into classes. I'd like the dependencies to know what class they are in. I can do that if I instantiate the class like new Logger<Type>(); but is that possible to manage with dependency injection?
Ex:
public class Logger<Type> : ILogger
{
}
public class Foo
{
private Ilogger _logger;
public Foo(ILogger logger)
{
_logger = logger;
}
public void DoStuff()
{
_logger.Log(); //<= knows it's in the Foo class.
}
}
How do I inject ILogger into Foo, and have the Logger know what Type it was injected into?
You can specify the type like this
public class Foo
{
private Ilogger<Foo> _logger;
}
Then in the Logger, you can know the type of T by
public class Logger<T> : ILogger<T>
{
public Type WhatType() => typeof(T);
}
You will need to register the service like this
serviceCollection.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
While more mature and feature rich DI Containers, such as Autofac and Simple Injector, do support context-based injection (which is the feature you are looking for), MS.DI does not support this feature.
It is for this very reason that all the Microsoft documentation describe the injection of a generic ILogger<T> where T equals the consuming type, as in:
public class C
{
public C(ILogger<C> logger) { ... }
}
Letting a consumer depend on the generic ILogger<T>, instead of simply depending on a non-generic ILogger, however, is more verbose and error prone. It makes you code harder to test and harder to maintain. This is likely the reason you are trying to inject a context-aware ILogger instead, and I applaud you for that.
You can kinda 'hack' this feature into MS.DI by iterating through the ServiceCollection, but there are practically too many limitations to it to be workable in your production application. For fun and entertainment, however, this is what you can try:
// Run just before finalizing the IServiceCollection
for (int i = 0; i < services.Count; i++)
{
ServiceDescriptor descriptor = services[i];
if (descriptor.ImplementationType != null)
{
var loggerParameters =
from ctor in descriptor.ImplementationType.GetConstructors()
from param in ctor.GetParameters()
where param.ParameterType == typeof(ILogger)
select param;
if (loggerParameters.Any())
{
// Replace registration
services[i] =
new ServiceDescriptor(
descriptor.ServiceType,
provider =>
ActivatorUtilities.CreateInstance(
provider,
descriptor.ImplementationType,
provider.GetRequiredService(
typeof(ILogger<>).MakeGenericType(
descriptor.ImplementationType))),
descriptor.Lifetime);
}
}
}
What this code does is:
search for registrations of
(closed or non-generic) implementation type
that uses Auto-Wiring (so no lambda registration, or instance registration)
and whose constructor depends on ILogger
and replaces that registration with a lambda registration that Auto-Wires the type (using ActivatorUtilities) while replacing the ILogger dependency with an ILogger<T> dependency.
Limitations:
Doesn't work on open-generic registrations
Doesn't work on delegate registrations
Might not work when replacing MS.DI with another DI Containers (e.g. might "blind" the container).
Behavior is undefined when working with multiple constructors
In practice, I would therefore not suggest using this approach but instead use a mature DI Container.
TIP: To get some inspiration, when using Simple Injector, such context-based registration can be made as follows:
container.RegisterConditional(
typeof(ILogger),
c => typeof(Logger<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
When integrating with ASP.NET Core, Simple Injector even contains an extension method that simplifies this. Here's the Simple Injector documentation on how to configure the container to inject ASP.NET Core's ILogger, and the basic description on how to apply context-based injection in Simple Injector can be found here.

Simple Injector and a Logging Abstraction Using Log4net

In order to try and get a nice logging abstraction with Log4net, I took the abstraction from this SO post and the adapter from this SO post and tried to get them working together.
All that was really left to do was configure the container and that is the part which I have not succeeded in doing.
The config which I have tried is
public static class InfrastructureRegistry
{
public static void RegisterLoggingServices(this Container container)
{
container.RegisterConditional(typeof(ILog), c => LogManager.GetLogger(
c.Consumer.ImplementationType).GetType(),
Lifestyle.Scoped, c => true);
container.RegisterPerWebRequest<ILogger, Log4netAdapter>();
}
}
As you can see from the code, I would like a specific log4net logger which takes its Type from the class into which it is injected. Whilst most logging would be done in a catch-all, I want some logging to happen in lower layers e.g. when a form validation fails.
The ActivationException which I get with that configuration is :
The constructor of type LogImpl contains the parameter with name
'logger' and type ILogger that is not registered. Please ensure
ILogger is registered, or change the constructor of LogImpl.
Not quite sure where to go from here, so any help would be appreciated.
Edit
Sorry, I should point out that I am trying to write it such that I only have to write this config once. The following factory function works, but I don't want to have to manually add more config every time I want to inject a logger:
container.RegisterPerWebRequest<ILog>(() => LogManager.GetLogger(typeof(LoginController)));
The example adapter you point at assumes a single logger for every component in the application, while what you wish is to have a specific logger that 'knows' about its consumer, so it can relate the log messages to the originating class.
Although this seems to be a very common practice when working with tools like log4net and NLog, in my experience, this requirement often comes from the fact that logging is done at too many places in the code. Please read this stackoverflow q/a for more information.
That said, if you want to register the logger conditionally, you will have to change the adapter to a generic class; that way you can make the registration conditional:
public class Log4netAdapter<T> : ILogger
{
private static readonly log4net.ILog logger = LogManager.GetLogger(typeof(T));
public void Log(LogEntry entry)
{
if(entry.LoggingEventType == LoggingEventType.Information)
logger.Info(entry.Message, entry.Exception);
else if(entry.LoggingEventType == LoggingEventType.Warning)
logger.Warn(entry.Message, entry.Exception);
else if(entry.LoggingEventType == LoggingEventType.Error)
logger.Error(entry.Message, entry.Exception);
else
logger.Fatal(entry.Message, entry.Exception);
}
}
With this generic class, you can do the following conditional/contextual registration:
container.RegisterConditional(
typeof(ILogger),
c => typeof(Log4netAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);

Use of ResolveUnregisteredType causes Torn Lifestyle warning in Simple Injector v3.0.3

I use a self-made "external" library to get some basic infrastructure in place when creating new web-applications. I recently made some changes to how my repositories work and came across this warning from Simple Injector Diagnostic Warnings:
SimpleInjector.DiagnosticVerificationException : The configuration is
invalid. The following diagnostic warnings were reported:
-[Torn Lifestyle] The registration for IUnitOfWork maps to the same implementation and lifestyle as the registrations for IUnitOfWork,
IUnitOfWork, IUnitOfWork and IUnitOfWork do. They all map to
EmptyUnitOfWork (Singleton). This will cause each registration to
resolve to a different instance: each registration will have its own
instance. See the Error property for detailed information about the
warnings. Please see https://simpleinjector.org/diagnostics how to fix
problems and how to suppress individual warnings.
The core assembly of my library has an empty implementation of IUnitOfWork called EmptyUnitOfWork which is just a simple no-op class:
internal sealed class EmptyUnitOfWork : IUnitOfWork
{
public void SaveChanges()
{
// Do nothing
}
}
This class is then registered in the container when there is no other unit of work avaliable. I do this by using the container.ResolveUnregisteredType(...) like so:
// Register an EmptyUnitOfWork to be returned when a IUnitOfWork is requested:
container.ResolveUnregisteredType += (sender, e) =>
{
if (e.UnregisteredServiceType == typeof(IUnitOfWork))
{
// Register the instance as singleton.
var registration = Lifestyle.Singleton.CreateRegistration<IUnitOfWork, EmptyUnitOfWork>(container);
e.Register(registration);
}
};
First time I've used above method - but works fine with this test:
[Fact]
public void RegistersEmptyUnitOfWork_AsSingleton_WhenIUnitOfWorkIsNotRegisted()
{
var instance = _container.GetInstance<IUnitOfWork>();
var registration = _container.GetRegistration(typeof (IUnitOfWork));
Assert.NotNull(instance);
Assert.IsType<EmptyUnitOfWork>(instance);
Assert.Equal(Lifestyle.Singleton, registration.Lifestyle);
}
Now for the fun part, I have an extension method in a supporting library which registers an EntityFramework IUnitOfWork if my application needs one:
public static void RegisterEntityFramework<TContext>(this Container container) where TContext : DbContext
{
if (container == null)
throw new ArgumentNullException(nameof(container));
var lifestyle = Lifestyle.CreateHybrid(() =>
HttpContext.Current != null,
new WebRequestLifestyle(),
new LifetimeScopeLifestyle()
);
container.Register<DbContext, TContext>(lifestyle);
container.Register<IUnitOfWork, EntityFrameworkUnitOfWork>(lifestyle);
container.Register(typeof (IRepository<>), typeof (EntityFrameworkRepository<>), lifestyle);
}
But somehow this throws the warning from Simple Injector - but I just injected the EntityFrameworkUnitOfWork so the EmptyUnitOfWork should not be triggered?
The reason for this design is that I have a CommandTransactionDecorator in my core library which uses the IUnitOfWork to save changes. I just want to have an empty one if a IUnitOfWork is not required by the application.
For reference this is the decorator:
internal sealed class CommandTransactionDecorator<TCommand> : IHandleCommand<TCommand> where TCommand : ICommand
{
private readonly IUnitOfWork _unitOfWork;
private readonly Func<IHandleCommand<TCommand>> _handlerFactory;
public CommandTransactionDecorator(IUnitOfWork unitOfWork, Func<IHandleCommand<TCommand>> handlerFactory)
{
_unitOfWork = unitOfWork;
_handlerFactory = handlerFactory;
}
public void Handle(TCommand command)
{
_handlerFactory().Handle(command);
_unitOfWork.SaveChanges();
}
}
UPDATE
It seems like this is the registration that makes the warning:
var registration = Lifestyle.Singleton.CreateRegistration<IUnitOfWork, EmptyUnitOfWork>(container);
e.Register(registration);
Changing it to e.Register(() => new EmptyUnitOfWork()); makes the warning go away, but then the lifestyle is not singleton?
What you are seeing is that ResolveUnregisteredType is called multiple times. This causes multiple singleton registrations for the same type to be made. Each registration gets its own instance. This will result in an application that consists of multiple instances of that type, which is usually not what you want to happen when you register a type as singleton. Since your EmptyUnitOfWork doesn't have any behavior, there is probably no problem, but Simple Injector can obviously not guess that this is the case, so it throws an exception.
What you are experiencing however is a breaking change / bug that was introduced in Simple Injector v3. In Simple Injector v1 and v2 the resulting registration of a ResolveUnregisteredType was cached; which meant that a call to Verify() would trigger your custom delegate just once. In Simple Injector v3.0 however, the resulting registration isn't cached anymore. This was an oversight, that has slipped through. The idea was to make ResolveUnregisteredType context aware. To be context aware, caching was not an option anymore. So caching was removed, but we eventually decided not to make ResolveUnregisteredType context aware, while we forgot to add the caching again.
The funny thing of this accidental behavior however is, that it expose a bug in your code. This bug already existed even when you used v2, but v3 now (accidentally) slaps you in the face with it. With v2, the correctness of your registration depended on the use of the Verify() method. Verify() builds all object graphs on a single thread. Without the use of Verify() however, the object graphs are compiled lazily and in case you are running a multi-threaded application, multiple threads can simultaneously call ResolveUnregisteredType; Simple Injector never locked ResolveUnregisteredType and this is documented.
So the result of this is that without a call to Verify() you could still end up in multiple registrations of that specific component, which of course again could lead to really ugly hard to find problems, that usually only appear once in a way in production.
This is how you should actually write that registration:
Lazy<Registration> registration = new Lazy<Registration>(() =>
Lifestyle.Singleton.CreateRegistration<IUnitOfWork, EmptyUnitOfWork>(container));
container.ResolveUnregisteredType += (sender, e) => {
if (e.UnregisteredServiceType == typeof(IUnitOfWork)) {
e.Register(registration.Value);
}
};
With Simple Injector v3 however, you hardly ever have to use the ResolveUnregisteredType event anymore. You can do make the following registration instead:
container.RegisterConditional<IUnitOfWork, EntityFrameworkUnitOfWork>(Lifestyle.Scoped,
c => true);
// NOTE: This registration must be made second
container.RegisterConditional<IUnitOfWork, EmptyUnitOfWork>(Lifestyle.Singleton,
c => !c.Handled);
This solves the problem of having to think about multi-threading completely. Here we make two conditional registrations, where the first is always applied (using the predicate c => true). You might be tempted to make the first registration unconditional using Register<IUnitOfWork, EFUoW>(), but that won't work, because Simple Injector will detect that the second registration can never be applied and an exception will be thrown. So the use of the c => true predicate suppresses this detection. I wouldn't usually advice such construct, because it blinds Simple Injector. In your case however it seems reasonable, because both registrations are made at different moment.
I now will have to think about whether or not I want to change this behavior in v3 and do caching. Advantage of caching is that it can improve performance, but the downside is that it hides bugs.

MVC5 Ninject binding and HttpContext

I am trying to set up a new project and I've added a new class MembershipService that requires the HttpContext to be passed in it's constructor.
In a previous project I used the code
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IMembershipService>()
.To<MembershipService>()
.InRequestScope()
.WithConstructorArgument("context", HttpContext.Current);
....
}
However in the new project I'm using Ninject Modules, and after some searching on StackOverflow and Google, I've come up with the code below:
public class ServiceHandlerModule : NinjectModule
{
public override void Load()
{
Bind<IMembershipService>()
.To<MembershipService>()
.WithConstructorArgument("context", ninjectContext=> HttpContext.Current);
this.Kernel.Bind(x =>
{
x.FromAssemblyContaining(typeof(NinjectWebCommon))
.SelectAllClasses()
.Where(t => t != typeof(MembershipService))
.BindDefaultInterface();
});
this.Kernel.Bind(x =>
{
x.FromAssemblyContaining<BrandServiceHandler>()
.SelectAllClasses()
.Where(t => t != typeof(MembershipService))
.BindDefaultInterface();
});
}
}
However, I get the error below:
Description: An unhandled exception occurred during the execution of
the current web request. Please review the stack trace for more
information about the error and where it originated in the code.
Exception Details: Ninject.ActivationException: Error activating
string No matching bindings are available, and the type is not
self-bindable. Activation path:
5) Injection of dependency string into parameter filename of
constructor of type HttpRequest
4) Injection of dependency HttpRequest into parameter request of
constructor of type HttpContext
3) Injection of dependency HttpContext into parameter httpContext of
constructor of type MembershipService
2) Injection of dependency IMembershipService into parameter
membershipService of constructor of type HomeController
1) Request for HomeController
Can someone point out where I'm going wrong?
Thanks,
John
Steven was right about the HttpContext being a runtime value. Its values are not even populated at the time the application is composed.
This makes sense if you think about it because the application should be initialized outside of any individual user context.
However, Steven's solution only moved the problem to a different service. After all, the class that implements IUserContext will still need to take HttpContext as a dependency.
The solution is to use an Abstract Factory to allow the HttpContext instance to be accessed at runtime instead of when the factory is wired up.
Important: HttpContext is not an abstraction, so it cannot be swapped or mocked. To ensure we are dealing with an abstraction, Microsoft has provided the HttpContextBase abstract class and the default concrete type HttpContextWrapper. HttpContextBase has exactly the same interface as HttpContext. You should always use HttpContextBase as the abstract reference type within your services, not HttpContext.
With those 2 things in mind, you can create a factory for your HttpContext, as follows:
public interface IHttpContextFactory
{
HttpContextBase Create();
}
public class HttpContextFactory
: IHttpContextFactory
{
public HttpContextBase Create()
{
return new HttpContextWrapper(HttpContext.Current);
}
}
Your MembershipService can then be modified to accept an IHttpContextFactory in its constructor:
public class MembershipService : IMembershipService
{
private readonly IHttpContextFactory httpContextFactory;
// This is called at application startup, but note that it
// does nothing except get our service(s) ready for runtime.
// It does not actually use the service.
public MembershipService(IHttpContextFactory httpContextFactory)
{
if (httpContextFactory == null)
throw new ArgumentNullException("httpContextFactory");
this.httpContextFactory = httpContextFactory;
}
// Make sure this is not called from any service constructor
// that is called at application startup.
public void DoSomething()
{
HttpContextBase httpContext = this.httpContextFactory.Create();
// Do something with HttpContext (at runtime)
}
}
And you need only inject the HttpContextFactory at composition time.
kernel.Bind<IHttpContextFactory>()
.To<HttpContextFactory>();
kernel.Bind<IMembershipService>()
.To<MembershipService>();
This alone might not solve the entire issue, though. You need to ensure that the rest of your application does not try to use HttpContext before it is ready. In terms of DI, it means you can't use HttpContext in any constructor of types that are composed in application start or any service members that one of those constructors calls. To solve that, you may need to create additional abstract factories to ensure those services don't call members of IMembershipService until HttpContext is ready.
See this answer for more information about how to accomplish that.
Steven's solution also entailed creating a Facade around HttpContext. While this does not really help solve the problem at hand, I agree that this might be a good idea if your MembershipService (and perhaps other services) only uses a small number of members of HttpContext. Generally, this pattern is to make a complex object simpler to work with (such as flattening it down to a few members that may be nested deep within its hierarchy). But you really need to weigh the extra maintenance of adding another type against the complexity of using HttpContext within your application (or the value of swapping out a section of it) to make that decision.
I've added a new class MembershipService that requires the HttpContext
to be passed in it's constructor.
This is where you're going wrong. The HttpContext is a runtime value, but your object graph should only consist of compile-time or configuration-time dependencies. Anything else, the runtime values, should either be passed through method calls, or should be exposed as properties from the services that are injected.
Not following this guideline, will make it much harder to compose and test your object graphs. Testing your composition root is a good example, since HttpContext.Current is not available when run inside a testing framework.
So prevent this MembershipService from taking a constructor dependency on HttpContext. Instead, inject a service that exposes the HttpContext as a property, because this allows you to request this context after the object graph is constructor.
But perhaps even better is to hide the HttpContext behind an abstraction that is application specific. HttpContext is not an abstraction; it is a big and ugly API that makes your code much harder to test and much harder to comprehend. Instead, create very narrow/focused interfaces, for instance an interface like this:
public interface IUserContext
{
User CurrentUser { get; }
}
Now your MembershipService can depend on a IUserContext that exposes a User object through a property. Now you can create an AspNetUserContext implementation that uses the HttpContext.Current internally, when the CurrentUser property is called. This results in much cleaner, more maintainable code.
Here's a possible implementation:
public class AspNetUserContext : IUserContext
{
public User CurrentUser
{
// Do not inject HttpContext in the ctor, but use it
// here in this property
get { return new User(HttpContext.Current.User); }
}
}
I agree with Steven, however, you could also:
kernel.Bind<HttpContext>().ToMethod(c => HttpContext.Current);

Categories

Resources