C# / WCF: Populate and Consume ServiceInterface through Metadata Endpoint - c#

I got a service which offers a named pipe as connection point/endpoint address for 3rd party applications.
what i did so far is:
Uri[] baseAddress = new Uri[]{
new Uri("net.pipe://localhost")};
string PipeName = "Calculator";
serviceHost = new ServiceHost(typeof(CalculatorImplementation), baseAddress);
// Add a mex endpoint
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.HttpGetUrl = new Uri("http://localhost:8001/CalculatorServer");
serviceHost.Description.Behaviors.Add(smb);
serviceHost.AddServiceEndpoint(typeof(ICalculator), new NetNamedPipeBinding(), PipeName);
serviceHost.Open();
I'm connecting in my client using a ChannelFactory like this:
ChannelFactory<ICalculator> pipeFactory = new ChannelFactory<ICalculator>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/Calculator"));
ICalculator pipeProxy = pipeFactory.CreateChannel();
But acutally I wonder if there is a more "usual" way to connect to the service.
Does I really need to tell every 3rd party app the "connection string"/Endpoint Address of my named pipe ("net.pipe://localhost/Calculator") ?
I thought that there might be a better way to accomplish this, but I did not found a way to do this so far.
I created already that "mex endpoint" but I'm not sure how to use this endpoint to populate the named pipe.
My questions are:
I'm populating the service interface the right way?
and
How do I use the Metadata Endpoint in a client application right?

Related

WCF Tcp binding in code issue

I've got a strange problem: I have a wcf service which needs to be hosted by tcp protocol on a standalone console application.
I have created a new console app project and added a lib reference for my wcf project. The problem occurs when I want to configure and broadcast the host.
var Uri = new Uri("net.tcp://myaddress:4322/MyService");
MyServiceHost = new ServiceHost(typeof(ImyService), Uri);
var binding = new NetTcpBinding();
MyServiceHost.AddServiceEndpoint(typeof(IImageExchangeService), binding, "");
var mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
MyServiceHost.AddServiceEndpoint(typeof(IMetadataExchange),mexBinding, "");
ServiceMetadataBehavior serviceBehavior = new ServiceMetadataBehavior();
serviceBehavior.HttpGetEnabled = true;
serviceBehavior.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
MyServiceHost.Description.Behaviors.Add(serviceBehavior);
When it comes to open the host, I get this message:
The contract name 'IMetadataExchange' could
not be found in the list of contracts implemented by the service WcfService.Ser
vices.MyService. Add a ServiceMetadataBehavior to the configuration
file or to the ServiceHost directly to enable support for this contract.
Now that I have better time to check this.
First you need to get the service behavior from the host or create a new one and add it if not found.
Setting the HttpGetEnabled requires you to also ad a metadata uri to the baseaddresses.
Also it does not seem to matter if the metadata endpoint is named "mex", as long as all endpoints added have unique names. So you can't use empty string for both endpoints.
var Uri = new Uri("net.tcp://myaddress:4322/MyService");
var MetadataUri = new Uri("http://myaddress:8000/MyService");
var MyServiceHost = new ServiceHost(typeof(MyService), Uri, MetadataUri);
var serviceBehavior = MyServiceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (serviceBehavior == null)
{
serviceBehavior = new ServiceMetadataBehavior();
MyServiceHost.Description.Behaviors.Add(serviceBehavior);
}
serviceBehavior.HttpGetEnabled = true;
serviceBehavior.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
MyServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
var binding = new NetTcpBinding();
MyServiceHost.AddServiceEndpoint(typeof(IImageExchangeService), binding, "image");

One class implements two service contracts

I want to create a class that implementing 2 service contracts, and exposing 2 end-points on different ports (I get the ports as input to the program).
My question is very similar to this question, but I want two end-points each one on different port.
EDIT:
Using this code:
var aConnectionString = "http://localhost:8200/A";
var bConnectionString = "http://localhost:8201/B";
ServiceHost host= new ServiceHost(typeof(abImp));
var binding = new BasicHttpBinding();
host.AddServiceEndpoint(typeof(A), binding, aConnectionString);
host.AddServiceEndpoint(typeof(B), binding, bConnectionString);
{
// Check to see if the service host already has a ServiceMetadataBehavior
ServiceMetadataBehavior smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
// If not, add one
if (smb == null)
smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
host.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
aConnectionString
);
}
host.Open();
I'm getting this error message on the host.Open() operation:
An unhandled exception of type 'System.InvalidOperationException' occurred in System.ServiceModel.dll
Additional information: A binding instance has already been associated to listen URI 'http://localhost:8200/A'. If two endpoints want to share the same ListenUri, they must also share the same binding object instance. The two conflicting endpoints were either specified in AddServiceEndpoint() calls, in a config file, or a combination of AddServiceEndpoint() and config.
SOLUTION
var aConnectionString = "http://localhost:" + portA+ "/A";
var bConnectionString = "http://localhost:" + portB+ "/B";
ServiceHost aHost = new ServiceHost(instance, new Uri(aConnectionString));
ServiceHost bHost = new ServiceHost(instance, new Uri(bConnectionString));
aHost.Description.Behaviors.Find<ServiceBehaviorAttribute>().InstanceContextMode = InstanceContextMode.Single;
bHost.Description.Behaviors.Find<ServiceBehaviorAttribute>().InstanceContextMode = InstanceContextMode.Single;
aHost.AddServiceEndpoint(typeof(A), new BasicHttpBinding(), aConnectionString);
bHost.AddServiceEndpoint(typeof(B), new BasicHttpBinding(), bConnectionString);
{
// Check to see if the service host already has a ServiceMetadataBehavior
var smb = aHost.Description.Behaviors.Find<ServiceMetadataBehavior>() ?? new ServiceMetadataBehavior();
aHost.Description.Behaviors.Add(smb);
aHost.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
aConnectionString + "/Mex"
);
}
{
// Check to see if the service host already has a ServiceMetadataBehavior
var smb = bHost.Description.Behaviors.Find<ServiceMetadataBehavior>() ?? new ServiceMetadataBehavior();
bHost.Description.Behaviors.Add(smb);
bHost.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
bConnectionString + "/Mex"
);
}
aHost.Open();
bHost.Open();
Given that you want two completely different addresses, only same implementation class, I'd recommend use of two different ServiceHost instances.

C# WCF Setup a Service and a Client for OASIS WS 1.1 X509 certificate token profile

I would like to setup a module which will communicate with other modules remotely acting both as a service and as a client. The communcation should go in SOAP 1.2 and it should use OASIS WSS 1.1, and X.509 certificate token profile.
OASIS WSS 1.1 X.509 specs
I already made a development certificate using makecert and it is trusted already.
Since the module is essentially C# based, all settings are given in code. So far I got the following service code:
The code for the binding:
System.ServiceModel.Channels.AsymmetricSecurityBindingElement asbe = new AsymmetricSecurityBindingElement();
asbe.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12;
asbe.InitiatorTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient };
asbe.RecipientTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient };
asbe.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
asbe.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
asbe.EnableUnsecuredResponse = true;
asbe.IncludeTimestamp = false;
asbe.SetKeyDerivation(false);
asbe.DefaultAlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128Rsa15;
asbe.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters());
asbe.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters());
CustomBinding myBinding = new CustomBinding();
myBinding.Elements.Add(asbe);
myBinding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap12, Encoding.UTF8));
HttpsTransportBindingElement httpsBindingElement = new HttpsTransportBindingElement();
httpsBindingElement.RequireClientCertificate = true;
myBinding.Elements.Add(httpsBindingElement);
The code for the behaviour:
//Then initiate the service host
_Host = new ServiceHost(typeof(TClass), baseAddress);
//Add the service endpoint we defined
_Host.AddServiceEndpoint(typeof(TInterface), _Binding, typeof(TInterface).ToString());//BindingHelper.GetUserNameBinding(), "");
//Set searching the certificate
_Host.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "MyServerCert");
_Host.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
_Host.Credentials.ClientCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck;
//Allow the metadata spreading
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpsGetEnabled = true;
smb.HttpGetEnabled = true;
_Host.Description.Behaviors.Add(smb);
ServiceDebugBehavior sdb = new ServiceDebugBehavior();
sdb.IncludeExceptionDetailInFaults = false; //Should only provide the endpoint property (GP WS-Message profile specs)
//Add the appropriate endpoint
if (baseAddress.AbsoluteUri.Contains("https"))
_Host.AddServiceEndpoint(
typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexHttpsBinding(),
"mex");
else
_Host.AddServiceEndpoint(
typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex");
On the client side I use the same code to create the binding, plus I use the following behavior:
channelFactory = new ChannelFactory<T>(bindIn, serviceAddress);
if (wsFeature != null)
{
channelFactory.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
channelFactory.Endpoint.Behaviors.Add(wsFeature);
channelFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "MyServerCert");
channelFactory.Credentials.ServiceCertificate.SetScopedCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "MyServerCert",serviceAddress.Uri);
}
_ProxiObject = channelFactory.CreateChannel();
Here basically the behavior wsFeature is a simple class doing practically nothing (just implements blank functions for IEndpointBehavior).
I have both service and client on the same machine at https://localhost.:8084/testhosting4, and even though both service and client are successfully created I only got the famous "An error occurred while making the HTTP request to https://localhost.:8084/testhosting4. etc." error.
I already managed to connect via an unsecure channel with the module (BasicHttpBinding - no security) and exchange messages, so I am sure that I make a mistake in defining the binding or assigning credentials. Obviously, I browsed a lot here already, but couldn't come up with a working solution.
This is the first time I meet WCF and X509 and I'm not in secure communications at all either. So plenty of occasions to make a mistake. Please point out those which I've made.
Thank you!

WCF Service error no config file or endpoint .Net 3.5

I am writing WCF Service - Client. The service is getting the endpoint url as arg, This is Windows Form Application.
The Service impl is:
BaseAddress = new Uri(args[0]);
using (ServiceHost host = new ServiceHost(typeof(DriverService), BaseAddress))
{
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
//host.AddServiceEndpoint(typeof(DriverService), new BasicHttpBinding(), BaseAddress);
host.Open();
After host.Open() i get the error, When i wrote same wcf code on another solution it worked just fine, i had the client and service. now i just need to open the service when wait until the client connects.
From what I understand, this is Service and i give it address, then it listens on the given address and exposing the methods on the interface to different clients.
Error:
Service 'DriverHost.DriverService' has zero application (non-infrastructure) endpoints. This might be because no configuration file was found for your application, or because no service element matching the service name could be found in the configuration file, or because no endpoints were defined in the service element.
Code of interface and class:
[ServiceContract]
public interface IDriverService
{
[OperationContract]
string WhoAmI();
}
public class DriverService : IDriverService
{
public string WhoAmI()
{
return string.Format("Im on port !");
}
}
since there is different between .net 4.5 and 3.5 i understand there is no default Endpoints.
So needed to declare:
BaseAddress = new Uri(args[0]);
using (ServiceHost host = new ServiceHost(typeof(Namespace.Classname), BaseAddress))
{
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
host.AddServiceEndpoint(typeof(Namespace.IInterface), new BasicHttpBinding(), args[0]);
host.Open();
Meaning - add the .AddServiceEndpoint(..)
and make sure that on ServiceHost() write the class, and on AddServiceEndpoint enter the Interface.

Why do I get WCF Exception "HTTP could not register URL http://+:80/MyService/"

I create my host with the endpointaddress it needs to use, like this:
Uri endpointAddress = new Uri("http://127.0.0.1:5555/MyService");
ServiceHost host = new ServiceHost(myServiceType, endpointAddress);
host.AddServiceEndpoint(implementedContract, basicHttpBinding, string.Empty);
but when I later do host.Open(); I get the exception "HTTP could not register URL http://+:80/MyService/ because TCP port 80 is being used by another application". The result is the same when I do
host.AddServiceEndpoint(implementedContract, basicHttpBinding, endpointAddress);
Why would it try to do anything with port 80? How can I solve this?
Update
While trying to provide a more complete code sample, I found the culprit. I added a ServiceMetadataBehavior as follows:
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.ExternalMetadataLocation = new Uri(this.ExternalMetadataLocation);
smb.HttpGetEnabled = true;
smb.HttpGetUrl = this.RemovePort(this.EndpointAddress);
host.Description.Behaviors.Add(smb());
It seems that in the past I needed to remove the port from the URL to get this to work, but now that's exactly what causes the problem.
So Pratik is right: metadata were the problem, and of course the problem with port 80 is that there's some newly installed application using that port.
Thanks, regards,
Miel.
This is because port 80 is already used by another applicatiion as the error message says, most likely by local IIS server. Try stopping IIS and see, or use another port.
On vista and above you can use netsh command to check which ports are already reserved
BTW do you have http metadata or mex endpoints in the app.config or web.config file ?
The following works fine for me:
class Program
{
[ServiceContract]
public interface IMyService
{
[OperationContract]
void Test();
}
public class MyService : IMyService
{
public void Test()
{
throw new NotImplementedException();
}
}
static void Main()
{
var endpointAddress = new Uri("http://127.0.0.1:5555/MyService");
using (var host = new ServiceHost(typeof(MyService), endpointAddress))
{
var basicHttpBinding = new BasicHttpBinding();
host.AddServiceEndpoint(typeof(IMyService), basicHttpBinding, string.Empty);
host.Open();
}
}
}
Maybe you have some other code which is interfering?

Categories

Resources