How to call a service using multiple Endpoint URIs - c#

To put into context, I have a client application that will attempt to call a webservice that will be deployed on multiple web servers. The URI list will be obtained from the Settings.settings file of the client and a foreach loop will cycle through the URIs until the available service responds.
Let's say I have a service with the following contract:
[ServiceContract]
public interface ICMMSManagerService
{
[OperationContract]
ServerInfo GetServerInfo(string systemNumber);
}
In the web.config of the service's project, I have defined CMMSManager service with the the endpoint name: BasicHttpBinding_IWorkloadMngrService
<system.serviceModel>
<services>
<service name="WorkloadMngr">
<endpoint binding="basicHttpBinding" contract="IMetadataExchange" />
</service>
<service name="CMMSManager">
<endpoint binding="basicHttpBinding" contract="IMetadataExchange" name="BasicHttpBinding_IWorkloadMngrService" />
</service>
</services>
<client>
<remove contract="IMetadataExchange" name="sb" />
</client>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding>
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
On the client side, I have the following code executed when the application starts:
private void QueryWebServiceUrls()
{
var webServiceUrls = Properties.Settings.Default.WebServiceUrls;
foreach (var webServiceUrl in webServiceUrls)
{
try
{
var client = new CMMSManagerServiceClient("BasicHttpBinding_IWorkloadManagerService");
client.Endpoint.Address = new EndpointAddress(new Uri(webServiceUrl),
client.Endpoint.Address.Identity, client.Endpoint.Address.Headers);
client.Open();
var result = client.GetServerInfo("test");
}
catch (EndpointNotFoundException e)
{
continue;
}
catch (InvalidOperationException e)
{
break;
}
}
}
But the application crashes with an InvalidOperationException when the CMMSManagerServiceClient class is instanciated.
Could not find endpoint element with name
'BasicHttpBinding_IWorkloadMngrService' and contract
'ComClientService.ICMMSManagerService' 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 name could be found in the client element.
I have the following configuration in the app.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ICMMSManagerService">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/WorkloadMngr/CMMSManagerService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ICMMSManagerService"
contract="ComClientService.ICMMSManagerService" name="BasicHttpBinding_ICMMSManagerService" />
</client>
</system.serviceModel>
I thought everything was valid by passing the BasicHttpBinding_ICMMSManagerService parameter to the CMMSManagerServiceClient class. I have no clue what am I missing at the moment... Any ideas?

The error is telling you exactly what's wrong: there is no endpoint with the name BasicHttpBinding_IWorkloadMngrService. The app.config says the endpoint is called BasicHttpBinding_ICMMSManagerService so your code should be:
var client = new CMMSManagerServiceClient("BasicHttpBinding_ICMMSManagerService");
Hope this helps.

Related

Self-hosted WCF can connect to localhost but can't connect remote

I have a self-hosted C# WCF .Net 4.6.1 Windows service that communicates with another self-hosted WCF service. This works fine when both services are on the same server. However, when I move the server to another computer, I get this error:
System.ServiceModel.CommunicationException: The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. There are no firewalls running on either computer and I get a response when using http://192.168.1.129:6253/eTutorWcfService (using net.tcp in app).
Client app.config:
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IeTutorMessage" />
</basicHttpBinding>
<netTcpBinding>
<binding name="NetTcpBinding_IeTutorMessage" />
</netTcpBinding>
</bindings>
<client>
<endpoint name="BasicHttpBinding_IeTutorMessage"
address="http://localhost:6253/eTutorWcfService"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IeTutorMessage"
contract="eTutorServiceReference.IeTutorMessage" />
<endpoint name="NetTcpBinding_IeTutorMessage"
address="net.tcp://localhost:6254/eTutorWcfService"
binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_IeTutorMessage"
contract="eTutorServiceReference.IeTutorMessage" >
<identity>
<servicePrincipalName value = ""/>
</identity>
</endpoint>
</client>
Server app.config:
<services>
<service name="eTutorServer.eTutorWcfService"
behaviorConfiguration="myeTutorServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:6253/eTutorWcfService"/>
<add baseAddress="net.tcp://localhost:6254/eTutorWcfService"/>
</baseAddresses>
</host>
<endpoint
address="http://localhost:6253/eTutorWcfService"
binding="basicHttpBinding"
contract="eTutorServer.IeTutorMessage" />
<endpoint
address="net.tcp://localhost:6254/eTutorWcfService"
binding="netTcpBinding"
contract="eTutorServer.IeTutorMessage" />
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
<endpoint
address="mex"
binding="mexTcpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="myeTutorServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
The client code:
EndpointAddress address = new EndpointAddress("net.tcp://" + eTutorServiceIp + ":6254/eTutorWcfService");
eTutorServiceReference.IeTutorMessageClient client = new eTutorServiceReference.IeTutorMessageClient("NetTcpBinding_IeTutorMessage", address);
try
{
rtn = client.eTutorMessage(itm);
client.Close();
}
When the client tries to connect, the output window of the server shows an SecurityTokenValidationException but I'm not sure what to do about that or if it means something relevant. I'm sure this has something to do with security but I don't know what to add where.
First, Nettcpbinding use transport security mode and authenticate the client with windows credential by default.
WCF throws exception that the server has rejected the client credentials, what is the default security mode for NetTCP in WCF
Then, when we change the server configuration and re-host the service, we should re-generate the client proxy class when we calling it. besides, we may need to change the endpoint address in the client configuration since Localhost is generated by default.
I can live with this but would really like to know how to do it
without security.
At last, when we change the security to None, the client does not need to provide the credentials to invoke the service. I suggest you re-host the service and re-generate the client proxy class. I have made a demo, wish it is useful to you.
Server end(console application)
class Program
{
static void Main(string[] args)
{
using (ServiceHost sh=new ServiceHost(typeof(MyService)))
{
sh.Opened += delegate
{
Console.WriteLine("Service is ready......");
};
sh.Closed += delegate
{
Console.WriteLine("Service is closed");
};
sh.Open();
Console.ReadLine();
sh.Close();
}
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
string SayHello();
}
public class MyService : IService
{
public string SayHello()
{
return "Hello Stranger";
}
}
App.config
<system.serviceModel>
<services>
<service behaviorConfiguration="Service1Behavior" name="VM1.MyService">
<endpoint address="" binding="netTcpBinding" bindingConfiguration="mybinding" contract="VM1.IService" >
</endpoint>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:13007/"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="mybinding">
<security mode="None">
</security>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="Service1Behavior">
<serviceMetadata />
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Client end.
ServiceReference1.ServiceClient client = new ServiceReference1.ServiceClient();
try
{
Console.WriteLine(client.SayHello());
}
catch (Exception)
{
throw;
}
App.config
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IService">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<client>
<!--we may need to change the generated endpoint address to autual server IP address.-->
<endpoint address="net.tcp://10.157.13.69:13007/" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_IService" contract="ServiceReference1.IService"
name="NetTcpBinding_IService" />
</client>
</system.serviceModel>
Feel free to let me know if there is anything I can help with.
I added the following code and it works:
client.ClientCredentials.Windows.ClientCredential.UserName = runAs;
client.ClientCredentials.Windows.ClientCredential.Password = runAsPassword;
client.ClientCredentials.Windows.ClientCredential.Domain = runAsDomain;
However, I'd like to do this without security since it will be placed on multiple servers, none of which will have a public IP. I've tried to add to the bindings but on the client it's not a valid node and on the server, it stops the service from starting. I tried to add the following code to the server but it won't open the ServiceHost:
serviceHost.AddServiceEndpoint(typeof(eTutorWcfService), new NetTcpBinding(SecurityMode.None), "");
I can live with this but would really like to know how to do it without security.

WCF: The provided URI scheme 'https' is invalid; expected 'http'. Parameter name: via when i call IInternal proxy = factory.CreateChannel(); on Client

Server's App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true"/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="NewBehaviour">
<serviceMetadata httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="Binding">
<security mode="Transport">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="Server.InternalClass" behaviorConfiguration="NewBehaviour">
<endpoint address="IInternal" binding="wsHttpBinding" bindingConfiguration="Binding" contract="Common.IInternal">
<identity>
<dns value="MyMachine"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="https://MyMachine:8733/"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
Client
static ChannelFactory<IInternal> factory = new ChannelFactory<IInternal>(new WSHttpBinding(), new EndpointAddress("https://MyMachine:8733/IInternal"));
When i call the method factory.CreateChannel(), i get error
I configure certificate
You have to tell the client to use a secure transport channel so that it uses https instead of http. This is true because the binding settings at the client must match the ones at the service side.
You can do this via configuration in the app.config file of the client, or you can do it via code like this:
var ws_http_binding = new WSHttpBinding();
ws_http_binding.Security.Mode = SecurityMode.Transport;
ChannelFactory<IInternal> factory =
new ChannelFactory<IInternal>(
ws_http_binding,
new EndpointAddress("https://MyMachine:8733/IInternal"));
var channel = factory.CreateChannel();

Rename WCF Service Name & Binding Name

Assumption:
I'm working with a WCF application called DemoWCF, in which I have a simple wcf service called Calculator.
The purpose of the application is obviously a demo, the WCF service has to take two numbers as parameters and make the sum of them.
Service Class:
public class Calculator : ICalculator
{
public int Sum(int firstValue, int secondValue)
{
return firstValue + secondValue;
}
}
Service Contract :
[ServiceContract(Namespace="http://ROCKET/Calculator")]
public interface ICalculator
{
[OperationContract]
int Sum(int firstValue, int secondValue);
}
Web.config, service model configuration:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpsBinding">
<security mode="Transport">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="DemoWCF.Services.ServiceClasses.Calculator">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpsBinding" contract="DemoWCF.Services.ServiceContracts.ICalculator" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
When I deploy the WCF application on my IIS and I try to consume the WCF service in SOAP UI or in an ASP.NET MVC application, everything works fine.
Goal:
When I consume the WCF service in SOAP UI, I note that from the wsdl of the web service is automatically generated the binding "WSHttpBinding_ICalculator".
When I consume the WCF service in an ASP.NET MVC application, I note that the from the wsdl of the web service is automatically generated the service model, precisely:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ICalculator">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://rocket/ServiceClasses/Calculator.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ICalculator" contract="Calculator.ICalculator" name="WSHttpBinding_ICalculator" />
</client>
</system.serviceModel>
What I want to do, is to rename the Service Name and the Binding Name of the WCF Service.
It's possibile to omit this WCF behavior of generating binding's name with the format : "BindingType_IServiceInterface" ?
What I have to do, if I want to rename my service name and binding name in "Calculator" ?

Instantiating WCF Service Weird Error

I am trying to add a reference to a WCF service from my C# Desktop app.
I can add the service reference OK but as soon as I try to open the form within this desktop app I get this error:
NB. I have a UserControl that instantiates a reference to my WCF service and the control in in my GUI Form Class.
Could not find default endpoint element that references contract '' 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 is in my app.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMotionUpdater" messageEncoding="Mtom" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://a url/MotionUpdater.svc/MotionUpdater.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMotionUpdater"
contract="wsCloudFeeder.IMotionUpdater" name="BasicHttpBinding_IMotionUpdater" />
</client>
</system.serviceModel>
</configuration>
And this is in my web.config file:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicHttpBindingEndPoint" maxReceivedMessageSize="10485760" messageEncoding="Mtom" closeTimeout="00:00:10" openTimeout="00:00:10" >
<readerQuotas maxArrayLength="32768"/>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="MotionUpdater" behaviorConfiguration="ThrottledBehavior">
<endpoint address="MotionUpdater.svc" binding="basicHttpBinding" bindingConfiguration="basicHttpBindingEndPoint" contract="IMotionUpdater"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ThrottledBehavior">
<serviceTimeouts transactionTimeout="1"/>
<serviceThrottling maxConcurrentCalls="64" maxConcurrentInstances="1" maxConcurrentSessions="50"
></serviceThrottling>/>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
If I invoke this reference from a browser window it displays all OK.
It is only where I have a variable in my form class I get the error:
UserControl.Class:
private static wsCloudFeeder.MotionUpdaterClient wsFeeder = new wsCloudFeeder.MotionUpdaterClient();
Server Class:
[ServiceContract]
public interface IMotionUpdater
{
[OperationContract]
void UploadMotion(byte[] jpegStream, string alias, Int16 camIndex);
}
The extra weird thing is that when I run my application it all works no problem.
Also, I have tried just doing this in my control Class but still cannot open up my GUI form..
private static wsCloudFeeder.MotionUpdaterClient wsFeeder = null;
Thanks...
New Error:

Could not find a base address that matches scheme net.tcp for the endpoint

I have a Wcf Service project. system.serviceModel tag in my web.config is :
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="RCISPNetTcpBinding" openTimeout="00:10:00" sendTimeout="00:10:00">
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign">
</transport>
<message clientCredentialType="Windows"/>
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service behaviorConfiguration="RCISP.WcfServiceBehaviour" name="RCISP.WcfService.PersonWcfService">
<endpoint address="PersonServices" binding="netTcpBinding" bindingConfiguration="RCISPNetTcpBinding"
contract="RCISP.Common.ServiceContract.IPersonService" >
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:40003/"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="RCISP.WcfServiceBehaviour">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceAuthorization principalPermissionMode="UseWindowsGroups" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
I have a runtime error when I want create self-hosting for service.
public class ServiceFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
if (!IsInitialised) InitialiseService();
return base.CreateServiceHost(serviceType, baseAddresses);
}
}
Message of Exception is :
Could not find a base address that matches scheme net.tcp for the endpoint with binding NetTcpBinding. Registered base address schemes are [http].
Why?
You said you were self hosting the service (within your own process) but based on the code above I think you're trying to host it inside of a web application. If so Visual Studio's web server can not host a net.tcp end point. You'll need to set the project up to run under IIS. Please follow the instructions here .
If you are truly self hosting than you can leave the configuration exactly how you have it and spin up the service using the following code:
var host = new ServiceHost(typeof(Service1));
host.Open();
You need to add a protocol mapping to your configuration file to tell it what the "net.tcp" protocol is. Right after your <bindings> section add this:
<protocolMapping>
<add scheme="net.tcp" binding="netTcpbinding"/>
</protocolMapping>

Categories

Resources