1
votes

I have a task to merge a wcf project into a web api project. I have copied the .svc files and svc.cs files and the part of the web.config into the web api project, updating the service names so they reference the svc files in the web api projects and the endpoints to reference the interfaces in a common project.

The web api project is building and I test the WCF service is working by entering the path to one of the services: http://localhost/WebAPI_Interface/Test.svc This gives a web page informing me that I have created a service (so no config errors).

I want to test one of the service operations getavailablelibraries. The operation contract is as follows:

[OperationContract(Action = "getavailablelibraries")]
[WebInvoke(Method = "POST", UriTemplate = "getavailablelibraries", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]
Libraries getavailablelibraries(SystemAuthentication auth);

In fiddler, I have setup a POST request to: http://localhost/WebAPI_Interface/Test.svc/getavailablelibraries

with header: Content-Type: application/json and message body:

{
"auth": {
      "username" : "Test",
      "password" : "Test",
      "systemname" : "Test"
  }
}

Executing this request returns a 504 error. I turned on WCF tracing and found that is throwing the following exception while processing the message:

OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'root' and namespace ''. Found node type 'None' with name '' and namespace ''

In fiddler when I try the same request on the old WCF service, it succeeds with 200.

If I retry the same request but this time with no message body, this time I find that it breaks out in the debugger in the getavailablelibraries, and the auth variable is set to null. So it appears to be a problem deserialising the json into the SystemAuthentication class, however, the same json works on the original WCF project so I am at a loss.

Any ideas?

EDIT: I tried adding Namespace and Name attributes to the ServiceContract and DataContract, but I still get the same error. I switched BodyStyle = WebMessageBodyStyle.Bare, and that results in a different error:

Unable to deserialize XML body with root name '' and root namespace '' (for operation 'getavailablelibraries' and contract ('ProcessExport', 'http://www.myurl.com/services')) using DataContractSerializer. Ensure that the type corresponding to the XML is added to the known types collection of the service.

Also the original wcf service stops working when I change BodyStyle to Bare: The data contract type 'Services.SystemAuthentication' cannot be deserialized because the required data members 'password, systemname, username' were not found.

More info, stack trace of error:

at System.ServiceModel.Dispatcher.DataContractJsonSerializerOperationFormatter.ValidateTypeObjectAttribute(XmlDictionaryReader reader, Boolean isRequest) at System.ServiceModel.Dispatcher.DataContractJsonSerializerOperationFormatter.DeserializeBody(XmlDictionaryReader reader, MessageVersion version, String action, MessageDescription messageDescription, Object[] parameters, Boolean isRequest) at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeBodyContents(Message message, Object[] parameters, Boolean isRequest) at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeRequest(Message message, Object[] parameters) at System.ServiceModel.Dispatcher.DemultiplexingDispatchMessageFormatter.DeserializeRequest(Message message, Object[] parameters) at System.ServiceModel.Dispatcher.UriTemplateDispatchFormatter.DeserializeRequest(Message message, Object[] parameters) at System.ServiceModel.Dispatcher.CompositeDispatchFormatter.DeserializeRequest(Message message, Object[] parameters) at System.ServiceModel.Dispatcher.DispatchOperationRuntime.DeserializeInputs(MessageRpc& rpc) at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc) at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet) at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext) at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext) at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(IAsyncResult result) at System.ServiceModel.Dispatcher.ChannelHandler.OnAsyncReceiveComplete(IAsyncResult result) at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result) at System.ServiceModel.Diagnostics.TraceUtility.<>c__DisplayClass14_0.<CallbackGenerator>b__0(AsyncCallback callback, IAsyncResult result) at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously) at System.Runtime.InputQueue1.AsyncQueueReader.Set(Item item) at System.Runtime.InputQueue1.EnqueueAndDispatch(Item item, Boolean canDispatchOnThisThread) at System.Runtime.InputQueue1.EnqueueAndDispatch(T item, Action dequeuedCallback, Boolean canDispatchOnThisThread) at System.ServiceModel.Channels.SingletonChannelAcceptor3.Enqueue(QueueItemType item, Action dequeuedCallback, Boolean canDispatchOnThisThread) at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult.CompleteParseAndEnqueue(IAsyncResult result) at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult.HandleParseIncomingMessage(IAsyncResult result) at System.Runtime.AsyncResult.SyncContinue(IAsyncResult result) at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult..ctor(ReplyChannelAcceptor acceptor, Action dequeuedCallback, HttpPipeline pipeline, AsyncCallback callback, Object state) at System.ServiceModel.Channels.HttpPipeline.EmptyHttpPipeline.BeginProcessInboundRequest(ReplyChannelAcceptor replyChannelAcceptor, Action dequeuedCallback, AsyncCallback callback, Object state) at System.ServiceModel.Channels.HttpChannelListener1.HttpContextReceivedAsyncResult1.ProcessHttpContextAsync() at System.ServiceModel.Channels.HttpChannelListener`1.BeginHttpContextReceived(HttpRequestContext context, Action acceptorCallback, AsyncCallback callback, Object state) at System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived(HostedHttpRequestAsyncResult result) at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.HandleRequest() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest(Object state) at System.ServiceModel.AspNetPartialTrustHelpers.PartialTrustInvoke(ContextCallback callback, Object state) at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow(Object state) at System.Runtime.IOThreadScheduler.ScheduledOverlapped.IOCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped) at System.Runtime.Fx.IOCompletionThunk.UnhandledExceptionFrame(UInt32 error, UInt32 bytesRead, NativeOverlapped* nativeOverlapped) at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

1
Maybe try using SoapUI and add as a new REST project to see how it is formatting your request (it will auto generate a request for testing). Also, maybe try setting body style to bare: BodyStyle = WebMessageBodyStyle.BarePopo
Try to add the namespace and name attribute to the ServiceContract and DataContract.Abraham Qian

1 Answers

0
votes

The problem turned out to be due to a message handler presumably throwing an exception. In Startup.Config of the web api project, we have a line: config.MessageHandlers.Add(new MessageLoggingHandler(ref globalLogger));

This MessageLoggingHandler class inherits from Microsoft class DelegatingHandler, and overrides the SendAsync function to do some logging when web api calls are made. We put in a check and to calls the base class definition if the request Uri contains the ".svc/", and it started working, so presumably that logging code is specific to web api requests.