wcf rest end point not found from remote computer - c#

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.

Related

Get Hostname in WCF on IIS

Based on below pic, there may be several WebSite on IIS with several services,
So the only thing which I have separate them from together is Hostname , in the other site sibling services may call together so I have decided to change hostname if they are not on localhost so in service I tried something like this:
HostName = OperationContext.Current.Channel.LocalAddress.Uri.Host.ToString();
and in service when I am calling another service by it's proxy I Rehome
public void ReHome(string hostName)
{
if (!string.IsNullOrEmpty(hostName))
{
if (this.Endpoint.Address.Uri.DnsSafeHost.ToLower().Equals("localhost"))
{
string newAddress = string.Format("{0}://{1}{2}/{3}", Endpoint.Address.Uri.Scheme
, hostName, string.IsNullOrEmpty(Endpoint.Address.Uri.Port.ToString()) ? string.Empty : ":" + Endpoint.Address.Uri.Port.ToString()
, Endpoint.Address.Uri.AbsolutePath);
this.Endpoint.Address = new EndpointAddress(newAddress);
}
}
}
call example in a service:
using (var hisProxy = new HISIntegrationClient("hisIntegrationEndPoint", Internals.SYSTEM))
{
hisProxy.ReHome(HostName);
....
}
so is OperationContext.Current.Channel.LocalAddress.Uri.Host give me what I want that mentioned in above pic?
You get the current base address of server(hostname and port) using following code snippet
var baseAddress = OperationContext.Current.Host.BaseAddresses[0].Authority;

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 - AddressFilter mismatch

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

WCF Rest service Windows authentication via Browser

Given is a wcf rest service which runs with HttpClientCredentialType.Windows and enforces a user to authenticate via kerberos.
private static void Main(string[] args)
{
Type serviceType = typeof (AuthService);
ServiceHost serviceHost = new ServiceHost(serviceType);
WebHttpBinding binding = new WebHttpBinding();
binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
ServiceEndpoint basicServiceEndPoint = serviceHost.AddServiceEndpoint(typeof(IAuthService), binding, "http://notebook50:87");
basicServiceEndPoint.Behaviors.Add(new WebHttpBehavior());
Console.WriteLine("wcf service started");
serviceHost.Open();
Console.ReadLine();
}
public class AuthService : IAuthService
{
public List<string> GetUserInformation()
{
List<string> userInfo = new List<string>();
userInfo.Add("Environment.User = " + Environment.UserName);
userInfo.Add("Environment.UserDomain = " + Environment.UserDomainName);
if (OperationContext.Current != null && OperationContext.Current.ServiceSecurityContext != null)
{
userInfo.Add("WindowsIdentity = " + OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name);
userInfo.Add("Auth protocol = " + OperationContext.Current.ServiceSecurityContext.WindowsIdentity.AuthenticationType);
}
else
{
userInfo.Add("WindowsIdentity = empty");
}
WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";
return userInfo;
}
}
[ServiceContract]
public interface IAuthService
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, UriTemplate = "test/")]
List<string> GetUserInformation();
}
When i run this as a console application, and then open the website http://notebook50:87/test/ in internet explorer from another computer, i get a 'bad request' response.
I did enable kerberos logging, and it shows me KDC_ERR_PREAUTH_REQUIRED
I can solve this problem by creating a windows service, and run it under 'Local System account'.
In this case, a client is able to authenticate.
Question: What permission/settings does a user(which runs this wcf service) need in order to get the same behavior as when the application is running as windows service under local system?
Is this related with the Service Principle Name?
It is working now.
It really was a problem with the SPN
At the beginning, I've set the SPN like setpn -A HTTP/notebook50.foo.com, and with this, the kerberos authentication didn't work.
Now, i've set it like setspn -A HTTP/notebook50.foo.com username where username is the user under which the service runs.
From the SPN documentation i've read, it was not clear to me that i have to set the user account in this way.
It would be great if one could explain what happens here, and probably a link to a documentation for this scenario.
You can stop this error pops up via enable the "Do not require Kerberos preauthentication" option for that user account in Active directory users & computers -> properties -> account.

WCF "Content Type was not supported" error

When I am trying to connect to my WCFService the following error occurred.
Content Type text/xml; charset=utf-8 was not supported by service
http://localhost:1978/Service1.svc. The client and service bindings
may be mismatched.
My service code is :
namespace WcfService1
{
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(string fName, string lName);
}
}
And in the client form I am calling this service as follows:
endPointAddr = "http://localhost:1978/Service1.svc";
BasicHttpBinding httpBinding = new BasicHttpBinding();
httpBinding.TransferMode = TransferMode.Buffered;
EndpointAddress endpointAddress = new EndpointAddress(endPointAddr);
Append("Attempt to connect to: " + endPointAddr);
IService1 proxy = ChannelFactory<IService1>.CreateChannel(httpBinding, endpointAddress);
using (proxy as IDisposable)
{
string strNew=proxy.GetData(textBox2.Text, textBox1.Text) ;
}
I am stuck on that error, if anybody knows please help.
I suspect that your WCF service has a binding of WSHttpBinding or similar - you need to change the client binding (which is currently using BasicHttpBinding) accordingly to make it work...

Categories