Consume a SOAP web service without relying on the app.config

后端 未结 3 1594
借酒劲吻你
借酒劲吻你 2020-12-01 02:07

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 gen

相关标签:
3条回答
  • 2020-12-01 02:28

    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.

    0 讨论(0)
  • 2020-12-01 02:35

    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.

    0 讨论(0)
  • 2020-12-01 02:45

    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.

    0 讨论(0)
提交回复
热议问题