locked
Zugriff auf WCF-Dienste RRS feed

  • Frage

  • Hallo,

    ich habe ein Problem beim Zugriff von Silverlight 4 auf WCF-Dienste.

    Die WCF-Dienste hoste ich in einer Consolen-Anwendung bzw. einem Windows-Dienst selber. Zugriff auf die WCF-Dienste erfolgt per https. Das Test-Zertifikat (von Freessl.com) ist auch erfolgreich eingerichtet.

    Wenn ich die Silverlight-Anwendung aus dem IE8 heraus öffne, wird auch beim ersten Aufruf eines WCF-Dienstes die clientaccesspolicy.xml geladen. Hier klappt alles problemlos.

    Wenn ich allerding die Silverlight-Anwendung aus dem Firefox oder Chrome aufrufe, wird zwar die clientaccesspolicy.xml geladen, aber der Aufruf des WCF-Dienstes bringt eine Fehlermeldung:

    Fehler beim Senden einer Anforderung an den URI "https://.../LoginService.svc". Ursache ist möglicherweise, dass ohne die entsprechende domänenübergreifende Richtlinie oder mit einer nicht für SOAP-Dienste geeigneten Richtlinie domänenübergreifend auf einen Dienst zugegriffen wurde. Möglicherweise müssen Sie sich an den Besitzer des Diensts wenden, damit eine domänenübergreifende Richtliniendatei veröffentlicht und das Senden von sich auf SOAP beziehenden HTTP-Headern zugelassen wird. Dieser Fehler kann auch durch Verwendung von internen Typen im Webdienstproxy ohne das InternalsVisibleToAttribute-Attribut verursacht werden. Weitere Details finden Sie in der inneren Ausnahme.

    Die clientaccesspolicy.xml sieht wie folgt aus:

    <?xml version="1.0" encoding="utf-8"?>
    <access-policy>
    <cross-domain-access>
    <policy>
    <allow-from http-request-headers="*">
    <domain uri="http://*"/>
    <domain uri="https://*" />
    </allow-from>
    <grant-to>
    <resource path="/" include-subpaths="true"/>
    </grant-to>
    </policy>
    </cross-domain-access>
    </access-policy>

    Die clientaccesspolicy.xml selber lässt sich in den jeweiligen Browern fehlerfrei über die https-Adresse runterladen.

    Wo kann man ggf. noch etwas einstellen, damit die Anwendung auch in den anderen Browsern läuft?

    VG

    René

    Mittwoch, 3. November 2010 08:10

Antworten

  • Hallo Michael,

     

    ich habe nach langem Probieren letztendlich die Lösung gefunden.

    Es lag gleich an zwei Problemen:
    1. Der ContentType der Response war nicht auf application/xml gestellt.
    2. Der Rückgabestream war nicht UTF-8-kodiert

        [ServiceContract(Namespace = ServiceConsts.Namespace)]
        public interface IClientAccessPolicy
        {
            [System.ServiceModel.Web.WebGet(UriTemplate = "/clientaccesspolicy.xml")]
            [OperationContract]
            Stream GetClientAccessPolicy();
        }
    
        public class PolicyService : IClientAccessPolicy
        {
            [OperationBehavior]
            public Stream GetClientAccessPolicy()
            {
                if (WebOperationContext.Current != null)
                    WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
                return ClientAccessPolicyLoader.Load();
            }
        }

     

        static class ClientAccessPolicyLoader
        {
            static string filename = AppDomain.CurrentDomain.BaseDirectory + "clientaccesspolicy.xml";
            static byte[] buffer = null;
     
            static ClientAccessPolicyLoader()
            {
                if (File.Exists(filename))
                {
                    ReadClientAccessPolicy();
                }
            }
     
            private static void ReadClientAccessPolicy()
            {
                using (StreamReader reader = new StreamReader(filename, Encoding.UTF8))
                {
                    string file = reader.ReadToEnd();
                    buffer = Encoding.UTF8.GetBytes(file);
                }
            }
     
            public static MemoryStream Load()
            {
                if (buffer != null)
                    return new MemoryStream(buffer);
                else
                    return null;
            }
        }


    Gruß

    René

    Donnerstag, 3. November 2011 19:01
  • Hallo Michael,

     

    auch hier kann es verschieden Ursachen geben.

    Gib mal im Browser die URL zu deiner clientaccesspolicy.xml an. Kann diese in allen Browsern geladen werden?

    Wenn du die clientaccesspolicy.xml als Datei auf dem IIS liegen hast, versuch mal, diese als UTF-8 zu speichern.

    Hast du Werkzeuge wie Fiddler oder andere zum "Belauschen" der http-Aktivitäten im Einsatz? Wird versucht, die clientaccesspolicy.xml zu laden?

    Hast du es mal auf anderen Ports versucht?

    Kannst du evtl. ein kleines Testprojekt bauen und mir zusenden, mit dem du das Problem nachstellen kannst?

     

    René

     

    • Als Antwort vorgeschlagen Michael23 Dienstag, 15. November 2011 09:22
    • Als Antwort markiert Robert Breitenhofer Mittwoch, 16. November 2011 12:57
    Montag, 14. November 2011 11:57
  • Hallo René

    Vielen Dank für Deine Antworten! Der Tip bezüglich den Ports hat's gebracht. Es war schlussendlich folgendes Problem:

    http://www.securitypronews.com/news/securitynews/spn-45-20061016SolutiontotheFirefoxportproblem.html

    Merci und Gruss
    Michael

    • Als Antwort vorgeschlagen Michael23 Dienstag, 15. November 2011 09:21
    • Als Antwort markiert Robert Breitenhofer Mittwoch, 16. November 2011 12:57
    Dienstag, 15. November 2011 09:21

Alle Antworten

  • Hallo Rene,

     

    deine Anwendung sieht also wie folgt aus:

    •  Webserver (ISS/Apache) der die Silverlight - Seite ausbringt und die ClientAccessPolicy hostet
    • Anwendungsserver (WCF) als Konsole oder WindowsDienst

    Oder habe ich das falsch verstanden?

    Falls die Aufstellung richtig ist, läuft beides über die gleichen Rechner/Ports? Ist das Zertifikat lokal als Vertrauenswürdig eingetragen oder musst du im Browser jedesmal eine Ausnahme bestätigen?

    Daniel

     


    Gruß Daniel MCPD SharePoint 2010 http://www.silverlight-community.de - Silverlight Community und Usergroups
    Mittwoch, 3. November 2010 22:17
  • Hallo Daniel,

    der WebServer läuft auf Port 80 (http), die WCF-Dienste laufen SSL-verschlüsselt auf Port 443 (https)

    Das Zertifikat wurde von einer vertrauenswürdigen Stammzertifizierungsstelle herausgegeben, die auch auf dem Client und Server in der Liste der vertrauenwürdigen Stammzertifizierungsstellen enthalten ist. Das Zertifikat zum Verschlüsseln muss ja nicht weiter auf dem Client eingerichtet werden, dies ist lediglich auf dem Server unter Lokaler Computer\Eigene Zertifikate registriert.

    Ich kann in jedem Browser ohne eine Ausnahme zu bestätigen die ClientAccessPolicy.xml in der Adresszeile aufrufen (https://www.meinedomaene.de/clientaccesspolicy.xml)

    Wenn ich die Silverlight-Anwendung im FF starte, sehe ich im Fiddler auch, wie das Silverlight-Plugin bzw. der Browser die clientaccesspolicy.xml erfolgreich heruntergeladen hat, bevor der erste eigentliche WCF-Call durchgeführt wird. Aber bei diesem ersten WCF-Call kommt es zu oben genanntem Fehler.

     

    René

     

    Dienstag, 9. November 2010 11:19
  • Hmm,

    du kannst ja mal versuchen die Domain beim "allow-from" komplett freizugeben: <domain uri="*"/>
    Ich kann mangels Zertifikat + Server leider auch nicht testen. Ansonsten würde ich mal direkt den MS - DeveloperSupport fragen.

    Daniel


    silverlight-community.de - deutsche Community mit Tutorials, Blogs und Usergroups
    Freitag, 12. November 2010 14:15
  • Hallo Daniel,

    dein Vorschlag brachte leider auch keine Änderung an der Fehlermeldung.

     

    René

     

    Dienstag, 23. November 2010 09:27
  • Hallo René,

    schaue mal über Fiddler2, was wirklich gesendet wird. Dort kann man meist bessere Fehlermeldungen einsehen und den Verkehr besser kontrollieren.

    Hervoragend Nachvollziehbarkeit ist bei WCF Dienste durch folgendes Tool gewährleistet:

    [Service Trace Viewer-Tool (SvcTraceViewer.exe)]
    http://msdn.microsoft.com/de-de/library/ms732023.aspx

    Es zeigt sogar den Datenverkehr grafisch an und kann beliebig filtern.

    Hier aber auch jemand, der es mal gelöst hatte, indem er auf .NET Framework anstatt auf ClientProfile schaltete (weiter unten im Link, bei dem Kommentaren):

    [Silverlight and non-IIS hosted WCF-services]
    http://chris.59north.com/post/Silverlight-and-non-IIS-hosted-WCF-services.aspx


    ciao Frank
    Mittwoch, 24. November 2010 13:00
  • Hallo Frank,

    im Fiddler sowie in anderen http/https-Trace-Tools sehe ich, dass als letzte Anfragen die beiden Dateien clientaccesspolicy.xml und crossdomain.xml geladen werden. Danach kommt gleich der genannte Fehler.

    Diese beiden Dateien werden aber nur im Firefox und Chrome geladen. Im IE wird nur die clientaccesspolicy.xml geladen und dann erfolgt gleich darauf der Aufruf des ersten Service-Methode.

    Scheinbar macht das Silverlight-Plugin im Firefox und Chrome etwas anderes als im IE, kann das sein? Möglicherweise sind die Dateien nicht korrekt eingestellt? Normalerweise wird doch nur die clientaccesspolicy.xml geladen. Wenn diese geladen werden konnte, wird doch die crossdomain.xml nicht mehr benötigt. Zumindest geht dies aus mehreren Beiträgen im Netz hervor.

    Momentan gebe ich die beiden xml-Dateien als Stream aus. Vielleicht muss hier ein anderer Datentyp gewählt werden?

    Das ServiceTraceTool zeigt mir auch nur die beiden Aufrufe der clientaccesspolicy.xml und crossdomain.xml an. Das ist alles.

    <MessageLogTraceRecord>
    <HttpResponse xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace">
    <StatusCode>OK</StatusCode>
    <WebHeaders>
    <Content-Type>application/octet-stream</Content-Type>
    </WebHeaders>
    </HttpResponse>... Datenstrom ...</MessageLogTraceRecord>

    Donnerstag, 2. Dezember 2010 14:16
  • Wurde hier eine Lösung oder zumindest eine Erkenntnis gefunden?

    Ich habe das selbe Problem mit SL4.0 und Firefox 7.0.1. Meine SL App läuft auf Port 100 und der WCF Service auf 109. Im IE kein Problem, clientaccesspolicy.xml und crossdomain.xml werden berücksichtigt. Im Firefox Cross-Domain Fehlermeldung.

    Thanks,
    Michael

    Donnerstag, 3. November 2011 15:42
  • Hallo Michael,

    da dieser Thread seit fast einem Jahr nicht mehr bearbeitet wird , eröffne bitte einen neuen Thread und füge mehr Details deines Problems hinzu (z.B. die Fehlermeldung)

    Schöne Grüße

    Oliver

    Donnerstag, 3. November 2011 16:15
  • Hallo Michael,

     

    ich habe nach langem Probieren letztendlich die Lösung gefunden.

    Es lag gleich an zwei Problemen:
    1. Der ContentType der Response war nicht auf application/xml gestellt.
    2. Der Rückgabestream war nicht UTF-8-kodiert

        [ServiceContract(Namespace = ServiceConsts.Namespace)]
        public interface IClientAccessPolicy
        {
            [System.ServiceModel.Web.WebGet(UriTemplate = "/clientaccesspolicy.xml")]
            [OperationContract]
            Stream GetClientAccessPolicy();
        }
    
        public class PolicyService : IClientAccessPolicy
        {
            [OperationBehavior]
            public Stream GetClientAccessPolicy()
            {
                if (WebOperationContext.Current != null)
                    WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
                return ClientAccessPolicyLoader.Load();
            }
        }

     

        static class ClientAccessPolicyLoader
        {
            static string filename = AppDomain.CurrentDomain.BaseDirectory + "clientaccesspolicy.xml";
            static byte[] buffer = null;
     
            static ClientAccessPolicyLoader()
            {
                if (File.Exists(filename))
                {
                    ReadClientAccessPolicy();
                }
            }
     
            private static void ReadClientAccessPolicy()
            {
                using (StreamReader reader = new StreamReader(filename, Encoding.UTF8))
                {
                    string file = reader.ReadToEnd();
                    buffer = Encoding.UTF8.GetBytes(file);
                }
            }
     
            public static MemoryStream Load()
            {
                if (buffer != null)
                    return new MemoryStream(buffer);
                else
                    return null;
            }
        }


    Gruß

    René

    Donnerstag, 3. November 2011 19:01
  • Hallo René

    Sieht super aus !! Vielen Dank.

    Kannst Du bitte noch ein paar Ausführungen vornehmen? Z.Bsp. woher kommt ServiceConsts und wo genau muss der Code hin?

    Vielen Dank.

    Michael

    Freitag, 11. November 2011 15:16
  • Hallo Michael,

    >>woher kommt ServiceConsts

    Rene benutzt eine eigene Klasse mit vordefinierten Properties als Konstanten . Du kannst den Namespace aber ausschreiben (URL - Typ: String)

    >>und wo genau muss der Code hin?

    Das Attribut ServiceContract in der obersten Zeile, zeigt das Ziel eigentlich relativ genau. Inwieweit Du dein Service Projekt in einzelne Teile aufgesplittet hast, weiss ich leider nicht.

    Schöne Grüße

    Oliver

     

    Freitag, 11. November 2011 15:45
  • Mir ist nicht klar wo der Code hin muss. Ich habe ein Standard WCF .NET 4.0 Project Template:

        [ServiceContract]
        public interface IService1
        {
    
            [OperationContract]
            string GetData(int value);
    
            [OperationContract]
            CompositeType GetDataUsingDataContract(CompositeType composite);
    
            // TODO: Add your service operations here
        }
    

    Muss ich dieses Interface jetzt ersetzen? Oder einfach in denselbem Namespace?

    Kommt der restliche Code schlicht in den selben Namespace?

    Ist das Namespace Property beim ServiceContract Pflicht?

    Muss ich die Methode

    GetClientAccessPolicy

    noch irgendwo aufrufen oder sollte die automatisch aufgerufen werden?

    Vielen Dank,
    Michael

    Freitag, 11. November 2011 16:18
  • Hallo Michael,

    wenn du einen WCF-Dienst im IIS hostest, brauchst du den ganzen Kram mit dem PolicyService gar nicht machen.
    Da genügt es, im Root-Verzeichnisse deines IIS die Datei clientaccesspolicy.xml abzulegen.

    Bsp.:
    Deinen WCF-Dienst hostest du im IIS unter der Adresse http://www.meine-domaene.de/MeinService/Service1.svc
    Wenn du aus einer Silverlight-Anwendung heraus auf diesen Dienst zugreifen möchtest (und die Silverlight-Anwendung wird nicht zufällig auch unter der Adresse http://www.meine-domaene.de gehostet, ruft Silverlight vor dem ersten Aufruf einer WCF-Dienstmethode die Datei clientaccesspolicy.xml aus dem Root-Verzeichnis des Servers ab, also http://www.meine-domaene.de/clientaccesspolicy.xml. Wenn es diese nicht findet, wird noch versucht die Datei crossdomain.xml aus dem Root-Verzeichnis abzurufen. Wenn auch dies fehlschlägt, bekommst du im Silverlight die berühmte Fehlermeldung: "Fehler beim Senden einer Anforderung an den URI "https://.../LoginService.svc". Ursache ist möglicherweise, dass ohne die entsprechende domänenübergreifende Richtlinie oder mit einer nicht für SOAP-Dienste geeigneten Richtlinie domänenübergreifend auf einen Dienst zugegriffen wurde..."

    Wenn du deinen WCF-Dienst aber nicht im IIS hosten möchtest, sondern in einer eigenen Anwendung (Windows-Dienst oder Windows-Anwendung), musst du deinem Server mitteilen, welche Methode aufgerufen werden soll, wenn von Silverlight die Anfrage nach der clientaccesspolicy.xml (http://www.meine-domaene.de/clientaccesspolicy.xml) kommt.
    Die erreichst du mit dem Attribut [System.ServiceModel.Web.WebGet(UriTemplate = "/clientaccesspolicy.xml")]
    Damit wird automatisch die Methode GetClientAccessPolicy aufgerufen, wenn nach der clientaccesspolicy.xml gesucht wird.

    Du fügst also zu deinem Projekt noch einen weiteren WCF-Dienst hinzu (Code siehe oben) und startest deinen Dienst.

     

    René

     

    Samstag, 12. November 2011 12:48
  • Hallo René

    Es spielt mir keine Rolle, wo der Service gehostet ist. Ich habe das Problem, dass Firefox und Chrome das clientaccesspolicy File nicht respektieren (siehe mein erster Post). Kann das mit Deiner Methode gelöst werden?

    Merci und Gruss
    Michael

    Montag, 14. November 2011 10:51
  • Hallo Michael,

     

    auch hier kann es verschieden Ursachen geben.

    Gib mal im Browser die URL zu deiner clientaccesspolicy.xml an. Kann diese in allen Browsern geladen werden?

    Wenn du die clientaccesspolicy.xml als Datei auf dem IIS liegen hast, versuch mal, diese als UTF-8 zu speichern.

    Hast du Werkzeuge wie Fiddler oder andere zum "Belauschen" der http-Aktivitäten im Einsatz? Wird versucht, die clientaccesspolicy.xml zu laden?

    Hast du es mal auf anderen Ports versucht?

    Kannst du evtl. ein kleines Testprojekt bauen und mir zusenden, mit dem du das Problem nachstellen kannst?

     

    René

     

    • Als Antwort vorgeschlagen Michael23 Dienstag, 15. November 2011 09:22
    • Als Antwort markiert Robert Breitenhofer Mittwoch, 16. November 2011 12:57
    Montag, 14. November 2011 11:57
  • Hallo René

    Vielen Dank für Deine Antworten! Der Tip bezüglich den Ports hat's gebracht. Es war schlussendlich folgendes Problem:

    http://www.securitypronews.com/news/securitynews/spn-45-20061016SolutiontotheFirefoxportproblem.html

    Merci und Gruss
    Michael

    • Als Antwort vorgeschlagen Michael23 Dienstag, 15. November 2011 09:21
    • Als Antwort markiert Robert Breitenhofer Mittwoch, 16. November 2011 12:57
    Dienstag, 15. November 2011 09:21