WCF - AddressFilter mismatch - c#

I have a self-hosted WCF service, and am getting the following exception when calling it:
The message with To 'net.tcp://localhost:53724/Test1' cannot be
processed at the receiver, due to an AddressFilter mismatch at the
EndpointDispatcher. Check that the sender and receiver's
EndpointAddresses agree.
The solution that works is to add [ServiceBehavior(AddressFilterMode = AddressFilterMode.Prefix)] before the service interface's implementation class. But that shouldn't be the case! So, I'm trying to get to the source of the error in order to remove it.
I've found that
When I do add the ServiceBehavior attribute and the call succeeds - the following: OperationContext.Current.EndpointDispatcher.EndpointAddress
Returns: net.tcp://localhost/Test1 - notice the absence of the port. That is actually what I feed the ServiceHost.Open method. But the port is added because I specify ListenUriMode.Unique .
So: How do I fix the error with AddressFilterMode.Exact ?
Code to reproduce:
[ServiceContract]
public interface IWCF1
{
[OperationContract]
bool SendMessage(string message);
}
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Prefix)]
public class WCF1 : IWCF1
{
public bool SendMessage(string message)
{
Debug.WriteLine("Message: " + message);
Debug.WriteLine(OperationContext.Current.EndpointDispatcher.EndpointAddress, "EndpointAddress");//Does not include the port!
return true;
}
}
public void test()
{
Uri uri2 = Service(typeof(WCF1), typeof(IWCF1), "Test1");
IWCF1 iwcf1 = CreateChannel(uri2.ToString());
new Task(() => iwcf1.SendMessage("abc")).Start();
}
public Uri Service(Type class1, Type interface1, string uri)
{
string serviceUri = "net.tcp://localhost/" + uri;
ServiceHost host = new ServiceHost(class1, new Uri(serviceUri));
ServiceEndpoint ep = host.AddServiceEndpoint(interface1, new NetTcpBinding(SecurityMode.None), serviceUri);
ep.ListenUriMode = ListenUriMode.Unique;
host.Open();
return host.ChannelDispatchers[0].Listener.Uri;
}
public static IWCF1 CreateChannel(string address)
{
EndpointAddress ep = new EndpointAddress(address);
ChannelFactory<IWCF1> channelFactory = new ChannelFactory<IWCF1>(new NetTcpBinding(SecurityMode.None), ep);
return channelFactory.CreateChannel();
}

I suspect that the source of the AddressFilterMode.Exact error involves the difference between the logical endpoint and physical service address.
The EndpointAddress is the logical address of a service, which is the address that SOAP messages are addressed to. The ListenUri is the physical address of the service. It has the port and address information where the service endpoint actually listens for messages on the current machine. The logical endpoint address, not the physical service location, is used for by the dispatcher for matching and filtering, thus the reason why an exact match does not find the service.
The Physical Address is not the same as the Logical Address:
net.tcp://localhost:53724/Test1 != net.tcp://localhost/Test1
A few options to consider:
Continue to use AddressFilterMode.Prefix
Try specifying HostNameComparisonMode
Specify the port in advance
References:
https://msdn.microsoft.com/en-us/library/aa395210%28v=vs.110%29.aspx
https://msdn.microsoft.com/en-us/magazine/cc163412.aspx#S4

Related

WCF client unable to connect to WCF server with error

I am unable to connect my WCF client to my WCF server on a Localhost network. The error that I am getting is the following:
Error while connecting to the Localhost server: Could not find default
endpoint element that references contract 'MyServiceReference.IMyService'
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.
The server connection is the following. Here is the code:
_host = new ServiceHost(typeof(MyService));
//Create Metadata exchange for the service
ServiceMetadataBehavior mexBehavior = new ServiceMetadataBehavior();
_host.Description.Behaviors.Add(mexBehavior);
//Add service endpoints for the service and mex
_host.AddServiceEndpoint(typeof(IMyService), new NetNamedPipeBinding(), "net.pipe://localhost/WFC_Server/MyService.svc");
_host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexNamedPipeBinding(), "net.pipe://localhost/WFC_Server/MyService.svc/mex");
_host.Open();
I am not setting up my client to connect to the server properly. Does anybody know why? Here is the code:
var callback = new MyServiceCallback();
var instanceContext = new InstanceContext(callback);
var client = new MyServiceReference.MyServiceClient(instanceContext);
client.Endpoint.Address = new EndpointAddress("net.pipe://localhost/WFC_Server/MyService.svc");
client.OpenSession();
Does anybody know why my client does not connect to the server?
I have replicated the problem and fixed the issue.
1. Specify the endpoint address while creating the client.
var callback = new MyServiceCallback();
var instanceContext = new InstanceContext(callback);
EndpointAddress remoteAddress = new EndpointAddress("net.pipe://localhost/WFC_Server/MyService.svc");
var client = new MyServiceClient(instanceContext,new NetNamedPipeBinding(),remoteAddress);
client.Hello(); // call the function
In the server, you can register like this:
Code:
Uri address1 = new Uri("http://localhost/WFC_Server/");
Uri address2 = new Uri("net.pipe://localhost/WFC_Server/");
ServiceHost _host = new ServiceHost(typeof(MyService), address1,address2);
//Create Metadata exchange for the service
ServiceMetadataBehavior mexBehavior = new ServiceMetadataBehavior();
mexBehavior.HttpGetEnabled = true;
_host.Description.Behaviors.Add(mexBehavior);
//Add service endpoints for the service and mex
_host.AddServiceEndpoint(typeof(IMyService), new NetNamedPipeBinding(), "MyService.svc");
_host.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex"
);
_host.Open();
I have used the following interfaces as an example:
class MyService : IMyService
{
public void Hello()
{
Console.WriteLine("Hello From Server..");
}
}
[ServiceContract(CallbackContract = typeof(ICallbackService))]
internal interface IMyService
{
[OperationContract]
void Hello();
}
[ServiceContract]
public interface ICallbackService
{
[OperationContract]
void CallClient();
}

Programmatically created web service fails on client service call

I made a console application project to host a web service programmatically, but when I try to create a client proxy to my web service and call a method on it, I get the following error:
An error occurred while making the HTTP request to
https://localhost:8000/FileRetrievalPoC. This could be due to the fact
that the server certificate is not configured properly with HTTP.SYS
in the HTTPS case. This could also be caused by a mismatch of the
security binding between the client and the server.
Its inner exception:
The underlying connection was closed: An unexpected error occurred on
a send.
Its inner exception:
Unable to read data from the transport connection: An existing
connection was forcibly closed by the remote host.
Its inner exception:
An existing connection was forcibly closed by the remote host
Program.cs:
class Program
{
static void Main(string[] args)
{
var address = "https://localhost:8000/FileRetrievalPoC";
Console.WriteLine("Starting a service at {0}...", address);
FileRetrievalService.Start(address, StoreLocation.LocalMachine, StoreName.My, "localhost");
Console.WriteLine("Service started.");
Console.WriteLine("Press Enter to create a new proxy client and call the Get method.");
Console.WriteLine("Press Escape to end the application.");
while (true)
{
var key = Console.ReadKey();
if (key.Key == ConsoleKey.Enter)
{
var proxy = FileRetrievalService.Connect(address, "localhost", "exampleUsername", "examplePassword", StoreLocation.LocalMachine, StoreName.My, "localhost");
proxy.Get(#"C:\Users\User\Desktop\Document.txt");
((IClientChannel)proxy).Close();
}
else if (key.Key == ConsoleKey.Escape)
break;
}
FileRetrievalService.Stop();
}
}
IFileRetrieval.cs:
[ServiceContract]
public interface IFileRetrieval
{
[OperationContract]
string Get(string path);
[OperationContract]
void Set(string path, string contents);
}
FileRetrievalService.cs:
class FileRetrievalService : IFileRetrieval
{
private static BasicHttpsBinding _binding = new BasicHttpsBinding()
{
Name = "FileRetrievalPoC",
HostNameComparisonMode = HostNameComparisonMode.Exact,
Security = new BasicHttpsSecurity()
{
Message = new BasicHttpMessageSecurity()
{
AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15,
ClientCredentialType = BasicHttpMessageCredentialType.UserName
},
Mode = BasicHttpsSecurityMode.TransportWithMessageCredential,
Transport = new HttpTransportSecurity()
{
ClientCredentialType = HttpClientCredentialType.Windows
}
},
SendTimeout = TimeSpan.FromMinutes(1),
CloseTimeout = TimeSpan.FromMinutes(1),
OpenTimeout = TimeSpan.FromMinutes(1),
ReceiveTimeout = TimeSpan.FromMinutes(1)
};
private static ChannelFactory<IFileRetrieval> _channelFactory;
private static ServiceHost _host;
public static void Start(string address, StoreLocation location, StoreName name, string subject)
{
_host = new ServiceHost(typeof(FileRetrievalService));
_host.Credentials.ServiceCertificate.SetCertificate(location, name, X509FindType.FindBySubjectName, subject);
_host.AddServiceEndpoint(typeof(IFileRetrieval), _binding, address);
_host.Open();
}
public static void Stop()
{
if (_host != null)
_host.Close();
if (_channelFactory != null)
_channelFactory.Close();
}
public static IFileRetrieval Connect(string address, string domain, string username, string password, StoreLocation location, StoreName name, string subject)
{
if (_channelFactory == null)
_channelFactory = new ChannelFactory<IFileRetrieval>(_binding, address);
_channelFactory.Credentials.ClientCertificate.SetCertificate(location, name, X509FindType.FindBySubjectName, subject);
_channelFactory.Credentials.UserName.UserName = username;
_channelFactory.Credentials.UserName.Password = password;
_channelFactory.Credentials.Windows.ClientCredential = new NetworkCredential(username, password, domain);
return _channelFactory.CreateChannel();
}
public string Get(string path)
{
throw new NotImplementedException();
}
public void Set(string path, string contents)
{
throw new NotImplementedException();
}
}
Its all done programmatically, and I've looked on Stack Overflow but couldn't find a good reason why this is happening. Does anyone know what the problem is? This source code, you can add to a new console application and run it to try it out on your local machine and see it happen for yourself. Is it the SSL certificate? If so, how can I get more verbosity for the error reason here? Its not a very helpful exception.
Edit: I think I may have missed a step here, such as using netsh to bind a certificate to my machine's port.
My issue was that I did not use netsh to bind the certificate to my machine's port. Open up an administrative command prompt and call:
netsh http add sslcert ipport=0.0.0.0:8000 appid=<A randomly generated GUID for your application> certhash=<Your localhost certificate's thumbprint from the default MY store, which is under Local Machine -> Personal, which you can get from the MMC Certificates snap-in>
The next step is to make sure its under Trusted People on the client side. At least, for me this is the case since I am using a self-signed certificate that I generated for testing purposes for localhost. So for example, if you get a certificate from Comodo or Verisign or some other CA, your certificate may not need this at all since the root CA will be trusted, usually, by default in Windows, since the root CA public certificate for these is shipped out of the box inside of the Trusted Root Certification Authorities section of the Certificates MMC snap-in.
Then, all you need to do, is make sure that your machine credentials are correct. I am using Windows authentication so it tries to assert that my credentials are valid (these are specified in my code on the call to the Connect method).
As I get older, I find I tend to answer my own questions more and more often...
Edit: You only need to use the Trusted People store for all of this. If you do want to do this, then use StoreName.TrustedPeople in my code above and in your netsh command, specify certstorename=TrustedPeople, otherwise it defaults to MY, which is the Personal store in the Certificates MMC snap-in.
Also, to delete an SSL certificate that has been bound, use netsh http delete sslcert ipport=0.0.0.0:8000
Also, my code doesn't need the client certificate to be set in order to function, so that can be removed from the Connect method. Also needs some more tightening up if any of you plan to use it in production.

wcf rest end point not found from remote computer

I have Wcf rest service.
I host it in console application.
when I try to access the service from my local computer it works but when I try from remote
computer the service is not found.
here is the code:
service definition:
[ServiceContract]
public interface IInstagramCallbackService
{
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "url/?hub.mode={mode}&hub.challenge={challenge}&hub.verify_token={token}")]
string CheckServiceAvailability(string mode, string challenge, string token);
}
public class InstagramCallbackService : IInstagramCallbackService
{
public string CheckServiceAvailability(string mode, string challenge, string token)
{
return challenge;
}
}
hosting:
ServiceHost host = new ServiceHost(typeof(InstagramCallbackService),new Uri[]{});
WebHttpBinding binding = new WebHttpBinding(WebHttpSecurityMode.None);
ServiceEndpoint endPoint = new ServiceEndpoint(
ContractDescription.GetContract(
typeof(InstagramCallbackService)), binding, new EndpointAddress(
"http://127.0.0.1:6064/InstagramCallbackService"));
WebHttpBehavior webBehavior = new WebHttpBehavior();
endPoint.Behaviors.Add(webBehavior);
host.AddServiceEndpoint(endPoint);
host.Open();
Console.WriteLine("ready");
Console.ReadLine();
127.0.0.1 is a local address. It's like saying localhost or "this computer". You can't hit 127.0.0.1 from another computer, because 127.0.0.1 from another computer would just be that computer. Surely your machine has other addresses you can use though no? Try ipconfig from the command line.

WCF service caching all requests

I'm trying to write WCF service in which one method will be catching all requests. Plan to host it within standalone executable. Here is the contract:
[ServiceContract]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, AddressFilterMode = AddressFilterMode.Any)]
public class Proxy
{
[WebInvoke(UriTemplate = "*", Method = "*")]
public string Test(Stream input)
{
return "Test";
}
}
Here is the hosting code:
static void Main(string[] args)
{
var uri = new Uri("http://localhost:2535/");
var binding = new WebHttpBinding();
var host = new ServiceHost(new Proxy(), uri);
host.AddServiceEndpoint(typeof(Proxy), binding, uri);
host.Open();
Console.ReadKey();
}
But when I'm pointing my browser to the localhost:2535 i just see information about service and fact that metadata is not enabled. And when I getting something like localhost:2535/bla-bla-bla/ error rises:
The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
I don't understand what I'm missing, to be frankly... Would be very grateful for helping me to get back on right track.
EDIT: Solved by explicitly adding WebHttpBehavior behavior to the endpoint. The resulting code become:
static void Main(string[] args)
{
var uri = new Uri("http://localhost:2535/");
var binding = new WebHttpBinding();
var host = new ServiceHost(new Proxy(), uri);
host.AddServiceEndpoint(typeof(Proxy), binding, uri).Behaviors.Add(new WebHttpBehavior());
host.Open();
Console.ReadKey();
}
I'm still looking for more detailed explanation why it's working that way...
Try add to your Endpoint's behaviour WebHttpBehavior, like this
host.AddServiceEndpoint(typeof(Proxy), binding, uri).Behaviours.Add(new WebHttpBehavior());
It looks a bit odd that your ServiceContract attribute is defined directly on the class that implements your service. Usually you'd define this on the interface that defines the service. Example here:-
MSDN ServiceContractAttribute
To enable metadata exchange you need to add ServiceMetadataBehavior just like that
ServiceMetadataBehavior serviceBehaviour = new ServiceMetadataBehavior() { HttpGetEnabled = true, HttpGetUrl = new Uri(String.Format("{0}/mex", endpointUrl)) };
Host.Description.Behaviors.Add(serviceBehaviour);
And then use localhost:2535/mex to retrieve the service metadata. If it succeeds have a look if your Test method is included in the metadata. If it fails try to configure WCF tracing to get more detailed and user friendly error messages.
Also make sure you marked you method with OperationContract attribute.
Hope it helps.

How to cleanly restart a WCF under new address?

I have a WPF C# application hosting a WCF service. I have a routine to start the service, closing it if it already exists. WebServce is a property of type ServiceHost:
public void Start()
{
try
{
var certificate = new X509Certificate2(certpath, "");
String uri = "net.tcp://" + WCFAddress + "/MyService";
Uri baseaddress = new Uri(uri);
if (WebService != null) {
try {
WebService.Close();
} catch (Exception) {
WebService.Abort();
}
}
WebService = new ServiceHost(MessageProvider, baseaddress);
WebService.Credentials.ServiceCertificate.Certificate = certificate;
WebService.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate;
WebService.AddServiceEndpoint(typeof(IMessageService), binding, baseaddress);
WebService.Open();
}
catch (Exception e)
{
//exception handling
}
}
This works fine on startup. It also works fine if I change the port number (in WCFAddress) and call the routine again. It also works if I change the address on the host computer and call it with the new IP address. However, if I change the IP address to an invalid one, the service goes into a Faulted state with the error:
e = {"A TCP error (10049: The requested address is not valid in its context) occurred while listening on IP Endpoint=192.168.1.4:5000."}
The Close() call in the above doesn't raise an exception.
If I then change the IP address to the correct one and call again, I get the same error, with the same old incorrect address, even though I passed it the correct one. Also this time the Close() call raises an error due to the Faulted state, which results in the Abort() call.
I thought the Abort() call would allow the service to then be recreated? Why is it giving me an error about the old address when I'm trying to create the service with a new one? It's like it's hanging onto the old ServiceEndpoint?
Abort(). Then just initiate a new instance with the new address.. then Open().

Categories