2009-11-05 44 views
20

Tôi đang gặp khó khăn khi cố truy cập phần cấu hình tùy chỉnh trong tập tin cấu hình của mình.Phần cấu hình tùy chỉnh: Không thể tải tập tin hoặc lắp ráp

Tệp cấu hình đang được đọc từ một tệp .dll được tải dưới dạng trình cắm. Tôi đã tạo cấu hình và mã cần thiết bằng cách sử dụng phần bổ trợ Configuration Section Designer VS.

Không gian tên là 'ImportConfiguration'. Lớp ConfigurationSection là 'ImportWorkflows'. Việc lắp ráp là ImportEPDMAddin.

Các xml:

<configSections> 
    <section name="importWorkflows" type="ImportConfiguration.ImportWorkflows, ImportEPDMAddin"/> 
    </configSections> 

Bất cứ khi nào tôi cố gắng đọc trong cấu hình, tôi nhận được lỗi:

xảy ra lỗi khi tạo phần xử lý cấu hình cho importWorkflows: Không thể tải tập tin hoặc lắp ráp ' ImportEPDMAddin.dll 'hoặc một trong các phụ thuộc của nó. Hệ thống không thể tìm thấy các tập tin được chỉ định.

dll sẽ không nằm trong cùng thư mục với tệp thực thi vì phần mềm tải plugin sẽ đặt dll và phụ thuộc vào thư mục riêng của nó. (Tôi không thể kiểm soát đó.)

Tôi chỉnh sửa các mã cho các dụ singleton như sau:

string path = System.Reflection.Assembly.GetCallingAssembly().CodeBase; 
path = path.Replace("file:///", ""); 
System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenExeConfiguration(path); 
return configuration.GetSection(ImportWorkflowsSectionName) as ImportConfiguration.ImportWorkflows; 

Tôi cũng đã cố gắng sử dụng một NameValueFileSectionHandler đơn giản là tốt, nhưng tôi nhận được một ngoại lệ nói rằng nó không thể tải tập tin hoặc lắp ráp 'Hệ thống'.

Tôi đã đọc nhiều bài đăng trên blog và các bài viết và có vẻ như có thể đọc một tệp cấu hình trong một dll, nhưng tôi không thể làm cho nó hoạt động. Bất kỳ ý tưởng? Cảm ơn.

+0

Bạn có copy 'ImportEPDMAddin.dll.config' đến cùng một vị trí quá? – ephemient

+0

Cấu hình có chắc chắn, vì tôi đã thử sử dụng một DictionarySectionHandler từ một lớp khác và hoạt động. – ehcanadian

Trả lời

34

Thật không may, bạn sẽ cần phải hoặc là có ImportEPDMAddin lắp ráp cư trú tại cùng một thư mục như thực thi của bạn, trú tại khuôn khổ thư mục Net liên quan đến khuôn khổ Net bạn đang sử dụng (ví dụ, C: \ Windows \ Microsoft.NET \ Framework \ v2.0.50727), hoặc được đăng ký trong Bộ đệm ẩn toàn cục.

Chỉ có tùy chọn khác là, nếu bạn biết đường dẫn đến lắp ráp có chứa lớp định xử lý cấu hình, bạn có thể tải nó mà không có một tài liệu tham khảo với một cái gì đó như thế này:

//Class global 
private Assembly configurationDefiningAssembly; 

protected TConfig GetCustomConfig<TConfig>(string configDefiningAssemblyPath, 
    string configFilePath, string sectionName) where TConfig : ConfigurationSection 
{ 
    AppDomain.CurrentDomain.AssemblyResolve += new 
     ResolveEventHandler(ConfigResolveEventHandler); 
    configurationDefiningAssembly = Assembly.LoadFrom(configDefiningAssemblyPath); 
    var exeFileMap = new ExeConfigurationFileMap(); 
    exeFileMap.ExeConfigFilename = configFilePath; 
    var customConfig = ConfigurationManager.OpenMappedExeConfiguration(exeFileMap, 
     ConfigurationUserLevel.None); 
    var returnConfig = customConfig.GetSection(sectionName) as TConfig; 
    AppDomain.CurrentDomain.AssemblyResolve -= ConfigResolveEventHandler; 
    return returnConfig; 
} 

protected Assembly ConfigResolveEventHandler(object sender, ResolveEventArgs args) 
{ 
    return configurationDefiningAssembly; 
} 

Hãy chắc chắn rằng bạn xử lý các AssemblyResolve sự kiện, vì điều này sẽ ném một ngoại lệ mà không có nó.

+0

Cảm ơn bạn rất, rất nhiều. Điều này làm việc 100% !! – ehcanadian

+0

Điều này làm việc như một nét duyên dáng để truy cập và truyền loại phần tùy chỉnh trong tệp T4. Cảm ơn! – Matt

+0

@AJ. Xin lỗi, bạn có thể giải thích cho tôi xin vui lòng 'configDefiningAssemblyPath' là gì .. nó là tệp .exe? – Ciccio

0

Bạn đã đảm bảo rằng tệp DLL được tải trước chưa? Có lẽ với Assembly.LoadFile("PATH")?

Nếu bạn không thể tải các lớp trong System.Configuration để hoạt động bình thường, bạn luôn có thể quay lại sử dụng XmlDocument để phân tích cú pháp tệp cấu hình theo cách thủ công. Sử dụng XPath để làm cho dữ liệu trở nên dễ dàng hơn. Ví dụ: (giả sử biến đường dẫn của bạn ở trên):

var document = new XmlDocument(); 
document.Load(path); 
var node = document.SelectSingleNode("configuration/importWorkflows/add[@name='KEY']"); 
// Do whatever with node 
+0

Phương pháp này hoạt động, nhưng tôi đã hy vọng gắn bó với các lớp Cấu hình. Nếu mọi thứ khác thất bại, tôi sẽ phải đi với đề xuất của bạn. – ehcanadian

1

Bạn có thể xác minh rằng đường dẫn thăm dò được thiết lập chính xác trong tệp cấu hình của ứng dụng Máy chủ của bạn không? Có thể là một tham chiếu cần thiết không được tải trong miền ứng dụng hiện tại của bạn.

Assembly Binding ->Probing

5

Trong chính tập tin ứng dụng cấu hình của bạn, thêm dòng sau (nơi plugins là thư mục để lắp ráp của bạn để tải từ. Bạn có thể sử dụng nhiều đường dấu chấm phẩy tách ra.

<runtime> 
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
     <probing privatePath=".;.\Plugins"/> 
    </assemblyBinding> 
</runtime> 

Taken từ http://msdn.microsoft.com/en-us/library/823z9h8w%28v=vs.90%29.aspx

+1

Lưu ý rằng việc sử dụng thăm dò để giải quyết vấn đề của OP sẽ chỉ hoạt động nếu thư mục plugins được chỉ định trong thuộc tính privatePath là thư mục con của thư mục gốc của ứng dụng. Xem [tài liệu msdn] (http://msdn.microsoft.com/en-us/library/15hyw9x3 (v = vs.110) .aspx) – BitMask777

4

Để mở rộng câu trả lời tuyệt vời của AJ, đây là lớp tùy chỉnh để hỗ trợ chi phí đăng ký và xóa sự kiện toàn cầu.

public sealed class AddinCustomConfigResolveHelper : IDisposable 
{ 
    public AddinCustomConfigResolveHelper(
     Assembly addinAssemblyContainingConfigSectionDefinition) 
    { 
     Contract.Assert(addinAssemblyContainingConfigSectionDefinition != null); 

     this.AddinAssemblyContainingConfigSectionDefinition = 
      addinAssemblyContainingConfigSectionDefinition; 

     AppDomain.CurrentDomain.AssemblyResolve += 
      this.ConfigResolveEventHandler; 
    } 

    ~AddinCustomConfigResolveHelper() 
    { 
     this.Dispose(false); 
    } 

    public void Dispose() 
    { 
     this.Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    private void Dispose(bool isDisposing) 
    { 
     AppDomain.CurrentDomain.AssemblyResolve -= this.ConfigResolveEventHandler; 
    } 

    private Assembly AddinAssemblyContainingConfigSectionDefinition { get; set; } 

    private Assembly ConfigResolveEventHandler(object sender, ResolveEventArgs args) 
    { 
     // often the name provided is partial...this will match full or partial naming 
     if (this.AddinAssemblyContainingConfigSectionDefinition.FullName.Contains(args.Name)) 
     { 
      return this.AddinAssemblyContainingConfigSectionDefinition; 
     } 

     return null; 
    } 
} 

tôi sẽ khuyên bạn nên tạo một thể hiện trong một tuyên bố sử dụng, như vậy:

// you'll need to populate these two variables 
var configuration = GetConfiguration(); 
var assembly = GetAssemblyContainingConfig(); 

using(new AddinCustomConfigResolveHelper(assembly)) 
{ 
    return (MyConfigSection)configuration.GetSection("myConfigSection"); 
} 
0

Tôi cố gắng trả lời AJ, với bổ sung rileywhite nhưng tôi thấy rằng đã không làm việc cho tôi.

Trong trường hợp của tôi, lớp ConfigurationSection tùy chỉnh đã có trong hội đồng hiện đang thi hành và cố tải nó gây ra tràn ngăn xếp. Tôi cũng không muốn đưa nó vào GAC mặc dù nó đã giải quyết vấn đề như được báo cáo bởi OP.

Cuối cùng, tôi thấy điều này hoạt động tốt cho mục đích của mình. Có lẽ người khác sẽ tìm thấy nó hữu ích:

public class CustomConfigurationSection : ConfigurationSection { 
    public CustomConfigurationSection() 
    { 
    var reader = XmlReader.Create(<path to my dll.config>); 
    reader.ReadToDescendant("CustomConfigurationSection"); 
    base.DeserializeElement(reader,false); 
    } 

    // <rest of code> 
} 
0

Đã phải sử dụng chuỗi loại đầy đủ của lắp ráp module/plugin của tôi, đó là trong một thư mục thăm dò, vì vậy nó có thể được bố trí. Sử dụng EntityFramework là một ví dụ ...

Sai:

type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework" 

Đúng

type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
Các vấn đề liên quan