2010-11-07 46 views
6

J'ai maintenant quelque chose comme ceci:Est-il possible de créer un service Web statefull en C#?

public class Service1 : System.Web.Services.WebService 
{ 
    [WebMethod] 
    public string Method1() 
    { 
     SomeObj so = SomeClass.GetSomeObj(); //this executes very long time, 50s and more 
     return so.Method1(); //this exetus in a moment 
    } 

    [WebMethod] 
    public string Method2() 
    { 
     SomeObj so = SomeClass.GetSomeObj(); //this executes very long time, 50s and more 
     return so.Method2(); //this exetus in a moment 
    } 

... 
} 

Est-il possible de rendre le service Web statefull afin que je puisse réutiliser SomeObj so et juste appeler des méthodes sur le même objet?

Ainsi, le client qui utilisera ce service appellera d'abord une méthode web qui créerait un objet so et renverrait un identifiant. Ensuite, lors des appels suivants, le service Web réutilisera le même objet so en fonction de l'ID.

EDIT


Voici mon code actuel:

[WebMethod] 
public List<ProcInfo> GetProcessList(string domain, string machineName) 
{ 
    string userName = "..."; 
    string password = "..."; 
    TaskManager tm = new TaskManager(userName, password, domain, machineName); 

    return tm.GetRunningProcesses(); 
} 

[WebMethod] 
public bool KillProcess(string domain, string machineName, string processName) 
{ 
    string userName = "..."; 
    string password = "..."; 
    (new TaskManager(userName, password, domain, machineName);).KillProcess(processName);    
} 

Répondre

6

services web ne sont pas Stateful évolutive et je ne les recommande pas. Au lieu de cela, vous pouvez stocker les résultats des opérations coûteuses dans le cache. Ce cache peut être distribué par des fournisseurs personnalisés pour une meilleure évolutivité:

[WebMethod] 
public string Method1() 
{ 
    SomeObj so = TryGetFromCacheOrStore<SomeObj>(() => SomeClass.GetSomeObj(), "so"); 
    return so.Method1(); //this exetus in a moment 
} 

[WebMethod] 
public string Method2() 
{ 
    SomeObj so = TryGetFromCacheOrStore<SomeObj>(() => SomeClass.GetSomeObj(), "so"); 
    return so.Method2(); //this exetus in a moment 
} 

private T TryGetFromCacheOrStore<T>(Func<T> action, string id) 
{ 
    var cache = Context.Cache; 
    T result = (T)cache[id]; 
    if (result == null) 
    { 
     result = action(); 
     cache[id] = result; 
    } 
    return result; 
} 
+0

Pouvez-vous stocker tous les objets dans le cache ou il y a des limites? Mes objets incluent des connexions WMI ouvertes à divers ordinateurs. – Primoz

+0

Par défaut, le cache est stocké en mémoire et si vous commencez à fonctionner avec peu de mémoire, il sera automatiquement expulsé. Alors oui, vous pouvez stocker autant que vous le souhaitez mais vous devez toujours vérifier que l'objet est dans le cache et ne jamais compter sur lui étant là parce que vous l'avez stocké. –

+0

@Darin Dimitrov, vous devez sécuriser votre solution en utilisant un verrou. Tandis qu'une requête exécute le "result = action()" line, qui prend du temps, toute autre requête verra également le cache comme étant nul et répétera le même "result = action();" ligne. Voir http://en.wikipedia.org/wiki/Double-checked_locking – Sklivvz

1

Option 1

Vous pouvez utiliser votre HttpSession. Notez que cela ne fonctionne que si un appel par client est effectué à la fois.

Option 2

Vous pouvez quitter la classe est d'utiliser mais le WebMethod différemment. Si vous appelez à partir d'une classe générée par .Net, des méthodes async sont fournies pour ces occurrences. Fondamentalement, vous invoquez la méthode de demande begin Method1 et vous recevez un rappel lorsque l'exécution est terminée. Vous devrez peut-être modifier le paramètre timeout de la classe client du service Web pour que cela fonctionne.

Option 3

Vous pouvez utiliser le caching features du SixPack library de le faire sans effort! ;-)


[Edité après commentaire]Il y a maintenant deux champs statiques dans l'option 1 pour permettre deux cas différents, un par méthode, comme l'a demandé.


[Edité après plus d'explications]En utilisant session pour faire les appels stateful.

Voir: http://msdn.microsoft.com/en-us/library/aa480509.aspx

ajouté aussi l'option 3.

+0

L'option 1 est interdite car différents clients ont besoin d'un objet "so" différent pour appeler la méthode. – Primoz

+0

Je pense que nous avons quelques malentendus. Client1 crée une instance de "so" Object et appelle ensuite method1 à methodN sur cette instance. Client2 crée une autre instance de "so" oject et appelle à nouveau des méthodes identiques ou différentes sur cette instance. Donc il doit y avoir une instance "so" différente pour chaque client – Primoz

+0

Ensuite, vous pourriez utiliser un dictionnaire à la place ... Le problème principal de cette approche est que les objets ne persistent pas au-delà de la durée de vie de l'AppDomain. – CodesInChaos