TL;DR;
It isn’t long, since i struggle to find out how to access DI registered classes in MVC using autofac, and I failed every time, with every phrase.
So, two days ago, I though to myself, let create access point, and it worked. cool, right?
The way i gonna show you, is not officially provided by those who right Autofac, It’s Cheat, a Trick, but it works. Isn’t that enough? Maybe not; so in case you found a better solution feel free to share it with me.
Other solutions:
I list some of the solutions in my mind, that did not worked for me:
- Create new Container:
This solution wasn’t good for me, because i had to register many stuff again and again, also changin one Mapping, require you to remember it and change it in all other containers too. - Using
Resolve
,GetService
or other similar functionalities:
Why this doesn’t work for me, I’m not sure, it look what i wanted to do, but just as i said, unfortunattely, it didn’t worked for me, if it works for you, Thats Great.
Here’s sample of resolvevar builder = new ContainerBuilder(); builder.RegisterType<MyComponent>().As<IService>(); var container = builder.Build(); // Later... using(var scope = container.BeginLifetimeScope()) { var service = scope.Resolve<IService>(); }
My Way, The Cheat
The only way rest for me, was to keep a pointer to the container, so I had to option, some static class, somewhere or a Singleton. I did it with a singleton. I made this class not only for Autofac, but for any unpredictable issue that may come later.
Here’s my Singleton:
using System.Diagnostics.CodeAnalysis; using Autofac; namespace MyProject { public class GlobalObjects { #region Singleton private static readonly GlobalObjects Instance = null; static GlobalObjects() { Instance = new GlobalObjects(); } private GlobalObjects() { } public static GlobalObjects GetInstance() { return Instance; } #endregion [SuppressMessage("ReSharper", "IdentifierTypo")] //if you are not using Resharper, you can remove these attributes. public IContainer AutofacContainer { private set; get; } [SuppressMessage("ReSharper", "IdentifierTypo")] public GlobalObjects SetAutofacContainer(IContainer container) { AutofacContainer = container; return Instance; } } }
Then i had to pass the Autofac Container reference to my SetAutofacContainer
Method of GlobalObjects
class.
So i did it after registering the container in Startup.cs
file.
... namespace Judgel.Web { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public IServiceProvider ConfigureServices(IServiceCollection services) { ... var builder = new ContainerBuilder(); var dependencyRegistrar = new DependencyRegistrar(); dependencyRegistrar.Register(builder); builder.RegisterType<LayoutService>().As<LayoutService>().InstancePerLifetimeScope(); builder.Populate(services); var container = builder.Build(); GlobalObjects.GetInstance().SetAutofacContainer(container); return container.Resolve<IServiceProvider>(); } ... } }
In the end, you can access it any where, for example i need it in my view, so i call it like this:
@{ var di = GlobalObjects.GetInstance().AutofacContainer; LayoutService layoutService = di.Resolve<LayoutService>(); var userId = Context.User.GetUserId(); Person person = layoutService.GetPerson(userId); //model ApplicationUser user= layoutService.GetUser(userId); } <!DOCTYPE html> <html lang="en" class="loading"> ... </html>
The first line is what you need, that’s how we access the Autofac Container.
The second line, is what I use, to resolve my desired object.
After that, i just use my object in my desired way, and it will be different in your scenario .
Thank you for reading,
Hassan Faghihi.