Inject values into custom VAB validator - dependency-injection

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.

Related

Configure Unity container per-request in OWIN middleware

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);
}
...

Property injection upon initializing object manually

When using Ninject property injection the following works only if the object is instantiated by the framework (not by developer in code) so that the injection works:
public class SomeController: Controller {
[Inject]
public DbContext db {get; set;}
...
}
However when the object has to be instantiated in the code by the developer the binding does not happen (I don't wanna say fail because it does not happen).
public class DataProvision {
[Inject]
public DbContext db {get; set;}
public List<T> GetList<T>() where T: class, new() {
return db.Set<T>().toList();
}
...
}
public class Test {
public static void Test(){
DataProvision dp = new DataProvision();
var getValue = dp.GetList<Person>();
}
}
Is it even supported by Ninject and if yes what is the solution.
Justification of why we are doing this: Switching between back-up databases and active DBs effortlessly in case emergency
This is expected behavior. The DI framework has no opportunity to inject anything if you new up your own instances. If your code has access to the DI bindings, set up a kernel and use it to instantiate your class:
public class Test {
public static void Test(){
var kernel = new StandardKernel(new YourDiModule());
DataProvision dp = kernel.Get<DataProvision>();
var getValue = dp.GetList<Person>();
}
}
Using the above strategy, you'll probably need to tweak your DI configuration a little so that your context gets disposed when you want it to. (Your web application is probably normally set up to dispose the context after each web request completes, and it doesn't look like your test code is set up to run in the same kind of environment.)
Otherwise, you'll need to manage the dependency injection by hand:
public class Test {
public static void Test(){
using (var context = new DbContext()) // or however you create contexts
{
DataProvision dp = new DataProvision();
dp.db = context;
var getValue = dp.GetList<Person>();
}
}
}

How to use RavenDB queries in Data Layer or Classes?

I have setup RavenDB embedded in my MVC application. I follower all the tutorials to make the RavenController and I can query the Session in the controller.
Now I would really like to break away from mixing data in the controller and create a Data layer so that I can do some Business logic which will help me create complex View Models.
How do I query the Session in a plain class file? I can't seem to find any info on how to do this.
Dependency Injection is great for this. You move aside the creation of the necessary services and let the container manage the lifecycle of the components, including scoping IDocumentSession to one instance per HTTP request.
As an example, using Autofac (you'd need both the Autofac and Autofac.Mvc5 packages) you could have a class in your App_Start folder like this, and then call AutofacConfig.Configure() from your Global.asax:
public static class AutofacConfig
{
public static IContainer Container { get; private set; }
public static void Configure()
{
var builder = new ContainerBuilder();
var thisAssembly = Assembly.GetExecutingAssembly();
// Register our controllers with the container
builder.RegisterControllers(thisAssembly).PropertiesAutowired(PropertyWiringOptions.PreserveSetValues);
// Provide injections of the HTTP abstractions (HttpContextBase, etc.)
builder.RegisterModule(new AutofacWebTypesModule());
// Create and register the Raven IDocumentStore
builder.Register(c =>
{
var store = new DocumentStore {ConnectionStringName = "RavenDB"};
store.Initialize();
Raven.Client.Indexes.IndexCreation.CreateIndexes(typeof (MvcApplication).Assembly, store);
return store;
})
.As<IDocumentStore>()
.SingleInstance();
// Provide injection of Raven IDocumentSession
builder.Register(c => c.Resolve<IDocumentStore>().OpenSession())
.InstancePerRequest();
Container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(Container));
}
}
Then, when you need an IDocumentSession some place outside of a controller:
// Business logic, or other class that injection is not provided for.
var session = AutofacConfig.Container.Resolve<IDocumentSession>();
Also include autofac otherwise you will get an error saying "does not contain definition Resolve ..."
using Autofac;
You can do similar things with most other DI container libraries; the API is just slightly different.
HttpContext.Current.Session holds current session, but you should definitely not use it in business logic layer. Business logic layer should not be aware of HttpContext.
Basic solution to this problem would be to create interface:
public interface ISession
{
int SomeValue { get; set; }
}
and implementation
public class HttpContextBasedSession : ISession
{
public int SomeValue
{
get
{
return Convert.ToInt32(HttpContext.Current.Session["SomeValue"]);
}
set
{
HttpContext.Current.Session["SomeValue"] = value;
}
}
}
Bind it with dependency injection framework.

MVC/Ninject Dependency Injection in business layer

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>();
}

Ninject - dynamically specifying a connection string based on a sub domain

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.

Resources