I am trying to integrate Ninject in my WebAPI 2 project but I am getting following error:
{
"message": "An error has occurred.",
"exceptionMessage": "An error occurred when trying to create a controller of type 'BrandController'. Make sure that the controller has a parameterless public constructor.",
"exceptionType": "System.InvalidOperationException",
"stackTrace": " at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
"innerException": {
"message": "An error has occurred.",
"exceptionMessage": "Type 'ADAS.GoTango.WebApi.Controllers.BrandController' does not have a default constructor",
"exceptionType": "System.ArgumentException",
"stackTrace": " at System.Linq.Expressions.Expression.New(Type type)\r\n at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
}
My package config is:
<package id="Ninject" version="3.2.2.0" targetFramework="net45" />
<package id="Ninject.Web.Common" version="3.2.3.0" targetFramework="net45" />
<package id="Ninject.Web.Common.WebHost" version="3.2.3.0" targetFramework="net45" />
<package id="Ninject.Web.WebApi" version="3.2.4.0" targetFramework="net45" />
<package id="Ninject.Web.WebApi.WebHost" version="3.2.4.0" targetFramework="net45" />
<package id="Ninject.WebApi.DependencyResolver" version="0.1.4758.24814" targetFramework="net45" />
My code :
public class BrandController : BaseApiController
{
readonly BrandsBusiness _brandsBusiness;
public BrandController(BrandsBusiness brandsBusiness)
{
_brandsBusiness = brandsBusiness;
}
//public BrandController()
//{
// _brandsBusiness = new BrandsBusiness(new BrandEfStore());
//}
public IHttpActionResult Get()
{
try
{
var allActiveBrands = _brandsBusiness.GetAllActiveBrands();
return Ok(allActiveBrands);
}
catch (Exception exception)
{
Logger.Error(exception);
return InternalServerError();
}
}
}
and NinjectWebCommon.cs file is
/// <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>();
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
RegisterServices(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)
{
var configuration = new HttpConfiguration();
kernel.Bind<DefaultModelValidatorProviders>().ToConstant(new DefaultModelValidatorProviders(configuration.Services.GetServices(typeof(ModelValidatorProvider)).Cast<ModelValidatorProvider>()));
kernel.Bind<BrandsBusiness>().ToSelf().InRequestScope();
kernel.Bind<IBrandManagement>().To<BrandEfStore>().InRequestScope();
}
I have alredy tried :
Parameterless constructor error with Ninject bindings in .NET Web Api 2.1
Ninject.ActivationException thrown only on first web request (WebAPI 2, OWIN 3, Ninject 3)
but none of them worked.
While I don't know Ninject, I'd imagine that you'll need to make sure that the CreateKernel method is called. You'd normally add an Application_Start method in your global.asax.
You may need to make the CreateKernel method internal or public in order to be able to call if from there.
Related
I'd like to use AOP to intercept calls to all methods within ASP.NET Controllers and ApiControllers.
Following http://structuremap.github.io/dynamic-interception/ I tried to get it to work as follows.
The interceptor at present does nothing much, but provide a way to see the method name and its attributes:
public class AuthorisationInterceptor : ISyncInterceptionBehavior
{
public IMethodInvocationResult Intercept(ISyncMethodInvocation methodInvocation)
{
var classType = methodInvocation.MethodInfo.DeclaringType;
var classAttributes = classType.Attributes;
string methodName = methodInvocation.MethodInfo.Name;
var methodAttributes = methodInvocation.MethodInfo.Attributes;
//var argument = methodInvocation.GetArgument("value");
return methodInvocation.InvokeNext();
}
}
The issue is how to attach it -- without getting errors.
I've tried a couple of different approaches, both raise the same type of error..
"Decorator Interceptor failed during object construction. Specified type is not an interface,Parameter name: interfaceToProxy"
The issue is that ASP.MVC is asking for the Controllers directly (eg: 'AboutController', and not 'IAboutController').
public class AppCoreControllerConvention : ICustomRegistrationConvention
{
public void ScanTypes(TypeSet types, Registry registry)
{
// Attach a policy to intercept all Controllers before attaching Controllers...but it raises error.
// "Decorator Interceptor failed during object construction. Specified type is not an interface,Parameter name: interfaceToProxy"
registry.Policies.Interceptors(
new DynamicProxyInterceptorPolicy(
x => (x.IsConcrete() | !x.IsOpenGeneric()) & (x.CanBeCastTo<Controller>() | x.CanBeCastTo<ApiController>()),
new IInterceptionBehavior[]
{
new AuthorisationInterceptor(),
new AuditingInterceptor()
}
));
// Now find all Controllers/ApiControllers:
var foundControllers = types.FindTypes(
TypeClassification.Concretes | TypeClassification.Closed)
.Where(x => x.CanBeCastTo<Controller>() | x.CanBeCastTo<ApiController>())
.ToArray();
// to register them with StructureMap as themselves (ie, no 'Use' statement):
foreach (var serviceType in foundControllers)
{
registry.For(serviceType).LifecycleIs(new UniquePerRequestLifecycle());
// Although when I tried use/fore, it also raised {"Specified type is not an interface\r\nParameter name: interfaceToProxy"}
// AttachBehaviour(registry, serviceType);
}
}
//private static void AttachBehaviour(Registry registry, Type serviceType)
//{
// var dynamicProxyInterceptorType = typeof(StructureMap.DynamicInterception.DynamicProxyInterceptor<>);
// var genericDynamicProxyInterceptorType = dynamicProxyInterceptorType.MakeGenericType(new[] { serviceType });
// var interceptorBehaviors = new StructureMap.DynamicInterception.IInterceptionBehavior[]
// {
// new AuthorisationInterceptor(),
// new AuditingInterceptor()
// };
// var args = new[] { interceptorBehaviors };
// // Create
// IInterceptor interceptor =
// (StructureMap.Building.Interception.IInterceptor)Activator.CreateInstance(
// genericDynamicProxyInterceptorType,
// (BindingFlags)0,
// null,
// args,
// null);
// // Attach interceptors to Service:
// registry.For(serviceType).Use(serviceType).InterceptWith(interceptor);
//}
}
I'm using:
<package id="StructureMap" version="4.5.1" targetFramework="net461" />
<package id="StructureMap.DynamicInterception" version="1.1.1" targetFramework="net461" />
<package id="StructureMap.MVC5" version="3.1.1.134" targetFramework="net461" />
<package id="structuremap.web" version="4.0.0.315" targetFramework="net461" />
<package id="StructureMap.WebApi2" version="3.0.4.125" targetFramework="net461" />
Thanks for any recommendation on how to proceed.
PS: I'm not sure if I exactly understood what https://stackoverflow.com/a/47582778/9314395 was recommending, but the following did not magically produce any interception:
registry.For<IController>().InterceptWith(new DynamicProxyInterceptor<IController>(new IInterceptionBehavior[]{new AuthorisationInterceptor()}));
I am developing an ASP.NET MVC application. In my application, I need to provide REST API. So I added Web Api 2 to my existing MVC application. Before I added Web API 2, I was using ninject for dependency injection. I installed it via Nuget Package.
The whole website is already developed and working. But the problem started when I added Web Api 2 to my project. Ninject for MVC cannot be used with Web Api. So I installed Ninject for Web Api 2. So my NinjectWebCommon class has been changed after I installed it.
This is my NinjectWebCommon file in App_Start folder
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(AyarDirectory.Web.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(AyarDirectory.Web.App_Start.NinjectWebCommon), "Stop")]
namespace AyarDirectory.Web.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();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(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)
{
System.Web.Mvc.DependencyResolver.SetResolver(new AyarDirectory.Web.Infrastructure.NinjectDependencyResolver(kernel));
}
}
}
I changed only that place after I installed ninject for web api 2.Then I run my application. Website is working fine. Website is still working. But Web Api is not working.
This is my resolver class
namespace AyarDirectory.Web.Infrastructure
{
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernelParam)
{
kernel = kernelParam;
AddBindings();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
private void AddBindings()
{
kernel.Bind<ICategoryRepo>().To<CategoryRepo>();
}
}
}
I do dependency injection in Api Controller like this:
public class RegionsController : ApiController
{
private IRegionRepo regionRepo;
private RegionsController(IRegionRepo regionParam)
{
this.regionRepo = regionParam;
}
. . . }
When I access one of the action of api controller, it is giving me the following error.
{"Message":"An error has occurred.","ExceptionMessage":"An error occurred when trying to create a controller of type 'RegionsController'. Make sure that the controller has a parameterless public constructor.","ExceptionType":"System.InvalidOperationException","StackTrace":" at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()","InnerException":{"Message":"An error has occurred.","ExceptionMessage":"Type 'AyarDirectory.Web.Controllers.Api.RegionsController' does not have a default constructor","ExceptionType":"System.ArgumentException","StackTrace":" at System.Linq.Expressions.Expression.New(Type type)\r\n at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"}}
So, what is missing or wrong with my code? How can I use Ninject for Web Api 2? I am using MVC 5.
Just do 2 more steps below:
From Nugget package manager:
install-package Ninject.Web.WebApi
Now Edit NinjectWebCommon.cs File and add the following line at the end of the CreateKernel() method and before returning kernel properties:
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
I am working on Struts2 Interceptors .
I have read that Struts2 Interceptors are just like Filters , which execute before the Action class is executed and one more time after processing the result ( Please correct me if i am wrong ) , that is two times
But when i ran the below code , the interceptors are executed only once .
Please correct me if i made any mistake .
Please see my code below :
This is My Struts.xml file
<struts>
<constant name="struts.devMode" value="true" />
<package name="test" extends="struts-default">
<interceptors>
<interceptor name="loginkiran" class="vaannila.MyLoginInterCeptor" />
</interceptors>
<action name="HelloWorld" class="vaannila.HelloWorld" method="kiran">
<interceptor-ref name="loginkiran" />
<result name="SUCCESS">/success.jsp</result>
</action>
</package>
</struts>
This is my Action class
public class HelloWorld
{
public HelloWorld() {
}
public String kiran() {
System.out.println("iNSIDE THE aCTION CLASS");
return "SUCCESS";
}
}
This is my Interceptor class
public class MyLoginInterCeptor implements Interceptor {
#Override
public void destroy() {
// TODO Auto-generated method stub
System.out.println("Destroying Interceptor");
}
#Override
public void init() {
}
#Override
public String intercept(ActionInvocation invocation) throws Exception {
HttpServletRequest request = (HttpServletRequest) ActionContext
.getContext().get(ServletActionContext.HTTP_REQUEST);
System.out.println("iNSIDE THE iNTERCEPTOR");
return invocation.invoke();
}
}
This is my JSP File :
<html>
<body>
<%
System.out.println("iNSIde THE jsp");
%>
</body>
</html>
The Output for the above code is this :
iNSIDE THE iNTERCEPTOR
iNSIDE THE aCTION CLASS
iNSIde THE jsp
Interceptors are not executed twice (nor are filters): interceptors (and filters) wrap the action (or servlet/etc.)
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("Before action invocation...");
return invocation.invoke();
System.out.println("After action invocation...");
}
I've set up castle windsor in my mvc app. everything works great except it also catches routes that are of type link or image. The problem is that right before exiting from the controller and generating the view "GetControllerInstance" is executed with 'null' type. This happends anytime there a link on a page like:
<link rel="stylesheet" type="text/css" href="non-existing.css"/>
Or a link to an image that does not exist. Why is this happening?
My windows class:
public class WindsorControllerFactory : DefaultControllerFactory
{
#region Constants and Fields
/// <summary>
/// The container.
/// </summary>
private readonly WindsorContainer container;
#endregion
// The constructor:
// 1. Sets up a new IoC container
// 2. Registers all components specified in web.config
// 3. Registers all controller types as components
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="WindsorControllerFactory"/> class.
/// </summary>
public WindsorControllerFactory()
{
// Instantiate a container, taking configuration from web.config
this.container = InversionOfControl.Container;
// Also register all the controller types as transient
IEnumerable<Type> controllerTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
where typeof(IController).IsAssignableFrom(t)
select t;
foreach (Type t in controllerTypes)
{
this.container.AddComponentLifeStyle(t.FullName, t, LifestyleType.Transient);
}
}
#endregion
#region Methods
/// <summary>
/// The get controller instance.
/// </summary>
/// <param name="requestContext">
/// The request context.
/// </param>
/// <param name="controllerType">
/// The controller type.
/// </param>
/// <returns>
/// Resolved controller instance.
/// </returns>
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
controllerType = typeof(HomeController);
}
return (IController)this.container.Resolve(controllerType);
}
#endregion
}
This is only natural. The non-existing image or css cannot find the controller but you are defaulting it to the HomeController while this controller cannot handle static content.
I do not think you need an override here. Let the default controller handle what it does and resource will get a 404 error if it cannot be found instead you forcing it to be served by that controller.
As I said, it is only natural for the type to be null if it cannot be found.
Change it to this:
if (controllerType == null)
{
return base.GetControllerInstance(requestContext, controllerType);
}
I found that I had to return null when the controllerType was null. Handing it on to the base class resulted in an exception. Below is the working code that I am using.
public class DependencyControllerFactory : DefaultControllerFactory, IDisposable
{
protected readonly WindsorContainer _container;
public DependencyControllerFactory()
{
_container = new WindsorContainer();
_container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel));
_container.Install(FromAssembly.This());
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return null;
}
else
{
return (IController)_container.Resolve(controllerType);
}
}
public override void ReleaseController(IController controller)
{
_container.Release(controller);
}
public void Dispose()
{
_container.Dispose();
}
}
How to inject IServiceLocator to my class constructor?
When I tried to do this via my config, described above I got an Exception that it could not to create a RequestHandlersFactory class because unity could't find the constructor with serviceLocator and assemblyName.
I got two interfaces
public interface IPublicService
{
[OperationContract]
[ServiceKnownType("GetKnownTypes", typeof(KnownTypeProvider))]
Response Handle(Request request);
}
public interface IRequestHandlersFactory
{
IRequestHandler GetHandler(Type requestType);
IRequestHandler GetHandler<T>()
where T : Request;
IRequestHandler<T, TK> GetHandler<T, TK>()
where T : Request
where TK : Response;
}
and two classes:
public sealed class PublicService: IPublicService
{
private readonly IRequestHandlersFactory _requestHandlersFactory;
public PublicService(IRequestHandlersFactory requestHandlersFactory)
{
_requestHandlersFactory = requestHandlersFactory;
}
public Response Handle(Request request)
{
var handler = _requestHandlersFactory.GetHandler(request.GetType());
return handler.Handle(request);
}
}
public sealed class RequestHandlersFactory : IRequestHandlersFactory
{
private readonly IServiceLocator _serviceLocator;
private RequestHandlersFactory(IServiceLocator serviceLocator)
{
_serviceLocator = serviceLocator;
...
}
public RequestHandlersFactory(IServiceLocator serviceLocator, String assemblyName) : this(serviceLocator)
{
AddHandlersFromAssembly(Assembly.Load(assemblyName));
}
public RequestHandlersFactory(IServiceLocator serviceLocator, Assembly assembly) : this(serviceLocator)
{
AddHandlersFromAssembly(assembly);
}
...
}
Now I want to create unity config file:
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<alias alias="IPublicService" type="MyAssembly.IPublicService, MyAssembly"/>
<alias alias="PublicService" type="MyAssembly.PublicService, MyAssembly"/>
<alias alias="IRequestHandlersFactory" type="MyAssembly.IRequestHandlersFactory, MyAssembly"/>
<alias alias="RequestHandlersFactory" type="MyAssembly.RequestHandlersFactory, MyAssembly"/>
<container>
<register type="IPublicService" mapTo="PublicService">
<lifetime type="singleton"/>
</register>
<register type="IRequestHandlersFactory" mapTo="RequestHandlersFactory">
<lifetime type="singleton"/>
<constructor>
<param name="assemblyName">
<value value="MyAssemblyWithHandlers" />
</param>
<param name="serviceLocator" dependencyName="WcfServiceLocator" dependencyType="Microsoft.Practices.ServiceLocation.IServiceLocator, Microsoft.Practices.ServiceLocation"/>
</constructor>
</register>
</container>
My config code:
var container = new UnityContainer();
//configure container
var unitySection = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
var serviceLocator = new UnityServiceLocator(container );
container.RegisterInstance<IServiceLocator>("WcfServiceLocator", serviceLocator, new ContainerControlledLifetimeManager());
unitySection.Configure(container);
Try swapping the order of the constructor parameters in the config file so they line up with the actual parameter list in the class.