使用 SOAP Web 服务而不依赖 app.config

发布于 2024-09-18 14:04:40 字数 460 浏览 4 评论 0原文

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

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

无效操作异常

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

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

I'm building a .NET component that will call an external web service. I used the "Add Service Reference" dialog to add the web service to my component, which generates the code needed to consume the service and adds the settings to the app.config file.

I'm testing the component by adding a reference to its DLL from a Console application and calling the appropriate method that creates a new instance of the web service: ... = new MyServiceSoapClient(). However, when I do this, I get the following exception:

InvalidOperationException

Could not find default endpoint element that references contract 'MyServicesSoap' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.

This makes sense since the app.config isn't being brought over with the component's DLL. How can I call the web service without having to rely on the settings in the App.Config?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

风透绣罗衣 2024-09-25 14:04:40

app.config 文件中 中的设置将告诉组件如何连接到外部 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 文件。

The settings in <system.ServiceModel> in the app.config file will tell the component how to connect to the external web service. The xml is simply a textual representation of the necessary classes and enumerations required to make the default connection to the web service.

For example, this is the code that was generated for the web service that I added:

<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>

This can be translated to code like so:

    '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)

Usually, when you use the parameterless constructor (i.e. new MyServicesSoapClient()), the settings in the app.config file will be used. However, you can bypass the app.config file by explicitly setting the binding and endpoint values in code and passing those instances into the constructor.

惟欲睡 2024-09-25 14:04:40

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

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

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

Microsoft 为此提供了类,ConfigurationChannelFactory 类就是其中之一。 MSDN 指出:

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

<块引用>

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

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

首先将生成的 App.config 文件重命名为 App.dll.config,并在其文件属性中将复制更改为Output Directory 属性设置为 Copy Always

创建一个类,该类具有返回 Channel 对象以访问 Web 服务的方法,如下所示:

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 使用它与服务进行通信。

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

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

SampleService 是我的 Web 服务的命名空间。 Client 保存 Web 服务的实例。

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

Setting the Binding and Endpoint configuration in code is one way but there is another way to use the consumer DLL and let the configuration stay in the existing App.config file.

The reason why the mentioned InvalidOperationException occurs is because the DLL does not contain the configuration settings in it. It always rely on App.config to provide for it but since you are using the DLL in another Console application it does not find the configuration settings.

When we use the "Add Service Reference" dialog to add the web service to client component and create instance of the Web service, we let Visual Studio handle the creation of the Communication channel and load the configuration setting.So, if we are able to create such channel explicitly our self then we can manage the configuration settings.

Microsoft provides Classes for this purpose, ConfigurationChannelFactory<TChannel> Class is one. MSDN states:

Provides the generic functionality to create a channel configuration element for a specific type.

The ConfigurationChannelFactory allows central management of WCF client configuration.

Use "Add Service Reference" dialog to add the web service to client component as we need the Service Channel Interface instance.

First rename the generated App.config file to App.dll.config and in its File properties change the Copy to Output Directory property to Copy Always

Create a class that has a method which returns the Channel object to access the web Service such as this:

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;
    }
}

Since we have set the property Copy Always VS copies the Project DLL as well as the App.dll.config into the bin folder. Assembly.GetExecutingAssembly().Location return the assembly location and ConfigurationManager.OpenExeConfiguration

Opens the specified client configuration file as a Configuration object.

PluginConfig holds the App.Config configuration file Object and ConfigurationChannelFactory<T> uses it to communicate with the service.

This method can be called by passing your Service Channel Interface Object like this:

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

SampleService is the namespace of my web service. Client holds the instance of the web Service.

If you need to handle Duplex Communication and Callbacks, then you can look at ConfigurationDuplexChannelFactory<TChannel> Class.

段念尘 2024-09-25 14:04:40

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

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

If this is a WCF service (which it sounds like, from the error messages), then, for the most part, you are going to need something is the app.config, because it's the app.config which tells the rest of WCF that MyServiceSoapClient is a web service (with a small change to the two app.config files, this could become a named pipe service, without recompiling the code....)

Now, if you really want to do this without the app.config, then you have to toss the generated MyServiceSoapClient(), and write your own, based on HttpWebRequest.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文