在不依赖 app.config 的情况下使用 SOAP Web 服务

Posted

技术标签:

【中文标题】在不依赖 app.config 的情况下使用 SOAP Web 服务【英文标题】:Consume a SOAP web service without relying on the app.config 【发布时间】:2011-04-11 20:33:32 【问题描述】:

我正在构建一个将调用外部 Web 服务的 .NET 组件。我使用“添加服务引用”对话框将 Web 服务添加到我的组件中,这会生成使用服务所需的代码并将设置添加到 app.config 文件中。

我正在通过从控制台应用程序添加对其 DLL 的引用并调用创建 Web 服务的新实例的适当方法来测试组件:... = new MyServiceSoapClient()。但是,当我这样做时,会出现以下异常:

无效操作异常

在 ServiceModel 客户端配置部分中找不到引用合同“MyServicesSoap”的默认端点元素。这可能是因为找不到您的应用程序的配置文件,或者因为在客户端元素中找不到与此协定匹配的端点元素。

这是有道理的,因为 app.config 没有随组件的 DLL 一起提供。如何在不依赖 App.Config 中的设置的情况下调用 Web 服务?

【问题讨论】:

InvalidOperationException while creating wcf web service instance的可能重复 简而言之:组件中的这些配置设置需要复制到 ConsoleApplication1.exe.config @Josh 这在我的情况下不起作用。我在我的问题中没有提到这一点,但是这个 .NET DLL 将从 VB6 COM 应用程序中调用,所以我正在编写的 .NET 组件必须能够成功调用 Web 服务而不依赖任何东西来自消费应用程序。 【参考方案1】:

app.config 文件中<system.ServiceModel> 中的设置将告诉组件如何连接到外部 Web 服务。 xml 只是建立与 Web 服务的默认连接所需的类和枚举的简单文本表示。

例如,这是为我添加的 Web 服务生成的代码:

<system.serviceModel>
 <bindings>
  <basicHttpBinding>
   <binding name="MyServicesSoap" closeTimeout="00:01:00" openTimeout="00:01:00"
     receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
     bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
     maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
     messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
     useDefaultWebProxy="true">
     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
       maxBytesPerRead="4096" maxNameTableCharCount="16384" />
     <security mode="None">
      <transport clientCredentialType="None" proxyCredentialType="None"
        realm="" />
      <message clientCredentialType="UserName" algorithmSuite="Default" />
     </security>
    </binding>
   </basicHttpBinding>
  </bindings>
 <client>
  <endpoint address="http://services.mycompany.com/WebServices/MyServices.asmx"
    binding="basicHttpBinding" bindingConfiguration="MyServicesSoap"
    contract="MyServices.MyServicesSoap" name="MyServicesSoap" />
 </client>
</system.serviceModel>

这可以翻译成这样的代码:

    'Set up the binding element to match the app.config settings '
    Dim binding = New BasicHttpBinding()
    binding.Name = "MyServicesSoap"
    binding.CloseTimeout = TimeSpan.FromMinutes(1)
    binding.OpenTimeout = TimeSpan.FromMinutes(1)
    binding.ReceiveTimeout = TimeSpan.FromMinutes(10)
    binding.SendTimeout = TimeSpan.FromMinutes(1)
    binding.AllowCookies = False
    binding.BypassProxyOnLocal = False
    binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard
    binding.MaxBufferSize = 65536
    binding.MaxBufferPoolSize = 524288
    binding.MessageEncoding = WSMessageEncoding.Text
    binding.TextEncoding = System.Text.Encoding.UTF8
    binding.TransferMode = TransferMode.Buffered
    binding.UseDefaultWebProxy = True

    binding.ReaderQuotas.MaxDepth = 32
    binding.ReaderQuotas.MaxStringContentLength = 8192
    binding.ReaderQuotas.MaxArrayLength = 16384
    binding.ReaderQuotas.MaxBytesPerRead = 4096
    binding.ReaderQuotas.MaxNameTableCharCount = 16384

    binding.Security.Mode = BasicHttpSecurityMode.None
    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None
    binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None
    binding.Security.Transport.Realm = ""
    binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName
    binding.Security.Message.AlgorithmSuite = Security.SecurityAlgorithmSuite.Default

    'Define the endpoint address'
    Dim endpointStr = "http://services.mycompany.com/WebServices/MyServices.asmx"
    Dim endpoint = New EndpointAddress(endpointStr)
    'Instantiate the SOAP client using the binding and endpoint'
    'that were defined above'
    Dim client = New MyServicesSoapClient(binding, endpoint)

通常,当您使用无参数构造函数(即new MyServicesSoapClient())时,将使用 app.config 文件中的设置。但是,您可以通过在代码中显式设置 bindingendpoint 值并将这些实例传递给构造函数来绕过 app.config 文件。

【讨论】:

+1 太好了,谢谢。虽然我确实发现在绑定上我只需要添加最少数量的设置。我只在绑定上使用了超时,它通过了。 我遇到了一个 VB6 应用程序的问题,该应用程序引用了一个调用 Web 服务的 .NET dll。问题源于 dll 的 app.config 文件,因为从 dll 中读取配置文件并不完全简单,这让我可以完全绕过配置文件。【参考方案2】:

在代码中设置 BindingEndpoint 配置是一种方法,但还有另一种方法可以使用使用者 DLL 并让配置保留在现有的 App.config 文件中.

出现上述InvalidOperationException的原因是DLL中不包含配置设置。它总是依赖 App.config 来提供它,但由于您在另一个控制台应用程序中使用 DLL,它找不到配置设置。

当我们使用“添加服务引用”对话框将 Web 服务添加到客户端组件并创建 Web 服务实例时,我们让 Visual Studio 处理通信通道的创建并加载配置设置。所以,如果我们能够明确地创建我们自己的此类通道,然后我们可以管理配置设置。

Microsoft 为此提供了 Classes,ConfigurationChannelFactory&lt;TChannel&gt; Class 就是其中之一。 MSDN 状态:

提供通用功能来为特定类型创建通道配置元素。

ConfigurationChannelFactory 允许集中管理 WCF 客户端配置。

使用“添加服务引用”对话框将 Web 服务添加到客户端组件,因为我们需要服务通道接口实例。

首先将生成的 App.config 文件重命名为 App.dll.config 并在其文件属性中更改 复制到输出目录属性以始终复制

创建一个类,该类具有返回 Channel 对象以访问 Web Service 的方法,例如:

public class ManageService

    public static T CreateServiceClient<T>(string configName)
    
        string _assemblyLocation = Assembly.GetExecutingAssembly().Location;
        var PluginConfig = ConfigurationManager.OpenExeConfiguration(_assemblyLocation);
        ConfigurationChannelFactory<T> channelFactory = new ConfigurationChannelFactory<T>(configName, PluginConfig, null);
        var client = channelFactory.CreateChannel();
        return client;
    

由于我们设置了属性 Copy Always VS 将项目 DLL 以及 App.dll.config 复制到 bin 文件夹中。 Assembly.GetExecutingAssembly().Location返回装配位置和ConfigurationManager.OpenExeConfiguration

将指定的客户端配置文件作为配置对象打开。

PluginConfig 持有 App.Config 配置文件对象,ConfigurationChannelFactory&lt;T&gt; 使用它与服务通信。

可以通过传递您的服务通道接口对象来调用此方法,如下所示:

Client = ManageService.CreateServiceClient<SampleService.IKeyServiceChannel>("MetadataExchangeTcpBinding_IKeyService"); 

SampleService 是我的 Web 服务的命名空间。 Client 持有 Web Service 的实例。

如果你需要处理双工通信和回调,那么你可以看看ConfigurationDuplexChannelFactory&lt;TChannel&gt; Class。

【讨论】:

【参考方案3】:

如果这是一个 WCF 服务(听起来像是,从错误消息中),那么,在大多数情况下,您将需要 app.config,因为它是 app.config 告诉其余部分WCF 的 MyServiceSoapClient 一个 Web 服务(对两个 app.config 文件稍作改动,这可以成为命名管道服务,无需重新编译代码......)

现在,如果您真的想在没有 app.config 的情况下执行此操作,那么您必须折腾生成的 MyServiceSoapClient(),并根据 HttpWebRequest 编写自己的。

【讨论】:

以上是关于在不依赖 app.config 的情况下使用 SOAP Web 服务的主要内容,如果未能解决你的问题,请参考以下文章

使用 app.config 配置卷影复制

System.load() 方法在不设置 LD_LIBRARY_PATH 环境变量的情况下不加载共享库

如何嵌入app.config并硬编码其Web服务端点?

Automake:如何在不安装的情况下构建共享库

Maven:在不扩展依赖项的情况下使用 flatten 解析版本

如何在不安装的情况下列出python库的依赖项? [复制]