UPDATE: During further investigation, I realized that the mistake was not in the custom ServiceHostFactory as I originally thought, but in the way I had wrapped OperationContext internally. I'm going to update this question later today.
I recently added a custom ServiceHostFactory to my IIS-hosted WCF web service, in attempt to use Ninject's dependency injection for my service constructor. For some reason, whenever I try to access properties belonging to OperationContext.Current
, the following exception trace is thrown:
2015-05-08 10:30:39.5718 MyErrorHandler System.ObjectDisposedException: Message is closed.
at System.ServiceModel.Channels.BufferedMessage.get_Headers()
at System.ServiceModel.Channels.DelegatingMessage.get_Headers()
at System.ServiceModel.OperationContext.get_IncomingMessageHeaders()
... (my code here)
at SyncInvokeFindCurves(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
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)
2015-05-08 10:31:51.2459 MyErrorHandler System.TimeoutException: The service's security session did not receive a 'close' message from the client within the configured timeout (00:00:10).
at System.ServiceModel.Security.SecuritySessionServerSettings.ServerSecuritySimplexSessionChannel.OnClose(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Close(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.OnClose(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Close(TimeSpan timeout)
at System.ServiceModel.Dispatcher.MessageRpc.CloseChannel()
In the debugger, I've noticed that the ObjectDisposedException is thrown not just for OperationContext.IncomingMessageHeaders
, but also for OperationContext.ServiceSecurityContext
and many others.
I've tried several different implementations of a service host factory, including:
- A custom service host factory that extends
ServiceHostFactory
and returns aServiceHost
with a customIInstanceProvider
- A custom service host factory that extends
NinjectServiceHostFactory
.
But to no avail, because all of them share this same problem. I've also tried plugging in an IErrorHandler
but it still sheds no light on the root cause of this problem. I've also tried googling this error message as well as the components that could have failed but I haven't yet found anything similar to my situation.
Here is the simplest code I can use to illustrate the problem:
public class WorkingServiceHostFactoryWithNinject : NinjectServiceHostFactory
{
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
// ReSharper disable once FieldCanBeMadeReadOnly.Local
private IKernel _kernel;
/// <summary>
/// Initializes the factory.
/// </summary>
public WorkingServiceHostFactoryWithNinject()
{
_kernel = new StandardKernel();
_kernel.Bind<IDummyDependency>().To<DummyDependency>();
...
SetKernel(_kernel);
}
}
My configurations include:
<wsHttpBinding>
<binding name="ServiceBinding"
maxBufferPoolSize="4000000000"
maxReceivedMessageSize="2000000000"
allowCookies="true">
<readerQuotas maxDepth="32"
maxBytesPerRead="2000000000"
maxStringContentLength="2000000000"
maxArrayLength="2000000000" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Basic" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
and
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceCredentials>
<serviceCertificate findValue="**redacted**" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="CustomUserNamePasswordValidator, MyAssembly" />
</serviceCredentials>
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceSecurityAudit
auditLogLocation="Application"
serviceAuthorizationAuditLevel="Failure"
messageAuthenticationAuditLevel="Failure"
suppressAuditFailure="true"/>
</behavior>
</serviceBehaviors>
What I know for sure is that OperationContext.Current
didn't behave like this before I wrote my own ServiceHostFactory. It almost seems as if the garbage collector disposes of the message too early...