Unity Container for holding User Session objects MVC - c#

I'm buold MVC4 C# website.
I have base controller with constructor
public BaseController(IUnityContainer container, SessionContext context)
The problem is that container is shared globally and when i try to resolve or register objects they are shared through sessions. On the other hand SessionContext (parameter) comes only is unique to user session. I want container to be unique for user sessions (to be able resolve unique objects for user sessions), but i don't know how to implement it.
I have UnityControllerFactory as follows:
public class UnityControllerFactory : DefaultControllerFactory
{
private IUnityContainer container;
public UnityControllerFactory(IUnityContainer container){
this.container = container;
this.RegisterTypes();
}
protected override IController GetControllerInstance(RequestContext context, Type controllerType)
{
if (controllerType != null)
{
return this.container.Resolve(controllerType) as IController;
}
return null;
}
private void RegisterTypes(){
container.RegisterType<SessionContext>(new UnityPerSessionLifetimeManager("private.SessionContext"));
container.RegisterType<DataService>(new UnityPerSessionLifetimeManager("private.Service"));
}
}
and lifetime manager
public class UnityPerSessionLifetimeManager : LifetimeManager
{
private string sessionKey;
public UnityPerSessionLifetimeManager(string sessionKey)
{
this.sessionKey = sessionKey;
}
public override object GetValue()
{
return HttpContext.Current.Session[this.sessionKey];
}
public override void RemoveValue()
{
HttpContext.Current.Session.Remove(this.sessionKey);
}
public override void SetValue(object newValue)
{
HttpContext.Current.Session[this.sessionKey] = newValue;
}
}

Related

Dependency Injection in Xamarin.Android

I am working on a Xamarin.Android project developed by another developer. I got to know that they have used Dependancy Injection. There is a class like this
public class RemoteSupportHandler : DataAccessor<FwDataContext>, IRemoteSupportSettingHandler
{
private RemoteSupportSetting[] _cached;
public RemoteSupportHandler(IDatabaseController db, ILogger logger, IPerfLogger perfLogger)
: base(db, logger, perfLogger)
{
}
public async Task<RemoteSupportSetting> GetRemoteSupportDemoVideoUrlAsync()
{
return await WithDataContextAsync(ctx =>
{
return (from row in ctx.RemoteSupportSettings
where row.ParamName == "DEMO_VIDEO"
select new RemoteSupportSetting
{
ParamName = row.ParamName
}).FirstOrDefault();
});
}
}
In another file, they have registered this class with UnityContainer. Now I want to call this GetRemoteSupportDemoVideoUrlAsync() method from my Activity. I know I cannot create an object using this constructor. I have no idea how I should I do this.
Registration Code
public class Registrar : IRegistrar {
protected virtual void OnApplyInitializedRegistrations(IUnityContainer container) {
container.RegisterType<IRemoteSupportSettingHandler, RemoteSupportHandler>(new ContainerControlledLifetimeManager());
}
}
public interface IRegistrar
{
void ApplySessionRegistrations(IUnityContainer container);
void ApplyInitializedRegistrations(IUnityContainer container);
}
UPDATE 2
public abstract class MyApplication : Application, IPlatformApplication {
public IUnityContainer AppUnityContainer => _container;
protected virtual void OnLaunched()
{
IActivityService activityService = new ActivityService(this);
AppUnityContainer.RegisterInstance(activityService);
AppUnityContainer.RegisterType<IRegistrar, PlatformRegistrar>();
}
}

MVC MEF Error: Make sure that the controller has a parameterless public constructor

For MVC app using MEF, sometimes I get the erorr ""
I have a .NET solution with
One MVC Web application project and,
Many class libraries projects which take care of authentication, getting configurations, making external API calls etc.
I have configured the MEF as shown below through the code and deployed this on Web Server using IIS. Observed the below error couple of times, after which I tried to load the page multiple times but it still throws the same error.
Once I refreshed the application pool, then only the error disappears. I had been trying hard to debug and understand the error, but with no success. Am I misconfiguring MEF anywhere?
Global.asax:
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
var pluginFolders = LoadMefComponents();
Bootstrapper.Compose(pluginFolders);
IControllerFactory mefControllerFactory = new MefControllerFactory(Bootstrapper.Container);
ControllerBuilder.Current.SetControllerFactory(mefControllerFactory);
}
protected List<string> LoadMefComponents()
{
var pluginFolders = new List<string>();
string ModulesPath = CommonUtility.GetApplicationDirectory();
var plugins = Directory.GetDirectories(ModulesPath).ToList();
plugins.ForEach(path =>
{
var directoryInfo = new DirectoryInfo(path);
pluginFolders.Add(directoryInfo.Name);
});
return pluginFolders;
}
}
MEFControllerFactory.cs: This file resides in App_Start
public class MefControllerFactory : DefaultControllerFactory
{
private readonly CompositionContainer _container;
private readonly Dictionary<IController, Lazy<object, object>> exports;
private readonly object syncRoot;
public MefControllerFactory(CompositionContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this._container = container;
this.exports = new Dictionary<IController, Lazy<object, object>>();
this.syncRoot = new object();
}
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
Lazy<object, object> export = _container.GetExports(controllerType, null, null).FirstOrDefault();
var controller = null == export ? base.GetControllerInstance(requestContext, controllerType)
: (IController)export.Value;
lock (this.syncRoot)
{
this.exports.Add(controller, export);
}
return controller;
}
public override void ReleaseController(IController controller)
{
lock (this.syncRoot)
{
var export = this.exports[controller];
this.exports.Remove(controller);
// this._container.ReleaseExport(export);
}
((IDisposable)controller).Dispose();
}
}
Bootstrapper.cs: This file resides in App_Start
public class Bootstrapper
{
private static CompositionContainer compositionContainer;
private static bool IsLoaded = false;
public static CompositionContainer Container
{
get { return compositionContainer; }
set { compositionContainer = value; }
}
public static void Compose(List<string> pluginFolders)
{
if (IsLoaded) return;
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
catalog.Catalogs.Add(new DirectoryCatalog(CommonUtility.GetApplicationDirectory()));
compositionContainer = new CompositionContainer(catalog);
compositionContainer.ComposeParts();
IsLoaded = true;
}
public static T GetInstance<T>(string contractName = null)
{
var type = default(T);
if (compositionContainer == null) return type;
if (!string.IsNullOrWhiteSpace(contractName))
type = compositionContainer.GetExportedValue<T>(contractName);
else
type = compositionContainer.GetExportedValue<T>();
return type;
}
}
CommonUtility.cs: This file resides in App_Start
public class CommonUtility
{
public static string GetApplicationDirectory()
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
}
HomeController.cs:
[CommonExceptionFilter]
public class HomeController : Controller
{
private IConfigurationManager _configurationManager;
[ImportingConstructor]
public HomeController()
{
_configurationManager = Bootstrapper.GetInstance<IConfigurationManager>();
}
public async Task<ActionResult> Index()
{
//Business Logic
return View()
}
}
IConfigurationManager.cs
[InheritedExport]
public interface IConfigurationManager
{
string GetConfigurationValue(string keyName)
}
ConfigurationManager.cs
[PartCreationPolicy(CreationPolicy.Shared)]
public class ConfigurationManager: IConfigurationManager
{
[ImportingConstructor]
public ConfigurationManager()
{
}
public string GetConfigurationValue(string keyName)
{
return "";
}
}
IHttpHandlers Used In The MVC Project:
public class CommonServiceHandler : HttpTaskAsyncHandler, IRequiresSessionState
{
private ICommonServiceHandlerManager _commonServiceHandlerManager;
public CommonServiceHandler()
{
_commonServiceHandlerManager = Bootstrapper.GetInstance<ICommonServiceHandlerManager>();
}
public override bool IsReusable
{
get
{
return false;
}
}
}
This error indicates that at least one controller exists that its constructor parameters are not resolved.
Every controller needs a constructor to be resolved at run-time. By default every c# class has a default (parameter-less) constructor that can be called when an instance of the class is needed to be created.
However, after defining an explicit constructor, you lose the default constructor, therefore, you need to make sure that all your controllers have either a parameter-less constructor or if instead they have a parametric constructor the parameters need to be registered through dependency injection.

Controller does not have a default constructor 500 internal server error

This is my controller
public class SuggestionController : ApiController
{
public ISuggestionRepository Repository { get; private set; }
public SuggestionController(ISuggestionRepository repository)
{
this.Repository = repository;
}
// to post suggestion
[HttpPost]
[ActionName("PostSuggestion")]
public HttpResponseMessage PostSuggestion(Suggestion suggestion)
{
var answerCorrect = this.Repository.CreateSuggestion(suggestion);
if (answerCorrect == true)
return Request.CreateResponse(HttpStatusCode.OK);
else
return Request.CreateResponse(HttpStatusCode.Conflict);
}
}
and this is my RegisterServices method in NinjectWebCommon.cs
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ICompetitionRepository>().To(typeof(CompetitionRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<Competition>());
kernel.Bind<ISubmissionRepository>().To(typeof(SubmissionRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<Submission>());
kernel.Bind<IUserRepository>().To(typeof(UserRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<User>());
kernel.Bind<ISuggestionRepository>().To(typeof(SuggestionRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<Suggestion>());
}
But am getting an exception that my suggestion controller does not have a default constructor and its showing a 500 internal server when am hitting the controller from a client app
I know that we get the exception of controller not having default constructor if the ninject dependency is not working properly but the below is another controller i have implemeneted similar to suggestion controller and its working absolutely fine.
public IUserRepository Repository { get; private set; }
public SSOController(IUserRepository repository)
{
this.Repository = repository;
}
[HttpPost]
[ActionName("PostUser")]
public HttpResponseMessage PostUser([FromBody]string id)
{
var accessToken = id;
var client = new FacebookClient(accessToken);
dynamic result = client.Get("me", new { fields = "name,email" });
string name = result.name;
string email = result.email;
var existingUser = this.Repository.FindByUserIdentity(name);
if (existingUser == null)
{
var newUser = new User
{
Username = name,
Email = email,
};
var success = this.Repository.CreateAccount(newUser);
if (!success)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError);
}
//return created status code as we created the user
return Request.CreateResponse<User>(HttpStatusCode.Created, newUser);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
}
I have no idea where am going wrong. Please let me know if u have any suggestions.
EDIT:
my Global.asax
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
AuthConfig.RegisterAuth();
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy =
IncludeErrorDetailPolicy.Always;
}
Dependency resolver am using
// Provides a Ninject implementation of IDependencyScope
// which resolves services using the Ninject container.
public class NinjectDependencyScope : IDependencyScope
{
IResolutionRoot resolver;
public NinjectDependencyScope(IResolutionRoot resolver)
{
this.resolver = resolver;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has been disposed");
return resolver.TryGet(serviceType);
}
public System.Collections.Generic.IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has been disposed");
return resolver.GetAll(serviceType);
}
public void Dispose()
{
IDisposable disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
}
// This class is the resolver, but it is also the global scope
// so we derive from NinjectScope.
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
and calling it in CreateKernel() method in NinjectWebCommon
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
// Install our Ninject-based IDependencyResolver into the Web API config
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
}
Suggestion Repository
public class SuggestionRepository : Repository<Suggestion>, ISuggestionRepository
{
public SuggestionRepository(IServiceContext<Suggestion> servicecontext)
: base(servicecontext)
{ }
public bool CreateSuggestion(Suggestion suggestion)
{
this.ServiceContext.Create(suggestion);
this.ServiceContext.Save();
return true;
}
}
ISuggestionRepository
public interface ISuggestionRepository
{
bool CreateSuggestion(Suggestion suggestion);
}
Repository
public abstract class Repository<T>
{
public IServiceContext<T> ServiceContext { get; private set; }
public Repository(IServiceContext<T> serviceContext)
{
this.ServiceContext = serviceContext;
}
}
IserviceContext
public interface IServiceContext<T>
{
IQueryable<T> QueryableEntities { get; }
void Create(T entity);
void Update(T entity);
void Delete(T entity);
void Save();
}
Since you're using WebApi, you will need to use the WebApi extension for Ninject. Unfortunately, the current Ninject.WebApi nuget package is out of date, and doesn't work with the released version of WebApi.
Temporarily, until Remo gets around to updating Ninject.WebApi to the release version, you can use Ninject.WebApi-RC http://nuget.org/packages/Ninject.Web.WebApi-RC
http://www.eyecatch.no/blog/2012/06/using-ninject-with-webapi-rc/
EDIT:
To recap the information discussed in comments, Here are the recommendations:
1) Use Ninject.MVC3 and Ninject.Web.WebApi (but use Ninject.Web.WebApi-RC until the official is updated) as discussed above. Do not use a custom DependencyResolver, and let Ninject.Web.Mvc and .WebApi do their job.
2) Change your bindings to this:
kernel.Bind<ICompetitionRepository>().To<CompetitionRepository>();
... similar bindings
3) Add a generic binding for your ServiceContext
kernel.Bind(typeof(IServiceContext<>)).To(typeof(InMemoryDataContext<>));
I think the problem is you're using the ApiController.
Controllers and apiControllers are using a different dependancy injection container.
Both of them however expose the same methods.
If the working controller is inheriting the Controller class then that's your cause.
For a work around take a look at
this topic
I have faced the same issue.
This is how I rectified:
I created a WebContainerManager which is just a static wrapper around container.
Static container wrappers useful when you don't control instantiation and can't rely on injection - e.g. action filter attributes
public static class WebContainerManager
{
public static IKernel GetContainer()
{
var resolver = GlobalConfiguration.Configuration.DependencyResolver as NinjectDependencyResolver;
if (resolver != null)
{
return resolver.Container;
}
throw new InvalidOperationException("NinjectDependencyResolver not being used as the MVC dependency resolver");
}
public static T Get<T>()
{
return GetContainer().Get<T>();
}
}
Inside your controller, call your empty constructor like this with no parameters:
public SuggestionController() : this(WebContainerManager.Get<ISuggestionRepository>())
{
}
This should work.
This technique i got from the book on MVC4 by Jamie Kurtz #jakurtz.
You probably need to do some dependency injection so you can inject the ISuggestionRepository parameter on your SuggestionController constructor. To do that you need to override methods in the DefaultControllerFactory class to customize the creation of controllers. Since you are using NInject, you can have something like:
public class NInjectControllerFactory : DefaultControllerFactory
{
private IKernel kernel = new StandardKernel(new CustomModule());
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
return controllerType == null ? null : (IController)kernel.Get(controllerType);
}
public class CustomModule : NinjectModule
{
public override void Load()
{
this.Bind<ICompetitionRepository>().To(typeof(CompetitionRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<Competition>());
this.Bind<ISubmissionRepository>().To(typeof(SubmissionRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<Submission>());
this.Bind<IUserRepository>().To(typeof(UserRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<User>());
this.Bind<ISuggestionRepository>().To(typeof(SuggestionRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<Suggestion>());
}
}
}
Then in your Global.asax.cs, you can add a line to swap out the controller factory
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new NInjectControllerFactory());
}

MVC3 IControllerFactory ReleaseController memory leak

In our project we use MefControllerFactory, these are the codes which we set at application_start in global.asax as ControllerBuilder.Current.SetControllerFactory(new Project.Helper.MefControllerFactory(container));
The problem is when we run .NET Profiler in result, it gives memory leak problem even we dispose controllers in "ReleaseController" method. The original message is "An instance is disposed but still reachable from one or more roots. Since a disposed instance should normally no longer be used, this can indicate a memory leak. Investigate the instance to find out whether the instance is unintentionally kept alive, or if the issue can be ignored."
Is there any solution for this problem ?
The second message is:
"Disposed instance with direct EventHandler roots
A disposed instance is directly rooted by an EventHandler, i.e., the instance is only used as the target of an EventHandler and it cannot be reached from any other root without passing through a delegate. Since a disposed instance should no longer be used and EventHandlers are a common cause of memory leaks, this issue is a strong indication of a memory leak."
public class MefControllerFactory : IControllerFactory
{
private CompositionContainer _container;
private DefaultControllerFactory defaultControllerFactory;
public MefControllerFactory(CompositionContainer container)
{
_container = container;
this.defaultControllerFactory = new DefaultControllerFactory();
}
#region IControllerFactory Members
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
IController controller = null;
controller = _container.GetExportedValueOrDefault<IController>(controllerName);
if (controller == null)
return this.defaultControllerFactory.CreateController(requestContext, controllerName);
return controller;
}
public void ReleaseController(IController controller)
{
IDisposable disposable = controller as IDisposable;
if (disposable != null)
disposable.Dispose();
}
#endregion
public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(System.Web.Routing.RequestContext requestContext, string controllerName)
{
return System.Web.SessionState.SessionStateBehavior.Default;
}
}
Thanks...
Here's the MEF-based Controller Factory I created for the code samples for my book:
public class MefControllerFactory : DefaultControllerFactory
{
private readonly CompositionContainer container;
private readonly Dictionary<IController, Lazy<object, object>> exports;
private readonly object syncRoot;
public MefControllerFactory(CompositionContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
this.exports = new Dictionary<IController, Lazy<object, object>>();
this.syncRoot = new object();
}
protected override IController GetControllerInstance(
RequestContext requestContext, Type controllerType)
{
var export = this.container.GetExports(
controllerType, null, null).Single();
var controller = (IController)export.Value;
lock (this.syncRoot)
{
this.exports.Add(controller, export);
}
return controller;
}
public override void ReleaseController(IController controller)
{
lock (this.syncRoot)
{
var export = this.exports[controller];
this.exports.Remove(controller);
this.container.ReleaseExport(export);
}
base.ReleaseController(controller);
}
}
In MEF, you can only Release object graphs by releasing the Export - not the exported value.

Castle Windsor - Injecting IActionInvoker Implementation Issue

I am trying to use the approach from this article, but I am missing something - I am currently getting an error within WindsorControllerFactory.GetControllerInstance when it tries to resolve IActionInvoker since WindsorActionInvoker has a dependency on IWindsorContainer.
Given that WindsorControllerFactory already has a reference to IWindsorContainer, could I pass that reference in? If so - how? The only examples I have found are about passing value types as constructor parameters, not reference types.
I'm feeling I'm missing something obvious...
Current setup as follows:
Within Global.asax Application_Start I call the following method:
protected virtual IWindsorContainer InitializeServiceLocator()
{
IWindsorContainer container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container));
container.RegisterControllers(typeof(HomeController).Assembly);
ComponentRegistrar.AddComponentsTo(container);
return container;
}
ComponentRegistrar:
public static void AddComponentsTo(IWindsorContainer container)
{
//add other components.....
container.AddComponentLifeStyle<IActionInvoker, WindsorActionInvoker>(LifestyleType.PerWebRequest);
}
WindsorActionInvoker:
public class WindsorActionInvoker : ControllerActionInvoker, IActionInvoker
{
readonly IWindsorContainer container;
public WindsorActionInvoker(IWindsorContainer container)
{
this.container = container;
}
protected override ActionExecutedContext InvokeActionMethodWithFilters(
ControllerContext controllerContext,
IList<IActionFilter> filters,
ActionDescriptor actionDescriptor,
IDictionary<string, object> parameters)
{
foreach (IActionFilter actionFilter in filters)
{
container.Kernel.InjectProperties(actionFilter);
}
return base.InvokeActionMethodWithFilters(controllerContext, filters, actionDescriptor, parameters);
}
}
WindsorControllerFactory:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IWindsorContainer container;
public WindsorControllerFactory(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public override void ReleaseController(IController controller)
{
var disposable = controller as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
this.container.Release(controller);
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return base.GetControllerInstance(requestContext, controllerType);
}
var controller = this.container.Resolve(controllerType) as Controller;
if (controller != null)
{
controller.ActionInvoker = this.container.Resolve<IActionInvoker>(this.container);
}
return controller;
}
}
Update
I missed a subtlety: I was trying to use this behaviour for the following:
public class CustomAuthorize : AuthorizeAttribute {...}
which doesn't implement IActionFilter.
Added the following to WindsorActionInvoker:
protected override AuthorizationContext InvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor)
{
foreach (IAuthorizationFilter authorizeFilter in filters)
{
this.kernel.InjectProperties(authorizeFilter);
}
return base.InvokeAuthorizationFilters(controllerContext, filters, actionDescriptor);
}
This now works as required. Thanks to Cristiano since it was analysis of his kindly provided code which put me on the right path.
Global.asax
private static void bootstrapContainer()
{
container = new WindsorContainer()
.Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}
Installer / filling container
public class ControllersInstaller : IWindsorInstaller
{
#region IWindsorInstaller Members
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<WpRegistration.Web.Filters.AgencyAuthorize>().LifeStyle.Transient);
container.Register(Component.For<IActionInvoker>().ImplementedBy<WindsorExtensions.Mvc.WindsorActionInvoker>().LifeStyle.Transient);
container.Register(AllTypes.FromThisAssembly()
.BasedOn<IController>()
.If(Component.IsInSameNamespaceAs<HomeController>())
.If(t => t.Name.EndsWith("Controller"))
.Configure((c => c.LifeStyle.Transient)));
}
#endregion
}
WindsorControllerFactory
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Castle.MicroKernel;
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public WindsorControllerFactory(IKernel kernel)
{
this.kernel = kernel;
}
public override void ReleaseController(IController controller)
{
kernel.ReleaseComponent(controller);
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
}
IController iController = (IController)kernel.Resolve(controllerType);
// new code
if (iController is Controller)
{
((Controller)iController).ActionInvoker = kernel.Resolve<IActionInvoker>();
}
return iController;
}
}
WindsorActionInvoker
namespace WindsorExtensions.Mvc
{
public class WindsorActionInvoker : ControllerActionInvoker
{
readonly IKernel kernel;
public WindsorActionInvoker(IKernel kernel)
{
this.kernel = kernel;
}
protected override ActionExecutedContext InvokeActionMethodWithFilters(
ControllerContext controllerContext
, IList<IActionFilter> filters
, ActionDescriptor actionDescriptor
, IDictionary<string, object> parameters)
{
foreach (IActionFilter actionFilter in filters)
{
kernel.InjectProperties(actionFilter);
}
return base.InvokeActionMethodWithFilters(controllerContext, filters, actionDescriptor, parameters);
}
}
public static class WindsorExtension
{
public static void InjectProperties(this IKernel kernel, object target)
{
var type = target.GetType();
foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (property.CanWrite && kernel.HasComponent(property.PropertyType))
{
var value = kernel.Resolve(property.PropertyType);
try { property.SetValue(target, value, null); }
catch (Exception ex)
{
var message = string.Format("Error setting property {0} on type {1}, See inner exception for more information.", property.Name, type.FullName);
throw new ComponentActivatorException(message, ex);
}
}
}
}
}
}
AgencyAuthorizeAttribute
namespace WpRegistration.Web.Filters
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class AgencyAuthorize : ActionFilterAttribute
{
CurrentUserService _currentUserSvc;
public AgencyAuthorize() { }
public CurrentUserService Service
{
get { return _currentUserSvc; }
set
{
this._currentUserSvc=value;
}
}

Categories