App.config / web.config içindeki değişkenler


92

app.configVeya web.configdosyalarında aşağıdaki gibi bir şey yapmak mümkün mü ?

<appSettings>
 <add key="MyBaseDir" value="C:\MyBase" />
 <add key="Dir1" value="[MyBaseDir]\Dir1"/>
 <add key="Dir2" value="[MyBaseDir]\Dir2"/>
</appSettings>

Daha sonra kodumdaki Dir2'ye sadece şunu söyleyerek erişmek istiyorum:

 ConfigurationManager.AppSettings["Dir2"]

Bu, uygulamamı tümünde yalnızca BİR girişi değiştirmem gereken farklı sunuculara ve konumlara yüklediğimde bana yardımcı olacaktır app.config. (Koddaki tüm birleştirmeyi yönetebileceğimi biliyorum, ancak bu şekilde tercih ederim).


Sanırım appSettings anahtarlarında kullanılacak değişkenleri doğrudan yapılandırma dosyalarında tanımlamaktan bahsediyor.
Michaël Carpentier

1
XML <! ENTITY> bildirimini kullanarak da kontrol ettim, ancak MS'in web.config dosyalarını işleme biçimi nedeniyle desteklenmiyor.
chilltemp

Çabaların için teşekkürler. Herhangi bir kodu değiştirmemeyi tercih ederim. Kodda zaten şunu belirten bir ifade var: string dir2 = ConfigurationManager.AppSettings ["Dir2"]. Yalnızca artık value = "[MyBaseDir] \ Dir2" yerine value = "D: \ blahdir \ Dir2" yazan app.config dosyasını temizlemek istiyorum
DeeStackOverflow

Yanıtlar:


7

İyi soru.

Olduğunu sanmıyorum. Kolay bir yol olsaydı bunun oldukça iyi bilineceğini düşünüyorum ve Microsoft'un Visual Studio 2010'da dağıtım ve test için farklı yapılandırma dosyalarını dağıtmak için bir mekanizma oluşturduğunu görüyorum.

Bununla birlikte, bununla birlikte; ConnectionStringsBölümde "| DataDirectory |" adında bir tür yer tutucunuzun olduğunu buldum . Belki orada ne iş yaptığına bir bakabilirsin ...

İşte machine.configbunu göstermekten bir parça :

 <connectionStrings>
    <add
        name="LocalSqlServer"
        connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
        providerName="System.Data.SqlClient"
    />
 </connectionStrings>

Bu ilginç bir bilgi. Belki değişkenlere boru sembolü ("|") kullanılarak erişilebilir? Hmm .. Bunun işe yarayıp yaramayacağını merak ediyorum: <add key = "Dir2" value = "| MyBaseDir | \ Dir2" />
DeeStackOverflow

4
DataDirectory değeri aslında AppDomain'deki bir veri öğesidir. AppDomain.CurrentDomain.SetData ("DataDirectory", dataPath) kullanarak değeri geçersiz kılabilirsiniz; Bunun gibi diğer değişkenleri tanımlayıp "otomatik olarak genişletir" yapıp yapamayacağınızı test etmedim ...
Peter

22

Biraz daha karmaşık, ancak çok daha esnek bir alternatif, bir yapılandırma bölümünü temsil eden bir sınıf oluşturmaktır. Senin içinde app.config/ web.configdosyasından, bu sahip olabilir:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <!-- This section must be the first section within the <configuration> node -->
    <configSections>
        <section name="DirectoryInfo" type="MyProjectNamespace.DirectoryInfoConfigSection, MyProjectAssemblyName" />
    </configSections>

    <DirectoryInfo>
        <Directory MyBaseDir="C:\MyBase" Dir1="Dir1" Dir2="Dir2" />
    </DirectoryInfo>
</configuration>

Ardından, .NET kodunuzda (örneğimde C # kullanacağım), aşağıdaki gibi iki sınıf oluşturabilirsiniz:

using System;
using System.Configuration;

namespace MyProjectNamespace {

    public class DirectoryInfoConfigSection : ConfigurationSection {

        [ConfigurationProperty("Directory")]
        public DirectoryConfigElement Directory {
            get {
                return (DirectoryConfigElement)base["Directory"];
            }
    }

    public class DirectoryConfigElement : ConfigurationElement {

        [ConfigurationProperty("MyBaseDir")]
        public String BaseDirectory {
            get {
                return (String)base["MyBaseDir"];
            }
        }

        [ConfigurationProperty("Dir1")]
        public String Directory1 {
            get {
                return (String)base["Dir1"];
            }
        }

        [ConfigurationProperty("Dir2")]
        public String Directory2 {
            get {
                return (String)base["Dir2"];
            }
        }
        // You can make custom properties to combine your directory names.
        public String Directory1Resolved {
            get {
                return System.IO.Path.Combine(BaseDirectory, Directory1);
            }
        }
    }
}

Son olarak, program kodunuzda, app.configyeni sınıflarınızı kullanarak değişkenlerinize şu şekilde erişebilirsiniz :

DirectoryInfoConfigSection config =
  (DirectoryInfoConfigSection)ConfigurationManager.GetSection("DirectoryInfo");
String dir1Path = config.Directory.Directory1Resolved;  // This value will equal "C:\MyBase\Dir1"

1
Teşekkürler ama bu aşamada bir acı olduğu için herhangi bir kodu değiştirmeden bunu yapmaya çalışıyorum.
DeeStackOverflow

Son kod satırında küçük bir hata var (kaşlı ayraçları saymaz): "return System.IO.Path.Combine (MyBaseDir, Dir1);" bunun yerine "return System.IO.Path.Combine (BaseDirectory, Dir1);" olmalıdır, aksi takdirde yöntem 'Temel Dizin'den' MyBaseDir '
TheWho

16

Benim kütüphanem Expansive'ı kullanarak başarabilirsiniz . Ayrıca Nuget geçerli buraya .

Bu, birincil kullanım durumu olarak tasarlandı.

Orta Düzey Örnek (belirteç genişletme için varsayılan kaynak olarak AppSettings kullanılarak)

App.config dosyasında:

<configuration>
    <appSettings>
        <add key="Domain" value="mycompany.com"/>
        <add key="ServerName" value="db01.{Domain}"/>
    </appSettings>
    <connectionStrings>
        <add name="Default" connectionString="server={ServerName};uid=uid;pwd=pwd;Initial Catalog=master;" provider="System.Data.SqlClient" />
    </connectionStrings>
</configuration>

Genişletilecek dizede .Expand () uzantı yöntemini kullanın :

var connectionString = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
connectionString.Expand() // returns "server=db01.mycompany.com;uid=uid;pwd=pwd;Initial Catalog=master;"

veya

Dynamic ConfigurationManager sarmalayıcısı "Config" i aşağıdaki gibi kullanın (Expand () için açık çağrı gerekli değildir):

var serverName = Config.AppSettings.ServerName;
// returns "db01.mycompany.com"

var connectionString = Config.ConnectionStrings.Default;
// returns "server=db01.mycompany.com;uid=uid;pwd=pwd;Initial Catalog=master;"

Gelişmiş Örnek 1 (simge genişletme için varsayılan kaynak olarak AppSettings kullanılarak)

App.config dosyasında:

<configuration>
    <appSettings>
        <add key="Environment" value="dev"/>
        <add key="Domain" value="mycompany.com"/>
        <add key="UserId" value="uid"/>
        <add key="Password" value="pwd"/>
        <add key="ServerName" value="db01-{Environment}.{Domain}"/>
        <add key="ReportPath" value="\\{ServerName}\SomeFileShare"/>
    </appSettings>
    <connectionStrings>
        <add name="Default" connectionString="server={ServerName};uid={UserId};pwd={Password};Initial Catalog=master;" provider="System.Data.SqlClient" />
    </connectionStrings>
</configuration>

Genişletilecek dizede .Expand () uzantı yöntemini kullanın:

var connectionString = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
connectionString.Expand() // returns "server=db01-dev.mycompany.com;uid=uid;pwd=pwd;Initial Catalog=master;"

4
Bu cevabın çok düşük puan aldığını düşünüyorum !!
Ahmad

Teşekkürler Ahmad! Expansive'ı ne kadar sevdiğinizi bana bildirin.
anderly

Bu, uygulama ayarlarının çalışma zamanı 'çözünürlüğü' olsa da, tekrarlayan anahtar değer çiftlerine sahip olma sorunlarımı çözüyor. Bunu kullanarak yapılandırma bakımımızı önemli ölçüde azalttık. Buradaki mutlak ütopya, bunun SlowCheetah ile birlikte çalışacak bir derleme zamanı eklentisi olması olacaktır. Yapabilseydim tekrar + 1 ederdim. Harika şeyler anderly.
Ahmad

Bunu başarmak için kütüphanenizin nasıl kullanılabileceğine dair kısa bir örnek verebilir misiniz?
Ryan Gates

Şu anda bununla karşılaşan başka biri için, proje 2011'den beri 6 yıldır ölü durumda :(
user1003916

4

Bu soruyu az önce gördüm sanıyordum.

Kısacası, hayır, bir uygulama yapılandırmasında değişken enterpolasyon yoktur.

İki seçeneğin var

  1. Çalışma zamanında değişkenlerin yerine geçmek için kendi değişkeninizi atabilirsiniz
  2. Derleme zamanında, uygulama yapılandırmasını hedef dağıtım ortamının belirli özelliklerine göre masaj yapın. Konfigürasyon kabusuyla başa çıkarken bununla ilgili bazı ayrıntılar

Bu doğru gönderi. Önceki gönderim (aynı soru) app.config xml girişi örneğini göstermedi. Bağlantınızı kontrol ettim - bu çok fazla iş ve orada vakit geçirmemeyi tercih ediyorum. Farklı kutular için ayrı app.config'lerimiz var ve bundan uzaklaşmak istiyorum.
DeeStackOverflow

3

Birkaç seçeneğin var. Bunu, değişkenlerinizi doğru değerle değiştirerek yapılandırma dosyanızı işleyecek bir oluşturma / dağıtma adımıyla yapabilirsiniz.

Diğer bir seçenek, bunu destekleyen kendi Yapılandırma bölümünüzü tanımlamak olacaktır. Örneğin şu xml'yi düşünün:

<variableAppSettings>
 <variables>
    <add key="@BaseDir" value="c:\Programs\Widget"/>
 </variables>
 <appSettings>
    <add key="PathToDir" value="@BaseDir\Dir1"/>
 </appSettings>
</variableAppSettings>

Şimdi bunu, çalışma zamanında sizin için değişkenleri değiştirmeyi işleyen özel yapılandırma nesnelerini kullanarak gerçekleştirirsiniz.


Gönderide xml'nizi göremiyorum (xml etiketlerini gönderebilmek için satırınızı 5 karakter girintili yapın - geçen sefer aynı sorunu yaşadım). Ayrıca, 'özel yapılandırma nesneleri' nedir? Bunu başarmak için sıfır kodlamayı tercih ediyorum çünkü bu aşamadaki kodlama değişiklikleri bizi çok geride bırakacaktır.
DeeStackOverflow

Özel yapılandırma kesinlikle [basit] kodlamayı içerir. Ancak IMHO her zaman en iyi seçeneğinizdir. Hemen hemen hiç appSettings kullanmıyorum, bunun yerine her proje için özel bir yapılandırma oluşturmayı tercih ediyorum.
Portman

3

Genellikle, web.config ayarımın her birine erişmek için özelliklere sahip statik bir sınıf yazıyorum.

public static class ConfigManager 
{
    public static string MyBaseDir
    {
        return ConfigurationManager.AppSettings["MyBaseDir"].toString();
    }

    public static string Dir1
    {
        return MyBaseDir + ConfigurationManager.AppSettings["Dir1"].toString();
    }

}

Genellikle, bu sınıfta gerektiğinde tür dönüşümleri de yaparım. Yapılandırmanıza yazılı erişim sağlar ve ayarlar değişirse, bunları yalnızca tek bir yerde düzenleyebilirsiniz.

Genellikle, ayarları bu sınıfla değiştirmek nispeten kolaydır ve çok daha fazla bakım kolaylığı sağlar.


3

app.configTanımladığınız senaryo için ortam değişkenlerini kullanabilirsiniz.

<configuration>
  <appSettings>
    <add key="Dir1" value="%MyBaseDir%\Dir1"/>
  </appSettings>
</configuration>

O zaman yolu kolayca elde edebilirsiniz:

var pathFromConfig = ConfigurationManager.AppSettings["Dir1"];
var expandedPath = Environment.ExpandEnvironmentVariables(pathFromConfig);

2

İçeride <appSettings>uygulama anahtarları oluşturabilirsiniz,

<add key="KeyName" value="Keyvalue"/>

Daha sonra bu değerlere aşağıdakileri kullanarak erişebilirsiniz:

ConfigurationManager.AppSettings["Keyname"]

ConfigurationManager sınıfını kullanmak için System.Configuration'a bir başvuru eklemeniz ve System.Configuration için bir using deyimi eklemeniz gerekir (
VB'de

2
Gösterge doğrudur, ancak sorulan soruya bir yanıt değildir.
Michaël Carpentier

1

Size DslConfig öneririm . DslConfig ile, her sunucu ana bilgisayarındaki uygulama başına yapılandırma yapmak için Global Config'den hiyerarşik yapılandırma dosyalarını, sunucu ana bilgisayarı başına Yapılandırma'yı kullanabilirsiniz (bkz. AppSpike).
Bu sizin için karmaşıksa, sadece global yapılandırma Variables.var'ı kullanabilirsiniz.
Sadece Varibales.var'da yapılandırın.

baseDir = "C:\MyBase"
Var["MyBaseDir"] = baseDir
Var["Dir1"] = baseDir + "\Dir1"
Var["Dir2"] = baseDir + "\Dir2"

Ve yapılandırma değerlerini elde edin

Configuration config = new DslConfig.BooDslConfiguration()
config.GetVariable<string>("MyBaseDir")
config.GetVariable<string>("Dir1")
config.GetVariable<string>("Dir2")

0

Bir yapılandırma dosyasında appSettings anahtarlarını tanımlamak için değişkenleri tanımlayıp kullanabileceğinizi sanmıyorum. Her zaman sizin gibi kodda birleştirmeleri yönettim.


0

İstediğiniz şeyle biraz uğraşıyorum, ancak uygulama ayarlarına bir geçersiz kılma dosyası ekleyebilir ve ardından bu dosyayı ortam başına bir geçersiz kılma dosyası ayarlayabilirsin.

<appSettings file="..\OverrideSettings.config">

0

Çok sayıda öğeyi benzer değerlerle yapılandırmamız gereken ürünleri kullanıma sunmak için, XML'yi okuyan ve iletilen parametrelere göre güncellenen küçük konsol uygulamaları kullanıyoruz. Bunlar daha sonra, kullanıcıdan Gerekli Bilgi.


0

Matt Hamsmith'in çözümünü takip etmenizi tavsiye ederim. Uygulanması bir sorunsa, neden bunu AppSettings sınıfında arka planda uygulayan bir uzantı yöntemi oluşturmuyorsunuz?

Gibi bir şey:

    public static string GetValue(this NameValueCollection settings, string key)
    {

    }

Yöntemin içinde Linq kullanarak DictionaryInfoConfigSection'da arama yaparsınız ve eşleşen anahtarla değeri döndürürsünüz. Yapılandırma dosyasını şu satırlar boyunca güncellemeniz gerekir:

<appSettings>
  <DirectoryMappings>
    <DirectoryMap key="MyBaseDir" value="C:\MyBase" />
    <DirectoryMap key="Dir1" value="[MyBaseDir]\Dir1"/>
    <DirectoryMap key="Dir2" value="[MyBaseDir]\Dir2"/>
  </DirectoryMappings>
</appSettings>

0

Bu çözümü buldum:

  1. Settings.settings uygulamasında bir değişken ConfigurationBase tanımladım (type = string Scope = Application ile)
  2. Settings.settings'deki hedef özelliklerde bir değişken ekledim, tüm bu özelliklerin Kapsam = Kullanıcı olarak ayarlanması gerekiyordu
  3. App.xaml.cs dosyasında ConfigurationBase
  4. App.xaml.cs dosyasında tüm değişkenleri ConfigurationBase değeriyle değiştirdim. Değerleri çalışma zamanında değiştirmek için özniteliklerin Scopr = Kullanıcı olarak ayarlanması gerekiyordu

Bu çözümden gerçekten memnun değilim, çünkü tüm öznitelikleri manuel olarak değiştirmem gerekiyor, yeni bir tane eklersem app.xaml.cs içinde dikkate almam gerekiyor.

Burada App.xaml.cs'den bir kod parçacığı:

string configBase = Settings.Default.ConfigurationBase;
Settings.Default.CommonOutput_Directory = Settings.Default.CommonOutput_Directory.Replace("${ConfigurationBase}", configBase);

GÜNCELLEME

Bir iyileştirme buldum (yine app.xaml.cs dosyasından bir kod parçası):

string configBase = Settings.Default.ConfigurationBase;

foreach (SettingsProperty settingsProperty in Settings.Default.Properties)
{
    if (!settingsProperty.IsReadOnly && settings.Default[settingsProperty.Name] is string)
    {
        Settings.Default[settingsProperty.Name] = ((string)Settings.Default[settingsProperty.Name]).Replace("${ConfigurationBase}", configBase);
    }
}

Şimdi değiştirmeler, ayarlarımdaki Type = string ve Scope = User olan tüm öznitelikler için çalışıyor. Sanırım bu şekilde beğendim.

UPDATE2

Görünüşe göre Kapsam = Uygulama, özellikler üzerinde çalışırken gerekli değildir.


0

Olası Üç Çözüm

Partiye geç kaldığımı biliyorum, değişken yapılandırma ayarları sorununa yeni bir çözüm olup olmadığına bakıyordum. Geçmişte kullandığım çözümlere değinen birkaç cevap var ama çoğu biraz karmaşık görünüyor. Aynı problemle mücadele eden insanlara yardımcı olması için eski çözümlerime bakıp uygulamaları bir araya getirmeyi düşündüm.

Bu örnek için bir konsol uygulamasında aşağıdaki uygulama ayarını kullandım:

<appSettings>
    <add key="EnvironmentVariableExample" value="%BaseDir%\bin"/>
    <add key="StaticClassExample" value="bin"/>
    <add key="InterpollationExample" value="{0}bin"/>
  </appSettings>

1. Ortam değişkenlerini kullanın

Autocro autocro'nun cevabının buna değindiğine inanıyorum . Ben sadece görsel stüdyoyu kapatmak zorunda kalmadan oluştururken veya hata ayıklarken yeterli olması gereken bir uygulama yapıyorum. Bu çözümü gün içinde kullandım ...

  • MSBuild değişkenlerini kullanacak bir önceden oluşturulmuş olay oluşturun

    Uyarı: Kolayca değiştirilmeyecek bir değişken kullanın, bu nedenle proje adınızı veya değişken adına benzer bir şey kullanın.

    SETX BaseDir "$(ProjectDir)"

  • Değişkenleri sıfırlayın; aşağıdakine benzer bir şey kullanarak:

    Stack Overflow'da Ortam Değişkenlerini Yenile

  • Kodunuzdaki ayarı kullanın:

'

private void Test_Environment_Variables()
{
    string BaseDir = ConfigurationManager.AppSettings["EnvironmentVariableExample"];
    string ExpandedPath = Environment.ExpandEnvironmentVariables(BaseDir).Replace("\"", ""); //The function addes a " at the end of the variable
    Console.WriteLine($"From within the C# Console Application {ExpandedPath}");
}

'

2. Dize enterpolasyonu kullanın:

  • String.Format () işlevini kullanın

'

private void Test_Interpollation()
{
    string ConfigPath = ConfigurationManager.AppSettings["InterpollationExample"];
    string SolutionPath = Path.GetFullPath(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, @"..\..\"));
    string ExpandedPath = string.Format(ConfigPath, SolutionPath.ToString());
    Console.WriteLine($"Using old interpollation {ExpandedPath}");
}

'

3. Statik bir sınıf kullanarak, çoğunlukla kullandığım çözüm budur.

  • Hayata geçirme

'

private void Test_Static_Class()
{
    Console.WriteLine($"Using a static config class {Configuration.BinPath}");
}

'

  • Statik sınıf

'

static class Configuration
{
    public static string BinPath
    {
        get
        {
            string ConfigPath = ConfigurationManager.AppSettings["StaticClassExample"];
            string SolutionPath = Path.GetFullPath(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, @"..\..\"));
            return SolutionPath + ConfigPath;
        }
    }
}

'

Proje Kodu:

App.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
  <appSettings>
    <add key="EnvironmentVariableExample" value="%BaseDir%\bin"/>
    <add key="StaticClassExample" value="bin"/>
    <add key="InterpollationExample" value="{0}bin"/>
  </appSettings>
</configuration>

Program.cs

using System;
using System.Configuration;
using System.IO;

namespace ConfigInterpollation
{
    class Program
    {
        static void Main(string[] args)
        {
            new Console_Tests().Run_Tests();
            Console.WriteLine("Press enter to exit");
            Console.ReadLine();
        }        
    }

    internal class Console_Tests
    {
        public void Run_Tests()
        {
            Test_Environment_Variables();
            Test_Interpollation();
            Test_Static_Class();
        }
        private void Test_Environment_Variables()
        {
            string ConfigPath = ConfigurationManager.AppSettings["EnvironmentVariableExample"];
            string ExpandedPath = Environment.ExpandEnvironmentVariables(ConfigPath).Replace("\"", "");
            Console.WriteLine($"Using environment variables {ExpandedPath}");
        }

        private void Test_Interpollation()
        {
            string ConfigPath = ConfigurationManager.AppSettings["InterpollationExample"];
            string SolutionPath = Path.GetFullPath(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, @"..\..\"));
            string ExpandedPath = string.Format(ConfigPath, SolutionPath.ToString());
            Console.WriteLine($"Using interpollation {ExpandedPath}");
        }

        private void Test_Static_Class()
        {
            Console.WriteLine($"Using a static config class {Configuration.BinPath}");
        }
    }

    static class Configuration
    {
        public static string BinPath
        {
            get
            {
                string ConfigPath = ConfigurationManager.AppSettings["StaticClassExample"];
                string SolutionPath = Path.GetFullPath(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, @"..\..\"));
                return SolutionPath + ConfigPath;
            }
        }
    }
}

Pre-build olayı:

Proje Ayarları -> Etkinlikleri Oluştur

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.