À l'aide de Simples Injecteur avec SignalR
J'ai pensé à l'aide de mon propre Cio serait assez simple avec SignalR et peut-être qu'il est; la plupart du temps je suis en train de faire quelque chose de mal. Voici mon code, j'ai jusqu'à présent:
private static void InitializeContainer(Container container)
{
container.Register<IMongoHelper<UserDocument>, MongoHelper<UserDocument>>();
//... registrations like about and then:
var resolver = new SimpleInjectorResolver(container);
GlobalHost.DependencyResolver = resolver;
}
et puis ma classe:
public class SimpleInjectorResolver : DefaultDependencyResolver
{
private Container _container;
public SimpleInjectorResolver(Container container)
{
_container = container;
}
public override object GetService(Type serviceType)
{
return _container.GetInstance(serviceType) ?? base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
return _container.GetAllInstances(serviceType) ?? base.GetServices(serviceType);
}
}
Il arrive, j'obtiens une erreur que IJavaScriptProxyGenerator ne peut pas être résolu, je pense donc que, eh bien, je vais ajouter l'enregistrement:
container.Register<IJavaScriptProxyGenerator, DefaultJavaScriptProxyGenerator>(
ConstructorSelector.MostParameters);
mais alors il y a un tas d'autres! J'arrive à:
container.Register<IDependencyResolver, SimpleInjectorResolver>();
container.Register<IJavaScriptMinifier, NullJavaScriptMinifier>();
container.Register<IJavaScriptProxyGenerator, DefaultJavaScriptProxyGenerator>(
ConstructorSelector.MostParameters);
container.Register<IHubManager, DefaultHubManager>();
container.Register<IHubActivator, DefaultHubActivator>();
container.Register<IParameterResolver, DefaultParameterResolver>();
container.Register<IMessageBus, InProcessMessageBus>(ConstructorSelector.MostParameters);
Qui me donne toujours "Aucun enregistrement de type ITraceManager
a pu être trouvé." ... mais maintenant je me demande si je fais ce droit à tous comme je l'espère, je n'aurais pas besoin de re-câbler tout SignalR est en train de faire...droit? Espérons? Si pas, je vais continuer de courir le long, mais je suis un SignalR et Simple de l'Injecteur newb donc pensé que je voudrais vous demander d'abord. 🙂
Supplémentaires: https://cuttingedge.it/blogs/steven/pivot/entry.php?id=88 depuis SignalR a plusieurs constructeurs.
Vous devez vous connecter pour publier un commentaire.
Bien, j'ai essayé hier et j'ai trouvé une solution.
Selon moi, le seul moment où je veux l'injection de dépendance dans SignalR est pour mon moyeux: je ne se soucient pas comment SignalR est de travailler à l'intérieur !
Donc, au lieu de remplacer le DependencyResolver, j'ai créé ma propre mise en œuvre de IHubActivator :
Que je puisse m'inscrire comme ceci (dans Application_Start) :
return (IHub)DependencyResolver.Current.GetService(descriptor.HubType);
RouteTable.Routes.MapHubs();
? Cette ligne je ne comprends pas. Si je l'omettre, il fonctionne également comme un charme.Envie de balancer mon 2 cents ici avec les autres réponses, qui peuvent être utiles pour trouver votre propre chemin avec l'injection de dépendance dans SignalR, soit à l'aide de SimpleInjector ou d'une autre Cio.
À l'aide de @Steven réponse
Si vous décidez d'utiliser Steven réponse, assurez-vous d'enregistrer votre hub route avant de composer la racine. Le
SignalRRouteExtensions.MapHubs
méthode d'extension (un.k.un.routes.MapHubs()
) va appelerRegister(Type, Func<object>)
sur leGlobalHost.DependencyResolver
lors de la cartographie du hub de routes, de sorte que si vous changer deDefaultDependencyResolver
avec Steven estSimpleInjectorResolver
avant que les routes sont mappés, vous allez courir dans sonNotSupportedException
.À l'aide de @Nathanael Marchand répondre
C'est mon préféré. Pourquoi?
SimpleInjectorDependencyResolver
.DefaultDependencyResolver
(un.k.un.GlobalHost.DependencyResolver
), ce qui signifie encore moins de code.DefaultDependencyResolver
, il "fonctionne".Comme Nathanaël dit cependant, c'est seulement si vous vous souciez de l'dépendances sur votre
Hub
des classes, ce qui sera probablement le cas pour la plupart. Si vous souhaitez s'amuser avec l'injection de dépendances dans SignalR, vous pouvez aller avec Steven réponse.Problèmes avec par web-demande de dépendances dans un
Hub
Il y a une chose intéressante à propos de SignalR... lorsqu'un client se déconnecte d'un hub (par exemple par la fermeture de la fenêtre de son navigateur), il va créer une nouvelle instance de la
Hub
classe pour invoquerOnDisconnected()
. Lorsque cela se produit,HttpContext.Current
est null. Donc, si ceHub
a toutes les dépendances qui sont enregistrés par le web demande, quelque chose va probablement aller mal.Dans Ninject
J'ai essayé SignalR l'injection de dépendance à l'aide Ninject et la ninject signalr solveur de dépendances sur nuget. Avec cette configuration, les dépendances qui sont liés
.InRequestScope()
sera créé de façon transitoire lorsqu'elle est injectée dans unHub
lors d'une déconnexion de l'événement. DepuisHttpContext.Current
est nul, je suppose que Ninject juste décide de l'ignorer et de créer les instances éphémères sans vous le dire. Peut-être il y avait un paramètre de configuration pour indiquer ninject pour avertir à ce sujet, mais il n'était pas le défaut.Dans SimpleInjector
SimpleInjector sur l'autre main va lever une exception lorsqu'un
Hub
dépend d'une instance qui est enregistré avecWebRequestLifestlyle
:...cette exception ne bulle quand
HttpContext.Current == null
, qui, autant que je peux dire, ne se produit que lorsque SignalR demande unHub
exemple dans le but d'invoquerOnDisconnected()
.Solutions pour par web-demande de dépendances dans un
Hub
Noter qu'aucune de ces sont vraiment l'idéal, tout dépend des exigences de votre application.
Dans Ninject
Si vous avez besoin non transitoires dépendances, il suffit de ne pas remplacer
OnDisconnected()
ou faire quelque chose de personnalisé avec la classe de dépendances. Si vous le faites, chaque dépendance dans le graphique sera séparé (transitoire) de l'instance.Dans SimpleInjector
Vous avez besoin d'un hybride de style de vie entre
WebRequestLifestlye
et soitLifestyle.Transient
,Lifestyle.Singleton
, ouLifetimeScopeLifestyle
. LorsqueHttpContext.Current
n'est pas null, dépendances ne vivre aussi longtemps que la demande web que vous auriez normalement s'attendre. Toutefois, lorsqueHttpContext.Current
est null, dépendances s'être injecté de façon transitoire, comme des singletons, ou à l'intérieur d'une durée de vie étendue.Plus sur
LifetimeScopeLifestyle
Dans mon cas, j'ai un EntityFramework
DbContext
de dépendance. Ces peut être difficile, car ils peuvent exposer les problèmes lors de l'enregistrement de façon transitoire ou comme des singletons. Lors de l'enregistrement de façon transitoire, vous pouvez vous retrouver avec des exceptions, tout en essayant de travailler avec des entités attachées à 2 ou plusDbContext
instances. Une fois inscrit en tant que singleton, vous vous retrouvez avec plus d'exceptions générales (ne jamais enregistrer unDbContext
comme un singleton). Dans mon cas, j'avais besoin de laDbContext
de vivre au sein d'une vie dans laquelle la même instance peut être réutilisé dans de nombreuses opérations imbriquées, ce qui signifie que j'ai besoin de l'LifetimeScopeLifestyle
.Maintenant, si vous avez utilisé le code hybride au-dessus de la
falseLifestyle: new LifetimeScopeLifestyle()
ligne, vous obtiendrez une autre exception lors de votre personnaliséIHubActivator.Create
méthode exécute:La façon dont vous avez configuré une durée de vie étendue de la dépendance va comme ceci:
Toutes les dépendances qui sont enregistrés auprès de la durée de vie de la portée doit être résolu dans ce
using
bloc. En outre, si l'une de ces dépendances mettre en œuvreIDisposable
, ils seront éliminés à la fin de lausing
bloc. Ne soyez pas tenté de faire quelque chose comme ceci:J'ai demandé à Steven (qui se trouve également être la SimpleInjector auteur dans le cas où vous ne le saviez pas) à ce sujet, et il a dit:
Vous ne pouvez pas utiliser
IHubActivator
à portée les dépendances, car il ne vivent pas aussi longtemps que laHub
exemple, qu'il crée. Donc, même si vous avez enveloppé leBeginLifetimeScope()
méthode dans unusing
bloc, vos dépendances être éliminés immédiatement après laHub
instance est créée. Ce que vous avez vraiment besoin ici, c'est une autre couche d'indirection.Ce que j'ai, avec beaucoup de grâce à Steven d'aide, est une commande décorateur (et une requête décorateur). Un
Hub
ne peut dépendre de la par web-demande d'instances lui-même, mais doit, au contraire, dépendent d'une autre interface dont la mise en œuvre dépend de la demande des instances. La mise en œuvre qui est injecté dans l'Hub
constructeur est décoré (via simpleinjector) avec un wrapper qui commence et dispose de la durée de vie étendue.... il est décoré de
ICommandHandler<T>
des instances qui en dépendent par web-demande d'instances. Pour plus d'informations sur le modèle utilisé, lire cette et cette.Exemple d'enregistrement
RegisterManyForOpenGeneric
, puis les décorer avecRegisterDecorator
passage de laCommandLifetimeScopeDecorator
. Vous pouvez effectivement modifier le code ci-dessus pour utiliser unICommandHandler<TCommand>
au lieu d'unFunc<ICommandHandler<TCommand>>
et il faudra encore injecter. Il suffit d'injecter de l'instance au lieu d'un délégué pour les paresseux injecter de l'instance. J'ai mis à jour la réponse avec un exemple.ExecutionContext
modes de vie, avez-vous encore besoin de votre hybride de style de vie? Ses une bonne lecture quand même!Mise à JOUR Cette réponse a été mis à jour pour SignalR version 1.0
C'est la façon de construire un SignalR
IDependencyResolver
pour un Simple Injecteur:Malheureusement, il y a un problème avec la conception de la
DefaultDependencyResolver
. C'est pourquoi la mise en œuvre ci-dessus n'hérite pas de lui, mais il encapsule. J'ai créé un problème à ce sujet sur le SignalR site. Vous pouvez lire à ce sujet ici. Bien que le concepteur d'accord avec moi, malheureusement, la question n'a pas été corrigé dans la version 1.0.J'espère que cette aide.
De SignalR 2.0 (et la version bêta de l') il y a un nouveau mode de réglage de la résolution de dépendances. SignalR déménagé à OWIN de démarrage pour effectuer la configuration. Avec de Simples Injecteur vous ferais comme ceci:
Vous devez explicitement injecter des hubs comme suit:
Cette config est en cours d'exécution en direct sur un haut trafic de site web sans problèmes.
GetServices
méthode. Vérification du code pourGetRegistration(serviceType, false) != null
, mais ce prédicat généralement rendement faux, puisqu'un enregistrement pour une collection est un autre enregistrement. FaireGetRegistration(typeof(IEnumerable<>).MakeGenericType(serviceType), false) != null
cependant ne fonctionnera pas, car ce ne sera jamais retourner la valeur null (depuis le Simple Injecteur fait de cette inscription pour vous si il est manquant). Donc blueling la réponse est beaucoup mieux.Container
à partir de votreStartup
classe?Container
exemple dans le morceau de code suivant:var config = new HubConfiguration() { Resolver = new SignalRSimpleInjectorDependencyResolver(Container) };
La suite travaillé pour moi. En outre, vous devrez vous inscrire à un délégué du conteneur pour votre classe hub avant l'instanciation de la résolution de dépendances.