2010-07-02 9 views
5

Ho un servizio Windows che svolge una serie di attività periodiche e desidero modificare le impostazioni di questo servizio da un'app Windows Form . Non sono sicuro, tuttavia, del modo migliore per assicurarsi che il servizio abbia le preferenze utente più aggiornate al suo interno (con quale frequenza eseguire, quali cartelle utilizzare per le cose, qualsiasi altra cosa l'utente possa specificare). L'utente può modificare le impostazioni in qualsiasi momento, a proprio piacimento, e mi piacerebbe che il servizio venisse a conoscenza quasi immediatamente. Qui ci sono le opzioni che sto pesatura:Mantieni sincronizzate le impostazioni tra l'applicazione moduli e il servizio Windows (o qualsiasi altro livello)

  1. La quota modulo e il servizio utilizzare lo stesso oggetto "Impostazioni" da un terzo progetto, condiviso, e la forma utilizza un WCF "updatesettings (newSettings)" chiamata di lasciare che il il servizio sa che ci sono stati cambiamenti (o, opzionalmente, una chiamata per aggiornare ogni singola impostazione, anche se questo sembra molto su diverse chiamate). Attualmente utilizzo WCF per i messaggi di base, ma l'oggetto impostazioni può essere enorme, poiché ci sono molte altre cose lì
  2. Modulo e servizio utilizzano un file di configurazione comune (XML o lo stesso oggetto impostazioni dal n. 1, ma serializzato su disco). Il modulo scrive appena una nuova copia dell'oggetto dopo che è stato modificato e il servizio controlla ogni tanto e lo preleva se è nuovo, aggiornando la sua copia delle impostazioni
  3. Come il numero 2, ma con una chiamata WCF di base quello che dice al servizio di andare a prendere le impostazioni. Essenzialmente, una versione "on demand" anziché "polling" di # 2.

So che il meglio è soggettivo, ma sono interessato a qualsiasi ovvio motivo di pro o contro per queste scelte. Dato che dovrò salvare le mie impostazioni tra i runnings dell'applicazione (riavvii, ecc.), Dovrò comunque serializzare le impostazioni sul disco, quindi mi sto già orientando verso il 2 o il 3. Avrò bisogno di un posto sul disco dove posso salvare le impostazioni, ma forse la cartella AppData funzionerà correttamente, anche se questo consentirà agli amministratori di modificare le impostazioni, poiché sono le uniche ad avere il permesso di scrivere in questa posizione (dove ogni utente, incluso l'account di servizio, può leggerlo).

Grazie per l'intuizione!

risposta

3

I kinda usare il tuo numero 2.

ma sto lavorando solo in .NET 2 con la mia domanda, ma dovrebbe comunque applicare.

Ho una classe di impostazioni che uso sui miei 2 programmi. All'interno di questa classe di impostazioni, ho impostato un oggetto FileSystemWatcher che esamina il file delle impostazioni.

Se il file delle impostazioni viene aggiornato dall'altra applicazione, la mia corrente riceve un trigger di evento per indicare che le impostazioni devono essere ricaricate.

È anche possibile applicare lo stesso principio nella schermata delle impostazioni in modo che se l'applicazione (servizio) altra aggiorna qualcosa durante la modifica delle impostazioni, ciò si riflette sullo schermo.

Uso l'AppData (la mia directory nome azienda/applicazione) per memorizzare il file.

L'altra cosa da tenere a mente è che il file può essere bloccato mentre è in fase di scrittura in modo da poter utilizzare un salvataggio temporaneo del nome, eliminare il vecchio, rinominare il metodo temp o inserire un blocco di protezione sul file durante la lettura dopo che l'evento filewatcher ha generato le modifiche apportate.

Io uso questo approccio nel mio FileSystemWatcher prima di procedere

IPSDependency.FileSystem.WaitForLockOnFile(Me.mFilePath) 

il codice per questo è così. (Dopo aver letto questa ora, ci può essere un metodo migliore la mia usando dormire un po 'qui per ridurre botte CPU)

Public Shared Function IsLockAvailable(ByVal filename As String, ByVal fnfIsOK As Boolean) As Boolean 
    Dim fi As FileInfo 
    fi = New FileInfo(filename) 
    Return IsLockAvailable(New FileInfo(filename), fnfIsOK) 
End Function 

Public Shared Function IsLockAvailable(ByVal theFile As FileInfo, ByVal fnfIsOK As Boolean) As Boolean 
    Dim fs As FileStream 
    Try 
     If theFile.Exists Then 
      fs = New FileStream(theFile.FullName, FileMode.Open, FileAccess.ReadWrite, FileShare.None) 
      fs.Close() 
      Return True 
     Else 
      Return fnfIsOK 
     End If 
    Catch ex As IOException 
     'we just let the exception go, because we are only testing the file rather than trying to use it. 
     Return False 
    End Try 
End Function 

Public Shared Sub WaitForLockOnFile(ByVal theFilename As String) 
    WaitForLockOnFile(New FileInfo(theFilename)) 
End Sub 

Public Shared Sub WaitForLockOnFile(ByVal theFile As FileInfo) 
    Dim lockAvailable As Boolean 
    If theFile.Exists Then 
     While Not lockAvailable 
      lockAvailable = IsLockAvailable(theFile, False) 
     End While 
    End If 
End Sub 
2

Di solito i servizi che eseguono un 'operazione di polling'(vale a dire di sincronizzazione file) hanno il tempo di ritardo abbastanza nella loro intervallo di polling che puoi facilmente leggere tutte le impostazioni di ogni loop, o anche se necessario.

Se il servizio è più simile a un back-end SOA, le modifiche possono influire sulle impostazioni generalmente utilizzate una sola volta durante la vita di un servizio. Se questo è il tuo tipo di applicazione, l'opzione 2 che descrivi sopra è la più affidabile. Non posso dire che mi interessi molto per l'implementazione di Paul, in quanto il polling di un file come quello produrrà risultati inaffidabili. Vorrei raccomandare l'utilizzo di un handle di attesa di nome globale per segnalare il processo per le modifiche. Sono sicuro che puoi trovare un esempio qui su SO. Se non si desidera eseguire questa operazione, è possibile eseguire il polling della modifica dell'ora dell'ultimo aggiornamento del file di configurazione.

Nel complesso la mia preferenza è per il primo approccio che utilizza il registro per l'archiviazione. Scrivi tutte le tue impostazioni in valori discreti in un hive del registro e leggerle su richiesta nel tuo servizio. È più veloce di quanto tu possa pensare e facile da implementare sia frontalmente che back-end.

0

Devo essere d'accordo con la vostra inclinazione iniziale verso il n. 2 e il n. Mi piace particolarmente il # 3 visto che non sono un fan del sondaggio, ma alla fine penso che la decisione tra # 2 o # 3 sarà guidata dai requisiti del tuo servizio.

Per quanto riguarda la memorizzazione delle impostazioni utente, suggerirei di esplorare Archiviazione isolata (http://msdn.microsoft.com/en-us/library/3ak841sy.aspx). Fornisce un meccanismo eccellente per l'accesso sicuro, coerente e affidabile ai file dell'utente. Non dovrai preoccuparti dell'autorizzazione dell'utente a meno che l'amministratore non abbia completamente disattivato l'archiviazione isolata. Inoltre, se abiliti il ​​roaming, gli utenti possono persino prendere le loro impostazioni con loro se utilizzano sistemi diversi nello stesso dominio, piuttosto chiari eh?

+0

L'utilizzo di "Archiviazione isolata" sembra essere specifico per l'utente: per quanto riguarda le mie impostazioni, sono essenzialmente per computer. Voglio che gli utenti siano in grado di visualizzarli, ma solo un amministratore può modificarli e ri-salvarli (o, con Vista/7, qualcuno che ha utilizzato l'elevazione admin). Posso utilizzare la memoria isolata per l'amministratore locale o la memoria di tipo "Tutti gli utenti"? – SqlRyan

+0

@rwmnau Ulteriori letture nei tipi di archiviazione isolati Lo vedo come sempre limitato all'utente che lo ha creato. C'è una bandiera IsolatedStorageScope.User che pensavo potesse essere disattivata ma che non sembra essere il caso. Proverò a pensare a un percorso alternativo. – Matthew

3

Supponendo che tutto è in esecuzione sulla stessa macchina, come su questo:

  1. definire una struttura # c comune che definisce le impostazioni. Tutti i progetti includono questo file .cs. Definire questa classe come struct con un StructLayout di sequenziale o esplicita quindi possono essere mappati direttamente nella memoria condivisa non gestita. Per esempio:

    [StructLayout (LayoutKind.Sequential)] non sicuri MySharedSettings struct {public int IMP1; public int setting2; impostazione stringa pubblica3; // aggiungi altri campi qui. }

  2. Usa chiamato memoria condivisa (aka: file mappati in memoria). Ciò consente a più processi sullo stesso computer di condividere dati, senza il sovraccarico di Remotazione o WCF.La memoria condivisa è estremamente veloce e, a differenza delle pipe, offre accesso casuale ai dati della memoria condivisa. Il servizio creerebbe la memoria condivisa denominata e le applicazioni dell'interfaccia utente apriranno la memoria condivisa. Dovresti usare pinvoke per usare le API di Windows sottostanti, ma questo non è un grosso problema.

  3. Le applicazioni di interfaccia utente scrivono MySharedSettings sulla memoria condivisa, mentre il servizio legge la memoria condivisa.

  4. Utilizzare un chiamato Semaforo e/o nome Mutex per proteggere l'accesso alla memoria condivisa e per segnalare la disponibilità di nuove impostazioni. Il servizio ha un thread in background dedicato che esegue semplicemente WaitOne() sul semaforo e il thread dell'interfaccia utente segnala quando vengono scritti nuovi dati.

+0

Sento che posso imparare molto da questa risposta, ma sto facendo fatica a trovare buoni esempi. Saresti così gentile da fornire questi? – Peter

Problemi correlati