使用 owin 和 ninject 的 webapi 应用程序中的无参数构造函数问题

Parameterless constructor issue within webapi application using owin and ninject

我有一个 Web api 应用程序,我想在其中使用 OwinOauthNinject ,所以我有这个配置

依赖注入器

public class NinjectDependencyResolver : IDependencyResolver
{
    private static IKernel kernel; 

    public NinjectDependencyResolver()
    {
        kernel = new StandardKernel();
       // AddBindings();
    }

    public object GetService(Type serviceType)
    {
        return kernel.TryGet(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return kernel.GetAll(serviceType);
    }

    private static void AddBindings()
    {
        kernel.Bind<INotifier>().To<Notifier>();
        kernel.Bind<IEventRepository>().To<EventRepository>();
        kernel.Bind<ICrud<Config>>().To<CrudConfig>();
        kernel.Bind<ICrud<Evenement>>().To<CrudEvent>();
        kernel.Bind<IAccount>().To<Account>();
    }



    public static Lazy<IKernel> CreateKernel = new Lazy<IKernel>(() =>
    {
        //var kernel = new StandardKernel();
        kernel.Load(Assembly.GetExecutingAssembly());
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
        AddBindings();

        return kernel;
    });


}

启动class

public partial class Startup
{
    public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
    public static string PublicClientId { get; private set; }

    // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
    public static void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context and user manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        app.UseCookieAuthentication(new CookieAuthenticationOptions());
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        // Configure the application for OAuth based flow
        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            // In production mode set AllowInsecureHttp = false
            AllowInsecureHttp = true
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);

        //app.UseNinjectMiddleware(CreateKernel);
    }

    public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration();
        WebApiConfig.Register(config);
        app.UseNinjectMiddleware(() => NinjectDependencyResolver.CreateKernel.Value);
        app.UseNinjectWebApi(config);
        ConfigureAuth(app);
    }
}

Global.cs

 protected void Application_Start()
        {
            DependencyResolver.SetResolver(new NinjectDependencyResolver());
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }

我有这个 class 还有

 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)
        {
        }        
    }

我有这个 api 控制器:

public class AccountController : BaseController
{
    #region ctors

    public AccountController()
    {

    }
    [Inject]
    public AccountController(INotifier _notifierParam,  IAccount _IAccount)
    {
        Notifier = _notifierParam; 
        Account = _IAccount;
    }

    #endregion
}

派生自 BaseController,它是一个没有构造器的 class。

问题是当我调用帐户控制器的服务时出现此异常:

"Message":"An error has occurred.", "ExceptionMessage":"An error occurred when trying to create a controller of type 'AccountController'. Make sure that the controller has a parameterless public constructor.", "ExceptionType":"System.InvalidOperationException", "StackTrace":" à System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n à System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n à System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()", "InnerException":{ "Message":"An error has occurred.", "ExceptionMessage":"Error activating INotifier\r\nNo matching bindings are available, and the type is not self-bindable.\r\nActivation path:\r\n 4) Injection of dependency INotifier into parameter _notifierParam of constructor of type AccountController\r\n 3) Injection of dependency AccountController into parameter resolutionRoot of constructor of type NamedScope\r\n 2) Injection of dependency NamedScope into parameter resolutionRoot of constructor of type OwinNinjectDependencyResolver\r\n 1) Request for IDependencyResolver\r\n\r\nSuggestions:\r\n 1) Ensure that you have defined a binding for INotifier.\r\n 2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.\r\n 3) Ensure you have not accidentally created more than one kernel.\r\n 4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.\r\n 5) If you are using automatic module loading, ensure the search path and filters are correct.\r\n", "ExceptionType":"Ninject.ActivationException", "StackTrace":" à Ninject.KernelBase.Resolve(IRequest request)\r\n à Ninject.Planning.Targets.Target1.GetValue(Type service, IContext parent)\r\n à Ninject.Planning.Targets.Target1.ResolveWithin(IContext parent)\r\n
à Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target)\r\n à Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.b__2(ITarget target)\r\n à System.Linq.Enumerable.WhereSelectArrayIterator2.MoveNext()\r\n à System.Linq.Buffer1..ctor(IEnumerable1 source)\r\n à System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source)\r\n à Ninject.Activation.Providers.StandardProvider.Create(IContext context)\r\n à Ninject.Activation.Context.ResolveInternal(Object scope)\r\n à Ninject.Activation.Context.Resolve()\r\n à Ninject.KernelBase.<>c__DisplayClass15.b__f(IBinding binding)\r\n à System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext()\r\n à System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable1 source)\r\n à Ninject.Web.WebApi.NinjectDependencyScope.GetService(Type serviceType)\r\n à System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n à System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"} }

所以我需要知道:

  1. 这个错误的原因是什么?
  2. 我该如何解决?

您正在混合依赖注入方法。您正在使用 OWIN 为 Web API 设置 ninject 中间件,但是您正在 OWIN 之外管理 Web API(使用 IIS 管道):

protected void Application_Start()
{
    //..
    GlobalConfiguration.Configure(WebApiConfig.Register);
    //..
}

第二个错误是您正在创建多个内核,并且您的异常消息警告您避免这种情况:

Ensure you have not accidentally created more than one kernel

首先重构您的代码。仅使用 OWIN 管理 Web API:

public void Configuration(IAppBuilder app)
{
    var config = new HttpConfiguration();
    WebApiConfig.Register(config);
    app.UseNinjectMiddleware(() => NinjectDependencyResolver.CreateKernel.Value);
    ConfigureAuth(app);
    app.UseNinjectWebApi(config);
}

并从 Global.asax.cs 中删除此行:

GlobalConfiguration.Configure(WebApiConfig.Register);

然后确保您在整个应用程序生命周期内只创建一个内核。您应该只有一个内核的静态实例,并从需要它的任何其他对象引用它。