I'm trying to specify a connection string dynamically based of the url using ninject.
I'm using the ninject.mvc nuget package that uses the webActivator.
My code is as follows:
my injection:
kernel.Bind<IUnitOfWork>().To<UnitOfWork>()
.WithConstructorArgument("connectionString", MvcApplication.GetConnectionStringName());
my global.asax
private static HttpContext _context;
public static string GetConnectionStringName() {
var subDomain = String.Empty;
if (_context != null) {
subDomain = _context.Request.Url.SubDomain();
}
return String.Format("{0}ConnectionString", subDomain);
}
The problem is the _context (which is set in my Application_BeginRequest) is always null because the WebActivator runs before the application_start.
Is it possible in ninject to specify to call MvcApplication.GetConnectionStringName() when a IUnitOfWork is required rather than on application start?
Is there a better approach to what I'm doing?
Thanks
You should use the Ninject binding like this.
kernel.Bind<IUnitOfWork>().To<UnitOfWork>()
.WithConstructorArgument("connectionString", context => MvcApplication.GetConnectionStringName());
Note that context here is of type Ninject's IContext and so has nothing to do with HttpContext.
Anyway I think you approach is suitable for this.
Sometimes (especially when there are multiple related parameters to be injected) I prefer creating an interface and specific implementations for the configurations and let them injected by standard bindings like this.
public interface IUnitOfWorkConfiguration {
string ConnectionString { get; }
}
public class AppConfigUnitOfWorkConfiguration : IUnitOfWorkConfiguration {
public string ConnectionString { get { ... } }
}
public class UnitOfWork {
public UnitOfWork(IUnitOfWorkConfiguration configuration) {
}
}
Bind<IUnitOfWorkConfiguration>().To<AppConfigUnitOfWorkConfiguration>();
Using this approach you can avoid specifying parameter names as string literals.
One more note about using HttpContext. I do not recommend using it that way because of thread safety issues. You should either mark your private static field _context with the [ThreadStatic] atribute or as a better choice simply use HttpContext.Current everywhere.
Related
I'm wanting to configure registrations in a Unity container being used by ASP.NET Web API 2 based on properties of a HTTP request. For example, a request to /api/database1/values should result in a Unity container configuration with an IDbContext configured for database1, while a request to /api/database4/values will get an IDbContext configured for database4.
I've gotten so far as using UnityHierarchicalDependencyResolver as the dependency resolver, so types registered with HierarchicalLifetimeManager last only for the lifetime of the request. This works well for getting types resolved per request. But how to get them registered per request using OWIN middleware is beyond me.
In my middleware, a call to System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IUnityContainer)) gets an instance of IUnityContainer, but it's the same container for all requests, including any registrations from previous requests.
By encapsulating UnityHierarchicalDependencyResolver with my own implementation of IDependencyResolver I can see that IDependencyResolver.BeginScope isn't called until much later in the process. So the problem would seem to be that the child container isn't created until Web API wakes up, long after my middleware calls Next(..).
Is there a way I can get the scope of my dependency resolver to start sooner? Is there some other strategy that I'm missing. In case it makes any difference, I'm hosting in IIS, but favouring the OWIN middleware approach.
Update
This isn't an answer, and it's too big for a comment, but after struggling to solve this with Unity I decided to switch to Autofac and it all just fell into place.
The Autofac OWIN packages (Autofac.Mvc5.Owin, Autofac.Owin, Autofac.WebApi2.Owin) make it dead easy to use Autofac within the OWIN pipeline and ensure appropriate lifetime management in ASP.NET MVC and Web API. This was the missing link.
I couldn't find a way to reconfigure the container per-request, but it did at least make it possible to configure a factory per-request (so yes, #Haukinger and #alltej, you were right to push in that direction.
So I register a factory like:
builder.RegisterType<DataDependencyFactory>().InstancePerRequest();
And register the create method of that factory like:
builder
.Register(c => c.Resolve<DataDependencyFactory>().CreateDataDependency())
.As<IDataDependency>()
.InstancePerRequest();
Registering the factory this way is particularly useful, because downstream dependents don't need to be aware of the factory. I like this because my dependents don't need a factory, they need an instance. The container bends to the needs of my dependents, not the other way around :)
Then, in a piece of OWIN middleware, I resolve the factory, and set a property on it according to the properties of the request. Subsequent resolution of IDataDependency in an MVC or Web API controller, or anything else later in the OWIN pipeline, will get an instance configured according to the property on the factory.
Based on your api URL ("/api/database4/values"), I suggest that you create a filter attribute(e.g. DbIdFilter) so that you can reuse the filter attribute to other controller methods that follow similar url path/segment like this below:
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/values")]
public IHttpActionResult GetValues()
{
return Ok();
}
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/products")]
public IHttpActionResult GetProducts()
{
return Ok();
}
First, create the filter attribute:
public class DbIdFilterAttribute : ActionFilterAttribute
{
private readonly string _routeDataId;
private const string defaultRouteName = "databaseId";
public DbIdFilterAttribute():this(defaultRouteName)
{}
public DbIdFilterAttribute(string routeDataId)
{
_routeDataId = routeDataId;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
var routeData = actionContext.Request.GetRouteData();
var dbId = routeData.Values[_routeDataId] as string;
//here we create the db instance at the filter level.
DbInstanceFactory.RegisterDbInstance(dbId);
}
}
Next, create an instance factory that will register/resolve the db instance during runtime:
public class DbInstanceFactory : IDbInstanceFactory
{
public static IDbInstance RegisterDbInstance(string databaseId)
{
var factory = UnityConfig.GetConfiguredContainer().Resolve<IDbInstanceFactory>();
return factory.CreateInstance(databaseId);
}
public IDbInstance CreateInstance(string databaseId)
{
var container = UnityConfig.GetConfiguredContainer();
//container.RegisterType<IDbInstance, DbInstance>();
container.RegisterType<IDbInstance, DbInstance>(new InjectionConstructor(databaseId));
var dbInstance = container.Resolve<IDbInstance>();
return dbInstance;
}
public IDbInstance GetInstance()
{
var container = UnityConfig.GetConfiguredContainer();
var dbInstance = container.Resolve<IDbInstance>();
return dbInstance;
}
}
public interface IDbInstanceFactory
{
IDbInstance CreateInstance(string databaseId);
IDbInstance GetInstance();
}
Register this factory class in UnityConfig.cs (or wherever you currently register the types):
container.RegisterType<IDbInstanceFactory, DbInstanceFactory>
(new ContainerControlledLifetimeManager());
It's registered ContainerControlledLifetimeManager since this factory does not have to be a per request.
So just a basic DbInstance class below(for clarity) that takes a parameter in the constructor (this parameter can be your connection string or a named connection):
public class DbInstance : IDbInstance
{
public string DbId { get; }
public DbInstance(string databaseId)
{
DbId = databaseId;
}
}
public interface IDbInstance
{
string DbId { get; }
}
In controller class, you can use it like this:
....
private IDbInstanceFactory _dbFactory;
public MyController(IDbInstanceFactory dbFactory)
{
_dbFactory = dbFactory;
}
// Alternate, if you want to use property injection instead of constructor injection
//[Dependency]
//public IDbInstanceFactory DbFactory { get; set; }
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/test")]
public IHttpActionResult Test()
{
var db = _dbFactory.GetInstance();
return Ok(db.DbId);
}
...
I've got an app in asp.net core using the built-in DI framework. I'd like to add a per-request (i.e. transient) service to the provider, but I'd like to actually make use of the request in its construction.
services.AddTransient<IMyService>(provider => { ... });
That's the closest overload I can find, but the provider object doesn't have anything about the current request. Is there a way to achieve what I'm trying to do, without upgrading to a more robust DI framework?
As posted in the comments, you can inject the IHttpContextAccessor into your services and access it, if the HttpContext is the only thing you need.
public class MyService : IMyService
{
private readonly HttpContext context;
public MyService(IHttpContextAccessor httpContextAccessor)
{
if(IHttpContextAccessor==null)
throw new ArgumentNullException(nameof(httpContextAccessor));
context = httpContextAccessor.HttpContext;
}
}
However, if you need something that's only available in the controller or outside of HttpContext, you can create a factory and pass the parameters to the factory
public class MyServiceFactory : IMyServiceFactory
{
// injecting the HttpContext for request wide service resolution
public MyServiceFactory(IHttpContextAccessor httpContextAccessor) { ... }
public IMyService Create(IDependency1 dep1, IDependency2 dep 2, string someRuntimeConfig)
{
IServiceProvider provider = this.context.RequestServices;
var myService = new MyService(provider.GetService<ISomeRepository>(), dep1, dep2, someRuntimeConfig);
return myService;
}
}
and then inject the IMyServiceFactory to your classes where you'd need IMyService.
I'm fairly new to Dependency Injection, and I'm looking for some advice on best practices. Sorry if this has been asked before, but I haven't been able to find a good solution yet.
Assume I have a MVC4 web app and a separate business layer. The MVC app is already set up using the Ninject NuGet package, so I have NinjectWebCommon, and it works fine.
My question is: How can I use Ninject when I need dependencies set up in other layers?
Assume I have this repository:
public class WidgetRepository : IWidgetRepository
{
// using an entity framework db context.
WidgetDbContext context = new WidgetDbContext();
public IQueryable<Widget> Widgets
{
get
{
return context.Widgets;
}
}
}
Each widget returned by the repository needs to perform calculations using a calculator object that I need to inject:
public class Widget
{
// how can I get Ninject to inject a calculator object
// when Widgets are loaded form the database?
public ICalculator calculator;
public int MyValue { get; set; }
public int CalculateSomething
{
get
{
return calculator.Calculate(MyValue);
}
}
}
What is the best practice to inject an ICalculator into each Widget instance, when Ninject is set up in the MVC web app, but the Widget objects are created in the business layer??
Prevent doing constructor injection or property injection in entities. You should either:
Let the service layer call the calculation on the Widget, like this:
var widget = this.repository.GetById(wigditId);
var value = this.calculator.Calculate(widget.MyValue);
Or use constructor injection into your entities:
var widget = this.repository.GetById(wigditId);
var value = widget.CalculateSomething(this.calculator);
A lot has been written about this. Take a look at these articles for instance:
How not to inject services in entities
Why not use an IoC container to resolve dependencies for entities/business objects?
If Widget and ICalculator are in the same project, just use constructor injection:
public class Widget
{
public Widget(ICalculator calculator)
{
_calculator = calculator;
}
private ICalculator _calculator;
public int MyValue { get; set; }
public int CalculateSomething
{
get
{
return _calculator.Calculate(MyValue);
}
}
}
In NinjectWebCommon, you'll need to register your ICalculator implementation, something like this:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ICalculator>()
.To<Calculator>();
}
I'm building a mvc webapp that shares model objects with an existing winforms app. I'm introducing VAB validation into it. One of the items I need to validate is an int that can be one of x levels.
I've written a LevelValidator, but it needs to have the levels accessible.
Regarding the new call in this code, it looks like I should inject the LevelValidator instead of Levels?
Other ways?
public class LevelValidatorAttribute : ValueValidatorAttribute
{
protected override Microsoft.Practices.EnterpriseLibrary.Validation.Validator DoCreateValidator(Type targetType)
{
LevelValidator validator = new LevelValidator();
validator.Levels = this.Levels;
return validator;
}
[Dependency]
public Levels Levels { get; set; }
}
You can't use dependency injection on attributes, because attributes are not controlled and created by a dependency injection framework, but controlled by the CLR itself. Try having a design were your attribute does not need dependency injection.
If all fails, you can use the Service Locator pattern inside the LevelValidator (best to leave the attribute allone) and make a call to the unity container from within the LevelValidator class. For this to work, you need to have a static field that holds the container. For instance:
public class LevelValidator : Validator
{
public static UnityContainer Container { get; set; }
public LevelValidator()
{
this.Levels = Container.Resolve<Levels>();
}
public Levels Levels { get; set; }
}
In the startup path of your application you need to set this static Container property, as follows:
public void Main()
{
var container = new UnityContainer();
// configure it
LevelValidator.Container = container;
}
This solution is far from ideal and should be prevented in most cases. However, the creation of the attribute and the LevelValidator is outside the control of Unity.
Some dependency injection containers enable you to inject configured services into an already constructed object.
Can this be achieved using Windsor, whilst taking account of any service dependencies there may be on the target object?
This is an old question but Google led me here recently so thought I would share my solution lest it help someone looking for something like StructureMap's BuildUp method for Windsor.
I found that I could add this functionality myself relatively easily. Here is an example which just injects dependencies into an object where it finds a null Interface-typed property. You could extend the concept further of course to look for a particular attribute etc:
public static void InjectDependencies(this object obj, IWindsorContainer container)
{
var type = obj.GetType();
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
if (property.PropertyType.IsInterface)
{
var propertyValue = property.GetValue(obj, null);
if (propertyValue == null)
{
var resolvedDependency = container.Resolve(property.PropertyType);
property.SetValue(obj, resolvedDependency, null);
}
}
}
}
Here is a simple unit test for this method:
[TestFixture]
public class WindsorContainerExtensionsTests
{
[Test]
public void InjectDependencies_ShouldPopulateInterfacePropertyOnObject_GivenTheInterfaceIsRegisteredWithTheContainer()
{
var container = new WindsorContainer();
container.Register(Component.For<IService>().ImplementedBy<ServiceImpl>());
var objectWithDependencies = new SimpleClass();
objectWithDependencies.InjectDependencies(container);
Assert.That(objectWithDependencies.Dependency, Is.InstanceOf<ServiceImpl>());
}
public class SimpleClass
{
public IService Dependency { get; protected set; }
}
public interface IService
{
}
public class ServiceImpl : IService
{
}
}
No, it can't.
As Krzysztof said, there is no official solution for this. You might want to try this workaround though.
Personally, I consider having to do this a code smell. If it's your code, why isn't it registered in the container? If it isn't your code, write a factory/adapter/etc for it.