J'utilise un Ninject DI dans mon application web avec un tas de technologies de la pile Asp.Net (MVC, Web Api 2, SignalR).Ninject avec Web Api, SignalR, MVC et OWIN
J'ai réussi à faire fonctionner DI pour toutes les technologies utilisées avec l'approche suivante:
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>
internal 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)
{
GlobalHost.DependencyResolver = new Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver(kernel);
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
// Binding services here
}
}
Jusqu'à présent, si bon.
Tout cela fonctionnait avec l'initialisation de Web Api dans Global.asax.
Maintenant, je passe à OWIN pipeline. Donc, je l'ai enlevé GlobalConfiguration.Configure(WebApiConfig.Register);
de Global.asax et ajouté
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
à ma classe OwinStartup
. DI pour Web Api a cessé de fonctionner.
J'ai commencé à chercher la solution appropriée et j'ai trouvé le paquet Ninject.Web.WebApi.OwinHost
. Ainsi, afin d'avoir une seule résolution des dépendances du noyau pour toutes les technologies, j'ai apporté les modifications suivantes:
dans OwinStartup:
app.UseNinjectMiddleware(NinjectWebCommon.CreateKernel);
app.UseNinjectWebApi(config);
dans NinjectWebCommon:
//[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(App.TradingServer.ConfiguratorApp.App_Start.NinjectWebCommon), "Start")]
//[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(App.TradingServer.ConfiguratorApp.App_Start.NinjectWebCommon), "Stop")]
Ces lignes ont été désactivées pour éviter d'initialiser le noyau deux fois.
Cette DI fixe pour API Web mais pas pour SignalR. Lorsque le client tente de se connecter au centre, je reçois l'exception suivante:
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.AspNet.SignalR.PersistentConnection.ProcessNegotiationRequest(HostContext context)
at Microsoft.AspNet.SignalR.PersistentConnection.ProcessRequest(HostContext context)
at Microsoft.AspNet.SignalR.Hubs.HubDispatcher.ProcessRequest(HostContext context)
at Microsoft.AspNet.SignalR.PersistentConnection.ProcessRequest(IDictionary`2 environment)
at Microsoft.AspNet.SignalR.Owin.Middleware.HubDispatcherMiddleware.Invoke(IOwinContext context)
at Microsoft.Owin.Infrastructure.OwinMiddlewareTransition.Invoke(IDictionary`2 environment)
at Microsoft.Owin.Mapping.MapMiddleware.<Invoke>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at System.Web.Http.Owin.HttpMessageHandlerAdapter.<InvokeCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Ninject.Web.Common.OwinHost.OwinBootstrapper.<Execute>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContextStage.<RunApp>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.<DoFinalWork>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.Owin.Host.SystemWeb.Infrastructure.ErrorState.Rethrow()
at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar)
at Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.EndFinalWork(IAsyncResult ar)
at System.Web.HttpApplication.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) | RuntimeMethodInfo.UnsafeInvokeInternal => RuntimeMethodHandle.InvokeMethod => Application.Application_Error
Je suis un peu perdu. Je lis deux douzaines d'articles mais aucun d'entre eux ne m'a donné la solution. Apprécierait toute aide.
Mon but final est de disposer d'un seul noyau qui serve Web Api, MVC et SignalR et supporte le pipeline OWIN.
Modifier: Depuis que j'ai un commentaire que mon cas pourrait être une copie d'une autre question, je crois que je dois donner quelques explications.
J'ai trois scénarios.
initialisation du WebAPI dans Global.asax avec
GlobalConfiguration.Configure(WebApiConfig.Register)
, l'initialisation Ninject avec NinjectWebCommon et d'amorçage.Cela me donne à la fois l'injection dans WebApi et SignalR. Mais puisque je voudrais déplacer l'initialisation de WebApi au démarrage d'OWIN, cette approche est obsolète.
Initialisation WebApi avec démarrage OWIN, initialisation Ninject avec NinjectWebCommon et Bootstrapper.
L'injection SignalR fonctionne, l'injection WebApi ne fonctionne pas.
Initialisation WebApi avec démarrage OWIN, initialisation Ninject avec UseNinjectMiddleware, UseNinjectWebApi.
L'injection WebApi fonctionne, l'injection SignalR ne fonctionne pas.
Donc, fondamentalement, j'ai besoin de savoir comment mettre cela ensemble pour que les deux WebAPI et le travail d'injection SignalR quand j'initialize WebAPI sur pipeline OWIN.
Le code de NinjectWebCommon est dans la question originale ci-dessous. Il contient du code pour créer résolveur SignalR mais il ne permet pas dans le scénario 3.
Edit 2: Après quelques heures de méthode essais et erreurs, je suis venu à la conclusion que l'appel
app.UseNinjectMiddleware(NinjectWebCommon.CreateKernel);
app.UseNinjectWebApi(config);
conflits avec cet appel:
GlobalHost.DependencyResolver = new Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver(kernel);
Donc la description du problème se réduit à ceci. Lorsque j'utilise le modèle suivant SignalR cesse de fonctionner:
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseNinjectMiddleware(CreateKernel);
app.UseNinjectWebApi(config);
GlobalHost.HubPipeline.AddModule(new GlobalSignalRExceptionHandler());
app.MapSignalR();
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
GlobalHost.DependencyResolver = new Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver(kernel);
DependencyResolver.SetResolver(new Ninject.Web.Mvc.NinjectDependencyResolver(kernel));
return kernel;
}
Mais si je commente la ligne
//GlobalHost.DependencyResolver = new Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver(kernel);
SignalR commence à travailler. Mais pas d'injection à l'intérieur des moyeux bien sûr.
double possible de [2 SignalR injection de dépendance avec Ninject] (http://stackoverflow.com/questions/21285934/signalr-2-dependency-injection-with-ninject) – mason
Le sujet mentionné ne couvre pas l'intégration avec le tuyau OWIN. Tous les trucs avec app.UseNinjectMiddleware et app.UseNinjectWebApi. Fondamentalement, ils décrivent l'approche que j'utilisais avant de passer à OWIN. – user1921819
Un commentaire général sur ce type de problème: Ma recherche montre qu'une 'NullReferenceException' avec cette trace de pile est levée si le conteneur DI utilisé par SignalR distribue plusieurs instances de certains types qui devraient être des singletons. Cela peut se produire pour diverses raisons, l'une étant que 'GlobalHost.DependencyResolver' est modifié après que le conteneur SignalR par défaut a déjà été utilisé. Dans OWIN, vous pouvez appeler MapSignalR tard dans le pipeline. Par exemple. avec Nancy 'app.UseNancy (o => o.PerformPassThrough = c => c.Request.Path.ToUpperInvariant(). StartsWith ("/SIGNALR ")). MapSignalR()'. –