Come assicurarsi che pubblichiamo la produzione sul server di produzione e testiamo sul server di prova
-
19-08-2019 - |
Domanda
Ho una voce nel mio file Web.Config che indica l'ambiente in cui mi trovo per le stringhe di connessione e la posta indesiderata:
<add key="AppEnv" value ="2" /> <!--(0 = Dev, 1 = test, 2 = prod)-->
Sto cercando un modo per avvisare lo sviluppatore, al momento della pubblicazione, per assicurarsi che abbiano controllato questa chiave / valore in modo da non pubblicare il "test" sul server "prod" e viceversa .
Grazie
Soluzione
Ho trovato la mia soluzione (probabilmente non convenzionale) a questo problema. Sviluppiamo molti progetti Web diversi per molti clienti diversi e li abbiamo migrati tutti a questo metodo a causa di tutti i problemi che abbiamo riscontrato con più file web.config o delle modifiche necessarie prima della pubblicazione.
Fondamentalmente, lasciamo che la nostra app ci dica in quale ambiente è in esecuzione in base all'URL in arrivo. Inizializziamo questo alla prima richiesta e lo memorizziamo in memoria per la vita dell'app. In questo modo possiamo memorizzare ciascuno dei nostri valori di configurazione specifici dell'ambiente nello stesso file di configurazione e qualificarli semplicemente con Sviluppo, Staging, Produzione, ecc. E qualsiasi impostazione che non differisce tra ambienti non deve essere qualificata.
Prima un esempio web.config:
<appSettings>
<add key="DevelopmentHost" value="dev.trackmyhours.com" />
<add key="StagingHost" value="staging.trackmyhours.com" />
<add key="ProductionHost" value="www.trackmyhours.com" />
</appSettings>
<connectionStrings>
<clear />
<add name="DevelopmentConnectionString" connectionString="your dev conn string" providerName="System.Data.SqlClient" />
<add name="StagingConnectionString" connectionString="your staging conn string (mine is typically same as staging)" providerName="System.Data.SqlClient" />
<add name="ProductionConnectionString" connectionString="your production conn string" providerName="System.Data.SqlClient" />
</connectionStrings>
Ora abbiamo un'app " App " classe che ci dà accesso al nostro " Sito " classe, ma potresti progettare le tue classi come meglio credi.
Public Class App
Private Shared _Site As New Site
Public Shared ReadOnly Property Site() As Site
Get
Return _Site
End Get
End Property
End Class
Imports System.Configuration
Imports System.Web
Public Class Site
Public Enum EnvironmentType
Development
Staging
Production
End Enum
Friend Sub New()
If HttpContext.Current IsNot Nothing Then
Dim URL = HttpContext.Current.Request.Url.DnsSafeHost
Select Case URL
Case ConfigurationManager.AppSettings("DevelopmentHost"), "localhost"
_Environment = EnvironmentType.Development
Case ConfigurationManager.AppSettings("StagingHost")
_Environment = EnvironmentType.Staging
Case ConfigurationManager.AppSettings("ProductionHost")
_Environment = EnvironmentType.Production
End Select
Else
'probably getting called from a winforms/console app, or unit tests
_Environment = EnvironmentType.Staging
End If
_ConnectionString = ConfigurationManager.ConnectionStrings(_Environment.ToString & "ConnectionString").ConnectionString
End Sub
Private _Environment As EnvironmentType
Public Property Environment() As EnvironmentType
Get
Return _Environment
End Get
Set(ByVal value As EnvironmentType)
_Environment = value
_ConnectionString = ConfigurationManager.ConnectionStrings(_Environment.ToString & "ConnectionString").ConnectionString
End Set
End Property
Private _ConnectionString As String
Public ReadOnly Property ConnectionString() As String
Get
Return _ConnectionString
End Get
End Property
End Class
Mettiamo le nostre classi nella nostra libreria di classi Biz Object. Abbiamo appena deciso che non è necessario determinare l'ambiente su ogni singola richiesta, dal momento che non può cambiare durante la vita dell'app. Inoltre, questo ci consente di fare riferimento a App.Site.Environment da ANYWHERE nel codice nella libreria o nel codice dietro. Ciò è utile anche se è necessario cospargere una logica condizionale nel codice, ad esempio non inviare e-mail a persone reali quando si esegue in sviluppo / messa in scena.
Un'ultima cosa: per i nostri Linq2SQL o EF Data / ObjectContexts, non memorizziamo la stringa di connessione nel file e sovraccarichiamo il costruttore in modo da poter fornire la nostra stringa di connessione all'ambiente corretta in questo modo:
Partial Class SampleDataContext
Sub New()
MyBase.New(App.Site.ConnectionString)
End Sub
End Class
Altri suggerimenti
Ecco una soluzione: archivia quel file come " Web.Config.in
" sotto il controllo del codice sorgente.
Su ciascun server (sviluppo, test, gestione temporanea, produzione), copiare Web.Config.in
in Web.Config
e modificare AppEnv valore attentamente.
Ad ogni spinta successiva da un ambiente all'altro, escludere i file Web.Config
. Cioè, non sovrascrivere quel particolare file. Scrivi ad esempio script di distribuzione che eseguono rsync --exclude WebConfig
.
Ho in grassetto rosso nella parte superiore della pagina in quale modalità si trova il sito se non è in modalità Produzione.
Ho anche una pagina di diagnostica che elenca su quale server è in esecuzione e a quale database è collegato.
Puoi anche inserire una tabella di ricerca in ogni database, per assicurarti di avere il flag giusto collegato ad esso. (nel DB di prova contrassegnarlo come 1 e verificare su Application_Start che i valori corrispondano)
Ogni volta che c'è un processo che richiede sempre più di un passaggio, so che lo rovinerò almeno la metà delle volte. Per questo motivo, adoro MSBuild.
Esistono numerose attività utili fornite con MSBuild, come attività AspNetCompiler , che sembra essere un'azione di compilazione / pubblicazione in un solo passaggio.
Esistono anche diversi progetti che aggregano un gran numero di "personalizzato" Attività di MSBuild per vari scopi. Il MSBuild Community Tasks Project ha un'attività XmlMassUpdate utile per apportare diverse modifiche a un file in formato xml. In altre parole, perfetto per l'aggiornamento dei file web.config.
Ho trovato un esempio dell'utilizzo dell'attività XmlMassUpdate in concerto con un progetto di distribuzione Web qui .
Un'eterna domanda che continua a spuntare! Immagino che qualsiasi sviluppatore ASP.NET serio abbia in qualche modo sbattuto la testa contro questo.
Per ASP.NET 4.0, ci sono alcuni aiuti in arrivo: le opzioni di implementazione web migliorate offriranno una funzione chiamata " trasformazioni web.config " ;.
Dai un'occhiata a Video del canale 9 sull'argomento - non ho ancora trovato alcun riferimento scritto decente ...
Marc
Prendo tutte le chiavi che saranno diverse nel test e nella produzione e le inserirò in un file .config completamente nuovo. Ho messo alla prova le impostazioni di prova e le impostazioni di produzione in produzione e non ho mai copiato questo file dalla prova alla produzione. Quindi, nel tuo normale web.config, puoi specificare questo nuovo file .config in questo modo:
<appSettings file="ExternalWeb.config>
.... common keys go here
</appSettings>
sul server di prova, " external.config " conterrà i valori specifici per quel server e in produzione avrà i valori prod. Ciò consente di copiare l'intero web.config tra i 2 server senza mai modificare manualmente il file.
Penso che sia una cattiva pratica archiviare stringhe di connessione in web.config, invece creo un file di configurazione separato al di fuori dei miei siti Web in una posizione nota comune come
C: \ xxxx \ config.xml
Quindi memorizzo tutte le impostazioni dipendenti dalla macchina. In modo che sul mio server live ho le mie impostazioni live, sulle stringhe di connessione del server di prova al DB di test e sulla mia macchina Dev ho ottenuto le mie impostazioni locali. Queste impostazioni possono quindi essere ridimensionate lungo tutti i siti Web e le app .net su quel server. Solo un unico posto da aggiornare quando il DB cambia.
Perfetto!
Imposta il tuo Web.Config su " Sola lettura " ;, pertanto non verrà sovrascritto durante la pubblicazione su questi server.
Il compromesso è che dovrai mantenere manualmente i tuoi web.configs su ciascun server e la tua pubblicazione dichiarerà di fallire perché non potrebbe sovrascrivere web.config sul server remoto; ma IMHO è preferibile per modificare la configurazione ogni volta che esegui un caricamento