Εδώ και μέρες ήθελα να γράψω αυτό το guide αλλά μόλις σήμερα κατάφερα να συγκεντρώσω τα resources μου… Λοιπόν, έχουμε και λέμε: Οι επιλογές που έχουμε στη διάθεσή μας για την αποθήκευση του connection string είναι λίγο-πολύ οι παρακάτω:
Web.config
Είναι πολύ απλός τρόπος και το μόνο που χρειάζεται είναι να βάλουμε στο Web.Config κάτι σαν το παρακάτω:
<configuration>
<appSettings>
<add key="ConnectionString" value="server=localhost;Trusted_Connection=true;database=Portal" />
</appSettings>
</configuration>
Για να διαβάσουμε το connection string χρησιμοποιούμε την κλάση ConfigurationSettings και το property AppSettings. Συνήθως, φτιάχνουμε ένα επιπλέον abstraction layer το οποίο είναι υπεύθυνο για την διαχείριση των settings.
Το κύριο πλεονέκτημα αυτής της λύσης είναι η ευκολία στο deployment, αφού το connection string θα γίνει deployed μαζί με το υπόλοιπο project. Για την περίπτωση που θα χρειαστεί να αλλάξει το connection string προκειμένου να αναφέρει τον production DB server, μπορούμε να φτιάξουμε ένα απλό Admin utility το οποίο θα ενημερώνει το appSetting και τα υπόλοιπα sections που μας ενδιαφέρουν. Το ωραίο είναι ότι παρότι τα settings είναι αποθηκευμένα σε ένα φυσικό αρχείο, πρόκειται για αρχείο το οποίο είναι cachαρισμένο (άρα συνεχώς στη μνήμη, άρα το fetch είναι ταχύτατο) και οποιαδήποτε αλλαγή σε αυτό προκαλεί το purge και re-cache του, όπερ σημαίνει ότι οι αλλαγές είναι αυτομάτως διαθέσιμες. Το κύριο μειονέκτημα είναι η έλλειψη security καθώς οι λεπτομέρειες του connection string είναι αποθηκεύμενες σε απλό text. Ένα workaround αυτού του προβλήματος είναι τα custom configuration sections που θα διαβάσετε παρακάτω ή χρήση του Enterprise Library Application Blocks (που θα διαβάσετε πιο παρακάτω).
Machine.config
Μια παραλλαγή της προηγούμενης μεθόδου, είναι η αποθήκευση του connection string στο Machine.config. Με αυτόν τον τρόπο μπορούμε να καθορίσουμε μόνο μία φορά τις ρυθμίσεις για τα διάφορα στάδια υλοποίησης του έργου (development, staging και production).
Σε αυτήν την περίπτωση δεν χρησιμοποιούμε το appSettings section (γιατί τότε δεν κερδίζουμε τίποτα αν θα πρέπει κάθε φορά να το κάνουμε edit) αλλά ορίζουμε ένα ή παραπάνω custom configuration sections που μπορεί να επαναχρησιμοποιηθούν ανάλογα την περίσταση. Για να υλοποιήσετε μια τέτοια λύση θα πρέπει να ανοίξετε το Machine.config (καλού-κακού κάντε το ένα backup πρώτα). Στην αρχή του Machine.config βρείτε το section tag για το appSettings και αντιγράψτετο αλλάζοντας το όνομα. Το type attribute προσδιορίζει την κλάση που θα χειριστεί τις τιμές που θα αποθηκέψετε στο section αυτό. Η κλάση
NameValueFileSectionHandler επιτρέπει την πρόσβαση με τη λογική των ζευγαριών name/value ενώ υπάρχει η δυνατότητα μέσα από το IConfigurationSectionHandler interface να φτιάξετε τους δικούς σας section handlers (αυτή η λύση έχει ιδιαίτερο ενδιαφέρον αν ενσωματωθεί και ένας encryptor/decryptror). Επειδή κατά πάσα πιθανότητα, το custom section θα θέλετε να περιέχει και sub-sections, μπορείτε να φτιάξετε κάτι όπως το παρακάτω:
<sectionGroup name="MySite">
<sectionGroup name="Settings">
<section name="Site"
type="System.Configuration. NameValueFileSectionHandler,,
System "/>
</sectionGroup>
</sectionGroup>
Κατόπιν, μπορείτε να ορίσετε το νέο custom section όπως παρακάτω (παρατηρήστε τις αντιστοιχίες):
<MySite>
<Settings>
<Site>
<add key= "DevelopConnectionString" value="devServer;Trusted_Connection=true;database=DevSite" />
<add key="StagingConnectionString"
value="stagingServer;Trusted_Connection=true;database=StagingSite"/>
<add key= "ProdConnectionString"
value="prodServer;Trusted_Connection=true;database=ProdSite" />
</Site>
</Settings>
</MySite>
Για να διαβάσετε αυτές τις ρυθμίσεις, μπορείτε να χρησιμοποιήσετε κάτι σαν τον παρακάτω κώδικα:
Imports System
Imports System.Collections
Imports System.Configuration
Public Class CustomConfiguration
Public Shared ReadOnly Property ProdSettings() As Hashtable
Get
Return CType(ConfigurationSettings.GetConfig(ConfigurationSettings.AppSettings("MySite/Settings/Site")("ProdConnectionString"), Hashtable)
End Get
End Property
End Class
Enterprise Library Application Blocks
Μια άλλη εναλλακτική λύση είναι η χρήση του ELAB. Μέσα σε αυτό υπάρχει το Configuration Application Block το οποίο παρέχει ένα ολοκληρωμένο framework για τη διαχείριση των ρυθμίσεων, με τη δυνατότητα αποθήκευσης των ρυθμίσεων σε οποιοδήποτε storage provider, ενώ σε συνδυασμό με το Cryptography Application Block, μπορούμε να υλοποιήσουμε λύσεις που είναι secure. Το πλεονέκτημα αυτής της λύσης είναι ότι παρέχει ένα πλήρες set από εργαλεία (και μάλιστα τα ίδια τα ELAB χρησιμοποιούν τον εαυτό τους) όμως θα πρέπει να υπολογίσει κανείς το learning curve που απαιτείται προκειμένου να τα μάθει και να τα ενσωματώσει στην εφαρμογή του, καθώς και την αύξηση της πολυπλοκότητας στο deployment.
Registry Settings
Η τελευταία εναλλακτική λύση είναι η αποθήκευση στο registry. Εδώ το πλεονέκτημα είναι ότι τα διάφορα registry keys μπορούν να προστατευθούν μέσω Access Control Lists (ACLs) ενώ το Framework παρέχει διάφορες κλάσεις για την πρόσβαση στο registry. To μειονέκτημα είναι ότι το deployment project θα πρέπει να δημιουργήσει αυτά το regisrty keys (με ότι αυτό συνεπάγεται ως προς την πολυπλοκότητα του εγχειρήματος)
Custom λύσεις
Εδώ περιλαμβάνονται διάφορες custom λύσεις όπως INI αρχεία, κλπ. Τυπικότερη όλων είναι το XML ή Binary serialization μιας κλάσης που λειτουργεί ως settings provider/manager. Αν ενδιαφέρεται κανείς, μπορώ να του δώσω δείγματα κώδικα…
Συμπερασματικά, ως προς το security, δεν υπάρχει καμία λύση out-of-the-box. Απαιτείται να γράψουμε εμείς τον κώδικα που θα κάνει αυτή τη (βρωμο)δουλειά. Εναλλακτικά μπορούμε να χρησιμοποιήσουμε διάφορα βοηθητικά εργαλεία όπως τα ELAB ή το DPAPI class helper (Search με keywords «IssueVison» και «DPAPI» για περισσότερες πληροφορίες) ή να περιμένουμε το ASP.NET 2.0 που (αν θυμάμαι καλά) θα επιτρέπει την αποθήκευση κρυπτογραφημένων strings μέσα στα config αρχεία.
Επιπρόσθετα, ρίξτε μια ματιά στα:
http://msdn.microsoft.com/msdnmag/issues/03/11/ProtectYourData/default.aspx
http://msdn.microsoft.com/msdnmag/issues/02/06/crypto/
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT07.asp
Vir prudens non contra ventum mingit