使用 owin 和 ninject 的 webapi 应用程序中的无参数构造函数问题
Parameterless constructor issue within webapi application using owin and ninject
我有一个 Web api 应用程序,我想在其中使用 Owin、Oauth 和 Ninject ,所以我有这个配置
依赖注入器
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.Target
1.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.Buffer
1..ctor(IEnumerable1 source)\r\n à
System.Linq.Enumerable.ToArray[TSource](IEnumerable
1 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](IEnumerable
1
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)"} }
所以我需要知道:
- 这个错误的原因是什么?
- 我该如何解决?
您正在混合依赖注入方法。您正在使用 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);
然后确保您在整个应用程序生命周期内只创建一个内核。您应该只有一个内核的静态实例,并从需要它的任何其他对象引用它。
我有一个 Web api 应用程序,我想在其中使用 Owin、Oauth 和 Ninject ,所以我有这个配置
依赖注入器
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.Target
1.GetValue(Type service, IContext parent)\r\n à Ninject.Planning.Targets.Target
1.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.Buffer
1..ctor(IEnumerable1 source)\r\n à System.Linq.Enumerable.ToArray[TSource](IEnumerable
1 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](IEnumerable
1 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)"} }
所以我需要知道:
- 这个错误的原因是什么?
- 我该如何解决?
您正在混合依赖注入方法。您正在使用 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);
然后确保您在整个应用程序生命周期内只创建一个内核。您应该只有一个内核的静态实例,并从需要它的任何其他对象引用它。