Il y a ce cadre que j'aide à concevoir. Certaines tâches courantes doivent être effectuées à l'aide de composants communs: la journalisation, la mise en cache et le déclenchement d'événements en particulier.
Je ne sais pas s'il est préférable d'utiliser l'injection de dépendances et d'introduire tous ces composants dans chaque service (comme propriétés par exemple) ou dois-je disposer d'une sorte de métadonnées sur chaque méthode de mes services et utiliser l'interception pour effectuer ces tâches courantes ?
Voici un exemple des deux:
Injection:
public class MyService
{
public ILoggingService Logger { get; set; }
public IEventBroker EventBroker { get; set; }
public ICacheService Cache { get; set; }
public void DoSomething()
{
Logger.Log(myMessage);
EventBroker.Publish<EventType>();
Cache.Add(myObject);
}
}
et voici l'autre version:
Interception:
public class MyService
{
[Log("My message")]
[PublishEvent(typeof(EventType))]
public void DoSomething()
{
}
}
Voici mes questions:
- Quelle solution est la meilleure pour un cadre complexe?
- Si l'interception réussit, quelles sont mes options pour interagir avec les valeurs internes d'une méthode (à utiliser avec le service de cache par exemple?)? Puis-je utiliser d'autres méthodes plutôt que des attributs pour implémenter ce comportement?
- Ou peut-être qu'il peut y avoir d'autres solutions pour résoudre le problème?
c#
dependency-injection
Beatles1692
la source
la source
Réponses:
Les préoccupations transversales telles que la journalisation, la mise en cache, etc. ne sont pas des dépendances, elles ne doivent donc pas être injectées dans les services. Cependant, alors que la plupart des gens semblent alors rechercher un cadre AOP entrelacé complet, il existe un joli modèle de conception pour cela: le décorateur .
Dans l'exemple ci-dessus, laissez MyService implémenter l'interface IMyService:
Cela maintient la classe MyService complètement exempte de préoccupations transversales, suivant ainsi le principe de responsabilité unique (SRP).
Pour appliquer la journalisation, vous pouvez ajouter un décorateur de journalisation:
Vous pouvez implémenter la mise en cache, la mesure, les événements, etc. de la même manière. Chaque décorateur fait exactement une chose, ils suivent donc également le SRP, et vous pouvez les composer de manière arbitrairement complexe. Par exemple
la source
Pour une poignée de services, je pense que la réponse de Mark est bonne: vous n'aurez pas à apprendre ou à introduire de nouvelles dépendances tierces et vous suivrez toujours de bons principes SOLID.
Pour une grande quantité de services, je recommanderais un outil AOP comme PostSharp ou Castle DynamicProxy. PostSharp a une version gratuite (comme dans la bière), et ils ont récemment publié PostSharp Toolkit for Diagnostics , (gratuit comme dans la bière ET la parole) qui vous donnera des fonctionnalités de journalisation prêtes à l'emploi .
la source
Je trouve que la conception d'un cadre est en grande partie orthogonale à cette question - vous devez d'abord vous concentrer sur l'interface de votre cadre, et peut-être en tant que processus mental d'arrière-plan, pensez à la façon dont quelqu'un pourrait réellement le consommer. Vous ne voulez pas faire quelque chose qui l' empêche d'être utilisé de manière intelligente, mais cela ne devrait être qu'une entrée dans la conception de votre framework; un parmi tant d'autres.
la source
J'ai rencontré ce problème à maintes reprises et je pense avoir trouvé une solution simple.
Au départ, je suis allé avec le modèle de décorateur et j'ai implémenté manuellement chaque méthode, lorsque vous avez des centaines de méthodes, cela devient très fastidieux.
J'ai alors décidé d'utiliser PostSharp mais je n'aimais pas l'idée d'inclure une bibliothèque entière juste pour faire quelque chose que je pouvais accomplir avec (beaucoup) de code simple.
J'ai ensuite emprunté la route proxy transparente qui était amusante mais impliquait l'émission dynamique d'IL au moment de l'exécution et ne serait pas quelque chose que je voudrais faire dans un environnement de production.
J'ai récemment décidé d'utiliser des modèles T4 pour implémenter automatiquement le modèle de décorateur au moment de la conception, il s'avère que les modèles T4 sont en fait assez difficiles à travailler et j'avais besoin que cela soit fait rapidement, j'ai donc créé le code ci-dessous. C'est rapide et sale (et il ne prend pas en charge les propriétés) mais j'espère que quelqu'un le trouvera utile.
Voici le code:
Voici un exemple:
Créez ensuite une classe appelée LoggingTestAdapter qui implémente ITestAdapter, obtenez Visual Studio pour implémenter automatiquement toutes les méthodes, puis exécutez-le via le code ci-dessus. Vous devriez alors avoir quelque chose comme ceci:
C'est tout avec le code de support:
la source