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

时间:2010-09-13 19:45:58

标签: c# .net vb.net web-services app-config

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

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

  

InvalidOperationException

     

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

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

3 个答案:

答案 0 :(得分:69)

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 :(得分:0)

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

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

当我们使用&#34;添加服务参考&#34;将Web服务添加到客户端组件并创建Web服务实例的对话框,我们让Visual Studio处理通信通道的创建并加载配置设置。所以,如果我们能够明确地创建这样的通道,那么我们可以管理配置设置。

Microsoft 为此提供了类,ConfigurationChannelFactory<TChannel> Class是一个。 MSDN声明:

  

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

     
    

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

  

使用&#34;添加服务参考&#34;用于将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设置为将Project DLL以及App.dll.config复制到 bin 文件夹中。 Assembly.GetExecutingAssembly().Location返回装配位置和ConfigurationManager.OpenExeConfiguration

  

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

PluginConfig包含App.Config配置文件Object,ConfigurationChannelFactory<T>使用它与服务进行通信。

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

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

SampleService是我的Web服务的命名空间。 Client包含Web服务的实例。

如果您需要处理双工通信和回调,那么您可以查看ConfigurationDuplexChannelFactory<TChannel>类。

答案 2 :(得分:-1)

如果这是一个WCF服务(从错误消息中听起来像),那么,在大多数情况下,你需要的是app.config,因为它是app.config,它告诉其余的对于MyServiceSoapClient Web服务的WCF(对两个app.config文件进行少量更改,这可能会成为命名管道服务,而无需重新编译代码....)

现在,如果确实希望在没有app.config的情况下执行此操作,那么您必须根据MyServiceSoapClient()投放生成的HttpWebRequest并编写自己的{{1}}