How can I get started with ASP.NET (5) Core and Castle Windsor for Dependency Injection? - dependency-injection

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);
}

Related

Registering Dependency with in NServiceBus with Autofac after upgrade

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.

How to add a custom ModelMetadataDetailsProvider that has a dependency that needs to be resolved by Autofac?

I'm trying to add a custom ModelMetadataDetailsProvider, but the provider implementation has dependencies that need to be resolved by the Service Provider (Autofac). If I Add the ModelMetadataDetailsProvider in ConfigureServices, I have to instantiate and manually provide all of the dependencies, some of which are singleton and are AutoActivated, so that won't work... Is it possible to add a ModelMetadataDetailsProvider outside of ConfigureServices?
It doesn't appear that this can be configured using DI, so the only thing I can think of is to use the Service Locator Anti Pattern to provide the dependencies when they are needed instead of in the constructor. Is there a more acceptable way to accomplish this?
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddMvcOptions(options => {
options.ModelMetadataDetailsProviders.Add(new MyProvider(???))
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddControllersAsServices();
services.AddAutofac();
ApplicationContainer = BuildContainer(services);
return new AutofacServiceProvider(ApplicationContainer);
}
public IContainer BuildContainer(IServiceCollection services)
{
var builder = new ContainerBuilder();
builder.Populate(services);
builder.RegisterType<HttpContextAccessor>()
.As<IHttpContextAccessor>()
.SingleInstance();
builder.RegisterType<DataAccess>()
.As<IDataAccess>()
.WithParameter("connectionString", Configuration.GetConnectionString("DatabaseContext"))
.InstancePerLifetimeScope();
....
builder.RegisterType<D1>()
.As<ID1>();
builder.RegisterType<D2>()
.As<ID2>();
builder.RegisterType<D3>()
.As<ID3>();
builder.RegisterType<MyProvider>()
.As<IMyProvider>();
}
public interface IMyProvider : IDisplayMetadataProvider
{
...
}
public class MyProvider : IMyProvider
{
public MyProvider (ID1 d1, ID2 d2, ID3 d3)
{
...
}
public void CreateDisplayMetadata(DisplayMetadataProviderContext context)
{
...
}
}
You can achieve this by creating a class that implements the IConfigureOptions<MvcOptions> interface:
public class AddCustomModelMetadataDetailsProvider : IConfigureOptions<MvcOptions>
{
private readonly MyCustomModelMetadataDetailsProvider _provider;
public AddCustomModelMetadataDetailsProvider(MyCustomModelMetadataDetailsProvider provider)
{
_provider = provider;
}
public void Configure(MvcOptions options)
{
options.ModelMetadataDetailsProviders.Add(_provider);
}
}
and register it as such in the Configure method:
services.AddTransient<IConfigureOptions<MvcOptions>, AddCustomModelMetadataDetailsProvider>();
The benefit of this approach, as you can see, is that you can use regular constructor injection in the AddCustomModelMetadataDetailsProvider class to get the instance of the service you're interested in.
ASP.NET automatically calls the Configure methods of all the IConfigureOptions<MvcOptions> services registered in the container.
Because creating these classes can be time-consuming, ASP.NET Core 2.2 introduced new overloads which allow you to do the following:
services
.AddOptions<MvcOptions>()
.Configure<MyCustomModelMetadataDetailsProvider>((options, customMetadataDetailsProvider) =>
{
options.ModelMetadataDetailsProviders.Add(customMetadataDetailsProvider);
});
In that case, customMetadataDetailsProvider would be resolved from the container.
You can include up to 5 services to configure your options. See this official documentation page.

How do you bind the dependencies of the service dll's at that layer in .NET Core

I would like to make a contained libraries/services in the new .NET Core world. Basically I have several SASS products:
ServiceProduct1: has a repository layer that the UI/Composistion root layer doesn't need to know about.
ServiceProduct2: has a repository layer that the UI/Composistion root layer doesn't need to know about. Has an Email service in it as well.
These two service products are used in multiple applications, but the consuming application has to know to bind the interfaces hidden in the repository. Also the Email service uses Dependency Injection and it has to be
bound in the consuming application, even though it is used by a service.
Prior to .NET Core I would have used Recursion to search the dlls for things to bind:
public static IKernel LoadAssemblies(IKernel kernel)
{
var type = typeof(INinjectDependency);
var dependencies = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetMatchingTypesInAssembly(y => type.IsAssignableFrom(y) && y.IsClass));
var assemblies = dependencies.Select(Assembly.GetAssembly).Distinct();
kernel.Load(assemblies);
return kernel;
}
Then in the consumed services you would do all your binding.
I am not using Ninject any longer but the concept is the same. Now unless you swap to publish the dll's on build, you cannot use this approach anymore. I do not want to publish my dll's.
Is there another way to handle this?
A lot of the documentation floating around points specifically to the implementation of ASP.NET Core, so I can see why this is confusing. The answer is rather simple. If your services are full executables, i.e.; when compiled they generate an *.exe then you need to wire-up you services at startup - somewhere near the main entry point. If your service is simply a *.dll, then you must have a host application (executable) that wires up the dependencies for you - and then hands you the service collection, such that you can construct an IServiceProvider.
Here is a great article on Dependency Injection with .NET Core. Here is the example of how you would achieve this:
public class Host
{
public static void Main()
{
IServiceCollection serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
var application = new Application(serviceCollection);
// Run
// ...
}
static void ConfigureServices(
IServiceCollection serviceCollection)
{
ILoggerFactory loggerFactory = new Logging.LoggerFactory();
serviceCollection.AddInstance<ILoggerFactory>(loggerFactory);
}
}
There are some standard naming conventions here, notice the ConfigureServices. Then the Application object is defined as such:
public class Application
{
public IServiceProvider Services { get; set; }
public ILogger Logger { get; set; }
public Application(IServiceCollection serviceCollection)
{
ConfigureServices(serviceCollection);
// The service-provider is not built until all services are configured.
Services = serviceCollection.BuildServiceProvider();
Logger =
Services.GetRequiredService<ILoggerFactory>()
.CreateLogger<Application>();
Logger.LogInformation("Application created successfully.");
}
public void MakePayment(PaymentDetails paymentDetails)
{
Logger.LogInformation(
$"Begin making a payment { paymentDetails }");
IPaymentService paymentService =
Services.GetRequiredService<IPaymentService>();
// ...
}
void ConfigureServices(IServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<IPaymentService, PaymentService>();
}
}
We can now imagine that the interface and corresponding implementation of the payment service looks something like this:
public class PaymentService: IPaymentService
{
public ILogger Logger { get; }
public PaymentService(ILoggerFactory loggerFactory)
{
Logger = loggerFactory?.CreateLogger<PaymentService>();
if (Logger == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
Logger.LogInformation("PaymentService created");
}
}
Note
This does not have to be an ASP.NET Core application.

How to use RavenDB queries in Data Layer or Classes?

I have setup RavenDB embedded in my MVC application. I follower all the tutorials to make the RavenController and I can query the Session in the controller.
Now I would really like to break away from mixing data in the controller and create a Data layer so that I can do some Business logic which will help me create complex View Models.
How do I query the Session in a plain class file? I can't seem to find any info on how to do this.
Dependency Injection is great for this. You move aside the creation of the necessary services and let the container manage the lifecycle of the components, including scoping IDocumentSession to one instance per HTTP request.
As an example, using Autofac (you'd need both the Autofac and Autofac.Mvc5 packages) you could have a class in your App_Start folder like this, and then call AutofacConfig.Configure() from your Global.asax:
public static class AutofacConfig
{
public static IContainer Container { get; private set; }
public static void Configure()
{
var builder = new ContainerBuilder();
var thisAssembly = Assembly.GetExecutingAssembly();
// Register our controllers with the container
builder.RegisterControllers(thisAssembly).PropertiesAutowired(PropertyWiringOptions.PreserveSetValues);
// Provide injections of the HTTP abstractions (HttpContextBase, etc.)
builder.RegisterModule(new AutofacWebTypesModule());
// Create and register the Raven IDocumentStore
builder.Register(c =>
{
var store = new DocumentStore {ConnectionStringName = "RavenDB"};
store.Initialize();
Raven.Client.Indexes.IndexCreation.CreateIndexes(typeof (MvcApplication).Assembly, store);
return store;
})
.As<IDocumentStore>()
.SingleInstance();
// Provide injection of Raven IDocumentSession
builder.Register(c => c.Resolve<IDocumentStore>().OpenSession())
.InstancePerRequest();
Container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(Container));
}
}
Then, when you need an IDocumentSession some place outside of a controller:
// Business logic, or other class that injection is not provided for.
var session = AutofacConfig.Container.Resolve<IDocumentSession>();
Also include autofac otherwise you will get an error saying "does not contain definition Resolve ..."
using Autofac;
You can do similar things with most other DI container libraries; the API is just slightly different.
HttpContext.Current.Session holds current session, but you should definitely not use it in business logic layer. Business logic layer should not be aware of HttpContext.
Basic solution to this problem would be to create interface:
public interface ISession
{
int SomeValue { get; set; }
}
and implementation
public class HttpContextBasedSession : ISession
{
public int SomeValue
{
get
{
return Convert.ToInt32(HttpContext.Current.Session["SomeValue"]);
}
set
{
HttpContext.Current.Session["SomeValue"] = value;
}
}
}
Bind it with dependency injection framework.

Hook Unity into Web API Filter Attributes

I have Unity running great for all the controllers in my ASP.NET Web API project - just using the default set up that comes out of the NuGet box. I have also managed to hook it up to MVC Filter Attributes - but can't seem to do the same for ASP.NET Web API filter attributes.
How to I extend this default implementation to inject a dependency into an ActionFilterAttribute, for example...
public class BasicAuthenticationAttribute : ActionFilterAttribute
{
[Dependency]
public IMyService myService { get; set; }
public BasicAuthenticationAttribute()
{
}
}
This filter is applied to controllers using attributes:
[BasicAuthentication]
I'm pretty sure I need to hook up the Unity container so it handles the creation of the attribute class, but need some clues about where to start as it does not use the same extensibility points as the MVC filters.
I just wanted to add, other things I have tried include service location rather than dependency injection, but the DependencyResolver you get back is not the same one you configure.
// null
var service = actionContext.Request.GetDependencyScope().GetService(typeof(IMyService));
Or
// null
var service = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IApiUserService));
The problem is that the Attribute class is created by .NET and not by the WebAPI framework.
Before reading farther, did you forget to configure your DependencyResolver with your IApiUserService?
(IUnityContainer)container;
container.RegisterType<IApiUserService, MyApiUserServiceImpl>();
...
var service = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IApiUserService));
I created an App_Start\UnityConfig class that holds my UnityContainer:
public class UnityConfig {
#region Unity Container
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() => {
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Gets the configured Unity container.
/// </summary>
public static IUnityContainer GetConfiguredContainer() {
return container.Value;
}
#endregion
public static void Configure(HttpConfiguration config) {
config.DependencyResolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
}
/// <summary>Registers the type mappings with the Unity container.</summary>
/// <param name="container">The unity container to configure.</param>
/// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to
/// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
private static void RegisterTypes(IUnityContainer container) {
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your types here
// container.RegisterType<IProductRepository, ProductRepository>();
container.RegisterType<MyClass>(new PerRequestLifetimeManager(), new InjectionConstructor("connectionStringName"));
}
}
The UnityDependencyResolver and PerRequestLifetimeManager came from this blog post and Unity.WebApi (Project/Nuget Package) which I internalized. (since it's a bootstrap)
When I need to make use of the UnityContainer in my other code, I passed it into the constructor:
config.Filters.Add(new MyFilterAttribute(UnityConfig.GetConfiguredContainer()));

Resources