How do I get a list of registered services in Autofac - autofac

In the Microsoft.Extensions.DependencyInjection,I can:
public static IServiceCollection BuildAopProxy(this IServiceCollection service)
{
foreach (ServiceDescriptor item in service)
{}
}
How do I get which registered components in Autofac?

The set of all registrations can be found in the ComponentRegistry, available in the container and any nested scopes:
var builder = new ContainerBuilder();
builder.RegisterType<MyType>();
var container = builder.Build();
// Here is the list you want.
container.ComponentRegistry.Registrations;
If you actually want to resolve all providers of a specific service, you can just resolve an IEnumerable<TService>:
var builder = new ContainerBuilder();
// Two implementations of the same service.
builder.RegisterType<MyTypeA>().As<IService1>();
builder.RegisterType<MyTypeB>().As<IService1>();
var container = builder.Build();
// This will return a set with 2 items.
container.Resolve<IEnumerable<IService1>>();

Related

autofac webapi owin integration problems with middleware exection order not correct

I'm confused with Autofac Examples : WebApiExample.OwinSelfHost, the startup class is following:
public class Startup
{
public void Configuration(IAppBuilder app)
{
// In OWIN you create your own HttpConfiguration rather than
// re-using the GlobalConfiguration.
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
"DefaultApi",
"api/{controller}/{id}",
new { id = RouteParameter.Optional });
var builder = new ContainerBuilder();
// Register Web API controller in executing assembly.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// OPTIONAL - Register the filter provider if you have custom filters that need DI.
// Also hook the filters up to controllers.
builder.RegisterWebApiFilterProvider(config);
builder.RegisterType<CustomActionFilter>()
.AsWebApiActionFilterFor<TestController>()
.InstancePerRequest();
// Register a logger service to be used by the controller and middleware.
builder.Register(c => new Logger()).As<ILogger>().InstancePerRequest();
// Autofac will add middleware to IAppBuilder in the order registered.
// The middleware will execute in the order added to IAppBuilder.
builder.RegisterType<FirstMiddleware>().InstancePerRequest();
builder.RegisterType<SecondMiddleware>().InstancePerRequest();
// Create and assign a dependency resolver for Web API to use.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// The Autofac middleware should be the first middleware added to the IAppBuilder.
// If you "UseAutofacMiddleware" then all of the middleware in the container
// will be injected into the pipeline right after the Autofac lifetime scope
// is created/injected.
//
// Alternatively, you can control when container-based
// middleware is used by using "UseAutofacLifetimeScopeInjector" along with
// "UseMiddlewareFromContainer". As long as the lifetime scope injector
// comes first, everything is good.
app.UseAutofacMiddleware(container);
// Again, the alternative to "UseAutofacMiddleware" is something like this:
// app.UseAutofacLifetimeScopeInjector(container);
// app.UseMiddlewareFromContainer<FirstMiddleware>();
// app.UseMiddlewareFromContainer<SecondMiddleware>();
// Make sure the Autofac lifetime scope is passed to Web API.
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}
}
The FirstMiddleware and SecondMiddleware code was as following:
public class FirstMiddleware : OwinMiddleware
{
private readonly ILogger _logger;
public FirstMiddleware(OwinMiddleware next, ILogger logger) : base(next)
{
this._logger = logger;
}
public override async Task Invoke(IOwinContext context)
{
this._logger.Write("Inside the 'Invoke' method of the '{0}' middleware.", GetType().Name);
await Next.Invoke(context);
}
}
public class SecondMiddleware : OwinMiddleware
{
private readonly ILogger _logger;
public SecondMiddleware(OwinMiddleware next, ILogger logger) : base(next)
{
this._logger = logger;
}
public override async Task Invoke(IOwinContext context)
{
this._logger.Write("Inside the 'Invoke' method of the '{0}' middleware.", GetType().Name);
await Next.Invoke(context);
}
}
According to the comments, the middleware registration order matters. FirstMiddleware first, then SecondMiddleware. but the output was second middleware was invoked first.
the program logs output here
What's wrong with the order?
This is the autofac official example.WebApiExample.OwinSelfHost
Looks like you've found a bug! I've filed an issue about it on your behalf. You can read more technical details about it there, but the short version is that over the years we've changed some Autofac internals to support .NET Core and this looks like something we've missed.
The workaround until this is fixed will be to register the middleware in reverse order, which isn't awesome because once the fix is applied you'll have to reverse them back. :(

Autofac fails to resolve enumerable of typed HttpClients

I have a number of services which require usage of typed HttpClient from HttpClientFactory.
Though I can resolve one service I can't resolve IEnumerable of this services.
interface IMyHttpClient
{
}
class MyHttpClient: IMyHttpClient
{
public MyHttpClient(HttpClient client)
{
}
}
class Program
{
static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddHttpClient()
.AddHttpClient<IMyHttpClient, MyHttpClient>();
var builder = new ContainerBuilder();
// Exception goes away when remove this line
builder.RegisterType<MyHttpClient>().As<IMyHttpClient>();
builder.Populate(services);
var provider = builder.Build();
// ============== This works
// provider.Resolve<IMyHttpClient>();
// ============== This throws exception
provider.Resolve<IEnumerable<IMyHttpClient>>();
}
}
Constructor will be called once and than exception is thrown:
```
DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'ConsoleApp2.MyHttpClient' can be invoked with the available services and parameters:
Cannot resolve parameter 'System.Net.Http.HttpClient client' of constructor 'Void .ctor(System.Net.Http.HttpClient)'.
```
The issue is that AddHttpClient adds it's own registration of IMyHttpClient. But I do want to register using Autofac only! Is there a way to use typed clients but still stay with Autofac?
The exception explains that Autofac can't resolve parameter 'System.Net.Http.HttpClient client'. I suppose this is because such type wasn't registered in your container for second resgistration of IMyHttpClient. To save an advantages of HttpClientFactory you can register excplicit constructor parameter for example like this:
static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddHttpClient();
var builder = new ContainerBuilder();
// exclicit resolving client for constructor
builder.RegisterType<MyHttpClient>().As<IMyHttpClient>().WithParameter(
(p, ctx) => p.ParameterType == typeof(HttpClient),
(p, ctx) => ctx.Resolve<IHttpClientFactory>().CreateClient());
builder.Populate(services);
var provider = builder.Build();
// ============== This works
provider.Resolve<IMyHttpClient>();
// ============== This works too
provider.Resolve<IEnumerable<IMyHttpClient>>();
}
In this example Resolve<IEnumerable<IMyHttpClient>> return enumeration with single IMyHttpClient, that is initialized with HttpClient from core HttpClientFactory.
UPD: the post was updated by #norekhov comment

Large number of SQL Active Sessions when injecting DBContext using Autofac in WebApi

I'm using Autofac for injecting dependencies in Web Api.
I set InstancePerRequest scope for EF DBContext.
Autofac Wiring up configuration:
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
var config = new HttpConfiguration();
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();
var asmb = typeof (TrafficDataService).Assembly;
builder.RegisterAssemblyTypes(asmb).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerRequest();
builder.RegisterType<TrafficServiceGlobalContext>().As<IUnitOfWork>().InstancePerRequest();
builder.RegisterType<EMSEntities>().As<IEmsDataModel>().InstancePerRequest();
builder.RegisterType<ViolationTrafficEntities>().As<IViolationDataModel>().InstancePerRequest();
builder.RegisterType<TrafficController>().As<IHttpController>().InstancePerRequest();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).InstancePerRequest();
builder.Register(c => app.GetDataProtectionProvider()).InstancePerRequest();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
WebApiConfig.Register(config);
}
After Service gets huge number of request, and when checking Active Sessions for my DB i see 500 Active Sessions over db.
Is really this a problem?
How to implement Connection Pooling?
Any idea?
Update:
All relevant classes depends on interfaces.
As Yacoub Massad asked in comments area, here is some of relevant classes signature and constructors:
public partial class ViolationTrafficEntities : DbContext, IViolationDataModel
{
.
.
.
}
public class TrafficDataService : ITrafficDataService
{
private readonly IViolationDataModel _violationDataModel;
public TrafficDataService(IViolationDataModel violationDataModel)
{
_violationDataModel = violationDataModel;
}
}

Can Autofac compose existing objects with Mef dependencies?

I am integrating a mef-based ServiceLocator with Autofac. The current locator is able to compose an existing object by setting up a CompositionBatch and then injecting dependecies on the object. A simple repro:
public void MefCompositionContainer_CanComposeExistingObjects()
{
//1. Initialize Mef
var composablePartCatalogs = new List<ComposablePartCatalog>
{
new AssemblyCatalog(Assembly.GetExecutingAssembly())
//A lot more here..
};
var aggregateCatalog = new AggregateCatalog(composablePartCatalogs);
var container = new CompositionContainer(aggregateCatalog, true);
//2. Mef is able to compose existing object
var objectWithPropertyImport = new ClassWithPropertyImport();
Compose(container, objectWithPropertyImport);
objectWithPropertyImport.ImportOfMefExport.Should().NotBeNull();
}
static T Compose<T>(CompositionContainer container, T value)
{
var batch = new CompositionBatch();
batch.AddPart(value);
container.Compose(batch);
return value;
}
The following classes are required:
[Export]
public class MefExport { }
//Note that this class does not have the [Export] attribute
public class ClassWithPropertyImport
{
[Import]
public MefExport ImportOfMefExport { get; set; }
}
Is it possible to accomplish the same with Autofac? If so - what should be added / changed here to compose objectWithPropertyImport?
public void Autofac_CanComposeExistingObjects()
{
//1. Initialize Mef
var composablePartCatalogs = new List<ComposablePartCatalog>
{
new AssemblyCatalog(Assembly.GetExecutingAssembly())
//A lot more here..
};
var aggregateCatalog = new AggregateCatalog(composablePartCatalogs);
//2. Initialize Autofac and setup mef-integration
var builder = new ContainerBuilder();
builder.Register(c => new AutofacExport()).Exported(x => x.As<AutofacExport>());
builder.RegisterComposablePartCatalog(aggregateCatalog);
var ioc = builder.Build();
var objectWithPropertyImport = new ClassWithPropertyImport();
// Now what?
// Updated according to solution from Travis Illig.
// The following code works for me:
ioc.InjectProperties(objectWithPropertyImport);
objectWithPropertyImport.ImportOfMefExport.Should().NotBeNull();
}
If all you need to do is inject the properties of a new object using Autofac, then use the InjectProperties method on the lifetime scope / container.
using Autofac;
public class ClassWithPropertyImport
{
public MyExport ImportedProperty { get; set; }
}
public class MyExport { }
var builder = new ContainerBuilder();
builder.RegisterType<MyExport>();
var container = builder.Build();
using(var scope = container.BeginLifetimeScope())
{
var c = new ClassWithPropertyImport();
scope.InjectProperties(c);
c.ImportedProperty.Should().NotBeNull();
}
As long as the types you're injecting are registered with Autofac, it should work fine. You don't need the type of the thing you're injecting onto registered. (Note the ClassWithPropertyImport is not registered with Autofac but the MyExport class is.)
Keep in mind it does mean Autofac needs to resolve the MyExport type - so if it has dependencies, those do need to be registered with Autofac as well.

Asp.net web api with autofac and Hangfire

I recently upgraded to a new version of Hangfire and I am struggeling trying to setup my webapi with autofac and Hangfire. I'm using Autofac Hangfire integration version 1.1 and Hangfire 1.4.2. I'm using Owin to host. I keep getting following error:
The requested service 'IFoo' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
Here is my owin startup configuration. All my registrations are made in the AutofacStandardModule class
public class Startup
{
public void Configuration(IAppBuilder app)
{
//we will have the firewall block all CE endpoints from the outside instead
//ConfigureOAuthTokenConsumption(app);
var storage = new SqlServerStorage("connection string");
JobStorage.Current = storage;
app.UseHangfireServer(new BackgroundJobServerOptions(),storage);
app.UseHangfireDashboard("/Hangfire",new DashboardOptions(),storage);
var builder = new ContainerBuilder();
builder.RegisterModule(new AutofacStandardModule());
var container = builder.Build();
GlobalConfiguration.Configuration.UseAutofacActivator(container);
}
}
Also, here is my web api config class. I dont see how I should be configuring Hangfire here also though..
public static class WebApiConfig
{
public static void Register(HttpConfiguration config, Autofac.Module moduleToAppend)
{
config.MapHttpAttributeRoutes();
config.EnableCors();
config.EnableSystemDiagnosticsTracing();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(
Assembly.GetExecutingAssembly())
.Where(t =>
!t.IsAbstract && typeof(ApiController).IsAssignableFrom(t))
.InstancePerLifetimeScope();
builder.RegisterModule(
new AutofacStandardModule());
if (moduleToAppend != null)
{
builder.RegisterModule(moduleToAppend);
}
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(
container);
//Hangfire.GlobalConfiguration.Configuration.UseAutofacActivator(container);
//JobActivator.Current = new AutofacJobActivator(container);
}
}
I solved the issue, it seemed I hadn't specified clearly enough which type my job was when enqueuing.
What is did was to change
_jobClient.Enqueue(
() => _foo.Bar(fooId, fooId2));
..into..
_jobClient.Enqueue<IFoo>(x => x.Bar(fooId, fooId2));