2010-11-07 34 views
6

Ora ho qualcosa di simile:È possibile creare un servizio Web di stato in 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 
    } 

... 
} 

E 'possibile rendere il servizio web statefull modo che io possa riutilizzare SomeObj so e basta chiamare metodi sullo stesso oggetto?

Quindi il client che utilizzerà questo servizio chiamerebbe prima il metodo web che creerebbe l'oggetto so e restituirà un ID. E quindi nelle chiamate successive il servizio Web riutilizzerà lo stesso oggetto so in base all'ID.

EDIT


Ecco il mio codice vero e proprio:

[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);    
} 

risposta

6

servizi web stateful non scalabili e io non li consiglio. Invece è possibile memorizzare i risultati di operazioni costose nel cache. Questa cache potrebbe essere distribuito attraverso provider personalizzati per una migliore scalabilità:

[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

è possibile memorizzare tutti gli oggetti nella cache o ci sono delle limitazioni? Gli oggetti personali includono connessioni WMI aperte a vari computer. – Primoz

+0

Per impostazione predefinita, la cache viene archiviata in memoria e se si avvia in esecuzione su una memoria insufficiente verrà automaticamente rimosso. Quindi sì, puoi archiviare quanto vuoi ma devi sempre controllare che l'oggetto sia nella cache e non fare mai affidamento sul fatto che sia lì perché lo hai archiviato. –

+0

@Darin Dimitrov, dovresti rendere sicura la tua soluzione usando un lucchetto. Mentre una richiesta sta eseguendo "result = action();" linea, che richiede tempo, qualsiasi altra richiesta vedrà anche la cache come null e ripeterà lo stesso "risultato = azione();" linea. Vedi http://en.wikipedia.org/wiki/Double-checked_locking – Sklivvz

1

Opzione 1

È possibile utilizzare il HttpSession.

//this executes very long time, 50s and more, but only once. 
private SomeObj SessionSomeObj { 
    get 
    { 
    var ret = (SomeObj)Session["SomeObjStore"] ?? SomeClass.GetSomeObj(); 
    SessionSomeObj = ret; 
    return ret; 
    } 
    set { Session["SomeObjStore"] = value; } 
} 

[WebMethod(EnableSession = true)] 
public string Method1() 
{ 
    return SessionSomeObj.Method1(); //this exetus in a moment 
} 

[WebMethod(EnableSession = true)] 
public string Method2() 
{ 
    return SessionSomeObj.Method2(); //this exetus in a moment 
} 

Si noti che ciò funzionerà solo se viene effettuata una chiamata per client alla volta.

Opzione 2

È possibile lasciare la classe come è ma utilizzare il WebMethod in modo diverso. Se si chiama da una classe .Net generata, vengono forniti i metodi async per queste occorrenze. Fondamentalmente si invoca il metodo di richiesta Method1 e si ottiene una richiamata al termine dell'esecuzione. Tuttavia, potrebbe essere necessario modificare il parametro di timeout della classe del client del servizio Web per farlo funzionare.

Opzione 3

È possibile utilizzare il caching features del SixPack library per fare questo sforzo! ;-)


[Modificato dopo il commento]Ora ci sono due campi statici in opzione 1 per consentire a due casi diversi, uno per ogni metodo, come richiesto.


[Modificato dopo ulteriori spiegazioni]Utilizzando sessione per rendere la stateful chiamate.

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

aggiunto anche l'opzione 3.

+0

L'opzione 1 è vietata poiché per client diversi è necessario utilizzare un metodo "così" diverso da chiamare. – Primoz

+0

Penso che abbiamo qualche incomprensione. Client1 crea un'istanza di "so" Object e quindi chiama method1 a methodN su questa istanza. Client2 crea un'altra istanza di "so" oject e di nuovo chiama metodi uguali o diversi su questa istanza. Quindi ci deve essere un'istanza "così" diversa per ogni cliente – Primoz

+0

Quindi è possibile utilizzare un dizionario invece ... Il problema principale con questo approccio è che gli oggetti non persistono oltre la durata di AppDomain. – CodesInChaos