0

J'essaie d'utiliser Ninject sur mon projet actuel, et jusqu'à présent, je l'aimais. Je suis en train de tenter de configurer un objet IInterceptor pour intercepter et gérer un appel de méthode ayant échoué vers ma couche de service. Ceci est hébergé dans une application ASP.NET MVC 5.La tentative de résolution d'un élément de Ninject dans IInterceptor échoue

Dans le IInterceptor, j'ai essayé plusieurs choses, telles que:

  1. Définition des variables privées à l'aide de l'injection de constructeur, mais il est venu découvrir qu'il semble Ninject réutilisera une instance IInterceptor pour une méthode indéfiniment, et je n'ai pas trouvé un moyen d'arrêter ça. Puisque l'une des choses que j'apporte dans la portée est une DbContext qui est disposée ailleurs, elle finit par échouer sur toutes les demandes futures que celle sur laquelle elle a été créée. J'ai trouvé que IInvocation a une propriété Request.Kernel. Cependant, lorsque je tente de résoudre mon UOW à partir du conteneur, qui est .InRequestScope(), il échoue, car il tente de résoudre les dépendances IUowService (l'une des dépendances dépend du HttpContext qui est null à ce stade), mais semble être le faire en dehors de la portée de la demande. Il ignore le fait que les dépendances dont il a besoin ont déjà été créées dans la requête ASP.NET et tente d'en créer de nouvelles.

  2. Définition d'une liaison pour l'intercepteur this.Bind<NinjectExceptionHandler>().ToSelf().InTransientScope(), mais cela n'a pas semblé arrêter la mise en cache de l'intercepteur.

J'imagine qu'il y a quelque chose qui me manque. Je comprends vouloir mettre en cache des objets IInterceptor pour la performance, mais je trouve ça ennuyeux que je ne peux pas facilement utiliser le conteneur ou l'injection IOC pour obtenir les objets dont j'ai besoin pour ma demande.

Ceci est le dernier problème que je rencontre pour obtenir l'interception en fonction de mes besoins, donc toute aide est grandement appréciée!

+1

concernant 2 .: Avez-vous essayé d'utiliser l'extension de préservation du contexte de ninject? Et puis vous devez faire 'Request.Kernel.ContextPreservingGet <...>()'. Nous avons rencontré le même problème et nous avons créé notre propre implémentation d'injection par proxy/interception où chaque instance de proxy obtient sa propre instance d'intercepteur. Cependant, nous avons eu une discussion avec le responsable du projet et je pense qu'il devrait y avoir un moyen de spécifier que l'intercepteur ne devrait pas être réutilisé, mais je ne me souviens pas exactement de quoi il s'agissait, désolé. – BatteryBackupUnit

+0

@BatteryBackupUnit, toute information supplémentaire que vous seriez en mesure de donner sur ce serait utile. J'ai juste essayé le plugin de préservation de contexte, et cela n'a pas semblé fonctionner - même problème, il semble fonctionner en dehors de la portée de la demande originale de Ninject - bizarre. Je devine par «discussion avec le mainteneur de projet» vous voulez dire Ninject? Comment avez-vous exactement écrit votre implémentation pour que chaque proxy ait son propre intercepteur? Merci pour votre réponse rapide! – tostringtheory

Répondre

0

Il semble donc qu'il n'y a aucun moyen de faire ce que j'essayais gracieusement avec Ninject. Une fois dans le IInterceptor et dans les dernières parties des opérations asynchrones, le HttpContext a été perdu et Ninject n'a pas pu résoudre les choses qu'il aurait dû penser être dans la portée. Couplé avec le fait qu'il a réutilisé IInterceptor pour une méthode (comme je l'ai dit, compréhensible, mais irritant), je ne pouvais tout simplement pas le faire fonctionner comme je le voulais.

Ce que j'ai pu faire pour contourner le fait était quelque chose de simple, mais un peu kludgy (je pense). Comme toutes les méthodes que j'interceptais se trouvaient dans ma couche de service, et tous mes services ont implémenté un IBaseService à travers une classe de base BaseService, qui possédait les objets dont j'avais besoin en tant que propriétés, j'ai pu le faire dans l'intercepteur:

var uow = (invocation.Request.Target as IBaseService).UnitOfWork; 

Cela m'a permis d'accéder à mon unité de travail et de l'échouer, ainsi que d'accéder à l'instance de journalisation sur laquelle je travaillais. Pendant que cela fonctionne, je voudrais voir comment l'injection du constructeur d'intercepteurs fonctionne correctement à travers plusieurs appels, ou les appels au noyau plus bas pour réaliser qu'il a déjà résolu un objet encore dans la portée (bien que je sois devinant qu'il peut penser que c'est hors de portée puisque ASP.Net a abandonné la portée sur l'attente).

Pour tout intéressé, je vais essayer et poster à ce sujet sur mon blog bientôt (voir ma page d'utilisateur si réellement intéressé, pas de spam moi-même).

1

Selon votre demande, je vais plus en détail sur la façon dont nous avons atteint "1 proxy: 1 intercepteur" instance relation navire.

Nous avons pris la voie facile qui n'offre pas autant de flexibilité que ce que les extensions officielles d'interception de ninjee offrent. Nous comptons directement sur le proxy dynamique castle.core et ainsi l'interface du château IInvocation.

(Veuillez noter que le code ci-dessous est pour un proxy sans cible, mais un proxy avec cible est assez similaire - la seule chose qui change est que vous devez connaître le type de classe cible et utiliser IResolutionRoot.Get<TargetClassType>() pour l'instancier).

Fondamentalement, nous avons créé une reliure comme:

IBindingRoot.Bind<IFoo>() 
    .ToProvider<InterfaceProxyWithoutTargetProvider<IFoo>>(); 

Nous avons maintenant besoin bien sûr de savoir quels intercepteurs le proxy doit utiliser. Encore une fois, nous utilisons un outil facile - et pas si agréable - conception:

public interface IInterceptorBindingDefinition<TTarget> 
{ 
    Type InterceptorType { get; } 
} 

public class InterceptorBindingDefinition<TTarget, TInterceptor> : IInterceptorBindingDefinition<TTarget> 
    where TInterceptor : IInterceptor 
{ 
    Type InterceptorType { get { return typeof(TInterceptor); } } 
} 

IBindingRoot 
    .Bind<IInterceptorBindingDefinition<IFoo>>() 
    .To<InterceptorBindingDefinition<TTarget, LoggingInterceptor>(); 

IBindingRoot 
    .Bind<IInterceptorBindingDefinition<IFoo>>() 
    .To<InterceptorBindingDefinition<TTarget, SomeOtherInterceptor>();  

Cela signifie IFoo doit obtenir deux intercepteurs: LoggingInterceptor et SomeOtherInterceptor.

et la mise en œuvre du fournisseur:

public class InterfaceProxyWithoutTargetProvider<TInterface> : IProvider<TInterface> 
    where TInterface : class 
{ 
    private readonly IProxyGenerator proxyGenerator; 
    private readonly IInterceptorFactory interceptorFactory; 

    public InterfaceProxyWithoutTargetProvider(IProxyGenerator proxyGenerator, IInterceptorFactory interceptorFactory) 
    { 
     this.proxyGenerator = proxyGenerator; 
     this.interceptorFactory = interceptorFactory; 
    } 

    public Type Type 
    { 
     get { return typeof(TInterface); } 
    } 

    public object Create(IContext context) 
    { 

     var interceptorTypes = context.Kernel.Get<IEnumerable<IInterceptorBindingDefinition<TInterface>>(); 

     IList<IInterceptor> interceptors = interceptorTypes 
       .Select(x => x.InterceptorType) 
       .Select(x => context.ContextPreservingGet(x)) 
       .ToList(); 

     return this.proxyGenerator.CreateInterfaceProxyWithoutTarget<TInterface>(interceptors); 
    } 
} 

nous poli la chose Maintenant, bien sûr un peu nous avons donc une syntaxe couramment la configuration de la liaison du proxy et l'intercepteur - ce qui est assez facile.

Cependant approche de ninject.extensions.interception avec ses IAdviceRegistry et IAdvice est certainement mieux (mais nécessite également plus d'informations sur comment fonctionne ninject).

+0

Merci beaucoup pour votre contribution, je pense vraiment que c'est une bonne chose d'avoir ici au cas où d'autres en ont besoin. Je vais augmenter votre réponse car vous fournissez tellement de détails, mais à moins que j'obtienne une autre réponse qui résout complètement le problème, je marquerai la mienne comme la réponse car elle reste fidèle à l'utilisation du IInterceptor et montre un moyen rapide de contourner le problème. question dans un cas d'utilisation spécifique. Merci encore! – tostringtheory

Questions connexes