I want to try out so SOA style logging using Snap in my MVC3 application. I'm using Ninject for IoC so have installed Ninject.MVC and Snap.Ninject via Nuget all had a look at the sample code in GitHub for Snap.Ninject. I also read Getting SNAP(AOP), NInject and ASP.Net MVC 3 working together
which seems to be doing exactly what I want.
I've updated my NinjctMVC3.cs accordingly but when I add the interceptor attribute to my method, I get an object ref error from Snap AspectUtility. Here is my NinjectMVC3.cs
public static class NinjectMVC3 {
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start() {
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule));
DynamicModuleUtility.RegisterModule(typeof(HttpApplicationInitializationModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop() {
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel() {
//var kernel = new StandardKernel();
NinjectAopConfiguration.NinjectAopConfigure();
var kernel = NinjectAopConfiguration._container.Kernel;
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel) {
kernel.Bind<ILogger>().To<NLogger>()
.WithConstructorArgument("currentClassName", x => x.Request.ParentContext.Request.Service.FullName); ;
kernel.Bind<ISomeDataFactory>().To<SomeDataFactory>();
}
}
public static class NinjectAopConfiguration {
public readonly static NinjectAspectContainer _container;
static NinjectAopConfiguration() {
_container = new NinjectAspectContainer();
}
public static void NinjectAopConfigure() {
SnapConfiguration.For(_container).Configure(c => {
c.IncludeNamespace("TestAopLogging.Model.*");
c.Bind<MyMethodInterceptor>().To<MyInterceptorAttribute>();
});
}
}
public class MyMethodInterceptor : MethodInterceptor {
public override void InterceptMethod(Castle.DynamicProxy.IInvocation invocation, MethodBase method, System.Attribute attribute) {
var logger = new NLogger(method.DeclaringType.ToString());
logger.LogInfo("Hello AOP Logger. Your method (" + method.Name + ") has been intercepted");
invocation.Proceed();
}
public override void BeforeInvocation() {
var logger = new NLogger("How do I work out what class I'm in?");
base.BeforeInvocation();
}
public override void AfterInvocation() {
var logger = new NLogger("How do I work out what class I'm in?");
logger.LogInfo("Hello AOP Logger. After Invocation");
base.AfterInvocation();
}
}
public class MyInterceptorAttribute : MethodInterceptAttribute { }
And the controller
public class HomeController : Controller
{
private ILogger _logger;
private ISomeDataFactory _someDataFactory;
public HomeController(ILogger logger, ISomeDataFactory someDataFactory) {
_logger = logger;
_someDataFactory = someDataFactory;
}
public ActionResult Index()
{
_logger.LogInfo("I've hit the index action");
_someDataFactory.GetStuffAndLogTheOldWay();
_someDataFactory.GetStuffAndLogUsingAOP();
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
}
and the factory class with the method with the intercept attribute
public interface ISomeDataFactory {
string GetStuffAndLogTheOldWay();
string GetStuffAndLogUsingAOP();
}
public class SomeDataFactory : ISomeDataFactory {
private ILogger _logger;
public SomeDataFactory(ILogger logger) {
_logger = logger;
}
public string GetStuffAndLogTheOldWay() {
_logger.LogInfo(MethodBase.GetCurrentMethod().Name + " was called");
return "I called GetStuffAndLogTheOldWay";
}
[MyInterceptor] // If I comment this out, then all is good
public string GetStuffAndLogUsingAOP() {
return "I called GetStuffAndLogUsingAOP";
}
}
and this results in the following exception
[NullReferenceException: Object reference not set to an instance of an object.]
Snap.AspectUtility.CreateProxy(Type interfaceType, Object instanceToWrap, IInterceptor[] interceptors) +29
Snap.AspectUtility.CreatePseudoProxy(IMasterProxy proxy, Type interfaceType, Object instanceToWrap) +184
Snap.Ninject.AspectProxyActivationStrategy.Activate(IContext context, InstanceReference reference) +376
Ninject.Activation.<>c__DisplayClass2.b__0(IActivationStrategy s) in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\Activation\Pipeline.cs:58
Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map(IEnumerable1 series, Action1 action) in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\Infrastructure\Language\ExtensionsForIEnumerableOfT.cs:23
Ninject.Activation.Pipeline.Activate(IContext context, InstanceReference reference) in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\Activation\Pipeline.cs:58
Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\Activation\Context.cs:182
Ninject.KernelBase.b__7(IContext context) in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\KernelBase.cs:375
System.Linq.<>c__DisplayClass123.<CombineSelectors>b__11(TSource x) +32
System.Linq.WhereSelectEnumerableIterator2.MoveNext() +151
System.Linq.Enumerable.SingleOrDefault(IEnumerable1 source) +4178557
Ninject.Planning.Targets.Target1.GetValue(Type service, IContext parent) in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\Planning\Targets\Target.cs:179
Ninject.Planning.Targets.Target1.ResolveWithin(IContext parent) in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\Planning\Targets\Target.cs:147
Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target) in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:97
Ninject.Activation.Providers.<>c__DisplayClass2.<Create>b__1(ITarget target) in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:81
System.Linq.WhereSelectArrayIterator2.MoveNext() +85
System.Linq.Buffer1..ctor(IEnumerable1 source) +325
System.Linq.Enumerable.ToArray(IEnumerable1 source) +78
Ninject.Activation.Providers.StandardProvider.Create(IContext context) in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:81
Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\Activation\Context.cs:157
Ninject.KernelBase.<Resolve>b__7(IContext context) in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\KernelBase.cs:375
System.Linq.<>c__DisplayClass123.b__11(TSource x) +32
System.Linq.WhereSelectEnumerableIterator2.MoveNext() +151
System.Linq.Enumerable.SingleOrDefault(IEnumerable1 source) +4178557
Ninject.Web.Mvc.NinjectDependencyResolver.GetService(Type serviceType) in c:\Projects\Ninject\Maintenance2.2\ninject.web.mvc\mvc3\src\Ninject.Web.Mvc\NinjectDependencyResolver.cs:56
System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +51
Thanks in advance. I want a working demo of it failing then let me know.
Thanks to Tyler Brinks for spotting my typo!
Update the namespace reference to
c.IncludeNamespace("TestAopLogging.Models.*");
and all is well.
Hope someone finds this useful.
Related
I have an Aspnet Web API project. I used repository pattern and I want to do dependency injection with ninject, but it's not working.
Ninject.Web.Common.cs
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(ProjectName.API.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(ProjectName.API.App_Start.NinjectWebCommon), "Stop")]
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IFirstService>().To<ServiceManager>().WithConstructorArgument("firstServiceDAL", new EFFirstDAL());
}
}
Is Ninject.Web.Common class correct? Because it isn't working.
My api's response;
"Message": "An error has occurred.",
"ExceptionMessage": "An error occurred when trying to create a controller of type 'FirstController'. Make sure that the controller has a parameterless public constructor.",
"ExceptionType": "System.InvalidOperationException",
FirstController.cs - My controller's constructor
public class FirstController : ApiController
{
private readonly IFirstService _firstService;
public FirstController(IFirstService firstService)
{
this._firstService = firstService;
}
}
What can I do ?
It seems that you don't have a public parameterless constructor.Your FirstController has to have a public,parameterless default constructor.
Add following code into your FirstController.
public FirstController()
{
}
It would be better if you had shared your controller.
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IFirstService>().To<FirstService>();
}
Here is my Error Message which is shown when I browse: ../api/User
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'RavenReader.Web.Controllers.UserController' does not have a default constructor
</ExceptionMessage>
<ExceptionType>System.ArgumentException</ExceptionType>
<StackTrace>
at System.Linq.Expressions.Expression.New(Type type) at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
</StackTrace>
</Error>
My Controller Classes are
public class BaseController : ApiController
{
private readonly ICookieStorageService _cookieStorageService;
public BaseController(ICookieStorageService cookieStorageService)
{
_cookieStorageService = cookieStorageService;
}
}
public class UserController : BaseController
{
private readonly RavenUserFacade _facade;
private readonly ICookieStorageService _cookieStorageService;
public UserController(ICookieStorageService cookieStorageService, RavenUserFacade facade):base(cookieStorageService)
{
_facade = facade;
}
// GET api/User
public IEnumerable<RavenUserView> Get()
{
var users = _facade.GetAllUser();
return users.RavenUsers;
}
..........................................
..........................................
}
According to http://www.peterprovost.org/blog/2012/06/19/adding-ninject-to-web-api/ this blog I organized my NinjectDependencyScope class, NinjectDependencyResolver class and NinjectWebCommon as follows:
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
Contract.Assert(resolver != null);
this.resolver = resolver;
}
public void Dispose()
{
var disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.GetAll(serviceType);
}
}
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
public static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IDbFactory>().To<IDbFactory>().InSingletonScope();
kernel.Bind<IUnitOfWork>().To<EFUnitOfWork>();
kernel.Bind<IRavenUserRepository>().To<RavenUserRepository>();
kernel.Bind<IRavenUserFacade>().To<RavenUserFacade>();
kernel.Bind<ICookieStorageService>().To<CookieStorageService>();
kernel.Bind<ICacheStorage>().To<HttpContextCacheAdapter>();
}
}
I am using visual Studio 2013 Ninject For MVC-3
I am posting this answer in order to help you track down the root issue you are facing. It is not a solution but this is how I reproduced the exact same error you are having.
First of all, you should use a different implementation for the NinjectDependencyResolver. I've set this gist. The reason behind that is avoiding problem with scopes (specially singletons), which you can learn more about here.
Back to your problem, the error is in your bindings, somewhere. First, try removing the InSingletonScope from your IDbFactory. Then, try removing one dependency from your controller constructor and check if that works. Finally, strip out the base class and see if it works.
These steps are just to guide you track down the problem. I've replicated your scenario here and I couldn't face the same issue. My setup was like this:
public class BaseController : ApiController
{
protected readonly IService _service;
public BaseController(IService service)
{
_service = service;
}
}
public class ValuesController : BaseController
{
public ISomeOtherDependency Dependency { get; set; }
public ValuesController(IService service, ISomeOtherDependency dependency) : base(service)
{
Dependency = dependency;
}
// GET api/values/5
public string Get(int id)
{
return _service.CreatedAt.ToString("u");
}
}
public interface ISomeOtherDependency
{
}
public class ConcreteDependency : ISomeOtherDependency
{
}
public interface IService
{
DateTime CreatedAt { get; }
}
public class Service : IService
{
public Service()
{
CreatedAt = DateTime.Now;
}
public DateTime CreatedAt { get; private set; }
}
And my bindings:
kernel.Bind<IService>().To<Service>(); // If I comment this, I get the same exception.
kernel.Bind<ISomeOtherDependency>().To<ConcreteDependency>();
But by commenting out one of these bindings, I get the exact same error as you:
ValuesController' does not have a default constructor
I hope this gets you on the right track to fix your issue.
Thanks for your reply. I followed each your steps but same results here. Finally I debugged by bindings that belongs inside NinjectWebCommon.cs and I found a problem here. While debugging it shows me following problem:
Locating source for
Bootstrapper.cs not found
You need to find Bootstrapper.cs to view the source for the current call stack frame
'c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs'. Checksum: MD5 {13 3e b1 f3 ba a7 65 14 f6 dc 4d f1 dd aa 21 bf}
The file 'c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs' does not exist.
Looking in script documents for 'c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs'...
Looking in the projects for 'c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs'.
The file was not found in a project.
Looking in directory 'C:\Program Files\Microsoft Visual Studio 11.0\VC\crt\src\'...
Looking in directory 'C:\Program Files\Microsoft Visual Studio 11.0\VC\crt\src\vccorlib\'...
Looking in directory 'C:\Program Files\Microsoft Visual Studio 11.0\VC\atlmfc\src\mfc\'...
Looking in directory 'C:\Program Files\Microsoft Visual Studio 11.0\VC\atlmfc\src\atl\'...
Looking in directory 'C:\Program Files\Microsoft Visual Studio 11.0\VC\atlmfc\include'...
The debug source files settings for the active solution indicate that the debugger will not ask the user to find the file: c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs.
The debugger could not locate the source file 'c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs'.
I'm having some difficulty using Ninject's InSingletonScope binding with Web Api RC. No matter how I create my binding, it looks like perhaps Web Api is handling scope/lifetime instead of Ninject.
I've tried a few variations on wiring up Ninject. The most common is identical to the answer here:
ASP.NET Web API binding with ninject
I've also tried this version:
http://www.peterprovost.org/blog/2012/06/19/adding-ninject-to-web-api/
In both, I'm literally creating an out of the box Web Api project, then adding the Ninject packages as described in either post. Finally, I'm adding the Resolver and Scope classes, such as this for the StackOverflow version:
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
Contract.Assert(resolver != null);
this.resolver = resolver;
}
public void Dispose()
{
IDisposable disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.GetAll(serviceType);
}
}
and:
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
Then, NinjectWebCommon looks like this:
using System.Web.Http;
using MvcApplication2.Controllers;
[assembly: WebActivator.PreApplicationStartMethod(typeof(MvcApplication2.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(MvcApplication2.App_Start.NinjectWebCommon), "Stop")]
namespace MvcApplication2.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
// Register Dependencies
RegisterServices(kernel);
// Set Web API Resolver
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ILogger>().To<Logger>().InSingletonScope();
}
}
}
The ILogger and Logger objects don't do anything, but illustrate the issue. Logger does Debug.Writeline so that I can see when it was instantiated. And each refresh of the page shows that it's being refreshed per call, rather than the singleton I'd hoped for. Here is a controller using the Logger:
public class ValuesController : ApiController
{
private readonly ILogger _logger;
public ValuesController(ILogger logger)
{
_logger = logger;
_logger.Log("Logger created at " + System.DateTime.Now.ToLongTimeString());
}
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post(string value)
{
}
// PUT api/values/5
public void Put(int id, string value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
}
When I put trace information into the creation of the kernel, it seems to show that the kernel is only created once. So... what am I not seeing? Why isn't the singleton persisted?
use
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel);
}
and don't dispose the kernel in the NinjectDependencyScope
#Remo Gloor
When I run your code in InMemoryHost of WebAPI and run Integration tests everything works fine and I do have singleton.
If I run WebAPI solution inside VS Cassini web server first run is successful
and when I click refresh I receive exception :
Error loading Ninject component ICache
No such component has been registered in the kernel's component container.
If I return old code with BeginBlock it works in Cassini but IsSingleton not working anymore in integration tests.
Instead of not disposing the kernel (which will not call the internal dispose) you can simply implement your own singleton:
public static class NinjectSingletonExtension
{
public static CustomSingletonKernelModel<T> SingletonBind<T>(this IKernel i_KernelInstance)
{
return new CustomSingletonKernelModel<T>(i_KernelInstance);
}
}
public class CustomSingletonKernelModel<T>
{
private const string k_ConstantInjectionName = "Implementation";
private readonly IKernel _kernel;
private T _concreteInstance;
public CustomSingletonKernelModel(IKernel i_KernelInstance)
{
this._kernel = i_KernelInstance;
}
public IBindingInNamedWithOrOnSyntax<T> To<TImplement>(TImplement i_Constant = null) where TImplement : class, T
{
_kernel.Bind<T>().To<TImplement>().Named(k_ConstantInjectionName);
var toReturn =
_kernel.Bind<T>().ToMethod(x =>
{
if (i_Constant != null)
{
return i_Constant;
}
if (_concreteInstance == null)
{
_concreteInstance = _kernel.Get<T>(k_ConstantInjectionName);
}
return _concreteInstance;
}).When(x => true);
return toReturn;
}
}
And then simply use:
i_Kernel.SingletonBind<T>().To<TImplement>();
Rather then
i_Kernel.Bind<T>().To<TImplement>().InSingletonScope();
note: although it is only matters for the first request, this implementation is not thread safe.
In a simple word I try to create Lifetime manager for Unity framework by using Http Session in my MVC3 project. My sample implementation of lifetime manager is:
public class UnityPerSessionLifetimeManager : LifetimeManager
{
private string sessionKey;
private HttpContext ctx;
public UnityPerSessionLifetimeManager(string sessionKey)
{
this.sessionKey = sessionKey;
this.ctx = HttpContext.Current;
}
public override object GetValue()
{
return this.ctx.Session[this.sessionKey];
}
public override void RemoveValue()
{
this.ctx.Items.Remove(this.sessionKey);
}
public override void SetValue(object newValue)
{
this.ctx.Session[this.sessionKey] = newValue;
}
}
In my global.asax.cs I replaced default controller factory with my own UnityControllerFactory
public class UnityControllerFactory : DefaultControllerFactory
{
private IUnityContainer container;
public UnityControllerFactory(IUnityContainer container)
{
this.container = container;
this.RegisterServices();
}
protected override IController GetControllerInstance(RequestContext context, Type controllerType)
{
if (controllerType != null)
{
return this.container.Resolve(controllerType) as IController;
}
return null;
}
private void RegisterServices()
{
this.container.RegisterType<IMyType, MyImpl>(new UnityPerSessionLifetimeManager("SomeKey"));
}
}
}
I set breakpoints on each function of UnityPerSessionLifetimeManager class, I noticed that when controller factory tries to solve dependencies of my controller, the HttpContext.Session is actually null, so the code fails retrieve from session or save to session.
Any idea why session is null at this stage?
My mistake, I should change code of UnityPerSessionLifetimeManager class to be
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;
}
}
because when the constructor was called to register type, session state is not ready yet and I already assigned http context of that time to a variable. But in later Get/Set functions session state is ready.
Hello am an trying to implement a global filter with injection.
The filter looks like this.
public class WikiFilter : IActionFilter
{
private IWikiService service;
public WikiFilter(IWikiService service)
{
this.service = service;
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
!!!Code here!!
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
throw new NotImplementedException();
}
}
And i have attached the filter with injection the following way in my global.asax.
public class MvcApplication : System.Web.HttpApplication,
IAuthenticationApplication<User>
{
protected void Application_Start()
{
Ninject();
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
RegisterGlobalFilters(GlobalFilters.Filters);
}
private void Ninject()
{
// Create Ninject DI kernel
IKernel kernel = new StandardKernel();
kernel.Bind<DataContext>().ToSelf().InRequestScope();
kernel.Bind<IWikiRepository>().To<WikiRepository>();
kernel.Bind<IWikiService>().To<WikiService>();
// Global filters
kernel.BindFilter<WikiFilter>(FilterScope.Global, 0);
DependencyResolver.SetResolver
(new NinjectDependencyResolver(kernel));
}
}
But for some reason is the filter never fired when the application runs, have i not implemented it correctly?
I would recommend you using the ~/App_Start/NinjectMVC3.cs file to configure the Ninject kernel:
[assembly: WebActivator.PreApplicationStartMethod(typeof(AppName.App_Start.NinjectMVC3), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(AppName.App_Start.NinjectMVC3), "Stop")]
namespace AppName.App_Start
{
using System.Web.Mvc;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Mvc;
using Ninject.Web.Mvc.FilterBindingSyntax;
public static class NinjectMVC3
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<DataContext>().ToSelf().InRequestScope();
kernel.Bind<IWikiRepository>().To<WikiRepository>();
kernel.Bind<IWikiService>().To<WikiService>();
kernel.BindFilter<WikiFilter>(FilterScope.Global, 0);
}
}
}
and the Global.asax stays unchanged. By the way that's the default setup when you install the Ninject.MVC3 NuGet package.