2010-08-09 22 views
1

Je construis un service web ASP.NET qui sera utilisé en interne dans mon entreprise. La journalisation d'exception et de trace/audit sera effectuée par la classe de service Web ainsi que par les objets métier que le service Web appellera. La consignation est gérée par une instance d'une classe d'aide de journal développée en interne. L'assistant de consignation doit être une instance lors du suivi de l'état et un guide de référence utilisé pour relier les messages de journal en groupes.Comment stocker un objet dans un service Web asp.net afin que les objets métier puissent référencer l'objet?

Dans le passé, nous avons géré cette situation en transmettant des références à l'instance d'aide de journal de classe en classe en utilisant les paramètres de la méthode. J'essaie de trouver un moyen fiable de trouver un moyen de stocker et d'accéder à l'instance tout au long de l'appel sans avoir à le transmettre explicitement.

Je tente de stocker l'instance dans HTTPContext au cours des premières étapes de l'appel de service Web. Lorsque mes objets métier en ont besoin plus tard pendant l'appel, ils y accèdent en tant que propriété d'une classe de base dont tous mes objets héritent.

Initialement, j'ai essayé de stocker l'instance dans Context.Cache du service Web. Cela a semblé fonctionner et mes recherches m'ont amené à croire que le cache serait thread safe. Ce n'est que lorsque j'ai commencé à appeler le service Web à partir de plus de 3 sessions simultanées que l'instance de l'enregistreur était partagée d'appel en appel plutôt que recréée pour chaque appel. J'ai essayé Context.Application et trouvé des résultats très similaires au stockage de cache.

J'ai été capable de trouver ce qui ressemble à une solution utilisable avec Context.Session. Cela m'oblige à utiliser EnableSession = true dans les attributs de chaque méthode mais il semble que l'instance reste unique par appel. Je n'ai pas besoin de suivre les données entre les appels, donc je ne stocke pas de cookies de session dans l'espace client.

La session est-elle le point de stockage optimal pour mes besoins? Cela semble un peu lourd étant donné que je n'ai pas besoin de suivre la session entre les appels. Je suis ouvert aux suggestions ou aux critiques. Je suis sûr que quelqu'un va suggérer d'utiliser la journalisation Trace intégrée ou des systèmes comme Elmah. Ce pourrait être une option pour l'avenir, mais pour l'instant, je n'ai pas le temps de suivre cette voie.

Mise à jour: Je devrais préciser que ce service devra fonctionner sur .Net Framework 2.0. Nous sommes en train de passer à 3.5/4.0 mais notre serveur de production actuel est Win2000 avec un maximum de 2.0.

+0

BTW, le terme "instance d'objet" est redondant. Un objet est une instance d'une classe. –

+0

Merci d'avoir mis à jour la question. "Instance d'un objet" est quelque chose que j'ai grandi en utilisant, mais je ne tenterais jamais d'argumenter comme correct. –

Répondre

1

Je suppose que, dans le passé, vous avez utilisé ces objets métier dans une application Windows Forms?

Vos objets métier ne doivent pas dépendre d'un objet ambiant. Au lieu de cela, vous devez utiliser injection de constructeur ou injection de propriété pour passer l'objet de consignateur aux objets métier. L'enregistreur doit être représenté par une interface, pas par une classe concrète. Les objets métier doivent être passés une référence à une classe qui implémente cette interface. Ils doivent jamais savoir où cet objet est stocké.Cela vous permettra de tester les objets métier en dehors du service Web.

Vous pouvez ensuite stocker l'objet de journalisation où vous le souhaitez. Je suggère de le stocker dans HttpContext.Current.Items, qui est seulement valide pour la demande actuelle.


public interface ILogger 
{ 
    void Log(string message); 
} 

public class Logger : ILogger 
{ 
    public void Log(string message) {} 
} 

public class BusinessObjectBase 
{ 
    public BusinessObjectbase(ILogger logger) 
    { 
     Logger = logger; 
    } 

    protected ILogger Logger {get;set;} 
} 

public class BusinessObject : BusinessObjectBase 
{ 
    public void DoSomething() 
    { 
     Logger.Log("Doing something"); 
    } 
} 
+0

La bibliothèque de journalisation est ancrée dans les applications WinForm et WebForm. Une grande partie de la base de code héritée à partir de laquelle je travaille n'est pas basée sur un objet et n'a pas à se soucier des mêmes choses que mon code. HttpContext.Current.Items fonctionne comme j'ai besoin et répond à ma question. J'ai accepté la réponse sur cette base. Vous parlez d'une forme d'injection de dépendance? J'ai regardé DI et ai l'intention de l'utiliser mais je ne peux pas argumenter jusqu'à ce que je puisse le comprendre fermement. Auriez-vous l'amabilité de publier un exemple de ce que vous décrivez en utilisant le scénario que j'ai décrit dans ma question? –

+0

Merci John. Votre exemple est assez proche de ce que je pensais que vous proposiez. Mon problème est que j'ai certains objets qui sont créés en utilisant des constructeurs avec plusieurs paramètres et j'ai des méthodes statiques qui ont besoin de journalisation. Aurais-je besoin de les étendre pour avoir des paramètres supplémentaires ou existe-t-il un autre moyen? J'ai regardé brièvement Unity et Castle Windsor mais les deux semblent trop complexes pour que je puisse les utiliser maintenant. –

+0

@Chris: pour une chose, vous avez trouvé une raison pour ne pas utiliser de méthodes statiques :-). Oui, vous devrez passer ces paramètres en tant que constructeur à tout ce qui doit utiliser la journalisation, à moins qu'ils n'aient déjà un autre objet en commun. Dans ce cas, vous pouvez placer l'instance ILogger dans cet objet commun. –

2

Vous pouvez essayer d'utiliser OperationContext.Current. Cela vous permettra de stocker des variables pour la durée de vie de l'appel de service Web. Comme vous n'avez pas WCF, vous pouvez créer quelque chose comme le stockage local de thread en créant une carte statique des ID de threads à votre objet. Assurez-vous simplement que vous nettoyez correctement cette carte statique lorsque les demandes sont terminées ou que l'appel suivant qui utilise ce thread récupère votre objet. Assurez-vous également de verrouiller la carte lorsque vous y accédez.

+0

Cela ressemble à une option très prometteuse, mais je suis verrouillé à. Net Framework 2.0. J'espère que nous aurons bientôt terminé notre migration de Windows 2000 et que 3.5/4.0 sera disponible en option. –

0

Ma compréhension est qu'une classe ASMX est instancié pour chaque appel. Par conséquent, il semble que vous pourriez instancier votre classe log-helper dans le constructeur d'ASMX, et le stocker dans une variable d'instance. Tout le traitement dans la classe ASMX ferait référence à cette variable d'instance. De cette manière, la même instance de log-helper serait utilisée tout au long du cycle de vie d'un seul appel de service Web et NE serait PAS partagée entre plusieurs appels.

Ceci serait probablement implémenté dans une super-classe commune, dont hériteraient toutes vos classes ASMX. Bien que je suppose que rien ne vous empêche de l'implémenter encore et encore dans chaque classe ASMX, si pour une raison quelconque vous évitez une superclasse commune.

+0

Il ne s'agirait pas d'une méthode propre pour créer des classes métier car l'objet de super-classe doit hériter de System.Web.Services.WebService. Ce serait beaucoup de poids à faire glisser dans les objets d'affaires simples. Interfaces pourraient prêter pour une solution possible si. –

+0

Désolé si j'ai mal compris votre question - Je suis absolument d'accord que ce serait une idée horrible pour vos objets d'affaires à sous-classe de WebService! :) Cependant, il serait également mauvais que vos objets métier référencent directement le contexte ou la session, car cela empêcherait leur réutilisation dans un contexte différent (service Windows, console, etc.). Je supposais que la classe ASMX gérerait le cycle de vie de l'instance de log-helper, et le fournirait aux classes de business selon les besoins. – mikemanne