How do I simplify component registration using Autofac - c#

I am new in using Autofac and I want to simplify registering Installation of my Queries. ie
Bootstrapper.Builder.RegisterType<TableOneQuery>().As<ITableOneQuery>().InstancePerLifetimeScope();
Bootstrapper.Builder.RegisterType<TableTwoQuery>().As<ITableTwoQuery>().InstancePerLifetimeScope();
Bootstrapper.Builder.RegisterType<TableThreeQuery>().As<ITableThreeQuery>().InstancePerLifetimeScope();
Bootstrapper.Builder.RegisterType<TableFourQuery>().As<ITableFourQuery>().InstancePerLifetimeScope();
Bootstrapper.Builder.RegisterType<TableFiveQuery>().As<IFiveOneQuery>().InstancePerLifetimeScope();
The queries are of the same type and they follow this convention
public class TableOneQuery : ITableOneQuery
{
private readonly IGenericRepository<TableOne> _tableOneRepository;
public TableOneQuery(
IGenericRepository<TableOne> tableOneRepository)
{
_tableOneRepository = tableOneRepository;
}
public TableOneViewModel Get(int id)
{
.....
}
public IList<TableOneViewModel> GetAll()
{
.....
}
}
Is there a way to just register it once for its type?
BTW Bootstrapper is an Autofac.ContainerBuilder

Dynamically-provided registrations in Autofac include assembly scanning to find and register types automagically.
var dataAccess = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(dataAccess)
.Where(t => t.Name.EndsWith("Query"))
.AsImplementedInterfaces();

Related

How should I pass parameters to the Autofac container for auto dependency resolution via Autofac.Dependency injection lib

Here is the problem. I'm currently using Autofac to resolve all the dependencies with TypedParameters in my AspNetCore MVC app, but I think I'm do something wrong and I can do it cleaner.
Below are following code samples
Configuration for the services.
Sample repository to inject
Current method used
What i want to do
Configuration:
public static void Configure(IConfiguration cfg,IServiceCollection services)
{
/// some code is skipped here. Module registrant is just pulling out
/// the services from dlls and register them.
ioCBuilder.Populate(services);
ioCBuilder.RegisterModule(new ModuleRegistrant(cfg, registrantOptions));
IoCHelper.Container = ioCBuilder.Build();
}
Sample Repository:
public class PriorityRepository: IPriorityRepository
{
public PriorityRepository(DbContext db)
{
Db = db;
}
/// <inheritdoc />
public Priority GetDefault()
{
return Db.Set<Priority>().SingleOrDefault(it => it.IsDefault);
}
}
Currently I get Repository with following:
public class PriorityController: Controller
{
public PriorityController(TestContext db)
{
var ctxParam = new TypedParameter(typeof(DbContext), db);
PriorityRepository = IoCHelper.Container.Resolve<IPriorityRepository>(ctxParam);
}
public IPriorityRepository PriorityRepository { get; set;}
}
I want it to be something like that
public class PriorityController: Controller
{
public PriorityController(IPriorityRepository priorityRepo)
{
PriorityRepository = priorityRepo;
}
public IPriorityRepository PriorityRepository { get; set;}
}
So basically the question is: How do I inject the already registered types which has slightly different type(more abstract) in the constructor?
The Func is used to resolve parameterized dependencies in Autofac.
Kindly go through the link https://autofaccn.readthedocs.io/en/latest/resolve/relationships.html#parameterized-instantiation-func-x-y-b for implementation details and other available options.

How to register decorator to be able to resolve decoree

I'm using Autofac.
I'm trying to register 2 classes with same interface using decorator pattern.
public interface IDoable
{
string Do();
}
public class Decoree : IDoable
{
public string Do()
{
return "decoree";
}
}
public class Decorator : IDoable
{
public IDoable InnerDecoree { get; set; }
public Decorator(IDoable doable)
{
this.InnerDecoree = doable;
}
public string Do()
{
return InnerDecoree.Do() + "decorator";
}
}
I'd like to use container for resolving two types for 2 different cases:
IDoable where I'd expect that instance would be instance of Decorator
and for specific Decoree where I really need to resolve specific Decoree instance.
Only way how I can achieve it is using following code:
[Fact]
public void Both()
{
var builder = new ContainerBuilder();
builder.RegisterType<Decoree>()
.Named<IDoable>("decoree")
.SingleInstance();
builder.RegisterType<Decoree>() // but this is not right I'd like to register it on line above somehow...
.AsSelf()
.SingleInstance();
builder.RegisterType<Decorator>()
.Named<IDoable>("decorator")
.SingleInstance();
builder.RegisterDecorator<IDoable>(
(c, inner) => c.ResolveNamed<IDoable>("decorator", TypedParameter.From(inner)), "decoree")
.As<IDoable>();
var container = builder.Build();
Assert.IsType<Decoree>(container.Resolve<Decoree>());
Assert.False(container.IsRegistered<Decorator>());
Assert.IsType<Decorator>(container.Resolve<IDoable>());
var decoree = container.Resolve<Decoree>();
var decorator = container.Resolve<IDoable>();
var doable = ((Decorator)decorator).InnerDecoree;
Assert.Same(decoree, doable); // FALSE :(
}
The thing is that I'd really love the last assertion to be true :) so It's same instance.
Basically my question is: Is it possible to register type both ways using named and type ?
Because you aren't specifying a scope in your registration, you are getting a different instance of Decoree every time it gets resolved. I would try something like
builder.RegisterType<Decoree>()
.Named<IDoable>("decoree").SingleInstance();
In addition, you might need to combine your 2 registrations of the Decoree type:
builder.RegisterType<Decoree>()
.Named<IDoable>("decoree")
.AsSelf()
.SingleInstance();

How to configure services based on request in ASP.NET Core

In ASP.NET Core we can register all dependencies during start up, which executed when application starts. Then registered dependencies will be injected in controller constructor.
public class ReportController
{
private IReportFactory _reportFactory;
public ReportController(IReportFactory reportFactory)
{
_reportFactory = reportFactory;
}
public IActionResult Get()
{
vart report = _reportFactory.Create();
return Ok(report);
}
}
Now I want to inject different implementations of IReportFactory based on data in current request (User authorization level or some value in the querystring passed with an request).
Question: is there any built-in abstraction(middleware) in ASP.NET Core where we can register another implementation of interface?
What is the possible approach for this if there no built-in features?
Update
IReportFactory interface was used as a simple example. Actually I have bunch of low level interfaces injected in different places. And now I want that different implementation of those low level interfaces will be injected based on request data.
public class OrderController
{
private IOrderService _orderService;
public OrderController(IOrderService orderService)
{
_orderService = orderService;
}
public IActionResult Create()
{
var order = _orderService.Create();
return Ok(order);
}
}
public class OrderService
{
private OrderBuilder _orderBuilder;
private IShippingService _shippingService; // This now have many different implementations
public OrderService(
OrderBuilder _orderBuilder,
IShippingService _shippingService)
{
_orderService = orderService;
_shippingService = shippingService;
}
public Order Create()
{
var order = _orderBuilder.Build();
var order.ShippingInfo = _shippingService.Ship();
return order;
}
}
Because we know which implementation we need to use on entry point of our application (I think controller action can be considered as entry point of application), we want inject correct implementation already there - no changes required in already existed design.
No, you can't. The IServiceCollection is populated during application startup and built before Configure method is called. After that (container being built), the registrations can't be changed anymore.
You can however implement an abstract factory, be it as factory method or as an interface/class.
// Its required to register the IHttpContextAccessor first
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IReportService>(provider => {
var httpContext = provider.GetRequired<IHttpContextAccessor>().HttpContext;
if(httpContext.User.IsAuthorized)
{
return new AuthorizedUserReportService(...);
// or resolve it provider.GetService<AuthorizedUserReportService>()
}
return new AnonymousUserReportService(...);
// or resolve it provider.GetService<AnonymousUserReportService>()
});
Alternatively use an abstract factory class
I'm afraid you can not directly acheive the goal via simple dependency injection , as the the dependency injection configured at Startup stage , in other words , all services and implementions has been configured before a request comming .
However , you can inject a Create Service delegate so that can we create the required service implemention instance in runtime .
For instance , if we have a IReportFactory Interface and two implementions as blew :
public interface IReportFactory
{
object Create();
}
public class ReportFactory1 : IReportFactory
{
public object Create()
{
return new { F = 1, };
}
}
public class ReportFactory2 : IReportFactory {
public object Create()
{
return new { F = 2, };
}
}
As we want to get the required implemention in future , we need to register the Implementions first .
services.AddScoped<ReportFactory1>();
services.AddScoped<ReportFactory2>();
and here's where the magic happens :
We don't register a IReportFactory
We just add a Func<HttpContext,IReportFactory> instead , which is a CreateReportFactoryDelegate
public delegate IReportFactory CreateReportFactoryDelegate(Microsoft.AspNetCore.Http.HttpContext context);
We need add the CreateReportFactoryDelegate to servies too.
services.AddScoped<CreateReportFactoryDelegate>(sp => {
// return the required implemention service by the context;
return context => {
// now we have the http context ,
// we can decide which factory implemention should be returned;
// ...
if (context.Request.Path.ToString().Contains("factory1")) {
return sp.GetRequiredService<ReportFactory1>();
}
return sp.GetRequiredService<ReportFactory2>();
};
});
Now , we can inject a CreateReportFactoryDelegate into controller :
public class HomeController : Controller
{
private CreateReportFactoryDelegate _createReportFactoryDelegate;
public HomeController(CreateReportFactoryDelegate createDelegate) {
this._createReportFactoryDelegate = createDelegate;
// ...
}
public async Task<IActionResult> CacheGetOrCreateAsync() {
IReportFactory reportFactory = this._createReportFactoryDelegate(this.HttpContext);
var x=reportFactory.Create();
// ...
return View("Cache", cacheEntry);
}
}
It is possible by using the HttpContextAccessor in Startup.cs
services.AddHttpContextAccessor();
services.AddScoped<IYourService>(provider =>
{
var contextAccessor = provider.GetService<IHttpContextAccessor>();
var httpContext = contextAccessor.HttpContext;
var contextVariable = httpContext. ...
// Return implementation of IYourService that corresponds to your contextVariable
});
Expanding on #JohanP comment about using IEnumerable
//Program.cs
//get the builder
var builder = WebApplication.CreateBuilder(args);
//register each type
builder.Services.AddScoped<IReport,Report1>();
builder.Services.AddScoped<IReport,Report2>();
builder.Services.AddScoped<IReport,Report3>();
//register the factory class
builder.Services.AddScoped<IReportFactory,ReportFactory>();
//IReport Interface
public interface IReport
{
string ReportType{ get; set; }
}
//ReportFactory.cs
public class ReportFactory : IReportFactory
{
private IEnumerable<IReport> _handlers;
//ctor
public ReportFactory(IEnumerable<IReport> handlers)
=> _handlers = handlers;
internal IReport? Creat(string reportType) =>
_handlers.Where(h => h.ReportType== reportType).First();
}
//Controller
public class ReportController
{
private IReportFactory _reportFactory;
public ReportController(IReportFactory reportFactory)
{
_reportFactory = reportFactory;
}
//modify to your project needs
public IActionResult Get([FromBody] string reportType)
{
if (HttpContext.User.IsAuthorized)
{
var report = _reportFactory.Create(reportType);
return Ok(report);
}
}
}

How to ensure that Autofac is calling Dispose() on EF6 DbContext

UPDATE
Found this little gem which helped me with DbContext
Josh Kodroff - Making Entity Framework More Unit-Testable
Original
After doing a lot of research I finally decided to implement IOC using Autofac in my MVC5 EF6 project. Autofac's documentation has been helpful, but I'm still not sure about whether or not I need to call Dispose() either in my Controller or Service Class?
I'm not using an abstracted UOW and Generic Repository, but just relying on DbContext and DbSet<> provided in EF6. Here's a snippet of my classes.
My DbContext
public class ProductContext : DbContext
{
public ProductContext() : base("ProductContext")
{
}
public DbSet<Availability> Availability { get; set; }
public DbSet<Category> Categories { get; set; }
....
}
My Service Class
public class ProductService : IProductService
{
private ProductContext _db;
public ProductService(ProductContext db)
{
_db = db;
}
public List<Product> GetProductsByCategory(string cleanCategory)
{
return _db.Products
.Include(p => p.Options.Select(o => o.OptionGroup))
.Include(p => p.Associations.Select(a => a.AssociatedGroup))
.Include(p => p.Variations).Include(p => p.Manufacturer)
.Where(p => p.Active && p.Category.Name.ToUpper().Equals(cleanCategory)).ToList();
}
.....
}
My Service Interface
public interface IProductService
{
List<Product> GetProductsByCategory(string cleanCategory);
....
}
My Contoller
public class ProductsController : Controller
{
private IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
//GET: Products/
public ActionResult Index(string category)
{
if (String.IsNullOrEmpty(category))
{
return HttpNotFound();
}
string cleanCategory = urlScrubber(category);
var viewModel = new ProductsVM();
viewModel.ProductList = _productService.GetProductsByCategory(cleanCategory);
}
My Autofac Container
var builder = new ContainerBuilder();
// Register your MVC controllers.
builder.RegisterControllers(typeof(MvcApplication).Assembly);
// REGISTER COMPONENTS HERE:
builder.RegisterType<ProductContext>().AsSelf().InstancePerRequest();
builder.RegisterType<ProductService>().As<IProductService>().InstancePerRequest();
// Set the dependency resolver to be Autofac.
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
I have removed Dispose() from the controller with the understanding that Autofac would handle the disposal of contexts that inherit from IDisposable. Since ProductContext inherits from DbContext which includes a Dispose() Method, this should work.
Do I need to include something like
builder.RegisterType<ProductContext>().As<DbContext>().InstancePerRequest();
or will my current container work as expected calling Dispose?
builder.RegisterType<ProductContext>().AsSelf().InstancePerRequest();
Thanks for any help, I'm having a hard time locating documentation using Autofac without a generic repository and UOW on top of DbContext similar to my current pattern.
As per the doucmentation,
Autofac integration libraries standard unit-of-work lifetime scopes will be created and disposed for you automatically. Autofac’s ASP.NET MVC integration, a lifetime scope will be created for you at the beginning of a web request and all components will generally be resolved from there. At the end of the web request, the scope will automatically be disposed - no additional scope creation is required on your part.
So I think if your class implments IDisposable then Dispose() would be automatically called for such objects. So simply,
builder.RegisterType<ProductContext>().As<DbContext>().InstancePerRequest();
Would do the Disposal via object life scope management.
Autofac also supports using Func<> in constructor injection. For example, you can register your data context like normal:
builder.RegisterType<ProductContext>().As<IProductContext>();
and use it as follows in your ProductService:
public class ProductService : IProductService
{
private IProductContext _dbCreator;
public ProductService(Func<IProductContext> dbCreator)
{
_db = db;
}
public List<Product> GetProductsByCategory(string cleanCategory)
{
using (var dbCtx = _dbCreator())
{
return dbCtx.Products
.Include(p => p.Options.Select(o => o.OptionGroup))
.Include(p => p.Associations.Select(a => a.AssociatedGroup))
.Include(p => p.Variations).Include(p => p.Manufacturer)
.Where(p => p.Active && p.Category.Name.ToUpper().Equals(cleanCategory)).ToList();
}
}
.....
}
Basically, your ProductService now has access to a Func<>(_dbCreator) that creates a new instance of your ProductContext based on your autofac registration every time it's called, allowing you to dispose the instance when you deem appropriate.
I realized after I wrote this that you don't have an IProductContext, I would usually recommend using this pattern, however, it isn't too important as far as your question is concerned. You can continue to use your current registration method for ProductContext and then just pass in a Func<ProductContext> instead of an IProductContext, i.e.,
builder.RegisterType<ProductContext>().AsSelf();
and
private ProductContext _dbCreator;
public ProductService(Func<ProductContext> dbCreator)
Sorry if the code doesn't compile, I didn't use an IDE... Hopefully it's close enough for you to get my point!

Autofac modules with their own dependencies

I'm struggling with how to organize my Autofac component registrations in modules given that some of the modules themselves have dependencies.
I've implemented an abstraction of configuration data (i.e. web.config) in an interface:
interface IConfigurationProvider
{
T GetSection<T>(string sectionName)
where T : System.Configuration.ConfigurationSection;
}
along with implementations for ASP.NET (WebConfigurationProvider) and "desktop" applications (ExeConfigurationProvider).
Some of my autofac modules then require an IConfigurationProvider as a constructor parameter, but some don't:
class DependentModule : Module
{
public DependentModule(IConfigurationProvider config)
{
_config = config;
}
protected override void Load(ContainerBuilder builder)
{
var configSection = _config.GetSection<CustomConfigSection>("customSection");
builder.RegisterType(configSection.TypeFromConfig);
}
private readonly IConfigurationProvider _config;
}
class IndependentModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(/* other stuff not based on configuration */);
}
}
Since the RegisterType() extension method doesn't accept a registration delegate (Func<IComponentContext, T>), like Register() does, I can't register the IConfigurationProvider up-front and then resolve it when I go to register the type specified in the configuration, something like:
// this would be nice...
builder.RegisterType(c => c.Resolve<IConfigurationProvider>().GetSection<CustomConfigSection>("sectionName").TypeFromConfig);
This means that I need to be able to register modules with and without a dependency on IConfigurationProvider.
It's obvious how to manually instantiate each module and register it:
IConfigurationProvider configProvider = ...;
var builder = new ContainerBuilder();
builder.RegisterModule(new DependentModule(configProvider));
builder.RegisterModule(new IndependentModule());
using (var container = builder.Build())
{
...
}
But I don't want to manually instantiate my modules - I want to scan assemblies for modules and register them automatically (as discussed in this question). So I have to use reflection to scan the assembly for IModule types, and use Activator.CreateInstance to make registerable instances. But how do I know whether or not to pass an IConfigurationProvider as a constructor parameter. And what happens when other modules have additional or different dependencies?
There's got to be a more straightforward way of accomplishing the basic task: register a type specified in some configuration provided via an interface, right? So how do I do that?
You could do something like this:
using System.Collections.Generic;
using System.Linq;
using Autofac;
using Autofac.Core;
using NUnit.Framework;
namespace Yo_dawg
{
[TestFixture]
public class I_heard_you_like_containers
{
[Test]
public void So_we_built_a_container_to_build_your_container()
{
var modules = GetModules();
Assert.That(modules.Length, Is.EqualTo(4));
var builder = new ContainerBuilder();
foreach (var module in modules)
builder.RegisterModule(module);
var container = builder.Build();
}
private IModule[] GetModules()
{
var builder = new ContainerBuilder();
var configurationProvider = new ConfigurationProvider();
builder.RegisterInstance(configurationProvider).AsImplementedInterfaces().ExternallyOwned();
builder.RegisterAssemblyTypes(GetType().Assembly)
.Where(t => t.IsAssignableTo<IModule>())
.AsImplementedInterfaces();
using (var container = builder.Build())
return container.Resolve<IEnumerable<IModule>>().ToArray();
}
}
public class ModuleA : Module
{
public ModuleA(IConfigurationProvider config)
{
}
}
public class ModuleB : Module
{
public ModuleB(IConfigurationProvider config)
{
}
}
public class ModuleC : Module
{
}
public class ModuleD : Module
{
}
public interface IConfigurationProvider
{
}
public class ConfigurationProvider : IConfigurationProvider
{
}
}
For this scenario, Autofac's own XML configuration seems to cover the scenarios you're targeting. Adding a new IConfigurationProvider mechanism seems like reinventing this functionality already provided by the container. The basics are documented at: https://code.google.com/p/autofac/wiki/XmlConfiguration. The configuration syntax has in-built support for modules.
There's a nice alternative by Paul Stovell that allows modules to be registered in code yet receive parameters from config - see: http://www.paulstovell.com/convention-configuration. Hope this helps!

Categories

Resources