Не удалось выполнить URL при вызове службы WCF с проверкой подлинности Windows - PullRequest
5 голосов
/ 30 марта 2012

У меня проблема со службой 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, я подозреваю, что это может намечь на причину проблемы - может быть, что-то связанное с маршрутизацией запросов?

У меня заканчиваются идеи, поэтому я публикую это здесь в надежде, что кто-то поймет, в чем может быть проблема. Любые предложения приветствуются.

Ответы [ 2 ]

1 голос
/ 09 апреля 2012

У вас включена перезапись URL на IIS?Это пахнет как разрешение какого-то рода. В чем разница между классическим и интегрированным режимами конвейера в IIS7? Может быть полезным.

0 голосов
/ 31 марта 2012

Проблемой может быть адрес "~ / Service1.svc / problem"

Когда адрес "~ / Service1.svc", вызов попадает в файл svc и использует информацию в файле для поиска интерфейса, а затем настройки для этого интерфейса.

Когда вы используете относительный адрес без файла svc, он смотрит на адрес в файле конфигурации.

У вас есть каталог "Service1.svc" на одном из серверов, или это адрес без ".svc" на сервере, где он работает?

...