Konfigurasi .NET (app.config / web.config / settings.settings)

162

Saya memiliki aplikasi .NET yang memiliki file konfigurasi berbeda untuk pembuatan Debug dan Rilis. Misalnya file app.config debug menunjuk ke pengembangan SQL Server yang telah debugging diaktifkan dan target rilis rilis ke SQL Server langsung. Ada juga pengaturan lain, beberapa di antaranya berbeda dalam debug / rilis.

Saat ini saya menggunakan dua file konfigurasi terpisah (debug.app.config dan release.app.config). Saya memiliki acara build di proyek yang mengatakan jika ini adalah rilis build kemudian salin release.app.config ke app.config, atau salin debug.app.config ke app.config.

Masalahnya adalah bahwa aplikasi tampaknya mendapatkan pengaturannya dari file settings.settings, jadi saya harus membuka settings.settings di Visual Studio yang kemudian meminta saya bahwa pengaturan telah berubah jadi saya menerima perubahan, simpan setting.settings dan miliki untuk membangun kembali untuk membuatnya menggunakan pengaturan yang benar.

Apakah ada metode yang lebih baik / direkomendasikan / disukai untuk mencapai efek yang sama? Atau sama-sama, sudahkah saya mendekati ini sepenuhnya salah dan apakah ada pendekatan yang lebih baik?

Gavin
sumber
Saya ingin menonaktifkan debug di windows dari, saya telah mencoba dengan menghapus centang pada semua kotak centang dalam pengaturan debug, tapi masih saya bisa men-debug exe rilis bin ..Ada yang membantu saya dalam hal ini ..
Vinoth Narayan

Jawaban:

62

Setiap konfigurasi yang mungkin berbeda di lingkungan harus disimpan di level mesin , bukan di level aplikasi . (Info lebih lanjut tentang tingkat konfigurasi.)

Ini adalah jenis elemen konfigurasi yang biasanya saya simpan di level mesin:

Ketika setiap lingkungan (pengembang, integrasi, pengujian, panggung, live) memiliki pengaturan uniknya sendiri di direktori c: \ Windows \ Microsoft.NET \ Framework64 \ v2.0.50727 \ CONFIG , maka Anda dapat mempromosikan kode aplikasi antar lingkungan tanpa modifikasi pasca-pembangunan.

Dan tentu saja, isi direktori CONFIG tingkat mesin dapat dikendalikan versi dalam repositori yang berbeda atau struktur folder yang berbeda dari aplikasi Anda. Anda dapat menjadikan file .config Anda lebih ramah kontrol sumber melalui penggunaan cerdas configSource .

Saya telah melakukan ini selama 7 tahun, pada lebih dari 200 aplikasi ASP.NET di 25+ perusahaan yang berbeda. (Tidak berusaha menyombongkan diri, hanya ingin memberi tahu Anda bahwa saya belum pernah melihat situasi di mana pendekatan ini tidak berhasil.)

Portman
sumber
3
Bagaimana dengan situasi di mana Anda tidak mengontrol server web dan karena itu tidak dapat mengubah konfigurasi level mesin? Contohnya termasuk server web pihak ke-3 atau server web yang dibagikan di antara banyak departemen dalam suatu perusahaan.
RationalGeek
1
Tidak akan bekerja Tetapi di era mesin virtual, Amazon EC2, dan server $ 400 dari Dell, apakah ada yang benar-benar melakukan sesuatu yang serius pada mesin bersama? Tidak mencoba untuk tidak berperasaan sama sekali - saya benar-benar berpikir bahwa jika Anda bekerja pada server web bersama Anda harus mengevaluasi kembali.
Portman
7
Sebagian besar perusahaan tempat saya bekerja dengan situs internal menjadi tuan rumah beberapa aplikasi pada satu server - ada penilaian ulang yang harus dilakukan di tingkat perusahaan
MPritchard
Banyak aplikasi di satu server baik-baik saja asalkan semua aplikasi berada di "lingkungan" yang sama. Yaitu, Anda tidak ingin instance LIVE dari App1 pada server yang sama dengan instance DEV dari App2. Misalnya, pengaturan SMTP Anda akan dibagikan di semua aplikasi Anda. Dalam produksi, Anda menunjuk ke server surat nyata; dalam pengembangan, Anda menunjuk ke file di disk.
Portman
7
Saya tahu ini akan berhasil, tetapi ini masih bertentangan dengan apa yang saya sarankan ketika mencoba untuk mengotomatiskan penyebaran. Saya pikir pengaturan adalah spesifik aplikasi, mereka perlu dikontrol versi bersama dengan aplikasi dan berkembang bersama dengannya. Mengandalkan konfigurasi Mesin hanya bergeser, dan menurut saya membuatnya lebih sulit. Saya suka menyatukan hal-hal yang berubah bersama dan menyebarkannya bersama. Jika saya menambahkan pengaturan baru untuk Dev saya cenderung membutuhkan yang setara untuk prod.
Miguel Madero
51

Ini mungkin membantu beberapa orang berurusan dengan Settings.settings dan App.config: Hati-hati terhadap atribut GenerateDefaultValueInCode di panel Properties saat mengedit salah satu nilai di grid Settings.settings di Visual Studio (Visual Studio 2008 dalam kasus saya).

Jika Anda mengatur GenerateDefaultValueInCode ke True (Benar adalah default di sini!), Nilai default dikompilasi ke dalam EXE (atau DLL), Anda dapat menemukannya tertanam dalam file ketika Anda membukanya di editor teks biasa.

Saya sedang mengerjakan aplikasi konsol dan jika saya gagal di EXE, aplikasi selalu mengabaikan file konfigurasi yang ditempatkan di direktori yang sama! Cukup mimpi buruk dan tidak ada informasi tentang ini di seluruh Internet.

Roma
sumber
7
Inilah yang terjadi pada saya selama akhir pekan lalu. Saya mencabut banyak rambut mencoba mencari tahu mengapa aplikasi saya tampaknya mengabaikan file app.config saya! Seharusnya terhubung ke layanan web dan url layanan di app.config saya. Tanpa sepengetahuan saya, ketika saya membuat referensi web, itu juga membuat file Settings.Settings DAN hardcoded nilai default ke dalam kode. Bahkan ketika saya akhirnya menemukan (dan menghapus) file pengaturan, nilai default tetap di hardcode dan tertanam di exe. SANGAT MENGGANGGU !! Berkat pos ini, sekarang saya dapat menyingkirkan "fitur" itu
Mike K
+1 Jawaban ini adalah yang paling penting : Jika Anda ingin pengaturan Anda masuk ke file app.config, atur atribut GenerateDefaultValueInCode ke False (defaultnya adalah True).
Sabuncu
34

Ada pertanyaan terkait di sini:

Meningkatkan Proses Pembuatan Anda

File konfigurasi datang dengan cara untuk menimpa pengaturan:

<appSettings file="Local.config">

Alih-alih memeriksa dalam dua file (atau lebih), Anda hanya memeriksa dalam file konfigurasi default, dan kemudian pada setiap mesin target, Anda meletakkan Local.config, dengan hanya bagian appSettings yang memiliki penggantian untuk mesin tertentu.

Jika Anda menggunakan bagian konfigurasi, padanannya adalah:

configSource="Local.config"

Tentu saja, merupakan ide bagus untuk membuat salinan cadangan dari semua file Local.config dari komputer lain dan memeriksanya di suatu tempat, tetapi bukan sebagai bagian dari solusi aktual. Setiap pengembang menempatkan "abaikan" pada file Local.config sehingga tidak diperiksa, yang akan menimpa file orang lain.

(Anda sebenarnya tidak harus menyebutnya "Local.config", hanya itu yang saya gunakan)

Eric Z Beard
sumber
14

Dari apa yang saya baca, sepertinya Anda menggunakan Visual Studio untuk proses pembuatan Anda. Sudahkah Anda berpikir untuk menggunakan MSBuild dan Nant ?

Sintaks xml Nant agak aneh, tetapi begitu Anda memahaminya, melakukan apa yang Anda sebutkan menjadi sangat sepele.

<target name="build">
    <property name="config.type" value="Release" />

    <msbuild project="${filename}" target="Build" verbose="true" failonerror="true">
        <property name="Configuration" value="${config.type}" />
    </msbuild>

    <if test="${config.type == 'Debug'}">
        <copy file=${debug.app.config}" tofile="${app.config}" />
    </if>

    <if test="${config.type == 'Release'}">
        <copy file=${release.app.config}" tofile="${app.config}" />
    </if>

</target>
Steven Williams
sumber
8

Kami dulu menggunakan proyek Penerapan Web tetapi sejak bermigrasi ke NAnt. Alih-alih melakukan percabangan dan menyalin file pengaturan yang berbeda, kami saat ini menanamkan nilai-nilai konfigurasi langsung di skrip build dan menyuntikkannya ke file konfigurasi kami melalui tugas xmlpoke:

  <xmlpoke
    file="${stagingTarget}/web.config"
    xpath="/configuration/system.web/compilation/@debug"
    value="true"
  />

Dalam kedua kasus, file konfigurasi Anda dapat memiliki nilai pengembang apa pun yang Anda inginkan dan mereka akan berfungsi dengan baik dari dalam lingkungan dev Anda tanpa merusak sistem produksi Anda. Kami telah menemukan bahwa pengembang cenderung untuk mengubah variabel skrip build secara sewenang-wenang ketika menguji berbagai hal, jadi kesalahan konfigurasi yang tidak disengaja lebih jarang terjadi dibandingkan dengan teknik lain yang telah kami coba, meskipun masih perlu menambahkan setiap var di awal proses sehingga nilai dev tidak terdorong ke prod secara default.

jasondoucette
sumber
7

Majikan saya saat ini memecahkan masalah ini dengan terlebih dahulu meletakkan level dev (debug, stage, live, dll) di file machine.config. Kemudian mereka menulis kode untuk mengambilnya dan menggunakan file konfigurasi yang tepat. Itu memecahkan masalah dengan string koneksi yang salah setelah aplikasi dikerahkan.

Mereka baru-baru ini menulis layanan web pusat yang mengirimkan kembali string koneksi yang benar dari nilai dalam nilai machine.config.

Apakah ini solusi terbaik? Mungkin tidak, tetapi berhasil untuk mereka.

Hector Sosa Jr
sumber
1
Sebenarnya saya pikir itu sangat elegan, karena saya suka menjaga berbagai versi konfigurasi terlihat dalam sebuah solusi, bahkan jika mereka tidak hidup.
annakata
1
Ini adalah solusi yang sangat menarik. Senang melihat contoh ini dalam tindakan.
Mike K
5

Salah satu solusi yang membuat saya baik-baik saja adalah menggunakan WebDeploymentProject. Saya memiliki 2/3 file web.config berbeda di situs saya, dan pada publikasi, tergantung pada mode konfigurasi yang dipilih (release / staging / etc ...) Saya akan menyalin melalui Web.Release.config dan ganti namanya ke web. konfigurasi dalam acara AfterBuild, dan hapus yang tidak saya butuhkan (Web.Staging.config misalnya).

<Target Name="AfterBuild">
    <!--Web.config -->
    <Copy Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " SourceFiles="$(SourceWebPhysicalPath)\Web.Release.config" DestinationFiles="$(OutputPath)\Web.config" />
    <Copy Condition=" '$(Configuration)|$(Platform)' == 'Staging|AnyCPU' " SourceFiles="$(SourceWebPhysicalPath)\Web.Staging.config" DestinationFiles="$(OutputPath)\Web.config" />
    <!--Delete extra files -->
    <Delete Files="$(OutputPath)\Web.Release.config" />
    <Delete Files="$(OutputPath)\Web.Staging.config" />
    <Delete Files="@(ProjFiles)" />
  </Target>
Adam Vigh
sumber
3

Proyek kami memiliki masalah yang sama di mana kami harus memelihara konfigurasi untuk dev, qa, uat dan prod. Inilah yang kami ikuti (hanya berlaku jika Anda terbiasa dengan MSBuild):

Gunakan MSBuild dengan ekstensi tugas Komunitas MSBuild. Ini termasuk tugas 'XmlMassUpdate' yang dapat 'memperbarui secara massal' entri dalam file XML apa pun setelah Anda memberinya simpul yang benar untuk memulai.

Untuk melaksanakan:

1) Anda perlu memiliki satu file konfigurasi yang akan memiliki entri dev env Anda; ini adalah file konfigurasi dalam solusi Anda.

2) Anda harus memiliki file 'Substitutions.xml', yang hanya berisi entri yang BERBEDA (sebagian besar pengaturan aplikasi dan ConnectionStrings) untuk setiap lingkungan. Entri yang tidak berubah di lingkungan tidak perlu dimasukkan dalam file ini. Mereka dapat tinggal di file web.config dari solusi dan tidak akan tersentuh oleh tugas

3) Dalam file build Anda, panggil saja tugas pembaruan massal XML dan berikan lingkungan yang tepat sebagai parameter.

Lihat contoh di bawah ini:

    <!-- Actual Config File -->
    <appSettings>
        <add key="ApplicationName" value="NameInDev"/>
        <add key="ThisDoesNotChange" value="Do not put in substitution file" />
    </appSettings>

    <!-- Substitutions.xml -->
    <configuration xmlns:xmu="urn:msbuildcommunitytasks-xmlmassupdate">
      <substitutions>
        <QA>
           <appSettings>
            <add xmu:key="key" key="ApplicationName" value="NameInQA"/>
           </appSettings>            
        </QA>
        <Prod>
          <appSettings>
            <add xmu:key="key" key="ApplicationName" value="NameInProd"/>
          </appSettings>            
        </Prod>
     </substitutions>
    </configuration>


<!-- Build.xml file-->

    <Target Name="UpdateConfigSections">
            <XmlMassUpdate ContentFile="Path\of\copy\of\latest web.config" SubstitutionsFile="path\of\substitutionFile" ContentRoot="/configuration" SubstitutionsRoot="/configuration/substitutions/$(Environment)" />
        </Target>

ganti '$ Environment' dengan 'QA' atau 'Prod' berdasarkan pada apa. Anda sedang membangun. Perhatikan bahwa Anda harus mengerjakan salinan file konfigurasi dan bukan file konfigurasi yang sebenarnya itu sendiri untuk menghindari kemungkinan kesalahan yang tidak dapat dipulihkan.

Jalankan saja file build dan kemudian pindahkan file konfigurasi yang diperbarui ke lingkungan penyebaran Anda dan Anda selesai!

Untuk ikhtisar yang lebih baik, baca ini:

http://blogs.microsoft.co.il/blogs/dorony/archive/2008/01/18/easy-configuration-deployment-with-msbuild-and-the-xmlmassupdate-task.aspx

Punit Vora
sumber
2

Seperti Anda, saya juga telah mengatur 'multi' app.config - misal app.configDEV, app.configTEST, app.config.LOCAL. Saya melihat beberapa alternatif bagus disarankan, tetapi jika Anda menyukai cara kerjanya, saya akan menambahkan yang berikut:

Saya memiliki
<appSettings>
<add key = "Env" value = "[Local] "/> untuk setiap aplikasi yang saya tambahkan ini ke UI di batang judul: dari ConfigurationManager.AppSettings.Get ("Env");

Saya baru saja mengubah nama konfigurasi menjadi yang saya targetkan (Saya punya proyek dengan 8 aplikasi dengan banyak basis data / konfigurasi wcf terhadap 4 evenioments). Untuk menerapkan dengan clickonce ke masing-masing saya mengubah 4 seetings dalam proyek dan pergi. (ini saya ingin mengotomatisasi)

Gotcha saya hanya ingat untuk 'membersihkan semua' setelah perubahan, karena konfigurasi lama 'macet' setelah mengubah nama manual. (Yang saya pikir AKAN akan memperbaiki Anda masalah setting.setting).

Saya menemukan ini bekerja dengan sangat baik (suatu hari saya akan mendapatkan waktu untuk melihat MSBuild / NAnt)

Tony Trembath-Drake
sumber
0

Web.config:

Web.config diperlukan ketika Anda ingin meng-host aplikasi Anda di IIS. Web.config adalah file konfigurasi wajib untuk IIS untuk mengonfigurasi bagaimana berperilaku sebagai proxy terbalik di depan Kestrel. Anda harus memelihara web.config jika Anda ingin menghostingnya di IIS.

AppSetting.json:

Untuk semua hal lain yang tidak terkait IIS, Anda menggunakan AppSetting.json. AppSetting.json digunakan untuk hosting Asp.Net Core. ASP.NET Core menggunakan variabel lingkungan "ASPNETCORE_ENVIRONMENT" untuk menentukan lingkungan saat ini. Secara default, jika Anda menjalankan aplikasi Anda tanpa menetapkan nilai ini, itu akan secara otomatis default ke lingkungan Produksi dan menggunakan file "AppSetting.production.json". Ketika Anda debug melalui Visual Studio itu mengatur lingkungan untuk Pengembangan sehingga menggunakan "AppSetting.json". Lihat situs web ini untuk memahami cara mengatur variabel lingkungan hosting di Windows.

App.config:

App.config adalah file konfigurasi lain yang digunakan oleh .NET yang terutama digunakan untuk Formulir Windows, Layanan Windows, Aplikasi Konsol, dan aplikasi WPF. Saat Anda memulai hosting Asp.Net Core Anda melalui app.config aplikasi konsol juga digunakan.


TL; DR

Pilihan file konfigurasi ditentukan oleh lingkungan hosting yang Anda pilih untuk layanan ini. Jika Anda menggunakan IIS untuk meng-host layanan Anda, gunakan file Web.config. Jika Anda menggunakan lingkungan hosting lainnya, gunakan file App.config. Lihat Mengkonfigurasi Layanan Menggunakan dokumentasi File Konfigurasi dan juga memeriksa Konfigurasi di ASP.NET Core.

Alper Ebicoglu
sumber
0

Dikatakan asp.net di atas, jadi mengapa tidak menyimpan pengaturan Anda dalam database dan menggunakan cache kustom untuk mengambilnya?

Alasan kami melakukannya karena lebih mudah (bagi kami) untuk memperbarui database terus menerus daripada mendapatkan izin untuk terus memperbarui file produksi.

Contoh dari Tembolok Kustom:

public enum ConfigurationSection
{
    AppSettings
}

public static class Utility
{
    #region "Common.Configuration.Configurations"

    private static Cache cache = System.Web.HttpRuntime.Cache;

    public static String GetAppSetting(String key)
    {
        return GetConfigurationValue(ConfigurationSection.AppSettings, key);
    }

    public static String GetConfigurationValue(ConfigurationSection section, String key)
    {
        Configurations config = null;

        if (!cache.TryGetItemFromCache<Configurations>(out config))
        {
            config = new Configurations();
            config.List(SNCLavalin.US.Common.Enumerations.ConfigurationSection.AppSettings);
            cache.AddToCache<Configurations>(config, DateTime.Now.AddMinutes(15));
        }

        var result = (from record in config
                      where record.Key == key
                      select record).FirstOrDefault();

        return (result == null) ? null : result.Value;
    }

    #endregion
}

namespace Common.Configuration
{
    public class Configurations : List<Configuration>
    {
        #region CONSTRUCTORS

        public Configurations() : base()
        {
            initialize();
        }
        public Configurations(int capacity) : base(capacity)
        {
            initialize();
        }
        public Configurations(IEnumerable<Configuration> collection) : base(collection)
        {
            initialize();
        }

        #endregion

        #region PROPERTIES & FIELDS

        private Crud _crud; // Db-Access layer

        #endregion

        #region EVENTS
        #endregion

        #region METHODS

        private void initialize()
        {
            _crud = new Crud(Utility.ConnectionName);
        }

        /// <summary>
        /// Lists one-to-many records.
        /// </summary>
        public Configurations List(ConfigurationSection section)
        {
            using (DbCommand dbCommand = _crud.Db.GetStoredProcCommand("spa_LIST_MyConfiguration"))
            {
                _crud.Db.AddInParameter(dbCommand, "@Section", DbType.String, section.ToString());

                _crud.List(dbCommand, PopulateFrom);
            }

            return this;
        }

        public void PopulateFrom(DataTable table)
        {
            this.Clear();

            foreach (DataRow row in table.Rows)
            {
                Configuration instance = new Configuration();
                instance.PopulateFrom(row);
                this.Add(instance);
            }
        }

        #endregion
    }

    public class Configuration
    {
        #region CONSTRUCTORS

        public Configuration()
        {
            initialize();
        }

        #endregion

        #region PROPERTIES & FIELDS

        private Crud _crud;

        public string Section { get; set; }
        public string Key { get; set; }
        public string Value { get; set; }

        #endregion

        #region EVENTS
        #endregion

        #region METHODS

        private void initialize()
        {
            _crud = new Crud(Utility.ConnectionName);
            Clear();
        }

        public void Clear()
        {
            this.Section = "";
            this.Key = "";
            this.Value = "";
        }
        public void PopulateFrom(DataRow row)
        {
            Clear();

            this.Section = row["Section"].ToString();
            this.Key = row["Key"].ToString();
            this.Value = row["Value"].ToString();
        }

        #endregion
    }
}
Tahanan NOL
sumber