Accessing Variables Created In Application_Start ASP.NET MVC 3 - c#

I have the following code running in my Application_Start method:
var builder = new ContainerBuilder();
var store = new DocumentStore { Url = "http://localhost:8081" };
store.Initialize();
builder.RegisterInstance(store);
var container = builder.Build();
I am using AutoFac to store the instance of my RavenDB DocumentStore. Now I know this only runs once when the application is started however how would I be able to access the container variable so that I can retrieve the DocumentStore that in stored in there from anywhere in my application.

The idea of DI is that you configure your container in the Application_Start and you wire all the necessary dependencies into your objects so that you never need to access the container in other parts of your code. So to answer your question: simply have the parts of your application that need to access the DocumentStore take it as constructor argument and then configure AutoFac to inject it.
Having other parts of your code depending on the container is a bad practice as they become tightly coupled to it.

Ok! As Darin pointed out, it's not a good practice but if you want to,
you could do
var container = builder.Build();
Application["container"] = container;
and access it by
var container = Application["container"] as Container; // assuming Container is the type

Related

Ninject bind two different parameters of same type in Global.asax

I have a web app with two different controllers and I use configuration files as input to the controllers. Earlier I was just using one single configuration file and could just bind that to the kernel and everything would work just fine. Now however I will be using two separate config files and need ninject to understand which one to use. Here is an example of how I thought I would do. Commented away is also what i did to bind the configuration before when I only had one.
var kernel = NinjectWebApi.Kernel;
//get base dependency instances from the container
var configurationClient = kernel.Get<IConfigurationClient>();
//initialise local dependencies
var config1 = configurationClient.Get(new GetConfigurationByKeyRequest("Config1"));
var config2 = configurationClient.Get(new GetConfigurationByKeyRequest("Config2"));
//bind local dependencies
//This is what I did when I had just one config
//kernel.Bind<IConfiguration>().ToMethod(c => config1.Configuration);
kernel.Bind<IMy1Controller>().To<My1Controller>()
.WithConstructorArgument("config1", config1.Configuration)
.WithConstructorArgument("config2", config2.Configuration);
kernel.Bind<IMy2Controller>().To<My2Controller>()
.WithConstructorArgument("config2", config2.Configuration);
//Set the dependency resolver to use ninject
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
What is the purpose of "WithConstructorArgument" if I can't use it to specify an input?
OK, so I found a solution. But I am not sure this is the proper way.
var kernel = NinjectWebApi.Kernel;
//get base dependency instances from the container
var configurationClient = kernel.Get<IConfigurationClient>();
//initialise local dependencies
var config1 = configurationClient.Get(new GetConfigurationByKeyRequest("Config1"));
var config2 = configurationClient.Get(new GetConfigurationByKeyRequest("Config2"));
//bind local dependencies
kernel.Bind<IConfiguration>().ToMethod(c => config1.Configuration).Named("config1");
kernel.Bind<IConfiguration>().ToMethod(c => config1.Configuration).Named("config1");
kernel.Bind<IMy1Controller>().To<My1Controller>()
kernel.Bind<IMy2Controller>().To<My2Controller>()
//Set the dependency resolver to use ninject
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
And to make ninject know which one to use I need to change the signature slightly in the constructor:
public My1Controller([Named("Config1")] IConfiguration config1)

How to get container for Autofac for WebAPI2?

In Ninject I can get object needed for interface by using class WebContainerManager
Ninject definition:
var logManager = new LogManagerAdapter();
container.Bind<ILogManager>().ToConstant(logManager);
Ninject usage:
var log = WebContainerManager.Get<ILogManager>().GetLog(typeof(WebApiApplication));
My question is how to do the same in Autofac, to get needed class for interface?
UPDATE 1: Im using WebAPi 2, not MVC.
If you need access to Autofac container from the class that was resolved by Autofac itself, then you can specify dependency on IComponentContext that is automatically provided by Autofac.
Example:
public void SomeComponent(IComponentContext context)
{
this.context = context;
}
...
// somewhere inside SomeComponent
context.Resolve<ILogManager>();
If your code is running inside ASP.Net environment, then you most probably set its DependencyResolver, thus you can always access it like:
DependencyResolver.Current.GetService<ILogManager>();
but as it is already mentioned in other comments, Service Locator is an anti-pattern that should be avoided.
In order to integrate autofac container with standard MVC dependency resolution mechanism you need to:
install Autofac.Mvc5 nuget package
set DependencyResolver with the following code
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
And in case you don't mind having explicit dependency on Autofac in your application code you can access global Autofac resolver reference the same way you use Ninject WebContainerManager:
var log = AutofacDependencyResolver.Current.Resolve<ILogManager>().GetLog(typeof(WebApiApplication));
You can create your builder.
var builder = new ContainerBuilder();
// Usually you're only interested in exposing the type
// via its interface:
builder.RegisterType<SomeType>().As<IService>();
// However, if you want BOTH services (not as common)
// you can say so:
builder.RegisterType<SomeType>().AsSelf().As<IService>();
Then you will be able to build your IoC:
IContainer Container = builder.Build();
And a simple example of How to get resource from container:
// Create the scope, resolve your IService,
// use it, then dispose of the scope.
using (var scope = Container.BeginLifetimeScope())
{
var writer = scope.Resolve<IService>();
writer.DoSomething();
}

How do I use MediatR with Autofac in ASP MVC 5?

The author provides an example of how to use MediatR in a console application using Autofac:
var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof (IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof (Ping).Assembly).AsImplementedInterfaces();
builder.RegisterInstance(Console.Out).As<TextWriter>();
var lazy = new Lazy<IServiceLocator>(() => new AutofacServiceLocator(builder.Build()));
var serviceLocatorProvider = new ServiceLocatorProvider(() => lazy.Value);
builder.RegisterInstance(serviceLocatorProvider);
I took this example and attempted to make it work with ASP MVC 5 and the Autofac.Mvc5 package:
var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof(IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof(AddPostCommand).Assembly).AsImplementedInterfaces();
builder.RegisterControllers(typeof(HomeController).Assembly);
var container = builder.Build();
var lazy = new Lazy<IServiceLocator>(() => new AutofacServiceLocator(container));
var serviceLocatorProvider = new ServiceLocatorProvider(() => lazy.Value);
builder.RegisterInstance(serviceLocatorProvider);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
When I run the web application, I get an error page telling me that the ServiceLocationProvider dependency has not been registered. What am I doing wrong?
I suspect that the problem is due to the fact that I am registering the ServiceLocatorProvider instance after calling Build - in the author's example, the Build method is invoked afterwards thanks to Lazy<>. I do not know how to work around this, though.
I had issues to properly register both the Mediator and ServiceLocatorProvider classes.
I pulled my hair for a while, but finally managed to get around it.
My mistake was to register ServiceLocatorProvider against the root Autofac container, like this:
var lazyContainer = new Lazy<IContainer>(() => builder.Build());
builder.Register(x => new ServiceLocatorProvider(() => new AutofacServiceLoator(lazyContainer.Value)));
DependencyResolver.SetCurrent(new AutofacDependencyResolver(lazyContainer.Value);
At runtime, Autofac was throwing an exception because one of my Request had a dependency on my EF DbContext that I configured to be scoped by HTTP request.
The trick is to register the ServiceLocatorProvider against the current HTTP request ILifetimeScope.
Thankfully, the error message from Autofac is self explanatory:
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance
was requested. This generally indicates that a component registered as per-HTTP request is being
requested by a SingleInstance() component (or a similar scenario.) Under the web integration
always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime,
never from the container itself.
This happens because the AutofacServiceLocator was fed with the root container.
The container, when asking to resolve the DbContext, has no knowledge of an inner - associated with to the current HTTP request - scope.
Using JustDecompile, I sax that the only class implementing the ILifetimeScopeProvider interface was AutofacDependencyResolver, and you can access the current instance with the static property AutofacDependencyResolver.Current.
You can access the current ILifetimeScope by using AutofacDependencyResolver.Current.RequestLifetimeScope as explained in the error message, so in the end the registration looks like:
builder
.Register(x => new ServiceLocatorProvider(() => new AutofacServiceLocator(AutofacDependencyResolver.Current.RequestLifetimeScope)))
.InstancePerHttpRequest();
The InstancePerHttpRequest() part is optional but since the ILifetimeScope will be the same during the whole HTTP request, this prevents Autofac from creating n instances of AutofacServiceLocator.
Hope this was clear, don't hesitate to make some edits if you feel like it's necessary, because I have a hard time explaining this clearly.
I am using Webapi 2 + Autofac + OWIN and manage to get it working. Here is my code:
Here is my autofac Constructor
//Constructor
var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof(IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsImplementedInterfaces();
// Register Web API controller in executing assembly.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();
var lazyContainer = new Lazy<IContainer>(() => builder.Build());
var serviceLocatorProvider = new ServiceLocatorProvider(() => new AutofacServiceLocator(lazyContainer.Value));
builder.RegisterInstance(serviceLocatorProvider);
config.DependencyResolver = new AutofacWebApiDependencyResolver(lazyContainer.Value);
// This should be the first middleware added to the IAppBuilder.
app.UseAutofacMiddleware(lazyContainer.Value);
// Make sure the Autofac lifetime scope is passed to Web API.
app.UseAutofacWebApi(config);
Here are my namespaces:
using System;
using System.Reflection;
using System.Web.Http;
using Autofac;
using CommonServiceLocator.AutofacAdapter.Unofficial;
using Autofac.Features.Variance;
using Autofac.Integration.WebApi;
using MediatR;
using Microsoft.Practices.ServiceLocation;
using Owin;
Everything worked fine and did not had to explict register every requestHandler or CommandHandler. Since I also lost a LOT of time to put it togueter I do hope that it will help others having the same issue. Past answers were helpfull to get to this one.
UPDATE:
Well, I just refactor de code to remove all the lazy binding making it much simpler. Bellow are the changes:
Instead of:
var lazyContainer = new Lazy<IContainer>(() => builder.Build());
var serviceLocatorProvider = new ServiceLocatorProvider(() => new AutofacServiceLocator(lazyContainer.Value));
builder.RegisterInstance(serviceLocatorProvider);
Just use :
builder.RegisterType<AutofacServiceLocator>().AsImplementedInterfaces();
var container = builder.Build();
//ServiceLocator.SetLocatorProvider(serviceLocatorProvider);
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
You cannot call Builder.Build before you finish registering types.
in your example you are calling Builder.Build before you call builder.RegisterInstance which explains why it cannot infer the type at runtime.
I came up with this after hitting the same issue today, but it is work in progress as it doesnt resolve my implementations yet...
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof(IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof(HomePageThumbnail).Assembly).AsImplementedInterfaces();
var lifetimeScope = new Lazy<ILifetimeScope>(() => builder.Build());
var lazy = new Lazy<IServiceLocator>(() => new AutofacServiceLocator(lifetimeScope.Value));
var serviceLocatorProvider = new ServiceLocatorProvider(() => lazy.Value);
builder.RegisterInstance(serviceLocatorProvider);
DependencyResolver.SetResolver(new AutofacDependencyResolver(lifetimeScope.Value));
app.UseAutofacMiddleware(lifetimeScope.Value);
app.UseAutofacMvc();
I am creating the container in a separate Lazy<T> and passing that around.
While this builds and the site loads, it cannot infer which handler to use for the request in my controller action...
var response = _mediator.Send(new RecentActivityThumbnailsQuery());
which raises the exception...
An exception of type 'Microsoft.Practices.ServiceLocation.ActivationException' occurred in Microsoft.Practices.ServiceLocation.dll but was not handled in user code
Additional information: Activation error occurred while trying to get instance of type IRequestHandler`2, key ""
This is using the same convention based registration provided in the Autofac examples project included in MediatR, and i have also tried registering it explicitly....
builder.RegisterType<RecentActivityThumbnailsHandler>().As<IRequestHandler<RecentActivityThumbnailsQuery, RecentActivityThumbnailsResults>>();
I will update when i get it working. Please do the same if you figure it out before i do.

Unity can't resolve interface in Session_Start and resolves wrong DbContext

I'm using Mvc3 and Unity.Mvc3 to build a testable and decoupled site, but I'm obviously doing something wrong.
In my Application_Start() i register a dependency:
// container is a property of the MvcApplication
// and the HierarchicalLifetimeManager should make sure that the registrations
// only last for this request (or should it?)
_container.Register<Interface, Class>(new HierarchicalLifetimeManager())
Then in the Session_Start() i try to resolve my dependency to save some data into the session:
var obj = _container.Resolve<Interface>();
At this point I get an exception saying that Unity can't resolve an interface, but I thought I registered a class for that interface???
I'm at a loss, and it's getting harder and harder to find a solution.
EDIT:
Here's my whole code, with some unnecessary parts left out:
public class MvcApplication : System.Web.HttpApplication
{
// as EDIT 2 says, this is wrong...
//private IUnityContainer _container = new UnityContainer();
protected void Application_Start()
{
// mvc stuff, routes, areas and whatnot
// create container here and it works, almost
var container = new UnityContainer();
// register dependencies
string connectionString = "String from config";
container.RegisterInstance<DbContext>(new CustomContext(connectionString), new HierarchicalLifetimeManager())
.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager())
.RegisterType(typeof(IRepository<>), typeof(Repository<>), new HierarchicalLifetimeManager());
// register controller resolver
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
// if i try to resolve repos here, it works and they all have the same context
// just like the unit of work
}
protected void Session_Start()
{
// here the container complains that it can't resolve the interface
// wrong
//var userRepo = _container.Resolve<IRepository<User>>();
// right, but still failes, because it is resolving DbContext
// instead of using the CustomContext instance
var userRepo = DependencyResolver.Current.GetService<IRepository<User>>();
// save some user data to session
}
}
public class SampleController : Controller {
// here the container tries to resolve the System.Data.Entity.DbContext
// instead of just giving the repo that instance that I registered
public SampleController(IRepository<Entity> repo) {
}
}
I'm obviously failing miserably at this Unit-of-work, dependency injection stuff, and the worst part is that I don't know why...
So please help before I start pulling my teeth out.
EDIT 2:
Partly there. If i create the container as above, it fails in the Session_Start(). If i create it in the Application_Start() as a local variable, and use the DependencyResolver, it works. How and why, beats me?
But it's still trying to resolve the DbContext instead of the CustomContext instance.
SOLUTION:
Ok, so here's the deal:
Problem 1) accessing the container in Session_Start():
As described in the EDIT 2, using a local container variable solves that, and accessing the container via the DependencyResolver works.
Problem 2) resolving the registered db context instance:
It turns out that registering an instance does not work.
This does though:
container.RegisterType<DbContext, CustomContext>(null, new HierarchicalLifetimeManager(), new InjectionConstructor(connectionString))
But I don't really feel satisfied, because I still didn't figure out why this works like this. Looks like I need to read a book or something for once in a long time.
Many thanks in advance.
The problem is you're using RegisterInstance with the HierarchecalLifetimeManager. I'm guessing you're trying to get a new instance per request, because the Unity.Mvc3 project uses that LifetimeManager to work that magic (as well as HttpModules to manage the creation and destruction of child containers).
The problem is, as a new request comes in, it will want to construct a new object, but doesn't know how to; you just registered an instance once, at the app start, and not a way to make an object. So you need to use RegisterType() for that to work.
You have two choices:
Specify the injected value using an InjectionConstructor: RegisterType<DbContext, CustomContext>(new HierarchecalLifetimeManager(), new InjectionConstructor(connectionString))
Use a factory: Container.RegisterType<DbContext>(new InjectionFactory(c => new CustomContext(connectionString)), new HierarcicalLifetimeManager()) (inspired by this)
*Note: parameter order may be wrong.
If you want a true singleton instance for your entire application, use the ContainerControlledLifetimeManager() (which is actually the default for RegisterInstance, so you don't even need to specify it). But then your DbContext will get rather huge as the site gets used.
Additionally, on your initial problem with the items not being registered in Session_Start():
ASP.NET maintains a pool of HttpApplication classes. That means if you make the Unity container a member variable, you'll have several instances which all have their own registrations. Application_Start() is called only once, and Session_Start() could be called using a different instance with no registrations. You'd need to use a static variable to solve that (which is what you ended up doing with the DependencyResolver).
Instead of accessing the container directly (it's not clear from your Q where you got the reference to the container?), why not let the MVC dependency resolver resolve it?
Set the Dependency resolver (Application_Start()):
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Resolve your interface (Session_Start()):
var obj = DependencyResolver.Current.GetService<IMyInterface>();

StructureMap, configure using container or objectfactory?

I did my configuration like this:
var container = new Container(x =>
{
x.For<IEngine>().Use<V6Engine>();
x.For<ICar>().Use<HondaCar>();
}
);
Then in my mvc controller action I did:
ICar car = ObjectFactory.GetInstance<ICar>();
Should I be setting up my container using Container or ObjectFactory somehow? It didn't resolve, so I tested things out in a c# console application and it worked if I did:
ICar car = container.GetInstance<ICar>();
But this only works if container is in local scope, and in a web app it isn't obviously since things are wired up in global.asax.cs
ObjectFactory is a static gateway for an instance of container. If you only ever want one instance of a container, and want a simple static way to get at it, use ObjectFactory. You must Initialize the ObjectFactory, and then retrieve your instances via ObjectFactory.
Alternatively, if you want to manage the lifetime of the container yourself, you can create an instance of Container, passing an initialization expression to the constructor. You then retrieve instances from the variable you declared to store the Container.
In your example, you are mixing the two approaches, which doesn't work.
I have got mine configured as below
global.asax
ObjectFactory.Initialize(action =>
{
action.For<ISomething>().Use<Something>;
});
Then everywhere else.
ObjectFactory.GetInstance<ISomething>();
This may not be the only way though. Also I think what you might be looking for is the
Scan(scanner =>
{
scanner.AssemblyContainingType(....);
scanner.AddAllTypesOf(....);
}

Categories

Resources