Getting SNAP(AOP), NInject and ASP.Net MVC 3 working together - asp.net-mvc-3

Has anyone got the SNAP AOP framework working with MVC 3 and Ninject.
The samples given when adding Snap using NuGet to an MVC 3 project don't specifcally work well with a previously added NInject package. I have tried to get it working based on the normal NInject approach but just cannot get it to actually intercept!
Can anyone show how to do this in code please?

I figured it out with the latest version of Ninject through NuGet which now adds a class call NinjectMVC3 in a new AppStart folder in the MVC3 application.
The code I used is as folows:
In the automatically created NinjectMVC3.cs CreateKernel() method:-
private static IKernel CreateKernel()
{
// Wire it up with AOP
NinjectAopConfiguration.NinjectAopConfigure();
//var kernel = new StandardKernel(); // Removed
RegisterServices(NinjectAopConfiguration._container.Kernel);
return NinjectAopConfiguration._container.Kernel;
}
I also wired up Ninject for the various injection targets in RegisterServices() method.
Next I took the sample code generated by NuGet when adding SNAP.Ninject to the MVC 3 application, renamed it NinjectAOP.cs and made it look like this:
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("MyNamespace.Model.*");
c.Bind<ExceptionLoggingInterceptor>().To<ExceptionLoggingAttribute>();
});
}
}
I also needed to do an assembly binding redirect for Ninject as follows because there is an assembly version conflict somewhere for Ninject:
I hope this helps someone.
I invite anyone to have a look and see if they can improve this please.

Related

MVC5, Web API 2 and Ninject

I have created a new MVC5 project with Web API 2, I then added the Ninject.MVC3 package from NuGet.
Constructor injection is working fine for the MVC5 controllers, but i am getting an error when trying to use it with the Web API Controllers.
An error occurred when trying to create a controller of type 'UserProfileController'. Make sure that the controller has a parameterless public constructor.
Constructor for working MVC5 controller:
public class HomeController : Controller
{
private IMailService _mail;
private IRepository _repo;
public HomeController(IMailService mail, IRepository repo)
{
_mail = mail;
_repo = repo;
}
}
Constructor for non-working Web API Controller:
public class UserProfileController : ApiController
{
private IRepository _repo;
public UserProfileController(IRepository repo)
{
_repo = repo;
}
}
Below is the full NinjectWebCommon.cs file:
[assembly: WebActivator.PreApplicationStartMethod(typeof(DatingSite.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(DatingSite.App_Start.NinjectWebCommon), "Stop")]
namespace DatingSite.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using DatingSite.Services;
using DatingSite.Data;
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>();
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)
{
#if DEBUG
kernel.Bind<IMailService>().To<MockMailService>().InRequestScope();
#else
kernel.Bind<IMailService>().To<MailService>().InRequestScope();
#endif
kernel.Bind<SiteContext>().To<SiteContext>().InRequestScope();
kernel.Bind<IRepository>().To<Repository>().InRequestScope();
}
}
}
The Ninject.Web.WebApi NuGet package has just been released. From now on the preferred solution is using that package.
I couldn't find any related documentation but after installing the package everything worked for me.
Install-Package Ninject.Web.WebApi
After installation both the normal MVC and the API controller instances are provided by Ninject.
If you have Ninject.Web.Common already installed make sure to save your bindings from NinjectWebCommon.cs and let Nuget rewrite NinjectWebCommon.cs during install and put back your bindings when finished.
As pointed out in the comments depending on your execution context you will need one of the following packages as well:
Ninject.Web.WebApi.WebHost
Ninject.Web.WebApi.OwinHost
Ninject.Web.WebApi.Selfhost
The most common scenario is IIS for that pick the WebHost package.
In the case you start an IIS MVC5 web app from scratch and want to use Ninject install the following packages:
Ninject - Ninject core dll
Ninject.Web.Common - Common Web functionality for Ninject eg. InRequestScope()
Ninject.MVC5 - MVC dependency injectors eg. to provide Controllers for MVC
Ninject.Web.Common.WebHost - Registers the dependency injectors from Ninject.MVC5 when IIS starts the web app. If you are not using IIS you will need a different package, check above
Ninject.Web.WebApi WebApi dependency injectors eg. to provide Controllers for WebApi
Ninject.web.WebApi.WebHost - Registers the dependency injectors from Ninject.Web.WebApi when IIS starts the web app.
You have this problem because Controller and ApiController use different Dependency Resolvers. Solution is very simple.
At first create new classes of Dependency Resolver and Dependency Scope. You can use this:
public class NinjectResolver : NinjectScope, IDependencyResolver
{
private readonly IKernel _kernel;
public NinjectResolver(IKernel kernel)
: base(kernel)
{
_kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectScope(_kernel.BeginBlock());
}
}
public class NinjectScope : IDependencyScope
{
protected IResolutionRoot resolutionRoot;
public NinjectScope(IResolutionRoot kernel)
{
resolutionRoot = kernel;
}
public object GetService(Type serviceType)
{
IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
return resolutionRoot.Resolve(request).SingleOrDefault();
}
public IEnumerable<object> GetServices(Type serviceType)
{
IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
return resolutionRoot.Resolve(request).ToList();
}
public void Dispose()
{
IDisposable disposable = (IDisposable)resolutionRoot;
if (disposable != null) disposable.Dispose();
resolutionRoot = null;
}
}
After that, add next line to method CreateKernel() in NinjectWebCommon
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
I had the same problem.
After installation of the following NuGet packages:
Ninject
Ninject.web.WebApi
Ninject.web.WebApi.WebHost
Ninject.MVC3
Ninject.web.Common
Ninject.web.Common.WebHost
everything works fine
I'm found that assembly Ninject.Web.WebApi.dll define own DependencyResolver and register it with kernel in class Ninject.Web.WebApi.WebApiModule automatically.
So I simply add to NinjectWebCommon.CreateKernel one line...
GlobalConfiguration.Configuration.DependencyResolver =
kernel.Get<System.Web.Http.Dependencies.IDependencyResolver>();
Finally my project has following dependencies:
Ninject 3.2.0
Ninject.Web.Common 3.2.0
Ninject.Web.WebApi 3.2.4
Just for others, who might have a similar set up to me, and got here via google like I did.
I had multiple applications using one WebApi project. I would get the above error if I hadn't included the binding in the RegisterServices method. So before pulling your hair out, just check you have the binding set up. The error doesn't tell you you have missing bindings. Which it would if the Application is in the same project as the WebApi.
I recently had to get Web Api 2 working with so I can answer that part of the question.
These are the nuget packages needed for Web Api 2-
Ninject
Ninject.Web.Common
Ninject.Web.Common.WebHost
Ninject.Web.WebApi
WebActivatorEx
Then edit NinjectWebCommon.CreateKernel(..) including
RegisterServices(kernel);
// the next line is the important one
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
I've written a more detailed post about this - http://NoDogmaBlog.bryanhogan.net/2016/04/web-api-2-and-ninject-how-to-make-them-work-together/ including a full solution to download.
You are supposed to install these packages from Nuget in webAPI project.
Ninject
Ninject.Web.Common
Ninject.Web.Common.WebHost
Ninject.Web.WebApi
Ninject.Web.WebApi.WebHost
Then you must install the Ninject package in the Repository project as well (the version must be the same as in API project). I had the same issue when there was a different version installed for Ninject.
I had this issue in a solution where the project in which I was using Ninject was not using Web API (I have 6 projects so far in my solution). I kept on getting the dreaded "parameterless constructor required" which obviously meant when I added it the Ninject injection was not getting instantiated as it was dropping into the empty constructor. I tried various solutions but in the end I checked my Ninject packages and saw that the Ninject.Web.Webapi package was installed. I uninstalled this and did a clean and rebuild. This solved the issue. My other lower level project was referencing the Ninject.Web.Api package and stupidly I had installed that into my Web front end project.
I hope this may help other people who have tried all the Stack solutions and got no where.

ASP.Net MVC 3 Unity 2.0 IoC

I am about to go live with an application I have built using ASP.Net MVC 3 and Entity Framework 4.1. For dependency injection I used the Unity 2.0 IoC. I used this tutorial as a guide to help setup the Unity IoC http://weblogs.asp.net/shijuvarghese/archive/2011/01/21/dependency-injection-in-asp-net-mvc-3-using-dependencyresolver-and-controlleractivator.aspx
Today I was checking through my code for any last minute bug fixes and I came across the
Application_Start() method in my Global.asax file. It looks something like this
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
IUnityContainer container = new UnityContainer();
container.RegisterType<IControllerActivator, CustomControllerActivator>(new HttpContextLifetimeManager<IControllerActivator>());
//container.RegisterType<IUnitOfWork, UnitOfWork>(new ContainerControlledLifetimeManager());
container.RegisterType<IUnitOfWork, UnitOfWork>(new HttpContextLifetimeManager<IUnitOfWork>());
container.RegisterType<IListService, ListService>(new HttpContextLifetimeManager<IListService>());
container.RegisterType<IShiftService, ShiftService>(new HttpContextLifetimeManager<IShiftService>());
}
The application is working fine, but I noticed I was missing the line of code
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Which goes after the line
IUnityContainer container = new UnityContainer();
As I say, my application was working fine (locally anyway) without this line of code. I have since added it and the application is again working as expected.
However, I am a bit worried that my Unity IoC wasn’t setup correctly. Why did my application work even without this additional line of code? And do I even need to add it?
Thanks for your help.
Update
Below shows the constructor for one of my Controllers
public class AccountController : Controller
{
private IAccountService _accountService;
private IUserService _userService;
private IFormsAuthenticationService _formsService;
private INotificationService _notifyService;
private ILoggingService _logService;
public AccountController(ILoggingService logService, IAccountService accountService, IUserService userService, IFormsAuthenticationService formsService, INotificationService notifyService)
{
_accountService = accountService;
_userService = userService;
_formsService = formsService;
_notifyService = notifyService;
_logService = logService;
}
Folks
Please ignore this question. I found out that the line
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
was included in my code after all.
Note to self - look harder at your code next time!!!

Plugin Architecture with ninject – load class and controller instances from plugin assembly to main MVC project

I use this tutorial to create Plugin Architecture in my solution and I also use ninject for the first time:
http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=358360&av=526320&msg=4308834#xx4308834xx
Now in MVC application while user is in the process of checkout I get the payment method he selects and need to retrieve the plugin for the selected payment method. I have succeeded in retrieving plugin controller this way, though I have no idea whether it is safe or acceptable practice:
Type type = Type.GetType(paymentMethod.PaymentMethodPluginType);
//get plugin controller
var paymentController = ServiceLocator.Current.GetInstance(type) as BasePaymentController;
//get validations from plugin
var warnings = paymentController.ValidatePaymentForm(form);
//get payment info from plugin
var paymentInfo = paymentController.GetPaymentInfo(form);
//…
I also need to access a plugin class for processing the payment.
I have an interface IPaymentMethod
public partial interface IPaymentMethod
{
void PostProcessPayment (PostProcessPaymentRequest postprocessPaymentRequest);
}
And plugin PaymentProcessor like this
public class PluginPaymentProcessor :IPaymentMethod
{
public void PostProcessPayment (PostProcessPaymentRequest postprocessPaymentRequest)
{
///
}
Now in MVC project I try to access PostProcessPayment method this way
IPaymentMethod pluginpaymentmethod = ServiceLocator.Current.GetInstance<IPaymentMethod>(paymentMethod.PaymentProcessor);
here paymentMethod.PaymentProcessor is “MyApp.Plugins.MyPlugin.PluginPaymentProcessor, MyApp.Plugins.MyPlugin,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”
And want to use pluginpaymentmethod like i do in controller example
pluginpaymentmethod.PostProcessPayment(postProcessPaymentRequest);
but it throws error that resource is not found and pluginpaymentmethod is not loaded. How can I fix it or can you suggest any tutorial with similar implementations? Thank you.
assuming you have a concrete class called MyPlugin which has the IPaymentMethod interface, then your ninject bindings should look a bit like:
private static void RegisterServices(IKernel kernel){
kernel.Bind<IPaymentMethod>().To<MyPlugin>().InRequestScope();
}
check that this is in place in your NinjectWebCommon.cs class under the App_Start folder. A trickier scenario might be that IPaymentMethod has to be registered in the same way that the Ninject IKernel is bound:
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
that would potentially be a trickier issue to work out.

MVC Controller - Inject 2 repositories in controller

I'm trying to inject a second repository into my asp.net mvc 3 controller. And I cant get it to work, not sure where to "add another" using Ninject.
I have a void function in global.asa.cs
kernel.Bind<INewsRepository>().To<NewsRepository>();
And in my controller I have:
private INewsRepository _newsRepository;
private IContentRepository _contentRepository;
public NewsController(INewsRepository newsRepository, IContentRepository contentRepository)
{
this._newsRepository = newsRepository;
this._contentRepository = contentRepository;
}
How can I register IContentRepository for the NewsController as well?
I use autofac instead of Ninject but the basics stay the same.
If you got your first dependency injection working then you should be able to bind others as well. You just have to add a new binding in Application_Start() in your Global.asax.
So under your first binding do this as well:
kernel.Bind<IContentRepository>().To<ContentRepository>();
You can have as many bindings as you like.
First off it's a good practice to move the bootstrapping of your application into a separate location. This keeps your Global.asax clean.
You should also be using convention based registration. It will end up saving you lots of time for the bindings you don't need to customize.
So for you I'd probably suggest the following
public static class Bootstrapper()
{
public static void Bootstrap()
{
kernel.Scan( k =>
{
k.FromAssemblyContaining<INewsRepository>();
k.BindWithDefaultConventions();
});
}
}
And in your Global.asax you add this..
Bootstrapper.Bootstrap();
Then I would suggest you spend some time on Google reading about ninject conventions.

Ninject MVC3 & Web Forms. Am I doing this right?

I have a new MVC3 application with a few legacy Web Form pages. I'm familiar with with Ninject and MVC but I want to use Ninject with the Web Form pages as well. I've hacked something together but I'm not sure if it's the right way to go about this.
I've exposed the Ninject kernel as follows:
public static IKernel Kernel { get { return CreateKernel(); } }
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
RegisterServices(kernel);
return kernel;
}
I then created a base class for my Web Form pages that injects the kernel:
public class NinjectBase : Page
{
public IKernel Kernel { get; private set; }
public NinjectBase() { Kernel = NinjectMVC3.Kernel; }
public void Page_Init() { Kernel.Inject(this); }
}
This seems to work well enough. Is there anything wrong with this approach? Is there another way I should be going about this?
Ninject 2.4 will support all the web technologies (ASP.NET, MVC, WCF) side a side.
If you are not yet on production go and get 2.3.0.x
the source from Github: https://github.com/ninject
or binaries from the Continuous Integration Server at http://teamcity.codebetter.com
You will need Ninject, Ninject.Web, Ninject.Web.Common, Nnject.Web.MVC3

Resources