Tương đương với 'app.config' cho thư viện (DLL)


149

Có tương đương app.configvới thư viện (DLL) không? Nếu không, cách dễ nhất để lưu trữ các cài đặt cấu hình dành riêng cho thư viện là gì? Vui lòng xem xét rằng thư viện có thể được sử dụng trong các ứng dụng khác nhau.

Câu trả lời:


161

Bạn có thể có tệp cấu hình riêng biệt, nhưng bạn sẽ phải đọc "thủ công", ConfigurationManager.AppSettings["key"]sẽ chỉ đọc cấu hình của cụm đang chạy.

Giả sử bạn đang sử dụng Visual Studio làm IDE, bạn có thể nhấp chuột phải vào dự án mong muốn → Thêm → Mục mới → Tệp cấu hình ứng dụng

Điều này sẽ thêm App.configvào thư mục dự án, đặt các thiết lập của bạn trong đó dưới <appSettings>phần. Trong trường hợp bạn không sử dụng Visual Studio và thêm tệp theo cách thủ công, hãy đảm bảo đặt tên như vậy: DLLName.dll.config , nếu không, đoạn mã dưới đây sẽ không hoạt động chính xác.

Bây giờ để đọc từ tập tin này có chức năng như vậy:

string GetAppSetting(Configuration config, string key)
{
    KeyValueConfigurationElement element = config.AppSettings.Settings[key];
    if (element != null)
    {
        string value = element.Value;
        if (!string.IsNullOrEmpty(value))
            return value;
    }
    return string.Empty;
}

Và để sử dụng nó:

Configuration config = null;
string exeConfigPath = this.GetType().Assembly.Location;
try
{
    config = ConfigurationManager.OpenExeConfiguration(exeConfigPath);
}
catch (Exception ex)
{
    //handle errror here.. means DLL has no sattelite configuration file.
}

if (config != null)
{
    string myValue = GetAppSetting(config, "myKey");
    ...
}

Bạn cũng sẽ phải thêm tham chiếu đến không gian tên System.Configuration để có sẵn lớp Cấu hình Trình quản lý.

Khi xây dựng dự án, ngoài DLL bạn cũng sẽ có DllName.dll.configtệp, đó là tệp bạn phải xuất bản với chính DLL.

Trên đây là mã mẫu cơ bản, đối với những người quan tâm đến một ví dụ quy mô đầy đủ, vui lòng tham khảo câu trả lời khác này .


1
@Rodney hãy thử thay đổi string exeConfigPath = this.GetType().Assembly.Location;thành một cái gì đó như:string exeConfigPath = @"C:\MyFolder\DllFolder\ExeName.exe";
Shadow Wizard là Ear For You

1
Bất kỳ ý tưởng làm thế nào để làm điều này nếu dll đang được sao chép vào một thư mục không xác định bởi công cụ kiểm tra đơn vị chia sẻ lại?
Tự động tìm kiếm

11
Một mẹo cho bất kỳ ai khác thực hiện điều này: để tự động hóa việc tạo DLLName.dll.config bằng cách tham chiếu các ứng dụng, tôi chỉ cần đổi tên app.config thành DLLName.dll.config và thay đổi thuộc tính "Sao chép vào Thư mục đầu ra" thành "Sao chép luôn" . Ngoài ra, nhu cầu của tôi là về các chuỗi kết nối, có thể được truy xuất bằng config.ConnectionStrings.ConnectionStrings [ConnStringName] .ConnectionString.
Jeff G

2
tên tệp app.cfg rất quan trọng để đọc các giá trị appcfg, tên tệp phải là "DLL_NAME.DLL.CONFIG"
SaddamBinSyed

2
Sửa chữa cho bình luận cuối cùng của tôi. Trong giải pháp VS2017 của tôi, bằng cách xóa các tệp App.config mới, không hoạt động của tôi khỏi các dự án thử nghiệm & DLL của tôi và chỉ cần thêm lại vào dự án thử nghiệm của tôi, nó đột nhiên bắt đầu hoạt động! Cài đặt App.config của tôi bây giờ sẽ tự động được bao gồm trong DLL.configs. Thật là nhẹ nhõm!
Zeek2

30

Thật không may, bạn chỉ có thể có một tệp app.config cho mỗi lần thực thi, vì vậy nếu bạn có DLL được liên kết với ứng dụng của mình, họ không thể có tệp app.config của riêng họ.

Giải pháp là: Bạn không cần đặt tệp App.config trong dự án của Thư viện lớp.
Bạn đặt tệp App.config trong ứng dụng đang tham chiếu dll của thư viện lớp của bạn.

Ví dụ: giả sử chúng ta có một thư viện lớp có tên MyClass.dll sử dụng tệp app.config như vậy:

string connect = 
ConfigurationSettings.AppSettings["MyClasses.ConnectionString"];

Bây giờ, giả sử chúng ta có Ứng dụng Windows có tên MyApp.exe tham chiếu MyClass.dll. Nó sẽ chứa một App.config với một mục như:

<appSettings>
    <add key="MyClasses.ConnectionString"
         value="Connection string body goes here" />
</appSettings>

HOẶC LÀ

Một tệp xml tương đương tốt nhất cho app.config. Sử dụng xml serialize / deserialize khi cần thiết. Bạn có thể gọi nó là những gì bạn muốn. Nếu cấu hình của bạn là "tĩnh" và không cần thay đổi, bạn cũng có thể thêm nó vào dự án dưới dạng tài nguyên nhúng.

Hy vọng nó mang lại một số ý tưởng


6
ConfigurationSettingsbây giờ đã lỗi thời và được thay thế bởi ConfigurationManager, vì vậy, tương đương bây giờ sẽ làConfigurationManager.AppSettings
Mã hóa

2
bỏ phiếu. câu hỏi là mỗi dll và không phải mỗi ứng dụng. giải pháp tốt nhất: stackoverflow.com/a/5191101/2935383
raiserle

3
Tôi nghi ngờ đề nghị này sẽ không hoạt động trong trường hợp các dll bị ràng buộc muộn mà sẽ không có kiến ​​thức về việc thực thi gọi chúng.
beanmf

9

Các tệp cấu hình là phạm vi ứng dụng và không có phạm vi lắp ráp. Vì vậy, bạn sẽ cần đặt các phần cấu hình thư viện của mình trong tệp cấu hình của mọi ứng dụng đang sử dụng thư viện của bạn.

Điều đó nói rằng, không phải là một thực hành tốt để có được cấu hình từ tệp cấu hình của ứng dụng, đặc biệt là appSettingsphần, trong một thư viện lớp. Nếu thư viện của bạn cần các tham số, có lẽ chúng sẽ được chuyển qua làm đối số phương thức trong hàm tạo, phương thức nhà máy, v.v. bởi bất cứ ai đang gọi thư viện của bạn. Điều này ngăn các ứng dụng gọi vô tình sử dụng lại các mục cấu hình được thư viện lớp mong đợi.

Điều đó nói rằng, các tệp cấu hình XML cực kỳ tiện dụng, do đó, sự thỏa hiệp tốt nhất mà tôi tìm thấy là sử dụng các phần cấu hình tùy chỉnh. Bạn có thể đặt cấu hình thư viện của mình trong một tệp XML được khung tự động đọc và phân tích cú pháp và bạn tránh được các tai nạn tiềm ẩn.

Bạn có thể tìm hiểu thêm về các phần cấu hình tùy chỉnh trên MSDNPhil Haack cũng có một bài viết hay về chúng.


7
"không phải là một cách thực hành tốt để lấy cấu hình từ tệp cấu hình trong thư viện lớp" - tôi hoàn toàn không đồng ý với điều này. Ví dụ, thư viện lớp DAL thường sẽ nhận được dữ liệu cấu hình, chẳng hạn như chuỗi kết nối từ tệp cấu hình ứng dụng thay vì thông tin này được truyền từ lớp BLL. Bất kỳ lớp Framework nào sử dụng cấu hình (ví dụ: Thành viên ASP.NET) đều hoạt động theo cách này.
Joe

Tôi sửa đổi câu trả lời của tôi một chút. Tôi vẫn đứng trước những gì tôi nói, nhưng bạn nói đúng, tôi không bao giờ có ý ám chỉ rằng các tập tin cấu hình không nên được sử dụng. Ý tôi là, thay vì các appSettingsphần tùy chỉnh dựa trên quy ước , cung cấp một sự thay thế tuyệt vời; Rốt cuộc, đó là khá nhiều những gì Thành viên ASP.NET sử dụng.
madd0

5
public class ConfigMan
{
    #region Members

    string _assemblyLocation;
    Configuration _configuration;

    #endregion Members

    #region Constructors

    /// <summary>
    /// Loads config file settings for libraries that use assembly.dll.config files
    /// </summary>
    /// <param name="assemblyLocation">The full path or UNC location of the loaded file that contains the manifest.</param>
    public ConfigMan(string assemblyLocation)
    {
        _assemblyLocation = assemblyLocation;
    }

    #endregion Constructors

    #region Properties

    Configuration Configuration
    {
        get
        {
            if (_configuration == null)
            {
                try
                {
                    _configuration = ConfigurationManager.OpenExeConfiguration(_assemblyLocation);
                }
                catch (Exception exception)
                {
                }
            }
            return _configuration;
        }
    }

    #endregion Properties

    #region Methods

    public string GetAppSetting(string key)
    {
        string result = string.Empty;
        if (Configuration != null)
        {
            KeyValueConfigurationElement keyValueConfigurationElement = Configuration.AppSettings.Settings[key];
            if (keyValueConfigurationElement != null)
            {
                string value = keyValueConfigurationElement.Value;
                if (!string.IsNullOrEmpty(value)) result = value;
            }
        }
        return result;
    }

    #endregion Methods
}

Chỉ cần một cái gì đó để làm, tôi tái cấu trúc câu trả lời hàng đầu vào một lớp. Cách sử dụng là một cái gì đó như:

ConfigMan configMan = new ConfigMan(this.GetType().Assembly.Location);
var setting = configMan.GetAppSetting("AppSettingsKey");

4

Nếu bạn thêm Cài đặt vào dự án Thư viện lớp trong Visual Studio (Thuộc tính dự án, Cài đặt), nó sẽ thêm tệp app.config vào dự án của bạn với các phần userSinstall / applicationatioNSinstall có liên quan và các giá trị mặc định cho các cài đặt này từ Cài đặt của bạn tập tin.

Tuy nhiên, tệp cấu hình này sẽ không được sử dụng trong thời gian chạy - thay vào đó thư viện lớp sử dụng tệp cấu hình của ứng dụng lưu trữ.

Tôi tin rằng lý do chính để tạo tệp này là để bạn có thể sao chép / dán cài đặt vào tệp cấu hình của ứng dụng máy chủ.


4

Tôi hiện đang tạo các plugin cho một thương hiệu phần mềm bán lẻ, thực sự là các thư viện lớp .net. Theo yêu cầu, mỗi plugin cần được cấu hình bằng tệp cấu hình. Sau một chút nghiên cứu và thử nghiệm, tôi đã biên soạn lớp sau. Nó làm công việc hoàn hảo. Lưu ý rằng tôi đã không thực hiện xử lý ngoại lệ cục bộ trong trường hợp của mình bởi vì, tôi bắt ngoại lệ ở mức cao hơn.

Một số điều chỉnh có thể cần thiết để có được dấu thập phân đúng, trong trường hợp số thập phân và nhân đôi, nhưng nó hoạt động tốt cho CultureInfo của tôi ...

static class Settings
{
    static UriBuilder uri = new UriBuilder(Assembly.GetExecutingAssembly().CodeBase);
    static Configuration myDllConfig = ConfigurationManager.OpenExeConfiguration(uri.Path);
    static AppSettingsSection AppSettings = (AppSettingsSection)myDllConfig.GetSection("appSettings");
    static NumberFormatInfo nfi = new NumberFormatInfo() 
    { 
        NumberGroupSeparator = "", 
        CurrencyDecimalSeparator = "." 
    };

    public static T Setting<T>(string name)
    {
        return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);
    }
}

Mẫu tệp App.Config

<add key="Enabled" value="true" />
<add key="ExportPath" value="c:\" />
<add key="Seconds" value="25" />
<add key="Ratio" value="0.14" />

Sử dụng:

  somebooleanvar = Settings.Setting<bool>("Enabled");
  somestringlvar = Settings.Setting<string>("ExportPath");
  someintvar =     Settings.Setting<int>("Seconds");
  somedoublevar =  Settings.Setting<double>("Ratio");

Tín dụng cho Shadow Wizard & MattC


1
Đây phải là câu trả lời được chấp nhận. Rất nhỏ gọn và "hoạt động ngay lập tức". Thứ tốt
nmarler

2

Để trả lời cho câu hỏi ban đầu, tôi thường thêm tệp cấu hình trong dự án thử nghiệm của mình dưới dạng liên kết; sau đó bạn có thể sử dụng thuộc tính DeploymentItem để thêm vào thư mục Out của lần chạy thử.

[TestClass]
[DeploymentItem("MyProject.Cache.dll.config")]
public class CacheTest
{
    .
    .
    .
    .
}

Đáp lại những bình luận rằng Hội đồng không thể là dự án cụ thể, họ có thể và nó cung cấp đặc biệt linh hoạt tuyệt vời. khi làm việc với các khung IOC.


2

Tôi đã đối mặt với cùng một vấn đề và giải quyết nó bằng cách tạo một lớp tĩnh Parameterssau khi thêm Tệp cấu hình ứng dụng vào dự án:

public static class Parameters
{
    // For a Web Application
    public static string PathConfig { get; private set; } =
        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "web.config");

    // For a Class Library
    public static string PathConfig { get; private set; } =
        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin", "LibraryName.dll.config");

    public static string GetParameter(string paramName)
    {
        string paramValue = string.Empty;

        using (Stream stream = File.OpenRead(PathConfig))
        {
            XDocument xdoc = XDocument.Load(stream);

            XElement element = xdoc.Element("configuration").Element("appSettings").Elements().First(a => a.Attribute("key").Value == paramName);
            paramValue = element.Attribute("value").Value;
        }

        return paramValue;
    }
}

Sau đó nhận được một tham số như thế này:

Parameters.GetParameter("keyName");

1
Xuất sắc! Điều này giúp tôi có được các bài kiểm tra tự động Trình điều khiển ứng dụng Windows chạy trên các máy đích. Các dll trong trường hợp của tôi là từ một dự án thử nghiệm. Điều duy nhất tôi muốn thêm là trong Win App Driver (và có thể cả các hình thức kiểm tra tự động khác), BaseDirectory thực sự là thư mục đầu ra thay đổi mỗi lần. Tôi đã phải chuỗi con như thế này ... AppDomain.CienDomain.BaseDirectory.Sub chuỗi (0, AppDomain.CienDomain.BaseDirectory.IndexOf ("TestResults")). bằng cách này tôi có thể cắt thư mục đầu ra không mong muốn vì tệp cấu hình của tôi nằm trong cùng thư mục với các dll thử nghiệm của tôi.
Ewan

1

các hội đồng không có tệp app.config của riêng họ. Họ sử dụng tệp app.config của ứng dụng đang sử dụng chúng. Vì vậy, nếu hội đồng của bạn đang mong đợi một số thứ nhất định trong tệp cấu hình, thì hãy đảm bảo rằng tệp cấu hình của ứng dụng của bạn có các mục đó trong đó.

Nếu tập hợp của bạn đang được sử dụng bởi nhiều ứng dụng thì mỗi ứng dụng đó sẽ cần phải có các mục đó trong tệp app.config của chúng.

Những gì tôi khuyên bạn nên làm là xác định các thuộc tính trên các lớp trong cụm của bạn cho các giá trị đó chẳng hạn

private string ExternalServicesUrl
{
  get
  {
    string externalServiceUrl = ConfigurationManager.AppSettings["ExternalServicesUrl"];
    if (String.IsNullOrEmpty(externalServiceUrl))
      throw new MissingConfigFileAppSettings("The Config file is missing the appSettings entry for: ExternalServicesUrl");
    return externalServiceUrl;
  }
}

Ở đây, thuộc tính InternalServiceUrl nhận giá trị của nó từ tệp cấu hình của ứng dụng. Nếu bất kỳ ứng dụng nào sử dụng cụm này bị thiếu thì cài đặt đó trong tệp cấu hình, bạn sẽ nhận được một ngoại lệ o rõ ràng là thiếu một cái gì đó.

MissingConfigFileAppS Settings là một Ngoại lệ tùy chỉnh. Bạn có thể muốn ném một ngoại lệ khác.

Tất nhiên, một thiết kế tốt hơn sẽ là phương thức của các lớp đó được cung cấp các giá trị đó dưới dạng tham số thay vì dựa vào cài đặt tệp cấu hình. Bằng cách đó, các ứng dụng sử dụng các lớp này có thể quyết định từ đâu và làm thế nào chúng cung cấp các giá trị này.


Hãy cẩn thận ở trên: khi chạy các bài kiểm tra xUnit trên DLL lắp ráp .NET của bạn, xUnit sẽ đọc .config của thư viện, trong thời gian chạy. Và nó sẽ bỏ qua mọi App.config được thêm vào dự án thử nghiệm hoặc DLL.
Zeek2

1

Sử dụng thêm mục hiện có, chọn cấu hình ứng dụng từ dự án dll. Trước khi nhấp vào thêm, hãy sử dụng mũi tên xuống nhỏ ở phía bên phải của nút thêm để "thêm dưới dạng liên kết"

Tôi làm điều này tất cả các thời gian trong dev của tôi.


1

Lời mở đầu : Tôi đang sử dụng NET 2.0;

Các giải pháp được đăng bởi Yiannis Leoussis là chấp nhận được nhưng tôi đã có một số vấn đề với nó.

Đầu tiên, static AppSettingsSection AppSettings = (AppSettingsSection)myDllConfig.GetSection("appSettings");trả về null. Tôi phải đổi nó thànhstatic AppSettingSection = myDllConfig.AppSettings;

Sau đó, return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);không có một lưu ý cho Ngoại lệ. Vì vậy, tôi đã thay đổi nó

try
{
    return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);
}
catch (Exception ex)
{
    return default(T);
}

Điều này hoạt động rất tốt nhưng nếu bạn có một dll khác, bạn phải viết lại mỗi lần mã cho mỗi hội đồng. Vì vậy, đây là phiên bản của tôi cho một Class để khởi tạo mỗi khi bạn cần.

public class Settings
{
    private AppSettingsSection _appSettings;
    private NumberFormatInfo _nfi;

    public Settings(Assembly currentAssembly)
    {
        UriBuilder uri = new UriBuilder(currentAssembly.CodeBase);
        string configPath = Uri.UnescapeDataString(uri.Path);
        Configuration myDllConfig = ConfigurationManager.OpenExeConfiguration(configPath);
        _appSettings = myDllConfig.AppSettings;
        _nfi = new NumberFormatInfo() 
        { 
            NumberGroupSeparator = "", 
            CurrencyDecimalSeparator = "." 
        };
    }


    public T Setting<T>(string name)
    {
        try
        {
            return (T)Convert.ChangeType(_appSettings.Settings[name].Value, typeof(T), _nfi);
        }
        catch (Exception ex)
        {
            return default(T);
        }
    }
}

Đối với cấu hình:

<add key="Enabled" value="true" />
<add key="ExportPath" value="c:\" />
<add key="Seconds" value="25" />
<add key="Ratio" value="0.14" />

Sử dụng nó như:

Settings _setting = new Settings(Assembly.GetExecutingAssembly());

somebooleanvar = _settings.Setting<bool>("Enabled");
somestringlvar = _settings.Setting<string>("ExportPath");
someintvar =     _settings.Setting<int>("Seconds");
somedoublevar =  _settings.Setting<double>("Ratio");

Xin vui lòng, xem lại phiếu bầu để xóa. Lỗi của tôi là gửi câu trả lời trong khi viết nó.
Matteo Gaggiano

0

Theo như tôi biết, bạn phải sao chép + dán các phần bạn muốn từ thư viện .config vào tệp .config ứng dụng. Bạn chỉ nhận được 1 app.config cho mỗi phiên bản thực thi.


nếu bạn đang sử dụng các phần cấu hình tùy chỉnh, bạn có thể sử dụng thuộc tính configSource: <MySection configSource = "mysection.config" /> và chỉ cấu hình tệp với dll
Jan Remunda

Tôi đã thêm các câu hỏi mới khi được hỏi, ví dụ về chức năng luôn trả về một chuỗi trống và cài đặt máy chủ thư> stackoverflow.com/questions/25123544/ và và stackoverflow.com/questions/25138788/ vì vậy tôi hy vọng ai đó trả lời chúng khi tôi Tôi gần như chỉ ở mức khó mã hóa các giá trị vào DLL!
MonkeyMagix

0

Tại sao không sử dụng:

  • [ProjectNamespace].Properties.Settings.Default.[KeyProperty] cho C #
  • My.Settings.[KeyProperty] cho VB.NET

Bạn chỉ cần cập nhật trực quan các thuộc tính đó tại thời điểm thiết kế thông qua:

[Solution Project]->Properties->Settings


Điều này sẽ tự động tạo một tập tin cấu hình cho dll. Nhưng bạn không thể đọc các giá trị được sửa đổi từ tệp cấu hình trong thời gian chạy. Cuối cùng, nó sẽ hiển thị các giá trị của ứng dụng gọi điện của bạn. Xem thêm @Joe trả lời
Mã Giáo hoàng

Không, nếu nó được cấu hình cho cấu hình của người dùng. Ý tưởng là chỉnh sửa những gì người dùng cần, cấu hình chúng trong thời gian chạy và sau đó lưu chúng. Sau đó, khi người dùng làm việc với thư viện, nó sẽ tải cấu hình của nó, được lưu trong đường dẫn người dùng tương ứng, nhưng chỉ hoạt động với anh ta.
Pedro Mora

0

sử dụng từ các cấu hình phải rất rất dễ dàng như thế này:

var config = new MiniConfig("setting.conf");

config.AddOrUpdate("port", "1580");

if (config.TryGet("port", out int port)) // if config exist
{
    Console.Write(port);
}

để biết thêm chi tiết, xem MiniConfig

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.