13 messaggi dal 23 maggio 2003
Salve ha tutti.
Sto lavorando a un'applicazione un pò grande e i progettisti hanno deciso, per ottimizzare alcune cose, di creare una cache temporanea implementata con un Dictionary in cui vengono temporaneamente aggiunte delle istanze. L'istanza di un oggetto viene aggiunta una sola volta.

Io ho implementato una pagina asp che fa delle chiamate ajax in post a un servizio web; in particolare la mia pagina chiama 4 metodi contenuti in uno stesso asmx e ogni metodo chiama a sua volta un metodo specifico di una stessa classe.

Ogni metodo crea l'istanza della classe però questo mi da errore quando appunto la classe base va ad aggiungere l'istanza al dictionary, ho pensato di mettere una proprietà pubblica che si occupa dell'istanza ma non è migliorato.

Il codice che da errore è il seguente:

if (!this.Providers.ContainsKey(entityTypeName))
this.Providers.Add(entityTypeName, provider);

Mi da in pratica chiave duplicata.

Come posso fare per evitare il problema?

Grzie
44 messaggi dal 01 febbraio 2017
FraNa ha scritto:
Salve ha tutti.
Sto lavorando a un'applicazione un pò grande e i progettisti hanno deciso, per ottimizzare alcune cose, di creare una cache temporanea implementata con un Dictionary in cui vengono temporaneamente aggiunte delle istanze. L'istanza di un oggetto viene aggiunta una sola volta.

Io ho implementato una pagina asp che fa delle chiamate ajax in post a un servizio web; in particolare la mia pagina chiama 4 metodi contenuti in uno stesso asmx e ogni metodo chiama a sua volta un metodo specifico di una stessa classe.

Ogni metodo crea l'istanza della classe però questo mi da errore quando appunto la classe base va ad aggiungere l'istanza al dictionary, ho pensato di mettere una proprietà pubblica che si occupa dell'istanza ma non è migliorato.

Il codice che da errore è il seguente:

if (!this.Providers.ContainsKey(entityTypeName))
this.Providers.Add(entityTypeName, provider);

Mi da in pratica chiave duplicata.

Come posso fare per evitare il problema?

Grzie

Quello che ti è stato chiesto di implementare è possibile farlo fare in automatico dal servizio tramite direttive su WEB.CONFIG (oltre che da codice). In pratica puoi creare (far creare) una istanza ad ogni richiesta , oppure una istanza condivisa oppure una terza opzione che adesso nn ricordo. Questo è possibile farlo con WCF, non so però se è supportato ahche dai vecchi web service (ASMX nel tuo caso).
La documentazione ufficiale MS è abbastanza esplicativa, con vantaggi e svantaggi.
Adesso vado di corsa, ma più tardi vedo se trovo il link relativo.
Ciao.
Gino.
Modificato da SensoBit il 13 aprile 2018 09.00 -
13 messaggi dal 23 maggio 2003
Grazie della risposta.

In effetti io utilizzo ASMX, se puoi mandarmi qualche link così vedo di risolvere da sola il problema.

Grazie
44 messaggi dal 01 febbraio 2017
Rieccomi con un poco di codice :

[ServiceBehavior(InstanceContextMode =
InstanceContextMode.PerSession)]
public class BiblioService : IBiblioService
{
public string AggiungiAlCarrello(string bookTitle)
... 


Il parametro che a te interessa è InstanceContextMode, i cui valori possono essere : PerCall, PerSession e Single che influenzano la creazione dell'istanza che avevo menzionato nel post precedente.

Ripeto questo funziona con WCF, ma nn so se si applcia anche ai vecchi web service.
10.530 messaggi dal 09 febbraio 2002
Contributi
Ciao,


Sto lavorando a un'applicazione un pò grande e i progettisti hanno deciso, per ottimizzare alcune cose, di creare una cache temporanea implementata con un Dictionary

La soluzione migliore consiste nell'usare l'oggetto MemoryCache, che è stato progettato appositamente allo scopo di tenere in cache degli oggetti.

Un Dictionary non è una buona scelta. La proprietà Providers è static, giusto? Se è così è un problema perché varie richieste contemporanee possono leggere/scrivere contemporaneamente il dizionario e avrai degli effetti indesiderati perché la classe Dictionary NON è thread-safe.
Inoltre, penso che l'errore di chiave duplicata lo hai perché tra la chiamata a ContainsKey e la chiamata a Add arriva una seconda richiesta contemporanea che aggiunge la chiave al dizionario.

La soluzione ad entrambi i problemi è la classe ConcurrentDictionary, che è thread-safe e ti permette, in maniera atomica, di ottenere un valore di una chiave dal dizionario o di aggiungerla se non dovesse esistere.

Quindi, dichiari il dizionario:
private static ConcurrentDictionary<string, object> providers = new ConcurrentDictionary<string, object>();
public static ConcurrentDictionary<string, object> Providers { get { return providers; } }


E poi ottieni il valore o lo aggiungi se non esiste, usando il metodo GeOrAdd. Nota come il secondo parametro sia una Func, che verrà invocata dal dizionario solo se c'è l'effettivo bisogno di creare il valore (che si presume sia costoso da costruire, altrimenti non useresti cache).
var valore = this.Providers.GetOrAdd(entityTypeName, chiave => OttieniIstanzaDiProvider());



Il parametro che a te interessa è InstanceContextMode,

Questo regola la creazione delle istanze del servizio e non aiuta a risolvere il problema della cache.

ciao,
Moreno

Enjoy learning and just keep making
13 messaggi dal 23 maggio 2003
Grazie Moreno,

ho letto e sarebbe davvero la mia soluzione.
Il problema è che tutto il progetto é .Net 3.5 e non possiamo fare un upgrade della versione del framework per motivi legati al tipo di cliente e a delle sue policy interne.

Penso di aver trovato, ho modificato il codice nel seguente modo:

cacheLock.EnterUpgradeableReadLock();
try
{
BaseProvider result = null;
if (!this.Providers.TryGetValue(entityTypeName, out result))
{
System.Diagnostics.Debug.WriteLine(String.Format("EntytyName {0} Not found", entityTypeName));

cacheLock.EnterWriteLock();
try
{
System.Diagnostics.Debug.WriteLine(String.Format("EntytyName {0} add", entityTypeName));

this.Providers.Add(entityTypeName, provider);
System.Diagnostics.Debug.WriteLine(String.Format("EntytyName {0} add OK", entityTypeName));

}
finally
{
cacheLock.ExitWriteLock();
}
}
}
finally
{
cacheLock.ExitUpgradeableReadLock();
}

dove cacheLock è

private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();

Che ne pensi?

F.
Modificato da FraNa il 16 aprile 2018 11.28 -

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.