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