500 Internal Server Error on a self hosted WCF Service - wcf

I am attempting to develop a new WCF service that is hosted using the ServiceHost object. I am able to get the console application to start and I can see that it is binding to port 80 via netstat. Using WireShark I am also able to see that the client is able to connect to that port and send over the data. I had a problem early on with the amount of data that is being sent in the SOAP message from the client, but was able to resolve that issue by setting the max receive size on the binding. The HTTP 500 error that I am getting is:
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).
The following is my WCF code and my service code.
public class MyWCFService
{
private ServiceHost _selfHost;
public void Start()
{
Uri baseAddress = new Uri(#"http://192.168.1.10");
this._selfHost = new ServiceHost(typeof(MyServiceImpl), baseAddress);
try {
WebHttpBinding binding = new WebHttpBinding();
binding.MaxBufferSize = 524288;
binding.MaxReceivedMessageSize = 524288;
this._selfHost.AddServiceEndpoint(typeof(IMyServiceContract), binding, "MyService");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
this._selfHost.Description.Behaviors.Add(smb);
this._selfHost.Open();
}
catch ( CommunicationException ce ) {
this._selfHost.Abort();
}
}
public void Stop()
{
this._selfHost.Close();
}
}
The following is my service contract. It is fairly simple and only has a single Operation. It is expected that it will be called upon the receipt of a SOAP based message.
[ServiceContract(Namespace = "http://www.exampe.com")]
public interface IMyServiceContract
{
[OperationContract (Action="http://www.example.com/ReportData", ReplyAction="*")]
string ReportData( string strReport );
}
The following the my implementation of the service contract
class MyServiceImpl : IMyServiceContract
{
public string ReportData( string strReport )
{
return "ok";
}
}
Here is what I am getting from my client (the strReport was very long so I excluded it)
POST /MyService HTTP/1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://www.example.com/ReportData"
Host: 192.168.1.10
Content-Length: 233615
Expect: 100-continue
Connection: Keep-Alive
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<ReportData xmlns="http://www.example.com/">
<strReport>
........
</strReport>
</ReportData>
</soap:Body>
</soap:Envelope>
Any help resolving this issue would be greatly appreciated.
Regards,
Richard

Do you want your service to be a SOAP service or a REST service?
On the service side, it is configured to be a REST services (because you are using WebHttpBinding). However, the request from your client is a SOAP request. If your client is a WCF client, it is probably using wsHttpBinding or basicHttpBinding. Both of these are for SOAP.
You can either:
Change your service to use basicHttpBinding or wsHttpBindding to match your client (if you want to use SOAP), or
Change your client to use webHttpBinding (if you want to use REST). This will need more changes because your operation contract is not properly Attributed for REST. And anyway, WCF is not a good option for REST. The ASP.Net Web API is much simpler and better supported.
Also
the Action specified in your operation contract should be just ReportData rather than the namespace qualified version. You may not need it at all in fact.
you can remove the ReplyAction (or specify a proper value if your client needs it)
Generally, you do not need to specify these. I'm not an expert on the innards of SOAP but I believe that WCF will specify these values based on the method name if you don't specify them. Uniqueness of method names in .Net will ensure that the action/replyaction are unique in that case.
With these changes in place It Works On My Machine (TM)

Related

WCF service discovery with message security

I have a client-server application based on WCF where I'm using ServiceDiscovery to find the server from the client. During development with security turned off discovery was working fine but when we turned on message security based on certificates the ServiceDiscovery stopped working.
When I searched for a solution I found this MSDN article, http://msdn.microsoft.com/en-us/library/dd456791%28v=vs.110%29.aspx where it says;
When using message level security it is necessary to specify an EndpointIdentity on the service discovery endpoint and a matching EndpointIdentity on the client discovery endpoint. For more information about message level security, see Message Security in WCF.
I have been searching, reading and writing code but I can't seem to get this into working code. Any ideas?
Exctract of original server code:
private Binding CreateBinding()
{
WSDualHttpBinding binding = new WSDualHttpBinding(WSDualHttpSecurityMode.Message);
// Set other binding properties
return binding;
}
private static void EnableServiceDiscovery(ServiceHostBase host)
{
host.AddServiceEndpoint(new UdpDiscoveryEndpoint());
host.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
}
Compact extract of original client code:
public IEnumerable<MyServiceEndpoint> FindServicesOnNetwork()
{
DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
var myServiceEndpoints = discoveryClient.Find(new FindCriteria(typeof (IMyService))).Endpoints;
discoveryClient.Close();
return myServiceEndpoints.Select(endpoint => new MyServiceEndpoint(endpoint.Address.Uri.ToString())).ToList();
}

WCF Discovery and DataService V3

I would like to expose discovery endpoints (both TCP and UDP) for my Data Services v3 and enable services to be discoverable from the client and discover them in another application. The main point in the discovery is to get the service endpoint address at the client.
I have tried to adapt the samples that Microsoft have provided for WCF Discovery, but so far I failed to achieve my goal.
I have created a custom Data Service Host Factory on server side:
public class CustomDataServiceHostFactory : System.Data.Services.DataServiceHostFactory
{
protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var serviceHost = base.CreateServiceHost(serviceType, baseAddresses);
EndpointDiscoveryBehavior endpointDiscoveryBehavior = new EndpointDiscoveryBehavior();
// Create XML metadata to add to the service endpoint
XElement endpointMetadata = new XElement(
"Root",
new XElement("Information", "This endpoint is Data Service v3!"),
new XElement("Time", System.DateTime.Now.ToString("MM/dd/yyyy HH:mm")));
// Add the XML metadata to the endpoint discovery behavior.
endpointDiscoveryBehavior.Extensions.Add(endpointMetadata);
//may be this is not the safest way to set the behaviour
foreach (var endpoint in serviceHost.Description.Endpoints)
{
endpoint.Behaviors.Add(endpointDiscoveryBehavior);
}
// Make the service discoverable over UDP multicast
serviceHost.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
serviceHost.AddServiceEndpoint(new UdpDiscoveryEndpoint());
return serviceHost;
}
}
On the client side I have tried the following code:
DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
// Find service endpoints
// ServiceReference.DataModel is the generated class for the Data Service client proxy
FindCriteria findCriteria = new FindCriteria(typeof(ServiceReference.DataModel));
findCriteria.Duration = TimeSpan.FromSeconds(30);
FindResponse findResponse = discoveryClient.Find(findCriteria);
// Check to see if endpoints were found & print the XML metadata in them.
if (findResponse.Endpoints.Count > 0)
{
foreach (XElement xElement in findResponse.Endpoints[0].Extensions)
{
Console.WriteLine("Printing Metadata from ServiceEndpoint:");
Console.WriteLine("Endpoint Information: " + xElement.Element("Information").Value);
Console.WriteLine("Endpoint Started at Time: " + xElement.Element("Time").Value);
Console.WriteLine();
}
}
Unfortunately this does not work. I get InvalidOperationException:
Attempted to get contract type for DataModel, but that type is
not a ServiceContract, nor does it inherit a ServiceContract.
If I am heading in the right direction I need a way to express the type for the service contract for the discovery. Too bad I am not sure that it will even work like the normal WCF Discovery...
Please share your ideas or even better - working solutions.
I think exception message is clear enough.
For service discovery You try to use type of your data model, while You must use type of your WCF service implementation - this is different things.
Basically DataServicesV3 service adapter uses your data model and exposes it as a WCF service with it's own service contract.
Look at DataServiceV3 type declaration see that it is implementing some interface, i just don't remember name, in this interface declaration you will find [ServiceContract] and [ServiceOperation] attributes. This is Your SERVICE CONTRACT for all ancestors of DataServiceV3. They use THE SAME contract. Here stands another problem I haven't managed to solve yet - how to make WS-Discovery work with DataServices if they share same contract. You'd better dig in this way.

WCF send and receive string?

im able to successfully use an MSDN example on sending a message to an MSMQ and reading it from a self hosted WCF service.
I am trying to use a simple string in a new project. I can send the string to the queue no problem but the WCF service hosted, faults.
After trying to figure out why, using the Microsoft Service Trace Viewer and enabling logging on the host, it says its a poison message!
but my contract defines MsmqMessage
This is what I am using to send:
System.Messaging.Message msg = new System.Messaging.Message(this.textBox1.Text);
And this is my contract (receiving):
[OperationContract(IsOneWay = true, Action = "*")] void
ProcessIncomingMessage(MsmqMessage<string> incomingMessage);
The content of the message when looking through MMC:
<?xml version="1.0"?>
<string>test</string>
any ideas?
Fixed: on the sender, define the formatter: msg.Formatter = new XmlMessageFormatter(new string[] { "System.String" }); on the contract, decorate it with a knowntype of string: [ServiceKnownType(typeof(String))]

Call a WCF Service using just manual code (no config or autogen code)

I am loosely following the method in WCF The Right Way ... The Manual Way to setup my WCF Service.
I have a manually generated proxy class that looks like this:
// Setup a client so we can call our web services.
public class EmployeeClient :IEmployeeService
{
private readonly IEmployeeService EmployeeChannel;
public EmployeeClient(Binding binding, string address)
{
var endpointAddress = new EndpointAddress(address);
EmployeeChannel = new ChannelFactory<IEmployeeService>
(binding, endpointAddress).CreateChannel();
}
public EmployeeResponse SaveOrUpdateEmployee(EmployeeContract employee)
{
return EmployeeChannel.SaveOrUpdateEmployee(employee);
}
}
I then want to call some of these services. But I don't want to use any config files (I am setting up some integration tests and I don't want more dependencies than needed.)
I am currently trying to call them like this:
serviceHost = SelfServiceHost.StartupService();
employeeClient = new EmployeeClient(new BasicHttpBinding(),
SelfServiceHost.StartUpUrl);
EmployeeResponse employeeResponse = employeeClient.SaveOrUpdateEmployee(emp);
When I do that I am getting this exception:
System.ServiceModel.ProtocolException: Content Type text/xml; charset=utf-8 was not supported by service http://localhost:8090/EmployeeService. The client and service bindings may be mismatched. ---> System.Net.WebException: The remote server returned an error: (415) Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'..
What do I need to do to get a call to my service working with code only?
From what you dessribe the binding is not configured in a compatible way.
I suspect that the WCF host has wsHttpBinding and your client-side has BasicHttpBinding or similar...
see http://social.msdn.microsoft.com/forums/en-US/wcf/thread/f29cd9c8-3c89-43d2-92ae-d2a270ab86b9/

Can Silverlight WCF client read exceptions from an ASMX web service?

I've seen no need to upgrade my services to WCF, but I have been using WCF clients for some time to access ASMX services from .NET 3.5 ASP.NET. I figured eventually I'd hit a wall in this mismatch and I just did - but with Silverlight.
When using Silverlight to access ASMX web services I get an error like this in a popup :
An exception occurred during the
operation, making the result invalid.
Check InnerException for exception
details.
If I'm debugging I get this error :
The remote server returned an error: NotFound.
If I look in Fiddler the exception/fault is there just fine :
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body><soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>Server was unable to process request. ---> ID does not match</faultstring>
<detail /></soap:Fault></soap:Body></soap:Envelope>
How do I actually get to this exception in the Silverlight client.
I need the error to be accessible at runtime with no fiddler and no debugger.
There is a property includeexceptiondetailinfaults that belongs in <behaviors> in the web.config - but this is for server side only as far as I can tell.
Am I correct in assuming that I will need to convert my asmx to svc to be able to get actual exception details in the silverlight client?
If you're happy to wrap the asmx SOAP request in your own IHttpHandler, you can force-feed a Response.StatusCode = 200 after the System.Web.Script.Services.ScriptHandlerFactory does it's work. Here's a sample;
static void ProcessService(HttpContext context)
{
//
// I'm also using this to fake/hide the path of my asmx so that
// domain.com/xml becomes the service end-point..
//
string asmx = "/Services/Some.Service.asmx";
string method = context.Request.Path.Substring("/xml".Length);
//
// ScriptHandlerFactory and friends are sealed so have to use reflection..
//
IHttpHandlerFactory fact = (IHttpHandlerFactory)Activator.CreateInstance(Type.GetType("System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions"));
Type vpt = Type.GetType("System.Web.VirtualPath, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
System.Reflection.MethodInfo mi = vpt.GetMethod("Create", new Type[] { typeof(string) });
object vp = mi.Invoke(null, new object[] { context.Request.Path });
System.Reflection.FieldInfo fi = context.Request.GetType().GetField("_pathInfo", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
System.Reflection.FieldInfo _virtualPath = vpt.GetField("_virtualPath", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
_virtualPath.SetValue(vp, method);
fi.SetValue(context.Request, vp);
IHttpHandler handler = fact.GetHandler(context, context.Request.RequestType, asmx, context.Server.MapPath(asmx));
try
{
// This will trap your asmx Exception and output 500 status and soap fault
handler.ProcessRequest(context);
// force 200 status for Silverlight to receive fault code
context.Response.StatusCode = 200;
context.ApplicationInstance.CompleteRequest();
}
finally
{
fact.ReleaseHandler(handler);
}
}
No client ever gets exceptions from web services. Web services don't send exceptions - they send faults.
The details of the fault are contained in the <detail/> element of the fault message. some platforms, including WCF, parse this information in order to translate from the fault to a platform-specific exception.
Since there is no information in the <detail/> element, no translation is likely to occur.