从一个类库中包含服务引用

23
我有一个C#类库和一个启动项目(控制台应用程序)。该类库包括对Web服务的服务引用。当我尝试运行项目时,会出现InvalidOperationException异常,因为启动项目没有读取类库的app.config,并且忽略了服务引用。为了让其正常工作,我被迫将相同的服务引用添加到启动项目中。是否有任何方法可以避免这种情况?我能否使启动项目识别类库的服务引用和app.config,而不必将其复制到启动项目中?
我已经尝试从类库中添加一个指向app.config的链接,但是无效。如果需要在启动项目中添加该服务引用,则该类库并不是非常易于移植的。

+1:嗨Zarjay,我也想问同样的问题。虽然我同意Andrew Hare的观点,并理解为什么这是不可能的,但我也同意这个解决方案并没有使库非常便携。我想知道,配置设置是否可以通过编程方式应用? - andy
我不确定,但我怀疑。虽然是个好主意。我知道可以写入配置文件,但我敢打赌,当你的代码能够这样做时,可能已经太晚添加服务引用了。 - JR.
5个回答

15

想想你想要做什么 - 你正在构建两个程序集:

Library
ConsoleApp

这两个程序集都有配置文件——我想它们的格式看起来应该像这样:

Library
    app.config
ConsoleApp
    ConsoleApp.exe.config
当你运行ConsoleApp时,它无法从或知道来自你的Library程序集的app.config。它知道或关心的唯一配置文件是ConsoleApp.exe.config。现在可以让配置文件相互引用,但这不是你尝试做的正确解决方案。
由于你的Library程序集没有入口点,因此它永远不会被加载到应用程序域中。因为它永远不会被加载到应用程序域中,所以它的应用程序配置文件将永远不会被使用。
你应该通过项目引用在ConsoleApp中引用Library。然后将所有相关的配置数据从app.config移动到ConsoleApp.exe.config,因为这是应用程序将使用的配置文件。
这将允许你拥有需要调用Web服务方法的两个东西:
1. Library中可以发送和接收SOAP消息的代码。
2. Library需要的配置元数据。

感谢您的解释,现在明白为什么它没有起作用了。我还是.NET的新手,虽然我更喜欢类库是一个自包含的模块,其内部实现对使用它的代码无关紧要,但我现在明白为什么在这种情况下它不起作用了。 - JR.
就它的价值而言,配置数据不是内部实现--它是库配置数据,应由库(即您的控制台应用程序)的用户提供。 我的一般做法是在需要配置文件时,在库项目中通过app.config提供示例配置文本,然后假定库的用户将该配置数据复制到自己的配置文件中,并根据需要进行更改。 如果不需要配置文件,则这些选项仅成为库上编程配置开关。 - Greg D
7
Greg,我不同意。图书馆配置数据相当于开发人员知道的 Web 服务 URL,而不是用户。用户不需要关心那个URL是什么;这是库的内部实现,作为接口(库)的用户,我不应该关心实现的细节(它使用的 Web 服务)。谢天谢地,我可以使用 Google 的 Java 客户端库,而不必关心它用于执行其功能的 URL 是什么。不幸的是,如果有一个 .NET 版本,我将被迫关注这些细节。在我看来,没有这个选项是 .NET 的一个重大缺陷。 - JR.
非常好的解释,帮助我解决了这个烦人的问题 - 谢谢 - wheelibin

3

一种替代在类库中使用服务引用并复制配置文件的方法是使用调用svcutil.exe的构建事件。我喜欢这个方法的原因是,当服务更改时,你不必进行“更新服务引用”的操作,它会自动更新。

在类库中,使用只生成代理代码的构建事件:

svcutil.exe net.tcp://localhost:3315/MyService/mex /noConfig

在应用程序中,使用一个生成配置文件的构建事件。您可以使用/mergeConfig选项将其合并到现有的app.config中。
svcutil.exe net.tcp://localhost:3315/MyService/mex 
            /config:App.config /mergeConfig

如果您不想在服务未运行时出现构建错误,请将以下内容放入项目文件中,这样您将收到一个警告而不是错误提示:
<Target
    Name="PreBuildEvent"
    Condition="'$(PreBuildEvent)'!=''"
    DependsOnTargets="$(PreBuildEventDependsOn)">
  <Exec WorkingDirectory="$(OutDir)"
        Command="$(PreBuildEvent)"
        ContinueOnError="true" />
</Target>

1

你只需要将指向服务的配置键从类库配置文件复制到控制台应用程序的配置文件中。


我的app.config没有配置键。我该如何指定一个? - JR.
当引用 Web 服务时,您可以选择使用静态或动态引用,请参阅属性。选择动态引用会使 IDE 在您的 Web 服务代理类中生成代码,以从配置文件中读取 URL。将库的配置生成的值复制到您的控制台应用程序的配置中。 - Martin Bring

1

您可以将类库配置中的相关部分从app.config复制到控制台应用程序的app.config中。

或者,如果您真的想使其真正可移植,您需要考虑另一种方式来引用类库内特定服务引用的地址。


我已经尝试复制app.config文件,但是控制台应用程序除非我也添加服务引用,否则无法运行。可移植性确实不是优先考虑的问题;我只是觉得在项目中冗余地包含某些内容很烦人。类库应该是自包含的。 - JR.
WCF客户端的类库故意不是自包含的。它们通常不适合重新分发。它们旨在在客户端端进行配置,这就是为什么app.config对于这些类库来说是典型的。您始终可以硬编码该值,但那样...嗯...就是硬编码了。 :) - David Morton

0

我认为如果有多个配置文件在运行,会更加令人困惑。

如果一个库具有可配置的项,我完全期望必须将该配置放入我的配置文件中,以正确地使用该库。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接