2009-02-27 106 views
171

Tôi đang cố gắng thêm tệp app.config vào tệp DLL của mình, nhưng tất cả các lần thử đều thất bại.C# Tệp cấu hình DLL

Theo MusicGenesis trong 'Putting configuration information in a DLL' điều này không phải là vấn đề. Vì vậy, rõ ràng là tôi đang làm gì đó sai ...

Các mã sau đây sẽ trả về ConnectionString của tôi từ DLL của tôi:

return ConfigurationManager.AppSettings["ConnectionString"]; 

Tuy nhiên, khi tôi copy file app.config để ứng dụng giao diện điều khiển của tôi, nó hoạt động khỏe.

Bất kỳ ý tưởng nào?

+0

Theo bài viết được giới thiệu: nếu tên của dll là MyDll.dll, thì tệp cấu hình phải là MyDLL.dll.config. Vì vậy, nếu bạn đọc các thiết lập cấu hình từ bên trong dll, nó nên tham khảo cấu hình riêng của nó phải không? – MegaByte

+10

Bất kể mã yêu cầu gì - nó đang tìm kiếm tệp như được chỉ định cho cài đặt AppDomain: AppDomain.CurrentDomain.SetupInformation.ConfigurationFile –

+0

Lưu ý: Câu hỏi "đặt thông tin cấu hình trong DLL" là cách tách cấu hình ứng dụng của bạn mã vào thư viện để tách biệt với mã ứng dụng chính. Điều này rất khác với một tập tin cấu hình riêng biệt và đặc biệt cho một DLL riêng của nó. –

Trả lời

13

Khi sử dụng ConfigurationManager, tôi chắc rằng nó đang tải tệp cấu hình/AppDomain (app.config/web.config). Nếu bạn muốn tải một tập tin cấu hình cụ thể, bạn sẽ phải yêu cầu cụ thể cho rằng tập tin theo tên ...

Bạn có thể thử:

var config = ConfigurationManager.OpenExeConfiguration("foo.dll"); 
config.ConnectionStrings. [etc] 
+0

Theo bài viết được giới thiệu: nếu tên của dll là MyDll.dll, thì tệp cấu hình phải là MyDLL.dll.config . Vì vậy, nếu bạn đọc các thiết lập cấu hình từ bên trong dll, nó nên tham khảo cấu hình riêng của nó phải không? – MegaByte

+0

Không ... Tôi không nghĩ vậy. "từ với dll" không có tỷ lệ cược; theo mặc định, nó đang xem tệp cấu hình được định nghĩa cho AppDomain: my.exe.config –

+1

Cụ thể, cài đặt AppDomain.CurrentDomain.SetupInformation.ConfigurationFile. –

12

ConfigurationManager.AppSettings trả về các thiết lập được xác định cho ứng dụng , không phải cho các DLL cụ thể, bạn có thể truy cập chúng nhưng đó là các thiết lập ứng dụng sẽ được trả về.

Nếu bạn đang sử dụng dll từ một ứng dụng khác thì ConnectionString sẽ nằm trong app.settings của ứng dụng.

1

Như Marc nói, điều này là không thể (mặc dù Visual Studio cho phép bạn thêm tệp cấu hình ứng dụng trong dự án thư viện lớp).

Bạn có thể muốn xem lớp học AssemblySettings có vẻ như làm cho tệp cấu hình lắp ráp có thể.

256

Nó không phải là tầm thường để tạo tệp cấu hình .NET cho tệp .DLL và vì lý do chính đáng. Cơ cấu cấu hình .NET có rất nhiều tính năng được tích hợp sẵn để tạo điều kiện dễ dàng nâng cấp/cập nhật ứng dụng và bảo vệ các ứng dụng đã cài đặt khỏi việc chà đạp các tệp cấu hình khác.

Có sự khác biệt lớn giữa cách sử dụng DLL và cách ứng dụng được sử dụng. Bạn không thể có nhiều bản sao của một ứng dụng được cài đặt trên cùng một máy cho cùng một người dùng. Nhưng bạn rất có thể có 100 ứng dụng hoặc thư viện khác nhau, tất cả đều sử dụng một số .NET DLL.

Trong khi hiếm khi cần theo dõi cài đặt riêng biệt cho các bản sao khác nhau của một ứng dụng trong một hồ sơ người dùng, rất không chắc bạn muốn sử dụng các tập tin DLL khác nhau để chia sẻ cấu hình với nhau. Vì lý do này, khi bạn lấy một đối tượng Cấu hình bằng cách sử dụng phương thức "bình thường", đối tượng bạn lấy lại được gắn với cấu hình của Miền ứng dụng mà bạn đang thực hiện, thay vì cấu hình cụ thể.

Miền ứng dụng bị ràng buộc vào cụm gốc đã tải bản lắp ráp mà mã của bạn thực sự đang in. Trong hầu hết các trường hợp, đây sẽ là bản sao của tệp .EXE chính của bạn, là thứ được tải lên .DLL. Bạn có thể quay lên các miền ứng dụng khác trong một ứng dụng, nhưng bạn phải cung cấp thông tin rõ ràng về những gì mà assembly gốc của miền ứng dụng đó.

Vì tất cả điều này, quy trình tạo tệp cấu hình dành riêng cho thư viện không thuận tiện. Nó là quá trình tương tự bạn sẽ sử dụng để tạo một tệp cấu hình di động tùy ý không gắn với bất kỳ hội đồng cụ thể nào, nhưng bạn muốn sử dụng nó.Lược đồ XML, cấu hình phần cấu hình và cấu phần của phần tử, vv Điều này đòi hỏi phải tạo ra một đối tượng ExeConfigurationFileMap, tải dữ liệu để xác định nơi tệp cấu hình sẽ được lưu trữ, và sau đó gọi ConfigurationManager. OpenMappedExeConfiguration để mở nó thành một phiên bản Configuration mới. Điều này sẽ cắt bạn khỏi bảo vệ phiên bản được cung cấp bởi cơ chế tạo đường dẫn tự động.

Nói theo thống kê, có thể bạn đang sử dụng thư viện này trong cài đặt trong nhà và bạn không thể sử dụng nhiều ứng dụng trong cùng một máy/người dùng. Nhưng nếu không, có điều bạn nên ghi nhớ. Nếu bạn sử dụng một tệp cấu hình chung duy nhất cho tệp DLL của mình, bất kể ứng dụng đang tham chiếu đến nó, bạn cần phải lo lắng về xung đột truy cập. Nếu hai ứng dụng tham chiếu thư viện của bạn xảy ra cùng một lúc, mỗi đối tượng có đối tượng Configuration riêng sẽ mở, sau đó khi một lần lưu thay đổi, nó sẽ gây ra ngoại lệ trong lần tiếp theo bạn cố truy xuất hoặc lưu dữ liệu trong ứng dụng khác.

Cách an toàn và đơn giản nhất để thực hiện việc này là yêu cầu lắp ráp DLL của bạn cũng cung cấp một số thông tin về chính nó hoặc phát hiện nó bằng cách kiểm tra Miền ứng dụng của hội đồng tham chiếu. Sử dụng điều này để tạo ra một số loại cấu trúc thư mục để giữ các tệp cấu hình người dùng riêng biệt cho từng ứng dụng tham chiếu đến tệp DLL của bạn.

Nếu bạn là nhất định bạn muốn có cài đặt chung cho tệp DLL của mình bất kể nó được tham chiếu ở đâu, bạn sẽ cần xác định vị trí của mình thay vì .NET. Bạn cũng sẽ cần phải tích cực về việc quản lý quyền truy cập vào tệp. Bạn sẽ cần bộ nhớ cache càng nhiều càng tốt, giữ trường hợp Configuration xung quanh CHỈ miễn là phải mất để tải hoặc lưu, mở ngay trước và xử lý ngay sau đó. Và cuối cùng, bạn sẽ cần một cơ chế khóa để bảo vệ tệp trong khi nó đang được chỉnh sửa bởi một trong các ứng dụng sử dụng thư viện.

+0

tôi nghĩ rằng cơ chế đồng bộ hóa phải là "sự kiện được đặt tên", v.v. bởi vì nó nằm ngang quy trình – Jacob

+7

:/ Meh. Của chúng tôi là một ứng dụng doanh nghiệp quái vật w/main .exe được viết bởi các chàng trai trong một múi giờ khác nhau và các mô-đun đại diện bởi các DLL khác nhau và tự động bị ràng buộc thông qua một khuôn khổ plugin tùy chỉnh. Tất cả điều này "bạn sẽ cần phải đảm bảo nhiều ứng dụng có thể sử dụng DLL của bạn cùng một lúc" pomposity là chính xác sai. – JohnL4

+0

Hơn nữa, trong phần lớn sự nghiệp của tôi, tôi đã thấy các cơ chế đối tượng chung chung đáng yêu này bị bỏ qua hoàn toàn, với các nhóm tạo DLL (hoặc JAR) chỉ có thể được sử dụng trong một ngữ cảnh (và phải có mặt hoặc ứng dụng thất bại). Họ cũng có thể bị ràng buộc tĩnh, nhưng đó là passe. – JohnL4

3

Có vẻ như tệp cấu hình này thực sự khó hiểu để làm rõ khi hành vi của họ thay đổi từ môi trường dev sang triển khai. Rõ ràng một DLL có thể có tập tin cấu hình riêng của nó, nhưng một khi bạn sao chép và dán dll (cùng với tập tin cấu hình của họ) ở nơi khác, toàn bộ điều ngừng làm việc. Giải pháp duy nhất là kết hợp thủ công tệp app.config vào một tệp duy nhất, tệp này sẽ chỉ được sử dụng bởi exec. Ví dụ: myapp.exe sẽ có tệp myapp.exe.config chứa tất cả các cài đặt cho tất cả các dll được myapp.exe sử dụng. Tôi đang sử dụng VS 2008.

Kenny Liew

85

nếu bạn muốn đọc cài đặt từ tập tin cấu hình của DLL nhưng không phải từ các ứng dụng gốc web.config hoặc App.config sử dụng mã dưới đây để đọc cấu hình trong dll.

var appConfig = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location); 
string dllConfigData = appConfig.AppSettings.Settings["dllConfigData"].Value; 
+0

Trong C++ được quản lý cho Hệ thống VS 2008 :: Cấu hình :: Cấu hình^appConfig = ConfigurationManager :: OpenExeConfiguration (Assembly :: GetExecutingAssembly() -> Vị trí); \t \t \t \t \t Chuỗi^name = appConfig-> AppSettings-> Settings ["name"] -> Value; – Hans

5

Tôi biết điều này là muộn đối với đảng, tuy nhiên tôi nghĩ tôi sẽ chia sẻ giải pháp tôi sử dụng cho DLL.

Tôi có nhiều hơn K.I.S.S. trường học của tư duy, vì vậy khi tôi có một DLL NET muốn lưu trữ các điểm dữ liệu bên ngoài kiểm soát cách nó hoạt động hoặc nơi nó đi, vv. Tôi chỉ đơn giản là tạo ra một "cấu hình" lớp mà chỉ có tài sản công cộng lưu trữ tất cả các điểm dữ liệu nó cần và tôi muốn có thể kiểm soát bên ngoài để DLL để ngăn chặn biên dịch lại nó để thực hiện các thay đổi. Sau đó, tôi sử dụng XML serialization của .Net để lưu và tải biểu diễn đối tượng của lớp vào một tệp. Có rất nhiều cách để xử lý việc đọc và truy cập nó, từ Singleton, một lớp tiện ích tĩnh, đến các phương thức mở rộng, vv Điều này phụ thuộc vào cách DLL của bạn được cấu trúc và phương thức nào sẽ phù hợp với DLL của bạn tốt nhất .

+0

Tôi cũng sử dụng cách tiếp cận này và tôi hài lòng với cách nó hoạt động cho đến nay. – Dave

2

Kể từ khi lắp ráp nằm trong một bộ nhớ cache tạm thời, bạn nên kết hợp các con đường để có được cấu hình của dll:

var appConfig = ConfigurationManager.OpenExeConfiguration(
    Path.Combine(Environment.CurrentDirectory, Assembly.GetExecutingAssembly().ManifestModule.Name)); 
+0

Cảm ơn, điều này đã làm việc cho tôi. –

2

tôi đã tìm thấy những gì có vẻ như một giải pháp tốt cho vấn đề này. Tôi đang sử dụng VS 2008 C#. Giải pháp của tôi liên quan đến việc sử dụng các không gian tên riêng biệt giữa nhiều tệp cấu hình. Tôi đã đăng giải pháp trên blog của mình: http://tommiecarter.blogspot.com/2011/02/how-to-access-multiple-config-files-in.html.

Ví dụ:

namespace này đọc/ghi các thiết lập dll:

var x = company.dlllibrary.Properties.Settings.Default.SettingName; 
company.dlllibrary.Properties.Settings.Default.SettingName = value; 

namespace này đọc/ghi các thiết lập exe:

company.exeservice.Properties.Settings.Default.SettingName = value; 
var x = company.exeservice.Properties.Settings.Default.SettingName; 

Có một số hãy cẩn thận đề cập trong bài viết . HTH

17

Tôi đã gặp sự cố tương tự và đã tìm kiếm trên web trong vài giờ nhưng tôi không thể tìm thấy giải pháp nào để tôi tự làm. Tôi tự hỏi tại sao hệ thống cấu hình .net lại không linh hoạt.

Bối cảnh: Tôi muốn có DAL.dll của mình để có tệp cấu hình riêng cho cài đặt cơ sở dữ liệu và DAL. Tôi cũng cần app.config cho Thư viện Doanh nghiệp và các cấu hình riêng của nó. Vì vậy, tôi cần cả app.config và dll.config.

Điều tôi không muốn làm là truyền qua mọi thuộc tính/cài đặt từ ứng dụng đến lớp DAL của tôi!

để uốn cong "AppDomain.CurrentDomain.SetupInformation.ConfigurationFile" là không thể vì tôi cần nó cho hành vi app.config bình thường.

yêu cầu của tôi/điểm quan điểm là:

  • NO tay bản sao của bất cứ điều gì từ ClassLibrary1.dll.config để WindowsFormsApplication1.exe.config vì đây là unreproducible cho nhà phát triển khác.
  • duy trì việc sử dụng gõ mạnh "Properties.Settings.Default.NameOfValue" (Hành vi cài đặt) vì tôi cho rằng đây là một tính năng chính và tôi không muốn mất nó
  • Tôi phát hiện ra thiếu ApplicationSettingsBase tới tiêm tập tin cấu hình hoặc quản lý tùy chỉnh của bạn (tất cả các trường cần thiết là riêng tư trong các lớp này)
  • việc sử dụng chuyển hướng tệp "configSource" là không thể vì chúng tôi phải sao chép/ghi lại ClassLibrary1.dll.config và cung cấp Các tệp XML cho một số phần (Tôi cũng không thích điều này)
  • Tôi không thích viết Trình cài đặt riêng cho nhiệm vụ đơn giản này như MSDN gợi ý vì tôi nghĩ đơn giản là quá nhiều
  • Tôi chỉ cần phần applicationSettings và connectionStrings từ tập tin cấu hình

tôi đã đưa ra sửa đổi các tập tin Settings.cs và thực hiện một phương pháp mà mở ClassLibrary1.dll.config và đọc thông tin phần bằng hình thức riêng cánh đồng. Sau đó, tôi đã overriden "this [string propertyName]" để các Settings.Desginer.cs được tạo ra thành các thuộc tính mới của tôi thay vì lớp cơ sở. Có cài đặt được đọc ra khỏi Danh sách.

Cuối cùng có đoạn mã sau:

internal sealed partial class Settings 
{ 
    private List<ConfigurationElement> list; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="Settings"/> class. 
    /// </summary> 
    public Settings() 
    { 
     this.OpenAndStoreConfiguration(); 
    } 

    /// <summary> 
    /// Opens the dll.config file and reads its sections into a private List of ConfigurationElement. 
    /// </summary> 
    private void OpenAndStoreConfiguration() 
    { 
     string codebase = System.Reflection.Assembly.GetExecutingAssembly().CodeBase; 
     Uri p = new Uri(codebase); 
     string localPath = p.LocalPath; 
     string executingFilename = System.IO.Path.GetFileNameWithoutExtension(localPath); 
     string sectionGroupName = "applicationSettings"; 
     string sectionName = executingFilename + ".Properties.Settings"; 
     string configName = localPath + ".config"; 
     ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); 
     fileMap.ExeConfigFilename = configName; 
     Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); 

     // read section of properties 
     var sectionGroup = config.GetSectionGroup(sectionGroupName); 
     var settingsSection = (ClientSettingsSection)sectionGroup.Sections[sectionName]; 
     list = settingsSection.Settings.OfType<ConfigurationElement>().ToList(); 

     // read section of Connectionstrings 
     var sections = config.Sections.OfType<ConfigurationSection>(); 
     var connSection = (from section in sections 
          where section.GetType() == typeof(ConnectionStringsSection) 
          select section).FirstOrDefault() as ConnectionStringsSection; 
     if (connSection != null) 
     { 
      list.AddRange(connSection.ConnectionStrings.Cast<ConfigurationElement>()); 
     } 
    } 

    /// <summary> 
    /// Gets or sets the <see cref="System.Object"/> with the specified property name. 
    /// </summary> 
    /// <value></value> 
    public override object this[string propertyName] 
    { 
     get 
     { 
      var result = (from item in list 
         where Convert.ToString(item.ElementInformation.Properties["name"].Value) == propertyName 
         select item).FirstOrDefault(); 
      if (result != null) 
      { 
       if (result.ElementInformation.Type == typeof(ConnectionStringSettings)) 
       { 
        return result.ElementInformation.Properties["connectionString"].Value; 
       } 
       else if (result.ElementInformation.Type == typeof(SettingElement)) 
       { 
        return result.ElementInformation.Properties["value"].Value; 
       } 
      } 
      return null; 
     } 
     // ignore 
     set 
     { 
      base[propertyName] = value; 
     } 
    } 

Bạn chỉ sẽ phải sao chép ClassLibrary1.dll.config của bạn từ thư mục đầu ra ClassLibrary1 vào thư mục đầu ra của ứng dụng của bạn. Có lẽ ai đó sẽ thấy nó hữu ích.

2

Nếu bạn đang sử dụng thư viện mà tìm kiếm một số lượng lớn các configation đằng sau hậu trường, chẳng hạn như WCF, bạn có thể xem xét việc này:

AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "MyWcfClientWrapper.dll.config"); 

Hoặc trong PowerShell:

[AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", "MyWcfClientWrapper.dll.config") 

IMO kỹ thuật này là một mùi mã và thực sự chỉ thích hợp để sử dụng trong đoạn mã đặc biệt. Nếu bạn thấy mình muốn làm điều này trong mã sản xuất, có lẽ đã đến lúc xem xét kiến ​​trúc.

Sau đây KHÔNG được khuyến nghị:
Như một sự tò mò về kỹ thuật, đây là một biến thể về chủ đề. Bạn có thể tạo một hàm tạo tĩnh bên trong một trong các lớp nằm trong DLL và thực hiện cuộc gọi này từ đó. Tôi sẽ không khuyên bạn nên làm điều này ngoại trừ một phương sách cuối cùng.

0

Trong bài này, một vấn đề tương tự đã được thảo luận và giải quyết vấn đề của tôi How to load a separate Application Settings file dynamically and merge with current settings? có thể helpfu

+0

Trong khi điều này về mặt lý thuyết có thể trả lời câu hỏi, [nó sẽ là thích hợp hơn] (http://meta.stackexchange.com/q/8259) để bao gồm các phần thiết yếu của câu trả lời ở đây, và cung cấp liên kết để tham khảo. – Adi

3

bạn là chính xác, bạn có thể đọc các tập tin cấu hình của một dll. Tôi đã vật lộn với điều này trong một ngày cho đến khi tôi phát hiện ra rằng tập tin cấu hình của tôi là vấn đề. Xem mã của tôi dưới đây. nó đã có thể chạy.

 ExeConfigurationFileMap map = new ExeConfigurationFileMap(); 
     map.ExeConfigFilename = Assembly.GetExecutingAssembly().Location + ".config"; 
     Configuration libConfig = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None); 
     AppSettingsSection section = (libConfig.GetSection("appSettings") as AppSettingsSection); 
     Console.WriteLine(section.Settings["dnd_shortcodes"].Value); 

Plugin1.dll.config của tôi trông như sau;

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
<appSettings> 
    <add key="cmd_location" value="http://..."/> 
    <add key="dnd_shortcodes" value="142,145,146,157,165,167,168,171,173,176,178,404,40"/> 
</appSettings> 
</configuration> 

tôi phát hiện ra rằng tập tin cấu hình của tôi thiếu thẻ <appSettings>, vì vậy nhìn xung quanh, vấn đề của bạn có thể đã khác nhưng không quá xa tôi.

0

Đối với một dll, nó không nên phụ thuộc vào cấu hình như cấu hình thuộc sở hữu của ứng dụng và không phải do dll.

này được giải thích tại here

0

bạn có thể sử dụng mã này:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Threading.Tasks; 

namespace GClass1 
{ 
[Guid("D6F88E95-8A27-4ae6-B6DE-0542A0FC7039")] 
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 
public interface _GesGasConnect 
{ 
    [DispId(1)] 
    int SetClass1Ver(string version); 


} 

[Guid("13FE32AD-4BF8-495f-AB4D-6C61BD463EA4")] 
[ClassInterface(ClassInterfaceType.None)] 
[ProgId("InterfacesSMS.Setting")] 
public class Class1 : _Class1 
{ 
    public Class1() { } 


    public int SetClass1(string version) 
    { 
     return (DateTime.Today.Day); 
    } 
} 
} 
0

Các giải pháp đầy đủ không thường được tìm thấy ở một nơi ...

1) Tạo một tập tin ứng dụng cấu hình và đặt tên nó là "yourDllName.dll.config"
2) Nhấp chuột phải vào tập tin cấu hình được tạo ở trên trong VS Solution Explorer, nhấp vào thuộc tính
--- đặt "Build Action" = Nội dung
--- set "Copy to Output Di xứ"= Luôn
3) Thêm một phần appSettings vào file cấu hình (yourDllName.dll.config) với yourKeyName của bạn và yourKeyValue

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <appSettings> 
    <add key="yourKeyName" value="yourKeyValue"/> 
    </appSettings> 
</configuration> 

4) Thêm hệ thống.Cấu hình để dll/lớp/dự án của bạn tham chiếu
5) Thêm những điều khoản sử dụng để mã của bạn, nơi bạn có ý định để truy cập các thiết lập

using System.Configuration; 
using System.Reflection; 

6) Để truy cập giá trị

string keyValue = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettings.Settings["yourKeyName"].Value; 

7 cấu hình) vui mừng, nó hoạt động

IMHO, điều này chỉ nên được sử dụng khi phát triển một thư viện/thư viện mới.

#if (DEBUG && !FINALTESTING) 
    string keyValue = ConfigurationManager.OpenExeConfiguration...(see 6 above) 
#else 
    string keyValue = ConfigurationManager.AppSettings["yourKeyName"]; 
#endif 

Tệp cấu hình kết thúc là tham chiếu tuyệt vời, khi bạn thêm ứng dụng của dllCài đặt vào ứng dụng thực tế của bạn.

Các vấn đề liên quan