Autofac.Integration.Wcf.AutofacServiceHostFactory not working with WCF REST service

356 views
Skip to first unread message

dm.ch...@gmail.com

unread,
Oct 15, 2015, 10:41:21 PM10/15/15
to Autofac
Hi again

We're currently attempting to move from Ninject to Autofac due to performance issues we're encountering with Ninject resolution.
However, I've hit a big and pretty urgent stumbling block, and I don't know enough about Autofac to understand what's happening.

We have a number of WCF REST services. I'm attempting to swap out the Ninject Wcf extensions for Autofac.Integration.Wcf.AutofacServiceHostFactory, but when as soon as I do so, I start getting a 400 response code with empty response body back from the service.
I've made a tiny proof of concept service with a single endpoint, and the problem's easily replicable.

Global.asax:

public class Global : HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        var containerBuilder = new ContainerBuilder();
        containerBuilder.RegisterType<HiService>().AsSelf();
            
        AutofacHostFactory.Container = containerBuilder.Build(); 
    }
}


Service contract:

[ServiceContract(Namespace = "http://hi.co/services/SayHi.Contracts/1")]
public interface IHiService
{
    [OperationContract]
    [WebGet(UriTemplate = "hi", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
    string Hi();
}

Implementation:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class HiService : IHiService
{
    public string Hi()
    {
        return "Hi";
    } 
}

svc file:

<%@ ServiceHost Language="C#" Debug="true" 
    Service="WcfAutofacTests.Host.ServiceImplementation.HiService, WcfAutofacTests.Host"
    Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>

When I request data from the endpoint using the AutofacServiceHostFactory, 


I get a bad request error

HTTP/1.1 400 Bad Request
Content-Length: 0


Running a WCF trace, I get the following error on "Receive bytes"

<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent"><System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system"><EventID>131076</EventID><Type>3</Type><SubType Name="Information">0</SubType><Level>8</Level><TimeCreated SystemTime="2015-10-16T02:27:38.3673722Z" /><Source Name="System.ServiceModel" /><Correlation ActivityID="{00000000-0000-0000-e028-0080010000f7}" /><Execution ProcessName="iisexpress" ProcessID="32164" ThreadID="9" /><Channel /><Computer>VDT086</Computer></System><ApplicationData><TraceData><DataItem><TraceRecord Severity="Information" Channel="Analytic" xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord"><TraceIdentifier>http://msdn.microsoft.com/en-NZ/library/System.ServiceModel.Diagnostics.TraceHandledException.aspx</TraceIdentifier><Description>Handling an exception.  Exception details: System.ServiceModel.ProtocolException: There is a problem with the XML that was received from the network. See inner exception for more details. ---&gt; System.Xml.XmlException: The body of the message cannot be read because it is empty.
   --- End of inner exception stack trace ---
   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.HttpChannelListener`1.HttpContextReceivedAsyncResult`1.ProcessHttpContextAsync()</Description><AppDomain>/LM/W3SVC/21/ROOT-1-130894360417227664</AppDomain><Exception><ExceptionType>System.ServiceModel.ProtocolException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>There is a problem with the XML that was received from the network. See inner exception for more details.</Message><StackTrace>   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.HttpChannelListener`1.HttpContextReceivedAsyncResult`1.ProcessHttpContextAsync()</StackTrace><ExceptionString>System.ServiceModel.ProtocolException: There is a problem with the XML that was received from the network. See inner exception for more details. ---&amp;gt; System.Xml.XmlException: The body of the message cannot be read because it is empty.
   --- End of inner exception stack trace ---
   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.HttpChannelListener`1.HttpContextReceivedAsyncResult`1.ProcessHttpContextAsync()</ExceptionString><InnerException><Exception><ExceptionType>System.Xml.XmlException, System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>The body of the message cannot be read because it is empty.</Message><StackTrace>   at System.Runtime.Diagnostics.EtwDiagnosticTrace.WriteExceptionToTraceString(XmlTextWriter xml, Exception exception, Int32 remainingLength, Int32 remainingAllowedRecursionDepth)
   at System.Runtime.Diagnostics.EtwDiagnosticTrace.GetInnerException(Exception exception, Int32 remainingLength, Int32 remainingAllowedRecursionDepth)
   at System.Runtime.Diagnostics.EtwDiagnosticTrace.WriteExceptionToTraceString(XmlTextWriter xml, Exception exception, Int32 remainingLength, Int32 remainingAllowedRecursionDepth)
   at System.Runtime.Diagnostics.EtwDiagnosticTrace.ExceptionToTraceString(Exception exception, Int32 maxTraceStringLength)
   at System.Runtime.Diagnostics.EtwDiagnosticTrace.GetSerializedPayload(Object source, TraceRecord traceRecord, Exception exception, Boolean getServiceReference)
   at System.Runtime.TraceCore.HandledException(EtwDiagnosticTrace trace, String param0, Exception exception)
   at System.Runtime.ExceptionTrace.TraceHandledException(Exception exception, TraceEventType traceEventType)
   at System.ServiceModel.Channels.HttpChannelListener`1.ContextReceiveExceptionHandled(Exception e)
   at System.ServiceModel.Channels.HttpChannelListener`1.HttpContextReceivedAsyncResult`1.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)
</StackTrace><ExceptionString>System.Xml.XmlException: The body of the message cannot be read because it is empty.</ExceptionString></Exception></InnerException></Exception></TraceRecord></DataItem></TraceData></ApplicationData></E2ETraceEvent>


If I use the Ninject or stock MS service host factory, the response is as expected:

HTTP/1.1 200 OK
Content-Length: 4
Content-Type: application/json; charset=utf-8

"Hi"


I'm getting desperate at this stage. Is WCF rest not supported, or am I doing something wrong?

There are some dependencies we're using that need to be per request scope (which I read, is supported in Autofac  via InstancePerLifetimeScope, as a separate lifetime scope is created for every wcf request).
So, I I'm assuming that means I can't just use a standard MS host factory, because it won't sort out the right lifetime scope.
Any help would be VERY gratefully received.

web.config here in case anyone is interested:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors> 
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <directoryBrowse enabled="true" />
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
       <assemblyIdentity name="Autofac" publicKeyToken="17863af14b0044da" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.5.0.0" newVersion="3.5.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Thanks!

Dana

Alex Meyer-Gleaves

unread,
Oct 15, 2015, 11:08:35 PM10/15/15
to Autofac
Hi Dana,

You will need to use AutofacWebServiceHostFactory instead of AutofacServiceHostFactory in your .svc file so that a WebServiceHost is created instead of a ServiceHost.

Cheers,

Alex.
Reply all
Reply to author
Forward
0 new messages