Windsor transient lifestyle - asp.net-mvc-3

I have some very odd behaviour in my Windsor Container.
I have configured my container like this.
Container = new WindsorContainer();
Container.Kernel.ComponentModelCreated += KernelComponentModelCreated;
Container.Install(FromAssembly.This());
private static void KernelComponentModelCreated(ComponentModel model)
{
if (model.LifestyleType == LifestyleType.Undefined)
model.LifestyleType = LifestyleType.Transient;
}
So I was supposing all my components where I don't specify the lifestyle would get a transient lifestyle and it seemed to don't give any issues until now.
I start multiple asynchronous task which all resolve some components. (So you would expect every task gets a new instance of the component)
However now I know the tasks don't get new instances, because my tasks fail because of crossthreading issues with the component. (so it is being used in multiple tasks)
When I replace the Container.Resolve(somecomponent); With just creating the new component in place everything works like it should.
var contextProvider = MvcApplication.Container.Resolve<IDbContextProvider>();
replaced with
var contextProvider = new DbContextProvider();
So my question is what am I missing here.
The tasks are started in transient configured MVC3 controllers, because of explicitly configured.
The DbContextProvider is resolved in all repositories also configured transient, because of above code.
Another thing I found in the documentation is. You have to release transient components. I implemented all components with IDisposable. But because of auto contructor injection in my controllers I am not completely sure if I have to release them manually and if so how can I do this. (Yes I know I have to call the Release method on the container)
UPDATE
Code below is responsible for releasing and resolving my controllers:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorControllerFactory(IKernel kernel)
{
_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));
}
return (IController)_kernel.Resolve(controllerType);
}
}
Is there some example available for testing if all dependencies are resolved and released the way they should be? (LifeStyle tests)

I'm not sure if this is what is causing your issues, but you should modify ComponentModel in an implementation of IContributeComponentModelConstruction only.
Check out the documentation of the component model construction contributors for help on how to effectively change the default lifestyle of the container.
Regarding disposal of IDisposables - if you release your controller like you should everything will just work with Windsor :)

Related

Inject IOwinContext with Web API and Ninject

Using Web API 2 and OWIN hosting with Ninject.
I would like to inject the current IOwinContext into certain services (so I can get at the Request to get the principal to do some data filtering).
With Web Hosting I would, in the old days, simply have used HttpContext.Current but that is not an option with OWIN hosting (and good riddance).
This SO question explains how to do it with Autofac. Essentially, you create a Dependency Scope and then, on each request, calls Autofac's Registerinstance to register the current IOwinContext into that dependency scope like so:
app.Use(async (ctx, next) =>
{
// this creates a per-request, disposable scope
using (var scope = container.BeginLifetimeScope(b =>
{
// this makes owin context resolvable in the scope
b.RegisterInstance(ctx).As<IOwinContext>();
}))
{
// this makes scope available for downstream frameworks
ctx.Set<ILifetimeScope>("idsrv:AutofacScope", scope);
await next();
}
});
That is very elegant. With Ninject and the Ninject.Web.WebApi.OwinHosting I already get a named scope for each request so that plumbing is taken care of. However, I haven't been able to find any way in ninject to mirror AutoFac's RegisterInstance method: The key here is that this binding is only valid within this particular dependency scope.
I have read up on the various options around Scope but everything I have found relies on being able to declare constants or ToMethod. What I am looking to do here is to say, "okay, I now have a ninject dependency scope and if anyone asks for an IOwinContext from this scope, give them this instance that I already have.
Note
I do understand that I can get the current context from within my controller and pass it on, but that rather defeats the purpose of what I am trying to do; I want my DbContext to understand who the user is so it can filter the data. And, of course, once I can get the IOwinContext I won't actually pass that to the DbContext, rather I will use a ToMethod or similar to extract the ClaimsPrincipal but that is out of scope of this question.
DISCLAIMER: This is a hack. It works, but it feels very unclean. Use at your peril.
In essence, you can create an OwinContextHolder class, bind it InRequestScope and use a DelegatingHandler to populate it on each request. Something like this:
public class OwinContextHolder
{
public IOwinContext OwinContext { get; set; }
}
public class OwinContextHolderModule : NinjectModule
{
public override void Load()
{
// Instead of a NinjectModule you can of course just register the service
this.Kernel.Bind<OwinContextHolder>().ToSelf().InRequestScope();
}
}
Your delegating handler:
public class SetOwinContextHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var holder = request.GetDependencyScope().GetService(typeof(OwinContextHolder)) as OwinContextHolder;
if (holder != null)
{
holder.OwinContext = request.GetOwinContext();
}
return base.SendAsync(request, cancellationToken);
}
}
Finally add the DelegatingHandler to your Startup class:
public void Configuration(IAppBuilder app)
{
var webApiConfiguration = new HttpConfiguration();
webApiConfiguration.Routes.MapHttpRoute(...);
webApiConfiguration.MessageHandlers.Add(new SetOwinContextHandler());
app.UseNinjectMiddleware(CreateKernel);
app.UseNinjectWebApi(webApiConfiguration);
}
You can now inject OwinContextHolder into your classes.
Note that if you have your API in a separate assembly from your host, you may have problems with InRequestScope silently not working (as in, you get a different object every time you request one and no errors). If you do, see https://groups.google.com/forum/#!topic/ninject/Wmy83BhhFz8.

Injection using NInject in ISiteMapNodeVisibilityProvider

I have a small problem which, hopefully, you will help me put behind.
I am using a MvcSiteMapProvider, and I want to define visibility for each node using access to a DB via a service interface.
public class AreaSiteMapNodeVisibilityProvider : MvcSiteMapProvider.Extensibility.ISiteMapNodeVisibilityProvider
{
[Inject]
public ISecurityService _SecurityService {get;set;}
public AreaSiteMapNodeVisibilityProvider()
{
}
public bool IsVisible(SiteMapNode node, HttpContext context, IDictionary<string, object> sourceMetadata)
{
MvcSiteMapNode thisNode = node as MvcSiteMapNode;
return _SecurityService.CalculateNodeVisibility(thisNode,context.Cache["someValueIHaveStoredHere"])
}
}
However, my _SecurityService member is always null. Any suggestions? I accept any type of directions, including getting rid of my injection and going another way.
Your ISecurityService is null, because in this case, Ninject is not managing the creation of MvcSiteMapProvider (in MVC app, Ninject resolves dependencies wired from controller root, because it manages the creation of controllers - it overrides the default method for creation controllers).
Options to resolve your issue:
1)
Use Ninject as service locator. Not recommended!, as it is widely considered to be an anti-pattern (but it depends...).
var app = HttpContext.ApplicationInstance as NinjectHttpApplication;
var service = app.Kernel.Get<ISecurityService>();
2) Read R. Gloor's answer on similar question: MVC3, Ninject, MvcSiteMapProvider - How to inject dependency to overridden method and do it his way.
Make sure that
The siteMapNodeVisibilityProvider is NOT configured in the web.config
There is a binding for ISiteMapNodeVisibilityProvider

Is there a better way to use Structuremap to inject dependencies into a custom RoleProvider?

I found http://www.devproconnections.com/content1/catpath/database-development/topic/a-perfect-storm-linq-to-sql-dependency-injection-and-asp-net-providers/page/2 and had similar code as from the webpage:
public class CustomProvider : MembershipProvider, IMembershipProvider
{
private IUserRepository _userRepo;
// this .ctor is used via unit tests (as a seam)
public CustomProvider(IUserRepository repo)
{
this._userRepo = repo;
}
// requisite parameter-less constructor:
public CustomProvider()
{
// do NOTHING here
}
public override bool ValidateUser(string username, string password)
{
// HACK:
IUserRepository repo = this._userRepo ?? ObjectFactory.GetInstance<IUserRepository>();
SiteUser user = repo.GetUserByEmailAddress(username.ToLower());
if (user == null)
return false;
if (!user.Active || !user.Verified)
return false;
if (user.PassPhrase.IsNullOrEmpty())
return false;
// do other verification... etc
}
}
Except mine is a custom RoleProvider. Is calling the ObjectFactory.GetInstance an accepted way to inject dependencies into a RoleProvider? I tried to setup a property to inject the dependency, but I could not get that to work. I'm sure my StructureMap registry is wrong. But hard to find out the right way when the documentation is out of date.
So for an ASP.NET MVC3 app, is calling the ObjectFactory ok in a custom RoleProvider? Or should I attempt to inject to a property?
If a property, how? I have For<RoleProvider>().Use(ctx => Roles.Provider); currently. But I'm not sure id the Use should be an Add, nor am I sure on the syntax to inject a dependency into a property.
Still Need help
I'm having an awful time trying to make miniprofiler not throw Null ref exceptions when I merely move the StructureMap ObjectFactory to a property for init. The goal is to allow roles to be cached. I get the same error as these questions mini-profiler nullreferenceexception Help Configure mvc mini profiler with Linq to Sql
I've updated to the latest MVCMiniProfiler and tried it's MVC package. Seems that profiling isn't enabled before the custom RoleProvider is init or the properties are initialized. If I set the field straight from the overridden GetRolesForUser method, everything is fine. If I make that field a backer to a public property, I get NULL exceptions in ProfiledDbCommand. Why?
The Microsoft "provider" pattern does not work well with dependency injection, because of its reliance on statics and singletons. If you have to use a Provider, just do the service location via ObjectFactory.GetInstance and move on.

Ninject into a Webactivator invoked class

I use the nuget template way of ninjectning my MVC3 app,
which means I have use WebActivator to invoke a method on a static class that in turn creates a Ninject bootstrapper and hooks up to MVC3.
That works fine for Controller, adapters etc. But I want to have another Webactivator activated class which gets its dependencies using Ninject.
I got it to work with a poor mans solution, but I would prefer a more elegant solution.
First I make sure my Webactivator class uses the PostApplicationStartMethod invoke, since the Ninject module uses the PreApplicationStartMethod I can ensure that ninject has been loaded and is ready to go.. THen in the Start method I do
var workers = DependencyResolver.Current.GetServices<IWorker>();
To get my dependencies, the whole class looks like this
[assembly: WebActivator.PostApplicationStartMethod(typeof(SHB.DALA.Web.App_Start.WorkflowRunner), "Start")]
namespace SHB.DALA.Web.App_Start
{
public static class WorkflowRunner
{
public static void Start()
{
var workers = DependencyResolver.Current.GetServices<IWorker>();
//Do stuff with worker collection
}
}
}
There must be a more elegant solution right?
WebActivator (ASP.NET really) doesn't have any knowledge of Ninject project and therefore cannot have any parameters injected. You would need a Ninject WebActivator extension (the same way you have a Ninject MVC extension) to achieve it. But frankly this is a bit of a catch-22: you want WebActivator to setup Ninject and at the same time Ninject to setup WebActivator.
I can think of 2 possible scenarios for you:
leave the code as it is - I honestly don't know why you don't like your WorkflowRunner class. It is a nice, small class, no other code has any dependency on it, You obtain your references through a DependencyResolver which abstracts you from Ninject itself, your workflow initialization is nicely encapsulated there. I do not smell anything wrong here, really.
Initialize your workflows in the other WebActivator class, where setup Ninject. You know there that your Ninject is initialized and you can still keep workflow initialization code in a separate class.
I would obviously choose 1. if I were you.
If you already have the Ninject bootstrapper working, are you sure you need another solution? For non-controller dependencies, I use a BindingFactory class which has a GetInstance() method. This just calls the Get() method on the Kernel object.
public class BindingFactory
{
private static readonly IKernel Kernel = new StandardKernel(new DefaultServices());
public static T GetInstance<T>()
{
return Kernel.Get<T>();
}
public static IController GetControllerInstance(Type controllerType)
{
return Kernel.Get(controllerType) as IController;
}
}
I then use a NinjectControllerFactory which utilises the BindingFactory.
public class NinjectControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext context, Type controllerType)
{
if (controllerType == null)
return null;
return BindingFactory.GetControllerInstance(controllerType);
}
}
So I'm thinking you could just adapt your current implementation.

Windsor Castle IoC Thread Safety Static Variables

I have a question for the Ioc gurus out there.
I am working with a co-worker to wrap our minds around Castle Windsor IoC. We are having a difference of opinion about static Domain Service objects within asp.Net webforms. We have a static factory called BLServiceFactory in our Infrastructure layer that retrieves the container.
public sealed class BLServiceFactory
{
private static BLServiceFactory _instance = new BLServiceFactory();
IWindsorContainer _container = new WindsorContainer();
public static BLServiceFactory Instance
{
get
{return _instance;}
}
public T Create<T>()
{
return (T)_container[typeof(T)];
}
private BLServiceFactory()
{
_container.AddComponent("DataContext", typeof(DAL.DataContextFactory), typeof(DAL.CPContextFactory));
_container.AddComponent("Repository", typeof(DAL.IRepository<>), typeof(DAL.Repository<>));
_container.AddComponent("UserManager", typeof(BL.IUserManager), typeof(BL.UserManager));
_container.AddComponent("RoleService", typeof(BL.IRoleService), typeof(BL.RoleService));
}
}
We are pulling instances from the factory in our code behinds like this.
public partial class PrintList : System.Web.UI.Page
{
private static readonly ISchoolManager _schoolService = BLServiceFactory.Instance.Create<ISchoolManager>();
Models.TechSchool _tech;
protected void Page_Load(object sender, EventArgs e)
{
_tech = _schoolService.GetSchoolForTechPrep(Profile.UserName);
}
protected void DoOtherStuff...
{
_schoolService.Foo(_tech);
}
}
To me this looks like we will be serving up the same instance to every session. That would indeed be bad! My co-worker thinks that since all of our Domain Services are marked Transient, each page request will get a new instance.
I have also read a bit about memory leaks due to objects marked transient not released for garbage collection. Has this been addressed in the latest release of Castle Windsor, or should I be explicitly releasing objects? Of course as it stands now, all the objects are static and this would be irrelevant.
The BLServiceFactory is a service locator. I recommend using CommonServiceLocator instead of your own if you're going to use a service locator. Component registration does not belong inside the service locator.
Now, in the code you posted, there is no mention of those components being transient, unless you marked them with the [Transient] attribute. If you didn't, those components will be singletons, which is the default lifestyle in Windsor.
Since the variable _schoolService in PrintList is static, the same instance of ISchoolManager will be used for all requests to the PrintList page. If you really want it to be transient, remove the "static" keyword.
About releasing components, see this article.
BTW: AddComponent-style registration is deprecated, use Register() instead.

Resources