-
-
Save tulbox/3aa080990536b1439d8aacc97e2be425 to your computer and use it in GitHub Desktop.
Inject Castle Windsor Dependencies into ASP.NET Web API Filter C#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Web.Http; | |
using System.Web.Http.Controllers; | |
using System.Web.Http.Filters; | |
using Castle.Windsor; | |
using Algorythmic.Web.API.Filters; | |
namespace Algorythmic.Web.API.Windsor.Filters | |
{ | |
/// <summary> | |
/// Custom filter provider for actions that include injected dependencies. | |
/// </summary> | |
public class ConfigurableFilterProvider : IFilterProvider | |
{ | |
private readonly IWindsorContainer _container; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="ConfigurableFilterProvider"/> class. | |
/// </summary> | |
public ConfigurableFilterProvider() | |
{ | |
} | |
/// <summary> | |
/// Initializes a new instance of the <see cref="ConfigurableFilterProvider"/> class. | |
/// </summary> | |
/// <param name="container">The container.</param> | |
internal ConfigurableFilterProvider(IWindsorContainer container) | |
{ | |
_container = container; | |
} | |
/// <summary> | |
/// Returns an enumeration of filters. | |
/// </summary> | |
/// <param name="configuration">The HTTP configuration.</param> | |
/// <param name="actionDescriptor">The action descriptor.</param> | |
/// <returns> | |
/// An enumeration of filters. | |
/// </returns> | |
public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor) | |
{ | |
List<FilterInfo> filters = new List<FilterInfo>(ConfigureGlobalFilters()); | |
filters.AddRange(ConfigureLocalFilters(actionDescriptor.GetFilters(), FilterScope.Action)); | |
filters.AddRange(ConfigureLocalFilters(actionDescriptor.ControllerDescriptor.GetFilters(), FilterScope.Controller)); | |
return filters; | |
} | |
/// <summary> | |
/// Configures the local filters. | |
/// </summary> | |
/// <param name="filters">The filters.</param> | |
/// <param name="scope">The scope.</param> | |
/// <returns>A list of filters or an empty list if none were found.</returns> | |
private IEnumerable<FilterInfo> ConfigureLocalFilters(IEnumerable<IFilter> filters, FilterScope scope) | |
{ | |
Debug.Assert(filters != null); | |
foreach (IFilter filter in filters) | |
{ | |
if (filter is LogUncaughtExceptionFilterAttribute) | |
{ | |
yield return new FilterInfo( | |
(LogUncaughtExceptionFilterAttribute)_container.Resolve(filter.GetType()), scope); | |
} | |
else | |
{ | |
yield return new FilterInfo(filter, scope); | |
} | |
} | |
} | |
/// <summary> | |
/// Configures global filters, e.g. those that are registered using config.Filters.Add(..). | |
/// </summary> | |
/// <returns>A list of filters or an empty list if none were found.</returns> | |
private IEnumerable<FilterInfo> ConfigureGlobalFilters() | |
{ | |
foreach (FilterInfo filter in GlobalConfiguration.Configuration.Filters) | |
{ | |
if (filter.Instance is LogUncaughtExceptionFilterAttribute) | |
{ | |
yield return new FilterInfo( | |
(LogUncaughtExceptionFilterAttribute)_container.Resolve(filter.Instance.GetType()), FilterScope.Global); | |
} | |
else | |
{ | |
yield return filter; | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Linq; | |
using System.Web.Http; | |
using System.Web.Http.Dispatcher; | |
using System.Web.Http.Filters; | |
using Castle.Facilities.Logging; | |
using Castle.MicroKernel.Registration; | |
using Castle.Windsor; | |
using Castle.Windsor.Installer; | |
using Algorythmic.Web.API.Windsor.Filters; | |
namespace Algorythmic.Web.API.Windsor | |
{ | |
/// <summary> | |
/// Contains startup functionality for use with the dependency container. | |
/// </summary> | |
internal static class ContainerContext | |
{ | |
internal static readonly IWindsorContainer Container = new WindsorContainer(); | |
/// <summary> | |
/// Configures the specified container. | |
/// </summary> | |
public static IWindsorContainer Configure() | |
{ | |
Container.Install(FromAssembly.This()); | |
Container.Register(Classes.FromThisAssembly().BasedOn<ApiController>().LifestyleTransient()); | |
Container.AddFacility<LoggingFacility>(f => f.LogUsing(LoggerImplementation.Log4net).WithAppConfig()); | |
// setup injection for API controllers | |
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new CompositionRoot(Container)); | |
// setup injection for filters | |
ConfigureFilters(); | |
return Container; | |
} | |
/// <summary> | |
/// Configures the filters by injecting any required dependencies. | |
/// </summary> | |
private static void ConfigureFilters() | |
{ | |
// remove default providers; prevents filters from being executed twice per scope | |
IFilterProvider defaultActionProvider = | |
GlobalConfiguration.Configuration.Services.GetFilterProviders() | |
.First(i => i is ActionDescriptorFilterProvider); | |
IFilterProvider globalConfigurationProvider = | |
GlobalConfiguration.Configuration.Services.GetFilterProviders() | |
.First(i => i is ConfigurationFilterProvider); | |
GlobalConfiguration.Configuration.Services.Remove(typeof(IFilterProvider), defaultActionProvider); | |
GlobalConfiguration.Configuration.Services.Remove(typeof(IFilterProvider), globalConfigurationProvider); | |
// add custom provider | |
GlobalConfiguration.Configuration.Services.Add(typeof(IFilterProvider), new ConfigurableFilterProvider(Container)); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Castle.MicroKernel.Registration; | |
using Castle.MicroKernel.SubSystems.Configuration; | |
using Castle.Windsor; | |
using Algorythmic.Web.API.Filters; | |
namespace Algorythmic.Web.API.Windsor.Installers | |
{ | |
/// <summary> | |
/// Installs <see cref="LogUncaughtExceptionFilterAttribute"/> dependencies. | |
/// </summary> | |
public class ExceptionFilterInstaller : IWindsorInstaller | |
{ | |
/// <summary> | |
/// Performs the installation in the <see cref="T:Castle.Windsor.IWindsorContainer" />. | |
/// </summary> | |
/// <param name="container">The container.</param> | |
/// <param name="store">The configuration store.</param> | |
public void Install(IWindsorContainer container, IConfigurationStore store) | |
{ | |
container.Register( | |
Component.For<LogUncaughtExceptionFilterAttribute>().LifestyleTransient()); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics.CodeAnalysis; | |
using System.Net; | |
using System.Net.Http; | |
using System.Web.Http.Filters; | |
using Castle.Core.Logging; | |
namespace Algorythmic.Web.API.Filters | |
{ | |
/// <summary> | |
/// Filter for handling otherwise uncaught <see cref="Exception"/> occurences. | |
/// </summary> | |
public class LogUncaughtExceptionFilterAttribute : ExceptionFilterAttribute | |
{ | |
private ILogger _logger = NullLogger.Instance; | |
/// <summary> | |
/// Gets or sets the logger. | |
/// </summary> | |
/// <value> | |
/// The logger. | |
/// </value> | |
[ExcludeFromCodeCoverage] | |
public ILogger Logger | |
{ | |
get { return _logger; } | |
set { _logger = value; } | |
} | |
/// <summary> | |
/// Gets a value that indicates whether multiple filters are allowed. | |
/// </summary> | |
/// <returns>true if multiple filters are allowed; otherwise, false.</returns> | |
public override bool AllowMultiple | |
{ | |
get { return false; } | |
} | |
/// <summary> | |
/// Raises the exception event. | |
/// </summary> | |
/// <param name="context">The context for the action.</param> | |
public override void OnException(HttpActionExecutedContext context) | |
{ | |
Exception ex = context.Exception; | |
if (ex != null) | |
{ | |
Logger.Fatal(ex.Message, ex); | |
context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment