I have a WCF service hosted by in a website I developed. The site is hosted by a hosting company. I also have a windows phone 8 application that consumes the service. My problem is everytime I query an operation contract with a parameter I get an error "System.ServiceModel.COmmunicationException: The remote server returned error: NotFound" but if I query an operation that takes no parameter the service works.
[ServiceContract]
public interface IParcelService
{
[OperationContract]
string TrackParcel(string pNumber);
}
public class ParcelService:IParcelService
{
public string TrackParcel(string pNumber)
{
return "some string";
}
}
The above a snippet from the service then on the client i have a reference to the service and I call it a follows
var service = new ParcelClient();
service.TrackParcel("1234");
service.TrackParcelCompleted +=(s,args) =>{var res = args.Result;//At this point reslt throws an exception};
Related
We've made a a WCF application that we're hosting inside an On-Premise Service fabric cluster. Accessing it through the Service Fabric reverse proxy is giving us some difficulties.
Our cluster has 3 nodes(eg. 10.0.0.1-3) and the application should be accessible through the reverse proxy (listening on port 19081) on every node. Unfortunatly it only works through the SF reverse proxy on the node hosting the WCF application(also listening on port 19081). Accessing it through the other nodes results in a 400 bad request.
If we run the WCF service on a different port, we can access it directly / locally, but not through the Service Fabric Reverse Proxy.
We're running multiple ASP.NET Core/REST services on the cluster and these work fine.
Example
If the service is running on the 10.0.0.1 node we can access it through:
http://10.0.0.1:19081/myserviceType/soaphost/myservice.svc
However these URL's result in a 400 bad request status code:
http://10.0.0.2:19081/myserviceType/soaphost/myservice.svc
http://10.0.0.3:19081/myserviceType/soaphost/myservice.svc
Code example
We're using the following code to create the WCF Service Instance Listener:
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new ServiceInstanceListener[] {
CreateWcfListener("ServiceEndpoint", serviceProvider.GetService<ServiceType>())
};
}
private ServiceInstanceListener CreateWcfListener<T>(string endpoint, T serviceImplementation)
{
return new ServiceInstanceListener((context) =>
{
var endpointConfig = context.CodePackageActivationContext.GetEndpoint(endpoint);
int port = endpointConfig.Port;
string scheme = endpointConfig.Protocol.ToString();
string host = context.NodeContext.IPAddressOrFQDN;
string uriStem = endpointConfig.PathSuffix;
string uri = $"{scheme}://{host}:19081{context.ServiceName.AbsolutePath}/{uriStem}";
CustomBinding listenerBinding = CreateListenerBinding();
WcfCommunicationListener<T> listener = new WcfCommunicationListener<T>(
wcfServiceObject: serviceImplementation,
serviceContext: context,
address: new EndpointAddress(uri),
listenerBinding: listenerBinding);
return listener;
}, endpoint);
}
We would like to know why it doesn't work, but more importantly how to fix it.
I've got an ASP.NET MVC/WebApi application that acts as a WCF client. My WCF services are authorizing via ClaimsPrincipalPermission and additionally throw a SecurityException if the combination of the current user and the data does not match (e.g. user is trying to access data from other user).
I catch this as a SecurityAccessDeniedException in my filters and return status code 403.
This however only works for communication that involves a single hop. If the service itself communicates with yet another service, then the SecurityAccessDeniedException gets turned into a FaultException before it reaches the web application.
Example flow:
Web client --> Service A [SecurityException] --> [SecurityAccessDeniedException] Web
Web client --> Service A --> Service B [SecurityException]
--> [SecurityAccessDeniedException] Service A [FaultException] --> [FaultException] Web
I tried implementing an IErrorHandler that handles the SecurityAccessDeniedException but I cannot just throw a SecurityException there.
What are my options to propagate the SecurityException up to the Web client?
Alternatively: how can I construct a message in my error handler, which the client then correctly interprets as a SecurityAccessDeniedException?
I'm now using an IErrorHandler which generates a corresponding FaultException. On the caller, this generates yet another SecurityAccessDeniedException, which I could then handle with the same IErrorHandler etc.
public void ProvideFault(Exception error, MessageVersion version, ref Message message)
{
if (error is SecurityAccessDeniedException)
{
var code = FaultCode.CreateSenderFaultCode(
"FailedAuthentication",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
var faultText = new FaultReasonText(error.Message, CultureInfo.CurrentCulture);
var faultException = new FaultException(new FaultReason(faultText), code);
MessageFault messageFault = faultException.CreateMessageFault();
message = Message.CreateMessage(version, messageFault, "FailedAuthentication"); // the last parameter might not be semantically correct...
}
}
I got this idea by looking at http://leastprivilege.com/2007/11/01/wcf-and-securityaccessdeniedexception/
I'm currently building a cross domain messaging service that uses claims to communicate with services inside the domain. In my messaging service I have:
this.messageFactory = MessagingFactory.Create();
this.namespaceManager = NamespaceManager.Create();
TokenProvider tokenProvider = TokenProvider.CreateSamlTokenProvider(saml,
new Uri("https://<Messaging service>:9355/<Application Namespace>/"));
this.messageFactory.GetSettings().TokenProvider = tokenProvider;
this.namespaceManager.Settings.TokenProvider = tokenProvider;
where the saml variable is a string of xml representing my saml token.
Later on I call
if (this.namespaceManager.TopicExists(topicName) == false)
{
this.namespaceManager.CreateTopic(topicName);
}
When the if statement is called I get this error:
The token provider service was not avaliable when obtaining a token for 'https://<Messaging service>:9355/<Application Namespace>/WRAPv0.9/'.
With an inner exception of:
The remote server returned an error: (404) Not Found.
But when I browse to address I get a response in the web page:
<feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Publicly Listed Services</title><subtitle type="text">This is the list of publicly-listed services currently available.</subtitle><id>uuid:7ad43729-3ed5-4c35-9987-48a34036d267;id=4</id><updated>2013-09-24T17:50:26Z</updated><generator>Service Bus 1.0</generator></feed>
Any ideas if this is a config issue or am I missing something that's needed for my token?
I have an application that makes a web service call to get the URL of an MSI depending on whether the user's computer is 32bit or 64bit.
The call GetURLByOS takes 2 methods (1. string AuthenticationInfo , 2. int osBit). As I'm debugging, I can see the authentication info. The osBit's value is 8 (for 64bit) when calling into the web service. But its value is lost (0) when actually in the web service.
Can someone help me figure out why the integer value is lost?
Update:
I'm attaching to the process. In the client, I see value 8 being passed in. In the web service call, I see 0.
This is a SOAP web service call.
Here's the WSDL code on the client:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://mydomain.com/product/1.0/GetURLByOs", RequestNamespace = "http://mydomain.com/product/1.0", ResponseNamespace = "http://mydomain/product/1.0", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string GetURLByOs(string eTicket, int OsBitType)
{
object[] results = this.Invoke("GetURLByOs", new object[] {
eTicket, OsBitType});
return ((string)(results[0]));
}
Here's the actual web service:
[WebMethod]
public string GetURLByOs(string eTicket, int osBitType)
{
return MyFacade.GetUrl(eTicket, osBitType);
}
BTW, when I change the parameter to type string, it gets passed properly (value "8"). It's only when I pass it as an integer that the value is zeroed out.
I found out what was the problem. On the (client) WSDL code, the parameter is OsBitType. But on the actual web service, the parameter is osBitType. After changing the web service parameter to OsBitType, it's working fine.
Strange thing is, this doesn't occur if the parameter is a string.
For my situation, after update reference of web service, it's working fine.
I've written both a WCF client and a remote internet WCF server.
The remote WCF server is running WPF hosted in a traditional Windows Service wrapper (i.e. not IIS).
Currently, its working perfectly with basic HTTP binding. I'm using Visual Studio 2010 + .NET 4.0 + C#.
Can anyone point me in the direction of the right steps to alter my code so that I can add username + SSL authentication?
EDIT:
At the service end, I've overridden UserNamePasswordValidator as follows:
public class CustomUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
Console.WriteLine("Got to here");
}
}
At the service end, I've specified a link to the username validation class:
ServiceHost serviceHost = new ServiceHost(typeof(PhiFeedServer.PhiFeed)); // ,baseAddress);
const bool passswordAuthentication = true;
if (passswordAuthentication)
{
// These two lines switch on username/password authentication (see custom class "CustomUserNameValidator" in common file PhiFeed.svc.cs)
// See http://msdn.microsoft.com/en-us/library/aa354513.aspx
serviceHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
serviceHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNameValidator();
}
// Start the service
serviceHost.Open();
At the client end:
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:20000/PhiFeed?wdsl");
BasicHttpBinding serviceBinding = new BasicHttpBinding();
serviceBinding.ReceiveTimeout = new TimeSpan(0, 0, 120);
proxy = new PhiFeedClient(serviceBinding, endpointAddress);
proxy.ClientCredentials.UserName.UserName = "myusername";
proxy.ClientCredentials.UserName.Password = "mypassword";
However, when I run everything, it never even calls the username validator - whats going on?
If i am getting this right, you will need to play around with service behaviour. I did that in 3.5 sp1 it should be the same in 4.0 i think.
read this:
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/7d589542-277a-404e-ab46-222794422233/
Aha! Found the solution to my problem.
Microsoft provides example code which demonstrates how to add username/password + SSL authentication to a console app.
Search for "Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4", download, unzip into C:, then run the sample here:
C:\WF_WCF_Samples\WCF\Extensibility\Security\UserNamePasswordValidator\CS