Mam problem z usługą WCF z uwierzytelnianiem systemu Windows na jednym z serwerów, na których go wdrażam (jest to komputer z systemem Windows Server 2008 R2), ale działa bezbłędnie na wszystkich innych komputerach, do których mam dostęp (Windows 7, Windows Server 2008 i Windows Server 2008 R2). Udało mi się odtworzyć problem za pomocą naprawdę prostej przykładowej aplikacji, która mniej lub bardziej całkowicie wyklucza mój kod jako przyczynę problemu.Nieudane wykonanie adresu URL podczas wywoływania usługi WCF z uwierzytelnianiem systemu Windows
Minimalna aplikacja mogę odtworzyć problem ze jest niewielka modyfikacja szablonu projektu usług 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);
}
}
Zasadniczo włączona kompatybilność ASP.NET (muszę, bo rzeczywisty kod wykorzystuje HttpHandler dla uwierzytelnianie) i zwracana jest nazwa użytkownika uwierzytelnionego użytkownika.
Zawartość web.config
są następujące:
<?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>
zauważy dwa punkty końcowe: jeden z domyślnym adresem, drugi ze względnym adresem. Wywołanie pierwszy udaje się nawet na serwerze problematycznej, natomiast rozmowa z drugim nie powiedzie się z następującym błędem:
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)
Wezwanie tylko zawodzi, gdy używany jest klasyczny rurociąg (muszę ją ze względu na HttpHandler, ale problem można odtworzyć nawet bez niego). Dzięki zintegrowanemu rurociągowi problem już minął. Ponadto, jeśli wyłączę uwierzytelnianie systemu Windows, problem również minął:
<binding name="HttpBinding" maxReceivedMessageSize="2147483647">
<readerQuotas maxBytesPerRead="2147483647" maxArrayLength="2147483647" maxStringContentLength="2147483647" maxNameTableCharCount="2147483647" maxDepth="2147483647"/>
<security mode="None">
<transport clientCredentialType="None" />
</security>
</binding>
Zauważyłem inny szczegół z zarejestrowanym HttpHandler. Wartość właściwości HttpRequest.CurrentExecutionFilePath dla punktu końcowego z adresem względnym różni się między problematycznym serwerem (~/Service1.svc/problem
) a działającymi serwerami (~/Service1.svc
). Chociaż nie jestem dobrze zaznajomiony z IIS, podejrzewam, że może to wskazywać na przyczynę problemu - może coś związanego z routingiem żądań?
Brakuje mi pomysłów, dlatego zamieszczam to tutaj w nadziei, że ktoś rozpozna, jaki może być problem. Wszelkie sugestie są mile widziane.
Czy masz włączone przepisywanie adresów URL w IIS? To pachnie jak pewnego rodzaju pozwolenie. [Jaka jest różnica między klasycznym i zintegrowanym trybem potoku w IIS7?] (Http://stackoverflow.com/questions/3062709/what-is-the-difference-between-classic-and-integrated-pipeline-mode-in- iis7) Może być pomocne. –
@PetarVucetin Sprawdziłem i przepisywanie adresów URL nie jest włączone na serwerze.Chociaż twój komentarz nie odpowiedział dokładnie na moje pytanie, podany link dał mi kilka pomysłów - udało mi się przekonfigurować moją aplikację, aby działała ze zintegrowanym trybem potoku, w którym problem się nie objawia. Nadal chciałbym wiedzieć, jak sprawić, by działało w klasycznym trybie potokowym, ale jeśli nie dostanę lepszej odpowiedzi wyjaśniającej, że dla mnie, twój komentarz jest najlepszym kandydatem do nagrody. W końcu udało mi się rozwiązać natychmiastowy problem. –
Dzięki Damir. Kiedy mam trochę czasu, mogę spróbować naprawić ten problem. Po prostu łaskocze moją debugowanie kości ... –