I am trying to configure an MVC 5 application to use SignalR 2.2.x and inject a service into my NotificationsHub.
We are using Autofac for MVC but I am not sure on how to correctly configure this.
Autofac documentation exists for NuGet Autofac.Integration.SignalR (3.0.2) and Autofac.Integration.Mvc (3.3.4).
What I am doing so far is register the hubs via:
ContainerBuilder builder = new ContainerBuilder();
// Register MVC controllers.
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<ServiceForSignalRHub>().AsImplementedInterfaces();
builder.RegisterType<...>().AsImplementedInterfaces();
builder.RegisterHubs(Assembly.GetExecutingAssembly());
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
However the call to .SetResolver(...) is ambigious as it exists in both MVC and SignalR integration packages. Now what? I am unable to confirm if the contructor injection of my service works for the Hub I am using.
EDIT
I can configure MVC5 with Autofac just fine. Where I get lost is how to do the same with SignalR, using the Autofac Signal integration NuGet.
Please see below.
This is my startup class:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var defaultFactory = LogManager.Use<DefaultFactory>();
defaultFactory.Directory("#D:\\NServiceBus\\ );
defaultFactory.Level(LogLevel.Debug);
var container = ConfigureAutofac(app);
ConfigureServiceBus(container, app);
app.UseAutofacMiddleware(container); // REGISTER WITH OWIN
app.UseAutofacMvc();
ConfigureAuth(app);
GlobalConfiguration.Configuration.UseSqlServerStorage("hangfire");
ConfigureSignalR(app);
}
}
This is the part where I configure SignalR:
public partial class Startup
{
public void ConfigureSignalR(IAppBuilder app)
{
var builder = new ContainerBuilder();
builder.RegisterHubs(Assembly.GetExecutingAssembly()).PropertiesAutowired();
builder.RegisterType<MaintenanceService>().As<IMaintenanceService>().PropertiesAutowired();
var container = builder.Build();
//var container = new AutofacContainer().Container;
var resolver = new AutofacDependencyResolver(container);
// Any connection or hub wire up and configuration should go here
app.MapSignalR(new HubConfiguration
{
Resolver = resolver,
EnableJSONP = true,
EnableDetailedErrors = true,
EnableJavaScriptProxies = true
});
builder.RegisterInstance(resolver.Resolve<IConnectionManager>());
}
}
How can this be correctly done?
You should tell SignalR explicitly to use the AutofacDependencyResolver when you are mapping it.
I assume that you know that in your Startup class you have to call app.MapSignalR();
When you are mapping it, you should tell it to use the custom dependency resolver (the AutofacDependencyResolver).
Here's how I do it:
var resolver = new AutofacDependencyResolver(container);
app.MapSignalR(new HubConfiguration
{
Resolver = resolver
});
This way, you are telling SignalR directly which dependency resolver to use.
I have a GitHub repo for SignalR Dependency Injection, but it's not configured to use MVC. Still, I think it will give you a hint in how to create your configuration.
Note: If you are using the OWIN Middleware, be sure not to use the GlobalHost static property AT ALL since it will have massive inconsistencies.
A common error in OWIN integration is use of the GlobalHost. In OWIN
you create the configuration from scratch. You should not reference
GlobalHost anywhere when using the OWIN integration.
Again, check the repo I gave you to see how to do this.
Hope this helps:)
Best of luck!
I ended up with this (pay attention to comments):
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
IContainer container = AutofacConfig(app);
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
DependencyResolver.SetResolver(new Autofac.Integration.Mvc.AutofacDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseAutofacWebApi(GlobalConfiguration.Configuration);
var hubConfiguration = new Microsoft.AspNet.SignalR.HubConfiguration()
{
// Resolve presolver from container
Resolver = container.Resolve<Microsoft.AspNet.SignalR.IDependencyResolver>(),
};
app.MapSignalR(hubConfiguration);
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
_
private static IContainer AutofacConfig(IAppBuilder app)
{
var builder = new ContainerBuilder();
RegisterSignalR(builder);
return builder.Build();
}
_
private static void RegisterSignalR(ContainerBuilder builder)
{
// Register Autofac resolver into container to be set into HubConfiguration later
builder.RegisterType<Autofac.Integration.SignalR.AutofacDependencyResolver>()
.As<Microsoft.AspNet.SignalR.IDependencyResolver>()
.SingleInstance();
// Register ConnectionManager as IConnectionManager so that you can get
// hub context via IConnectionManager injected to your service
builder.RegisterType<Microsoft.AspNet.SignalR.Infrastructure.ConnectionManager>()
.As<Microsoft.AspNet.SignalR.Infrastructure.IConnectionManager>()
.SingleInstance();
// Register hubs one by one
builder.RegisterType<MessageNotificationsHub>().ExternallyOwned();
builder.RegisterType<SystemNotificationsHub>().ExternallyOwned();
}
Thanks to #Nathan and his answer (originally found here) and logical thinking to figure out to register ConnectionManager as IConnectionManager
Install nuget package Autofac.SignalR, for example:
<package id="Autofac.SignalR" version="3.0.2" targetFramework="net471" />
Register your hubs
// during creation of the IContainer, register signalr hubs automatically
var executingAssembly = Assembly.GetExecutingAssembly();
builder.RegisterHubs(executingAssembly);
// alternatively register hubs individually
// ExternallyOwned() ensures SignalR is allowed to control disposal of the hubs rather than Autofac.
builder.RegisterType<NotificationHub>().ExternallyOwned();
Set signalr service locator
// replace the Signalr dependency resolver once your IContainer 'container' is ready
GlobalHost.DependencyResolver = new AutofacDependencyResolver(container);
// or this can alternatively be set in the HubConfiguration instance when using OWIN IAppBuilder map.RunSignalR(hubConfiguration);
var hubConfiguration = new HubConfiguration
{
Resolver = new AutofacDependencyResolver(container),
//...
}
For more information:
https://autofaccn.readthedocs.io/en/latest/integration/signalr.html
https://learn.microsoft.com/en-us/aspnet/signalr/overview/advanced/dependency-injection
Related
I am having a problem working out how to register dependencies in my NServiceBus endpoint. I am using NServiceBus 7.2 and Autofac 5.0 and NServiceBus.Autofac 7.0.0 and can't find any examples that use these versions. I am using Asp.Net Core 3.
My Program.cs code looks like this
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
My ConfigureServices method looks like this
public void ConfigureServices(IServiceCollection services)
{
services.InstallServicesInAssembly(Configuration);
services.AddAutoMapper(typeof(Startup));
services.AddMediatR(typeof(Startup).Assembly);
}
This runs all the installers I have but this runs BEFORE the ConfigureContainer method called by the Framework. AutoFac automatically adds all the services that have been added in COnfigureServices. I have a separate class for each installer. My ConfigureContainer method is currently empty since the Automapper and MediatR services are added anyway because the services are added in ConfigureServices. This resolves both IMediatR and IMapper when they are injected into the controllers of the Api. But they are not available in the NServiceBus Message Handlers. This is because I can't see how to register the endpoint configuration or share the Autofac container after it is created. See the NServiceBus installer code comment below.
//here we register stuff directly with autofac
public void ConfigureContainer(ContainerBuilder builder)
{
// Register your own things directly with Autofac, like:
//builder.AddAutoMapper(typeof(Startup).Assembly);
// builder.AddMediatR(typeof(Startup).Assembly);
}
I want to be able to make use of AutoMapper and MediatR in my NServiceBus Message Handlers and so want these dependencies injected into the constructors of the handlers.
And My NServiceBusInstaller is as follows
public class NServiceBusInstaller : IInstaller
{
public async void InstallServices(IServiceCollection services, IConfiguration configuration)
{
var rabbitMQSettings = new RabbitMQSettings();
configuration.Bind(nameof(rabbitMQSettings), rabbitMQSettings);
services.AddSingleton(rabbitMQSettings);
var endpointConfiguration = new EndpointConfiguration(rabbitMQSettings.SilvaDirectory);
endpointConfiguration.EnableInstallers();
//Here I want to configure the endpoint to use the dependencies in the AutoFac container
//How to get reference to this container??
/*
endpointConfiguration.UseContainer<AutofacBuilder>(
customizations: customizations => {
customizations.ExistingLifetimeScope(container);
});
*/
var transport = endpointConfiguration.UseTransport<RabbitMQTransport>();
transport.UseConventionalRoutingTopology();
transport.ConnectionString(rabbitMQSettings.ConnectionString);
transport.TimeToWaitBeforeTriggeringCircuitBreaker(TimeSpan.FromMinutes(1));
//services.AddNServiceBus(endpointConfiguration);
await Endpoint.Start(endpointConfiguration).ConfigureAwait(false);
}
}
ANd finally one of my message handlers looks like this. Currently I am getting an Exception because NServiceBus cannot resolve the IMapper and IMediator..
public class CreateDirectoryEntryHandler : IHandleMessages<CreateDirectoryEntry>
{
private readonly IMapper _mapper;
private readonly IMediator _mediator;
public CreateDirectoryEntryHandler(IMapper mapper, IMediator mediator)
{
_mapper = mapper;
_mediator = mediator;
}
public async Task Handle(CreateDirectoryEntry message, IMessageHandlerContext context)
{
var command = _mapper.Map<CreateNewCustomerCommand>(message);
CommandResponse response = await _mediator.Send(command);
if(response.Success)
{
await context.Reply(new DirectoryEntryCreated() { Email = message.Email }).ConfigureAwait(false);
}
else
{
await context.Reply(new DirectoryEntryRejected() { Email = message.Email, Error = response.Error }).ConfigureAwait(false);
}
}
}
I am probably missing something obvious. My mental block is because the ConfigureContainer method is called after the Configure services method by the framework so I don't have the container reference to pass in to the NServiceBus installer. What am I missing? Any help would be greatly appreciated.
Thanks
you might want to look at this sample https://docs.particular.net/samples/dependency-injection/aspnetcore/. It shows how to use Asp.Net Core 3 with NServiceBus and Autofac.
In your sample code, you use endpointConfiguration.UseContainer<AutofacBuilder>() API that assumes it's NServiceBus that controls the lifecycle of the DI container. This obviously isn't the case.
The sample uses NServiceBus.Extensions.Hosting and Autofac.Extensions.DependencyInjection packages. First, makes sure that NServiceBus can work with DI container that is managed externally by via Microsoft.Extensions.Hosting and the second is Autofac adapter for Microsoft DI abstractions.
Background:
I've used Castle Windsor with Installers and Facilities according to the Castle Windsor tutorial with earlier versions of MVC (pre-6) and WebAPI.
ASP.NET (5) Core has included some Dependency Injection support but I still haven't figured out exactly how to wire it up, and the few samples I have found look a lot different than how I've used it before (with the installers/facilities). Most examples predate ASP.NET (5) cores recent release and some seem to have outdated information.
It seems to have changed quite radically from the previous versions composition root setup, and not even Microsoft.Framework.DependencyInjection.ServiceProvider can resolve all of the dependencies when I set it as the Castle Windsor DI fallback. I'm still digging into the details but there isn't much up to date information.
My attempt to use Castle Windsor for DI
I've found an adapter like this: Github Castle.Windsor DI container.
Startup.cs
private static IWindsorContainer container;
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
{
container = new WindsorContainer();
app.UseServices(services =>
{
// ADDED app.ApplicationServices FOR FALLBACK DI
container.Populate(services, app.ApplicationServices);
container.BeginScope();
return container.Resolve<IServiceProvider>();
});
// ... default stuff
WindsorRegistration.cs
I added a few lines to add a Castle Windsor ILazyComponentLoader fallback.
using Castle.MicroKernel.Lifestyle;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;
using Castle.Windsor;
using Microsoft.Framework.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Notes.Infrastructure
{
/// <summary>
/// An adapted current autofac code to work with Castle.Windsor container.
/// https://github.com/aspnet/Home/issues/263
/// </summary>
public static class WindsorRegistration
{
public static void Populate(
this IWindsorContainer container,
IEnumerable<IServiceDescriptor> descriptors,
IServiceProvider fallbackProvider // ADDED FOR FALLBACK DI
)
{
// ADDED FOR FALLBACK DI
// http://davidzych.com/2014/08/27/building-the-castle-windsor-dependency-injection-populator-for-asp-net-vnext/
// Trying to add a fallback if Castle Windsor doesn't find the .NET stuff
var fallbackComponentLoader = new FallbackLazyComponentLoader(fallbackProvider);
container.Register(Component.For<ILazyComponentLoader>().Instance(fallbackComponentLoader));
// Rest as usual from the Github link
container.Register(Component.For<IWindsorContainer>().Instance(container));
container.Register(Component.For<IServiceProvider>().ImplementedBy<WindsorServiceProvider>());
container.Register(Component.For<IServiceScopeFactory>().ImplementedBy<WindsorServiceScopeFactory>());
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
Register(container, descriptors);
}
private static void Register(
IWindsorContainer container,
IEnumerable<IServiceDescriptor> descriptors)
{
foreach (var descriptor in descriptors)
{
if (descriptor.ImplementationType != null)
{
// Test if the an open generic type is being registered
var serviceTypeInfo = descriptor.ServiceType.GetTypeInfo();
if (serviceTypeInfo.IsGenericTypeDefinition)
{
container.Register(Component.For(descriptor.ServiceType)
.ImplementedBy(descriptor.ImplementationType)
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
else
{
container.Register(Component.For(descriptor.ServiceType)
.ImplementedBy(descriptor.ImplementationType)
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
}
else if (descriptor.ImplementationFactory != null)
{
var service1 = descriptor;
container.Register(Component.For(descriptor.ServiceType)
.UsingFactoryMethod<object>(c =>
{
var builderProvider = container.Resolve<IServiceProvider>();
return
service1.ImplementationFactory(builderProvider);
})
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
else
{
container.Register(Component.For(descriptor.ServiceType)
.Instance(descriptor.ImplementationInstance)
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
}
}
private static ComponentRegistration<object> ConfigureLifecycle(
this ComponentRegistration<object> registrationBuilder,
LifecycleKind lifecycleKind)
{
switch (lifecycleKind)
{
case LifecycleKind.Singleton:
registrationBuilder.LifestyleSingleton();
break;
case LifecycleKind.Scoped:
registrationBuilder.LifestyleScoped();
break;
case LifecycleKind.Transient:
registrationBuilder.LifestyleTransient();
break;
}
return registrationBuilder;
}
private class WindsorServiceProvider : IServiceProvider
{
private readonly IWindsorContainer _container;
public WindsorServiceProvider(IWindsorContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
return _container.Resolve(serviceType);
}
}
private class WindsorServiceScopeFactory : IServiceScopeFactory
{
private readonly IWindsorContainer _container;
public WindsorServiceScopeFactory(IWindsorContainer container)
{
_container = container;
}
public IServiceScope CreateScope()
{
return new WindsorServiceScope(_container);
}
}
private class WindsorServiceScope : IServiceScope
{
private readonly IServiceProvider _serviceProvider;
private readonly IDisposable _scope;
public WindsorServiceScope(IWindsorContainer container)
{
_scope = container.BeginScope();
_serviceProvider = container.Resolve<IServiceProvider>();
}
public IServiceProvider ServiceProvider
{
get { return _serviceProvider; }
}
public void Dispose()
{
_scope.Dispose();
}
}
}
}
First hiccup and resolution attempt
From that example I was getting:
An exception of type 'Castle.MicroKernel.ComponentNotFoundException' occurred in Castle.Windsor.dll but was not handled in user code
Additional information: No component for supporting the service Microsoft.Framework.Runtime.IAssemblyLoaderEngine was found
It wasn't available looking in the debugger at the Castle Fallback - Microsoft.Framework.DependencyInjection.ServiceProvider (table of services).
From http://davidzych.com/tag/castle-windsor/ I have tried to add a Fallback since Windsor couldn't resolve all of the ASP.NET dependencies.
FallbackLazyComponentLoader.cs
/// <summary>
/// https://github.com/davezych/DependencyInjection/blob/windsor/src/Microsoft.Framework.DependencyInjection.Windsor/FallbackLazyComponentLoader.cs
/// </summary>
public class FallbackLazyComponentLoader : ILazyComponentLoader
{
private IServiceProvider _fallbackProvider;
public FallbackLazyComponentLoader(IServiceProvider provider)
{
_fallbackProvider = provider;
}
public IRegistration Load(string name, Type service, IDictionary arguments)
{
var serviceFromFallback = _fallbackProvider.GetService(service);
if (serviceFromFallback != null)
{
return Component.For(service).Instance(serviceFromFallback);
}
return null;
}
}
It was seemingly necessary (to inject all the .NET dependencies)
I could comment out startup.cs app.UseBrowserLink(); to get rid of the IAssemblyLoaderEngine exception.
if (string.Equals(env.EnvironmentName, "Development", StringComparison.OrdinalIgnoreCase))
{
//app.UseBrowserLink(); //
Now I run into an exception:
An exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll but was not handled in user code
Trying to get the service: {Name = "IUrlHelper" FullName = "Microsoft.AspNet.Mvc.IUrlHelper"}
public IRegistration Load(string name, Type service, IDictionary arguments)
{
var serviceFromFallback = _fallbackProvider.GetService(service);
How to move forward?
What is wrong with this attempt to wire up Castle Windsor DI into ASP.NET (5) Core?
For now I don't think you can use Castle Windsor Container as the DI container because Windsor doesn't support the new DNVM. But AutoFac does and they follow the same rule.
In the Startup.cs there is a ConfigureServices method whose return type is void. You can change the return type to ISerivceProvider and return a concrete IServiceProvider, the system will use the new IServiceProvider as the default DI container. Below is the AutoFac example.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.Configure<AppSettings>(Configuration.GetSubKey("AppSettings"));
services.AddMvc();
var builder = new ContainerBuilder();
AutofacRegistration.Populate(builder, services);
var container = builder.Build();
return container.Resolve<IServiceProvider>();
}
The other DI adapters also implemented the similar interfaces. You can try yourself, but note AutoFac is in beta5 now so you need to make some adjustment to make your application run.
Hope this helps
There is a lot going on in your question, and to be honest I don't understand all of it.
However, there is a working Castle Windsor composition root in MvcSiteMapProvider that you are welcome reverse-engineer. Follow these steps to get a working composition root demo project for Windsor:
Create a new MVC 5 project.
Install MvcSiteMapProvider.MVC5.DI.Windsor.
Analyze the following files for the basic structure:
/App_Start/DIConfig.cs
/App_Start/CompositionRoot.cs
/DI/InjectableControllerFactory.cs
/DI/Windsor/WindsorDependencyInjectionContainer.cs
/DI/Windsor/Installers/MvcInstaller.cs
/DI/Windsor/Installers/MvcSiteMapProviderInstaller.cs
Once you have this working configuration, you can then refactor it and add to it to suit your application's needs.
As I recall, there weren't any changes required to make the MVC 4 DI configuration work with MVC 5. So, the problem you are running into is most likely one of the following:
You are using a 3rd party DI component that is not compatible with MVC 5.
You are using DependencyResolver, and your configuration doesn't include the necessary code to resolve the dependencies of MVC 5.
You are using advanced features of Castle Windsor that we are not using, and have them misconfigured in some way.
ControllerFactory vs DependencyResolver
Do note that according to Dependency Injection in .NET by Mark Seemann (which I highly recommend), it is ill-advised to use IDependencyResolver with Castle Windsor because it guarantees resource leaks. In fact, this is probably the most compelling argument that he makes for his reasoning for declaring service locator as anti-pattern.
The recommended approach is to use IControllerFactory as the integration point into MVC, which implements a ReleaseController method to solve this issue.
So looking at your code, literally all of it can be replaced by Castle.Windsor.MsDependencyInjection library.
Add Castle.Windsor.MsDependencyInjection to your project then use like so:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Normal component registration can go here...
return WindsorRegistrationHelper.CreateServiceProvider(yourWindsorContainer, services);
}
I gets '..make sure that the controller has a parameterless public constructor autofac..'
My controller:
public class AccountController : ApiController
{
private IAccountService _accountService;
public AccountController(IAccountService accountService)
{
_accountService = accountService;
}
...
}
My autofac configuration:
protected void Application_Start()
{
var builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<AccountService>().As<IAccountService>().InstancePerRequest();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
Whats wrong with my code?
Full error message:
Exception=System.InvalidOperationException: An error occurred when trying to create a controller of type 'AccountController'. Make sure that the controller has a parameterless public constructor. ---> Autofac.Core.DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'MyProj.Api.Controllers.AccountController' can be invoked with the available services and parameters:
Cannot resolve parameter 'MyProj.Engine.Services.Interfaces.IAccountService accountService' of constructor 'Void .ctor(MyProj.Engine.Services.Interfaces.IAccountService)'.
Fixed myself. Actually the issue was that project is Azure Mobile Service.
It was my first experience with it and I have configured it as I used to do for WebApi. But as I understood after last googling this project type base on OWIN.
That's good article about: http://blogs.msdn.com/b/azuremobile/archive/2014/04/19/autofac-and-azure-mobile-services-net-backend.aspx
So it should be like this:
ConfigOptions options = new ConfigOptions();
ConfigBuilder builder = new ConfigBuilder(options, (httpConfig, autofac) =>
{
autofac.RegisterInstance(new MyService()).As<IMyService>();
});
HttpConfiguration config = ServiceConfig.Initialize(builder);
Can someone please tell me the exact role of the OWIN startup class. Basically what I am looking for :
Whats its purpose
When is it called, it is just once or per request
Is this a good place to configure my Dependency Injection library.
Owin is designed to be pluggable deisgn. there are a set of services which you can change/replace from the configuration. For example in the following configuration, i have
enabled webapi
Enabled Signalr
Enabled Attribute Based routing for Signalr
Configured default Dependency Resolver
Replaced Logging service with custom logger
So , this way, you can configure the complete configuration. It will be called only once at startup. You can set/use dependency resolver and configure it here, but that depends mainly on your overall design.
public class OwinStartup
{
//initialize owin startup class and do other stuff
public void Configuration(IAppBuilder app)
{
app.UseWelcomePage("/");
//var container = new UnityContainer();
HttpConfiguration httpConfiguration = new HttpConfiguration();
httpConfiguration.Routes.MapHttpRoute(
name: "MyDefaultApi",
routeTemplate: "api/v2/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//Maps the attribute based routing
httpConfiguration.MapHttpAttributeRoutes();
//Set the unity container as the default dependency resolver
httpConfiguration.DependencyResolver = new UnityWebApiDependencyResolver(new UnityContainer());
//replace (or add) the exception logger service to custom Logging service
httpConfiguration.Services.Replace(typeof(IExceptionLogger), new ExLogger());
app.UseWebApi(httpConfiguration);
//Add Signalr Layer
app.MapSignalR(new HubConfiguration
{
EnableJSONP = true,
EnableDetailedErrors = true
});
}
public class ExLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
base.Log(context);
//do something
}
}
}
I have a WebAPI Controller which has a dependency on another class:
public class HealthCheckController : System.Web.Http.ApiController
{
private readonly IHealthCheckReport _healthCheckReport;
public HealthCheckController(IHealthCheckReport healthCheckReport)
{
this._healthCheckReport = healthCheckReport;
}
}
I'm using Autofac and inside the Register method of my WebApiConfig class, I've added:
var builder = new ContainerBuilder();
builder.RegisterType<HealthCheckReport>().As<IHealthCheckReport>();
var container = builder.Build();
// Set the dependency resolver for Web API.
var webApiResolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = webApiResolver;
But when I call the Index() action, it complains that my controller doesn't have a default constructor. Whereas, I expected Autofac just magically inject the type I have registered above.
How should this be configured?
You need to register the api controller too.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
Source: http://code.google.com/p/autofac/wiki/WebApiIntegration