【问题标题】:How to import a .NET DLL having App.config with a configuration section handler?如何使用配置节处理程序导入具有 App.config 的 .NET DLL?
【发布时间】:2013-02-11 10:01:51
【问题描述】:

我正在尝试使用我们内部 .net 应用程序中的 DLL。

DLL 有一个 App.config 文件,并且有一个指定配置处理程序的配置部分。

我无法让我的 PowerShell 脚本加载此 dll。

我已将问题归结为最简单的形式。

这是我正在尝试的 PowerShell 脚本:

[appdomain]::CurrentDomain.SetData("APP_CONFIG_FILE", "D:\CustomConfig\CustomConfig\CustomConfigTestHarness\bin\Debug\CustomConfigTestHarness.exe.config")
Add-Type -Path 'D:\CustomConfig\CustomConfig\CustomConfigTestHarness\bin\Debug\CustomConfig.dll'
$mainClass = New-Object CustomConfig.Main
$mainClass.TestConfig()

这是配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="PrimarySqlServers" type="CustomConfig.ServerConfiguration, CustomConfig" />
    </configSections>
    <PrimarySqlServers>
        <Server name="data source=SQL\SQL2005; Initial Catalog=master;  Trusted_Connection=yes;"/>
    </PrimarySqlServers>
</configuration>

这是 DLL:

namespace CustomConfig
{
    public class Main
    {
        public string TestEcho(string message)
        {
            return message;
        }

        public string TestConfig()
        {
            Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            string sectionName = "PrimarySqlServers";
            ServerConfiguration serverConfiguration = configuration.GetSection(sectionName) as ServerConfiguration;
            if (serverConfiguration == null || serverConfiguration.ServerList.Count == 0)
            {
                throw new ConfigurationErrorsException(string.Format(CultureInfo.InvariantCulture, "ERR_MISSING_OR_EMPTY_SECTION", sectionName));
            }
            ServerConfigurationEntry entry = serverConfiguration.ServerList[0];
            {
                return entry.Name;
            }
        }
    }
}

configClass.cs 文件内容如下:

using System;
using System.Configuration;
using System.Diagnostics;

namespace CustomConfig
{
    /// <summary>
    /// Contains individual configuration information about a site to be deployed
    /// </summary>
    public class ServerConfiguration : ConfigurationSection
    {
        /// <summary>
        /// Get the collection of assembly items
        /// </summary>
        [ConfigurationProperty("", IsDefaultCollection = true)]
        public ServerConfigurationCollection ServerList
        {
            get { return (ServerConfigurationCollection) base[""]; }
        }
    }

    /// <summary>
    /// ContextCollection - represents the collection of context nodes
    /// </summary>
    public class ServerConfigurationCollection : ConfigurationElementCollection
    {
        /// <summary>
        /// Get the assembly item element with the given name
        /// </summary>
        /// <param name="name">The name of the item you want</param>
        /// <returns>The item specified</returns>
        public new ServerConfigurationEntry this[string name]
        {
            get
            {
                if (IndexOf(name) < 0) return null;
                return (ServerConfigurationEntry) BaseGet(name);
            }
        }

        /// <summary>
        /// Get a assembly item element by index
        /// </summary>
        /// <param name="index">The index of the item to get</param>
        /// <returns>The item specified</returns>
        public ServerConfigurationEntry this[int index]
        {
            get { return (ServerConfigurationEntry) BaseGet(index); }
        }

        /// <summary>
        /// Clear the collection of items
        /// </summary>
        public void Clear()
        {
            BaseClear();
        }

        /// <summary>
        /// Add a new item to the collection
        /// </summary>
        /// <param name="name">The name of the site to add</param>
        public void AddItem(string name)
        {
            ServerConfigurationEntry newEntry = new ServerConfigurationEntry();
            newEntry.Name = name;
            this.BaseAdd(newEntry, true);
        }


        /// <summary>
        /// Get the index of a given assembly item
        /// </summary>
        /// <param name="name">The name of the item to get the index of</param>
        /// <returns>The index of the given item, or -1 if not found</returns>
        public int IndexOf(string name)
        {
            for (int index = 0; index < base.Count; index++)
            {
                if (string.Compare(this[index].Name, name, StringComparison.OrdinalIgnoreCase) == 0)
                    return index;
            }

            return -1;
        }

        /// <summary>
        /// Get the type of collection. BasicMap in this case.
        /// </summary>
        public override ConfigurationElementCollectionType CollectionType
        {
            get { return ConfigurationElementCollectionType.BasicMap; }
        }

        /// <summary>
        /// Factory up a new element
        /// </summary>
        /// <returns>A new element</returns>
        protected override ConfigurationElement CreateNewElement()
        {
            return new ServerConfigurationEntry();
        }

        /// <summary>
        /// Get the unique key for a assembly item element
        /// </summary>
        /// <param name="element">The element to get the key for</param>
        /// <returns>A unique identifier for the element</returns>
        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ServerConfigurationEntry) element).Name;
        }

        /// <summary>
        /// Get the XML element name for elements of this type
        /// </summary>
        protected override string ElementName
        {
            get { return "Server"; }
        }
    }

    /// <summary>
    /// ContextElement - represents a single context element in the config
    /// </summary>
    [DebuggerDisplay("{Name}")]
    public class ServerConfigurationEntry : ConfigurationElement
    {
        private const string NAME = "name";

        /// <summary>
        /// Get or set the server name or connection string
        /// </summary>
        [ConfigurationProperty(NAME, DefaultValue = "", IsRequired = true, IsKey = true)]
        public string Name
        {
            [DebuggerStepThrough]
            get { return (string) this[NAME]; }
            [DebuggerStepThrough]
            set { this[NAME] = value; }
        }
    }
}

我尝试运行它时收到的错误消息是:

 Exception calling `"TestConfig" with "0" argument(s)`: 

 "An error occurred creating the configuration section handler for PrimarySqlServers:
 Could not load file or assembly 'CustomConfig' or one of its dependencies. The system cannot find the file specified. 
(D:\CustomConfig\CustomConfig\CustomConfigTestHarness\bin\Debug\CustomConfigTestHarness.exe.config line 4)"
    At C:\dll.ps1:15 char:1
    + $mainClass.TestConfig()
    + ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ConfigurationErrorsException

【问题讨论】:

  • 据我所知,CustomConfig.ServerConfiguration 没有在任何地方定义
  • TestEcho 方法有效吗?如果没有,您可以查看stackoverflow.com/questions/2094694/…
  • 感谢您查看我的问题。是的,TestEcho 工作正常。
  • 您好 Kieren,感谢您阅读我的问题。你是对的,对不起,我错过了添加 configclass.cs 文件。

标签: c# .net powershell exception-handling app-config


【解决方案1】:

您遇到的问题是程序集不在 .net 的程序集搜索路径中。

您可以通过许多不同的方式来解决这个问题(包括将程序集放入 GAC 等)。

将有关程序集的其余信息添加到您的部分密钥(版本、文化、公钥令牌......类似这样的东西)可能就足够了:

<section name="PrimarySqlServers" type="CustomConfig.ServerConfiguration, CustomConfig, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 

另一种方法是编写事件处理程序:

$configdll = 'D:\CustomConfig\CustomConfig\CustomConfigTestHarness\bin\Debug\CustomConfig.dll'

[System.AppDomain]::CurrentDomain.add_AssemblyResolve({
    param($source, $assembly)
    # Detect that they're looking for YOUR assembly specifically
    if($assembly.Name.Split(",")[0] -eq "CustomConfig") {
        # And load it for them: your path will be difference
        return [System.Reflection.Assembly]::LoadFile( $configdll  )
    }
})

另一种方法是将 dll 放在应用程序的主目录中。 但在这种情况下,那是你的 Windows\System32\WindowsPowerShell\v1.0\ ...所以这可能不是一个好计划。

【讨论】:

  • 一个有用的注意事项是非常谨慎地使用处理程序块中的其他引用。使用 join-pathSystem.IO.Path.Combine 导致重新进入 AssemblyResolve 处理程序,该处理程序又执行重新进入处理程序的语句等,最终导致 StackOverflowException。
  • 谢谢,我遇到了同样的问题并添加了对我有用的其余信息(版本=1.0.0.0,Culture=neutral,PublicKeyToken=null)
【解决方案2】:

好吧,我认为在您的自定义配置部分中您的程序集名称不正确。

根据你的帖子,应该是:

<section name="PrimarySqlServers" type="CustomConfig.ServerConfiguration, CustomConfigTestHarness.exe" />

第二个参数是包含 CustomConfig.ServerConfiguration 类型定义的程序集或可执行文件名称。

【讨论】:

  • 谢谢大卫,我忘了添加 configclass.cs 文件,我现在已经包含了。
猜你喜欢
  • 2011-05-16
  • 2012-03-30
  • 2010-10-20
  • 2023-03-21
  • 2011-09-15
  • 2010-10-12
  • 1970-01-01
  • 2018-05-30
  • 2013-05-08
相关资源
最近更新 更多