У меня проблема со службой WCF, использующей проверку подлинности Windows на одном из серверов, на которых я ее развертываю (это компьютер с Windows Server 2008 R2), в то время как он работает безупречно на всех других компьютерах, к которым у меня есть доступ (Windows 7 Windows Server 2008 и Windows Server 2008 R2). Мне удалось воспроизвести проблему с помощью действительно простого примера приложения, которое более или менее полностью исключает мой код как причину проблемы.
Минимальное приложение, с которым я могу воспроизвести проблему, это небольшая модификация шаблона проекта службы WCF:
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}\nUsername: {1}",
value,
ServiceSecurityContext.Current == null ?
"<null>" :
ServiceSecurityContext.Current.PrimaryIdentity.Name);
}
}
По сути, я включил совместимость с ASP.NET (мне это нужно, потому что реальный код использует HttpHandler для аутентификации), и возвращается имя пользователя аутентифицированного пользователя.
Содержимое web.config
выглядит следующим образом:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="Windows"/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="HttpWindowsBinding" maxReceivedMessageSize="2147483647">
<readerQuotas maxBytesPerRead="2147483647" maxArrayLength="2147483647" maxStringContentLength="2147483647" maxNameTableCharCount="2147483647" maxDepth="2147483647"/>
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
<services>
<service name="TestService.Service1" behaviorConfiguration="ServiceBehavior">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="HttpWindowsBinding"
contract="TestService.IService1" />
<endpoint address="problem"
binding="basicHttpBinding"
bindingConfiguration="HttpWindowsBinding"
contract="TestService.IService1" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Обратите внимание на две конечные точки: одна с адресом по умолчанию, другая с относительным адресом. Вызов первого успешно выполняется даже на проблемном сервере, в то время как вызов второго завершается неудачно со следующей ошибкой:
Exception type: HttpException
Exception message: Failed to Execute URL.
at System.Web.Hosting.ISAPIWorkerRequestInProcForIIS6.BeginExecuteUrl(String url, String method, String childHeaders, Boolean sendHeaders, Boolean addUserIndo, IntPtr token, String name, String authType, Byte[] entity, AsyncCallback cb, Object state)
at System.Web.HttpResponse.BeginExecuteUrlForEntireResponse(String pathOverride, NameValueCollection requestHeaders, AsyncCallback cb, Object state)
at System.Web.DefaultHttpHandler.BeginProcessRequest(HttpContext context, AsyncCallback callback, Object state)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Вызов завершается неудачно только при использовании классического конвейера (он мне нужен из-за HttpHandler, но проблема может быть воспроизведена даже без него). С интегрированным конвейером проблема исчезла. Также, если я отключу аутентификацию Windows, проблема исчезнет:
<binding name="HttpBinding" maxReceivedMessageSize="2147483647">
<readerQuotas maxBytesPerRead="2147483647" maxArrayLength="2147483647" maxStringContentLength="2147483647" maxNameTableCharCount="2147483647" maxDepth="2147483647"/>
<security mode="None">
<transport clientCredentialType="None" />
</security>
</binding>
Я заметил еще одну деталь с зарегистрированным HttpHandler. Значение свойства HttpRequest.CurrentExecutionFilePath для конечной точки с относительным адресом отличается между проблемным сервером (~/Service1.svc/problem
) и рабочими серверами (~/Service1.svc
). Хотя я не очень хорошо знаком с IIS, я подозреваю, что это может намечь на причину проблемы - может быть, что-то связанное с маршрутизацией запросов?
У меня заканчиваются идеи, поэтому я публикую это здесь в надежде, что кто-то поймет, в чем может быть проблема. Любые предложения приветствуются.