Webservice funktioniert lokal, gibt aber auf Server einen Timeout



  • Ich habe einen WCF-Webservice und einen dazugehörigen Client. Wenn ich das ganze lokal ausführe, funktioniert alles gut. Wenn ich den Webservice jedoch auf einen extra Server deploye und eine Funktion aufrufe, dann bekomme ich einen Timeout.

    Nun zu den merkwürdigen Phänomenen:

    Der Service selbst ist durchaus da. Ich kann ihn in einem Browser aufrufen. Der Timeout kommt nur beim Invoken einer Funktion.

    Wenn der Client ein ungültiges Servicezertifikat angibt, dann weist der Service den Request direkt mit einer entsprechenden Meldung ab. Also auch der Client kann den Service erreichen. Erst wenn das Zertifikat richtig ist (und der Service dann den nächsten Schritt tut), kommt er irgendwie nie in die Funktion rein.

    Die Webservicefunktion ist übrigens ein simples return "Hallo"; . Es ist also nicht möglich, dass die Funktion selbst tatsächlich einfach nur lange braucht, um zum Ende zu kommen, weil der programmierte Code so lang wäre.

    Wenn auf dem Server Visual Studio installiert ist, dann geht es auch! Nur wenn der Server kein Visual Studio installiert hat, passiert das Phänomen.

    Was könnte hier das Problem sein?

    Zum Schluss noch die beiden Config-Dateien, die ich benutze:

    <!-- web.config (Service) -->
    
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <system.webServer>
        <defaultDocument>
          <files>
            <add value="MyService.svc"/>
          </files>
        </defaultDocument>
      </system.webServer>
    
      <system.web>
        <compilation debug="true" targetFramework="4.0" />
      </system.web>
    
      <system.serviceModel>
        <services>
          <service behaviorConfiguration="MyServiceBehavior" name="MyService">
            <endpoint binding="customBinding" bindingConfiguration="MyServiceBinding"
              contract="IMyService" />
          </service>
        </services>
    
        <bindings>
          <customBinding>
            <binding name="MyServiceBinding">
              <textMessageEncoding messageVersion="Soap11" />
              <security
                defaultAlgorithmSuite="Basic128Rsa15"
                allowSerializedSigningTokenOnReply="true"
                authenticationMode="MutualCertificate"
                messageProtectionOrder="SignBeforeEncrypt"
                messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"/>
              <httpsTransport maxBufferSize="5000000" maxReceivedMessageSize="5000000"/>
            </binding>
          </customBinding>
        </bindings>
    
        <behaviors>
          <serviceBehaviors>
            <behavior name="MyServiceBehavior">
              <serviceCredentials>
                <clientCertificate>
                  <authentication
                    certificateValidationMode="Custom"
                    customCertificateValidatorType="CustomX509CertificateValidator, MyService"/>
                </clientCertificate>
                <serviceCertificate
                  storeLocation="CurrentUser"
                  storeName="My"
                  x509FindType="FindByThumbprint"
                  findValue="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" />
              </serviceCredentials>
    
              <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
              <serviceDebug includeExceptionDetailInFaults="true" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
    
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
      </system.serviceModel>
    </configuration>
    
    <!-- app.config (Client) -->
    
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <system.serviceModel>
        <client>
          <endpoint
            name="ServiceClientEndpoint"
            address="https://localhost:12345/"
            behaviorConfiguration="ServiceClientBehavior"
            binding="customBinding"
            bindingConfiguration="ServiceClientBinding"
            contract="IMyService">
    
            <!-- This identity needs to be the same as in the certificate,
                 otherwise the web service call will fail. -->
            <identity>
              <dns value="MyServiceCertificate"/>
            </identity>
          </endpoint>
        </client>
    
        <bindings>
          <customBinding>
            <binding name="ServiceClientBinding">
              <textMessageEncoding messageVersion="Soap11" />
              <security
                defaultAlgorithmSuite="Basic128Rsa15"
                allowSerializedSigningTokenOnReply="true"
                authenticationMode="MutualCertificate"
                messageProtectionOrder="SignBeforeEncrypt"
                messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"/>
              <httpsTransport maxBufferSize="5000000" maxReceivedMessageSize="5000000"/>
            </binding>
          </customBinding>
        </bindings>
    
        <behaviors>
          <endpointBehaviors>
            <behavior name="ServiceClientBehavior">
              <clientCredentials>
                <clientCertificate
                  storeLocation="CurrentUser"
                  storeName="My"
                  x509FindType="FindBySubjectName"
                  findValue="MyClientCertificate"/>
                <serviceCertificate>
                  <authentication revocationMode="NoCheck"/>
                  <scopedCertificates>
                    <!-- The targetUri needs to be the same as the address in endpoint. -->
                    <add
                      targetUri="https://localhost:12345/"
                      storeLocation="CurrentUser"
                      storeName="AddressBook"
                      x509FindType="FindByThumbprint"
                      findValue="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" />
                  </scopedCertificates>
                </serviceCertificate>
              </clientCredentials>
            </behavior>
          </endpointBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>
    


  • Da du sagst, das es funktioniert, wenn Visual Studio vorhanden ist eine Frage: Hast du überprüft ob die benötigte .NET Framework Version installiert ist?



  • Im Zweifelsfall einfach mal das 4.5er Framework installieren.



  • Ja, auf dem Server ist das .NET Framework 4.0 installiert, welches ich auch für meine Projekteinstellung genommen habe.

    Wie gesagt: Der Service selbst startet ja. Es ist nicht so, dass er auf dem Server generell nicht läuft. Dieses Infofenster im Broswer:

    You have created a service.

    To test this service, you will need to create a client and use it to call the service. You can do this using the svcutil.exe tool from the command line with the following syntax:

    das wird alles ganz normal angezeigt.

    Nur das Invoken der Funktion klappt dann nicht. Wobei auch hier der Service prinzipiell erstmal erreicht wird. Denn wenn ich ein falsches Zertifikat übergebe, sagt er mir, dass es falsch ist. Es wird also nicht in jedem Fall eine Timeout-Exception geworfen. Nur dann, wenn credentialmäßig erstmal alles richtig ist und er als nächstes in die eigentliche Webservicefunktion springen sollte. Als wenn der Service zwar die ganzen generellen Prüfungen vornehmen, aber dann seine eigene Webservicefunktion nicht erreichen kann.



  • Nachtrag: Gibt es irgendwas, was zu den Webservices gehört, das beim normalen .NET Framework vielleicht nicht standardmäßig dabei ist und das man manuell nachinstallieren muss, was aber von Visual Studio gleich mitgeliefert wird?



  • Das 4.5er ersetzt das 4.0er komplett. D.h. auch Programme die gegen 4.0 gebaut wurden laufen dann mit dem 4.5er.
    Und es gibt vermutlich auch Dinge, die im 4.0er zwar enthalten sind, aber dann nicht richtig funktionieren.

    Und ja nachdem welche Studio Version du installiert hast, wird da auch das 4.5er Framework mit installiert.

    Von daher würde ich es einfach mal probieren.



  • Als Zusatz noch:

    Der Service selbst ist durchaus da. Ich kann ihn in einem Browser aufrufen. Der Timeout kommt nur beim Invoken einer Funktion.

    Hast du das auf dem Server geprüft (Aufruf im Browser und Invoke der Funktion) oder auf einem anderen System?



  • hustbaer schrieb:

    Und ja nachdem welche Studio Version du installiert hast, wird da auch das 4.5er Framework mit installiert.

    Von daher würde ich es einfach mal probieren.

    Wäre jetzt wahrscheinlich ein bisschen aufwändiger, die Leute dazu zu bringen, das dort zu installieren, ich hab's aber mal weitergegeben.
    Ist es denn realistisch, dass es daran überhaupt liegen könnte?

    inflames2k schrieb:

    Der Service selbst ist durchaus da. Ich kann ihn in einem Browser aufrufen. Der Timeout kommt nur beim Invoken einer Funktion.

    Hast du das auf dem Server geprüft (Aufruf im Browser und Invoke der Funktion) oder auf einem anderen System?

    Das habe ich auf einem anderen System getestet. Der Service liegt auf einem Server und ich rufe den Service von meiner lokalen Maschine aus auf. Im Broswer erscheint der Service und auch in meinem Konsolen-Test-Clientprogramm wird er prinzipiell erstmal erreicht (das sieht man daran, dass er direkt weiß, wenn das Zertifikat nicht passt).
    Nur das Invoken der Funktion per Clienttesttool funktioniert nicht. (Im Browser habe ich übrigens keine Möglichkeit, die Funktion zu invoken. Würde auch wahrscheinlich nicht funktionieren, weil er ja in dieser speziellen Konstellation gar kein Zertifikat vom Client kriegen würde.)



  • Ok, dann versuche mal mittels Konfigurieren von Timeoutwerten das Timeout zu erhöhen.



  • @Starman
    Also ich wundere mich gerade... Visual Studio am Server zu installieren war kein Problem, aber das .NET Framework 4.5 zu installieren wäre "aufwendig"? Echt jetzt?

    Und wenn du wissen willst ob es funktioniert dann stell die Sache halt lokal in einer VM nach...



  • inflames2k schrieb:

    Ok, dann versuche mal mittels Konfigurieren von Timeoutwerten das Timeout zu erhöhen.

    Wie gesagt, es ist nur eine Testfunktion, in der lediglich sowas wie return "Hallo"; steht. Es liegt nicht daran, dass der Algorithmus in der Funktion selbst einfach nur lange braucht. Also würde auch das Hochsetzen des Timeoutwerts nichts nützen. Eine Funktion, die aus einer Zeile besteht, darf nicht einmal eine Minute brauchen, um fertig zu werden.

    hustbaer schrieb:

    @Starman
    Also ich wundere mich gerade... Visual Studio am Server zu installieren war kein Problem, aber das .NET Framework 4.5 zu installieren wäre "aufwendig"? Echt jetzt?

    Nicht die Installation selbst, sondern die Administratoren dazu zu bringen, jetzt irgendwas auf dem Server upzudaten, nur für eine vage Vermutung, an der es dann nachher wahrscheinlich doch nicht liegt.

    Eine andere Frage dazu: Kann es sein, dass in der web.config Knoten fehlen, die gesetzt sein müssen, damit alles funktioniert?
    Die app.config des Clients ist nach einer Spezifikation eines anderen Webservices erstellt. (Also sprich: In der Doku des anderen Webservices stand "So muss eure Clientdatei aussehen, wenn Ihr unseren Service ansprechen wollt.") Und unser Service soll mit denselben Clientprogrammen angesprochen werden können wie dieser andere Service, indem man eben einfach nur die URL umstellt. Leider haben wir auf den anderen Service quellcodetechnisch keinen Zugriff, deshalb ist unsere web.config nur auf Grundlage der Client-app.config aus der Doku des anderen Service erstellt.
    Und deshalb frage ich: Könnte es in der web.config des Servers noch irgendwas geben, was da zwingend reingehört, damit es in jeder Umgebung funktioniert? Oder ist diese Idee prinzipiell erstmal komplett abwegig?



  • Hallo,

    die Timeoutwerte die gesetzt werden können, umfassen nicht nur die Anfragezeit. - Ich dachte eher an den Timeout beim Aufbau der Verbindung. - Probleme an der Konfiguration können natürlich immer vorliegen. - Das lässt sich aber ohne die Anwendungen schwer sagen.

    (Und jetzt poste bitte nicht die Quellcodes von Client und Server)



  • Starman schrieb:

    hustbaer schrieb:

    @Starman
    Also ich wundere mich gerade... Visual Studio am Server zu installieren war kein Problem, aber das .NET Framework 4.5 zu installieren wäre "aufwendig"? Echt jetzt?

    Nicht die Installation selbst, sondern die Administratoren dazu zu bringen, jetzt irgendwas auf dem Server upzudaten, nur für eine vage Vermutung, an der es dann nachher wahrscheinlich doch nicht liegt.

    Lass dir eine Kopie der Server VM machen (bzw. wenns keine VM ist dann mach eine VM Kopie mit VMware Converter o.ä.). Dann bring diese Kopie bei dir online, mach nen Snapshot, und fang an Sachen durchzuprobieren.
    Wenns nix gebracht hat -> revert auf den Snapshot und nächsten Schuss ins Blaue probieren.
    Wenns funktioniert -> Info an Admins dass die den Step im Produktivsystem durchführen sollen.



  • Ich hab jetzt nochmal was anderes rausgefunden:

    Ich habe den Webservice mal auf basicHttpBinding umgestellt. Und jetzt sehe ich konkret, wo es eigentlich hackt: Wenn ich folgendes deklariere:

    <security mode="Message">
      <message clientCredentialType="Certificate"/>
    </security>
    

    dann haben wir dasselbe Problem: Lokal geht alles, aber auf dem Server kommt ein Timeout. Wenn ich jedoch <security mode="None"> schreibe, dann läuft auch auf dem Server alles korrekt durch.

    Weiß einer, was da zu tun ist? Warum hat er Probleme, wenn die Security eingeschaltet ist?


Anmelden zum Antworten