I would like to host a REST-full WCF 4.0 service on an already-created IIS 7.5 website based on ASP.NET v4.0 and secured by forms authentication. So, I tried to configure my WCF stack using mixed mode authentication (aspNetCompatibilityEnabled="false") and configured the service host to use no security at all but So long, all my efforts was completely unsuccessful. When I try to call my service from the browser after a while the connection to the host is closed without a response and my browser raises an error indicating the connection to the target webstie is closed without any response.
However, if I write a dummy code in Application_BeginRequest to authenticate a dummy user in forms authentication module using FormsAuthentication.Authenticate or call the service in an authenticated browser session everything works fine and the service is called successfully.
I tried to find the problem causing this strange behavior using WCF tracing. What I have found from the resulting svclog file is this exception:
Message: Object reference not set to an instance of an object.
StackTrace:
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.get_LogonUserIdentity()
System.ServiceModel.Channels.HttpChannelListener.ValidateAuthentication(IHttpAuthenticationContext authenticationContext)
System.ServiceModel.Channels.HttpRequestContext.ProcessAuthentication()
System.ServiceModel.Channels.HttpChannelListener`1.HttpContextReceived(HttpRequestContext context, Action callback)
Any idea about the problem?
UPDATE: I even set the authentication mode of the website to "None" and authorized anonymous users. Still the same results. Nothing changed. The question is that can I use unauthenticated WCF RESTfull services with aspNetCompatibilityEnabled="false" on an ASP.NET website at all???
To be more specific, What I have tried to do is:
- Implemented my WCF service in the form of a .svc file
- Configured WCF in my web.config file as the following (note AspNetCompatibilityEnabled="false"):
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="false" />
</system.serviceModel>
- Created and used my own ServiceHostFactory like this:
public class MyServiceHostFactory : ServiceHostFactoryBase
{
#region Methods
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
var type = Type.GetType(constructorString);
var host = new WebServiceHost(type, baseAddresses);
var serviceBehavior = host.Description.Behaviors.OfType<ServiceBehaviorAttribute>().Single();
serviceBehavior.ConcurrencyMode = ConcurrencyMode.Multiple;
serviceBehavior.MaxItemsInObjectGraph = int.MaxValue;
var metadataBehavior = host.Description.Behaviors.OfType<ServiceMetadataBehavior>().SingleOrDefault();
if (metadataBehavior == null)
{
metadataBehavior = new ServiceMetadataBehavior();
host.Description.Behaviors.Add(metadataBehavior);
}
var debugBehavior = host.Description.Behaviors.OfType<ServiceDebugBehavior>().SingleOrDefault();
if (debugBehavior == null)
{
debugBehavior = new ServiceDebugBehavior();
host.Description.Behaviors.Add(debugBehavior);
}
metadataBehavior.HttpGetEnabled = true;
debugBehavior.IncludeExceptionDetailInFaults = true;
var binding = new WebHttpBinding { MaxBufferPoolSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue };
binding.Security.Mode = WebHttpSecurityMode.None;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
WebHttpBehavior webHttpBehavior = new WebHttpBehavior { HelpEnabled = true };
foreach (var contract in type.GetInterfaces().Where(i => i.GetCustomAttributes(typeof(ServiceContractAttribute), true).Length > 0))
{
var endpoint = host.AddServiceEndpoint(contract, binding, "");
endpoint.Behaviors.Add(webHttpBehavior);
}
host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
return host;
}
#endregion
}