generik0 / Windsor.AspNetCore

An experimental facility for integrating windsor as a non-conforming container into aspnet core

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ASPNET Core Facility

The ASPNET Core facility provides Castle Windsor integration using a custom activators for .NET Core web based projects.

How does it work?

Custom activators are injected into the ASPNET Core framework when the services.AddCastleWindsor(container) extension is called from the ConfigureServices(IServiceCollection services) method in the Startup class. This allows components to be resolved from Windsor when web requests are made to the server.

This method also adds a sub resolver for dealing with the resolution of ASPNET Core framework types. An example might be something like an ILoggerFactory. It is important to note that this extension also injects custom middleware for the management of scoped lifestyles. This middleware calls the WindsorContainer.BeginScope extension. It will also dispose the scope once the request is completed.

Controllers, ViewComponents and TagHelpers are registered automatically for you when the app.UseCastleWindsor<Startup>(container) extension is called from the Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) method in the Startup class. Controllers are registered with a scoped lifestyle, and are assumed to be a single instance for the duration of the web request. The ViewComponents and TagHelpers however are transient. It is assumed that they will called multiple times for a single request and cannot share state.

If you would like to change the lifestyles of any of these components it is recommended that you do not call app.UseCastleWindsor<Startup>(container) extension. Instead you can opt for your own conventional registrations like so:

container.Register(Classes.FromAssemblyInThisApplication(typeof(TStartup).Assembly)
	.BasedOn<Controller>().LifestyleScoped());
container.Register(Classes.FromAssemblyInThisApplication(typeof(TStartup).Assembly)
	.BasedOn<ViewComponent>().LifestyleTransient());
container.Register(Classes.FromAssemblyInThisApplication(typeof(TStartup).Assembly)
	.BasedOn<TagHelper>().LifestyleTransient());

It is also very important to note that you should never register any framework services in Windsor. This is handled by the framework for you. In the case of ILoggerFactory mentioned earlier, you will notice it is not installed anywhere in the Startup.cs example below.

What do I need to set it up?

You will need to install the Castle.Facilities.AspNetCore nuget, after which you can add the missing code to your Startup.cs. Here is a complete example:

public class Startup
{
	private readonly WindsorContainer container = new WindsorContainer();

	public Startup(IHostingEnvironment env)
	{
		var builder = new ConfigurationBuilder()
			.SetBasePath(env.ContentRootPath)
			.AddJsonFile("appsettings.json", true, true)
			.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true)
			.AddEnvironmentVariables();

		Configuration = builder.Build();
	}

	public IConfigurationRoot Configuration { get; }

	// This method gets called by the runtime. Use this method to add services to the container.
	public void ConfigureServices(IServiceCollection services)
	{
		// Add framework services.
		services.AddMvc();
		services.AddCastleWindsor(container); // <- Registers activators
	}

	// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
	public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
	{
		app.UseCastleWindsor<Startup>(container); // <- Registers controllers, view components and tag helpers

		RegisterApplicationComponents();

		// Add custom middleware
		app.UseCastleWindsorMiddleware<CustomMiddleware>(container);

		app.UseStaticFiles();

		app.UseMvc(routes =>
		{
			routes.MapRoute(
				"default",
				"{controller=Home}/{action=Index}/{id?}");
		});
	}

	private void RegisterApplicationComponents()
	{
		// Custom Windsor registrations
		container.Register(Component.For<IUserService>().ImplementedBy<AspNetUserService>().LifestyleScoped());
	}
}

public interface IUserService { }

public class AspNetUserService : IUserService { }

// Example of some custom user-defined middleware component.
public sealed class CustomMiddleware : ICastleWindsorMiddleware
{
	private readonly IUserService userService;

	public CustomMiddleware(ILoggerFactory loggerFactory, IUserService userService)
	{
		this.userService = userService;
	}

	public async Task Invoke(HttpContext context, Func<Task> next)
	{
		// Do something before
		await next();
		// Do something after
	}
}

Special credit goes to @dotnetjunkie for pioneering the discussions with the ASPNET team for non-confirming containers and providing valuable input on issue: castleproject/Windsor#120

About

An experimental facility for integrating windsor as a non-conforming container into aspnet core

License:Apache License 2.0


Languages

Language:C# 98.6%Language:CSS 1.3%Language:JavaScript 0.1%