2009-03-12 5 views
2

Ich versuche, einen Web-Service-Client in Silverlight für einen RESTful WCF-Dienst zu programmieren, den ich entwickelt habe. In Silverlight konstruiere ich den Körper der WebRequest mit einer DataContractSerializer-Instanz.Wie kann ich WCF OperationContract-Nachrichtentext manuell erstellen?

Dieser Ansatz funktioniert gut, wenn es ein einziges Argument für den OperationContract gibt. Es funktioniert nicht so gut, wenn im OperationContract mehrere Argumente definiert sind. Ich glaube, dies liegt daran, dass ein dynamischer Typ von WCF erstellt wird, der nach dem OperationContract benannt ist, und die Member dieses Typs nach den für die Operation definierten Parametern benannt sind. Der Zweck des dynamischen Typs besteht darin, sicherzustellen, dass ein einzelnes XML-Element im Nachrichtentext vorhanden ist, der an den WCF-Dienst übergeben wird. Frage: Wie konstruiere ich diesen dynamischen Typ selbst, damit ich ihn selbst an den DataContractSerializer senden kann?

Das erste Beispiel ist ein Arbeitsbeispiel, das einen einzelnen Parameter definiert. Zweites Beispiel ist das Szenario, das ich zu lösen versuche (mehrere Parameter).


Beispiel 1:

[OperationContract, 
WebInvoke(Method = HttpMethodType.Post, 
    BodyStyle = WebMessageBodyStyle.Bare, 
    UriTemplate = "UnregisterProvider"), 
WebHelp(Comment = "Unregistered the provider type with the specified URI.")] 
void UnregisterProvider(RdfUri providerUri); 

-Code verwendet Nachrichtenkörper serialisieren:

StringBuilder msgBody = new StringBuilder(250); 
using (XmlWriter xw = XmlWriter.Create(msgBody)) 
{ 
    var serializer = new DataContractSerializer(typeof(RdfUri)); 
    serializer.WriteObject(xw, providerUri); 
} 

resultierende Körper:

<RdfUri xmlns="http://schemas.datacontract.org/2004/07/Intellidimension.Rdf">esp:semanticserver</RdfUri> 

Beispiel 2:

[OperationContract, 
WebInvoke(Method = HttpMethodType.Post, 
    BodyStyle = WebMessageBodyStyle.WrappedRequest, /* WrappedRequest must somehow signal WCF to create the anonymous type as it is required for multiple parameter OperationContracts */ 
    UriTemplate = "RegisterProvider"), 
WebHelp(Comment = "Registered a provider type with the specified URI.")] 
void RegisterProvider(PoolableEntityServiceProviderDescriptor descriptor, RdfUri providerUri); 

-Code verwendet Nachrichtentext serialisiert:

//????? 

resultierende Körper:

<RegisterProvider xmlns="http://tempuri.org/"> 
    <descriptor i:type="a:SemanticServerProviderDescriptor" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:a="http://schemas.datacontract.org/2004/07/Intellidimension.RdfEntity.Service.DataContracts"> 
    <a:ConnectionString>Data Source=.\sqlexpress;Initial Catalog=RdfTest1;Persist Security Info=True;User ID=sa;Password=password</a:ConnectionString> 
    <a:ProviderGraphUri>http://entitystore/graph-provider</a:ProviderGraphUri> 
    </descriptor> 
    <providerUri>esp:semanticserver</providerUri> 
</RegisterProvider> 

Update 1:

Hier ist ein Typ in den MSDN-Foren, die eine ähnliche Frage stellen: Can I use DataContractSerializerOperationFormatter to format a list of parameters from client to server?

DataContractSerializerOperationFormatter ist eine interne Klasse. Sieht so aus, als müsste ich sein Verhalten für meinen Kunden implementieren.

Update 2:

Einige fragen sich, warum ich gerade nicht das normale Silverlight WCF-Client von einer Service-Referenz erzeugt. Der Grund dafür ist, dass der WCF-Dienst auf dem Server ein REST-fähiger Dienst ist. Von der docs:

Kein Analog zur WebHttpBinding in WCF zur Verfügung gestellt wird. Verwenden Sie für den Zugriff auf reine HTTP-, REST-, RSS/Atom- oder AJAX-Dienste von Silverlight 2 die in Direkt auf HTTP-basierte Dienste zugreifen wie in der WebClient-Klasse beschriebenen Techniken. Informationen zum Zugriff auf ASP.NET AJAX-Dienste finden Sie unter Zugreifen auf ASP.NET AJAX Services.

Antwort

0

Lassen Sie mich Ihnen eine Frage zurückgeben. Sagen wir, du kannst das zum Laufen bringen.Was ist der Inhaltstyp des POST-Anfragetexts?

Sie missbrauchen HTTP, indem Sie versuchen, so zu tun, dass ein POST zwei Dinge senden kann. Wenn Sie das tun wollen, was Sie tun, dann verwenden Sie regelmäßig WCF-Serviceverträge. Es ist einfach, mehrere Parameter mit diesen zu senden.

Das Problem mit System.ServiceModel.Web ist, dass es nur 90% entkoppelt den Client von WCF. Damit die Dinge wirklich funktionieren, benötigen Sie WCF auf der Client-Seite. Warum nicht bei den regelmäßigen WCF-Serviceverträgen bleiben?

Wenn Sie HTTP wirklich so verwenden möchten, wie es beabsichtigt war, dann verwenden Sie eine Technologie, die Ihnen helfen wird, statt zu behindern.

+0

Ich denke, das ist das zweite Mal, dass Sie mir gesagt haben, WCF nicht zu benutzen :) Ich finde das etwas amüsant. Ich schätze Ihre Ausdauer. Es gibt nicht mehrere Dinge, die im POST-Body veröffentlicht werden, obwohl es ein Element gibt, das auf dem Server in mehrere Methodenparameter verpackt und zerlegt wird. –

+0

Außerdem verwende ich Silverlight und verwende den DataContractSerializer, weil es bequem ist, aber ich sehe nicht, wie WCF verlangt, dass der Klient WCF auch in irgendeiner Weise hat. Ein RESTful WCF-Endpunkt ist derselbe wie jeder andere RESTful-Endpunkt. Recht? –

+0

Ich sage nicht, dass es nicht möglich ist, einen Nicht-WCF-Client zu erstellen, der mit einem WCF-Dienst kommuniziert, aber Sie werden viele Probleme haben. Versuchen Sie, einen Stream an einen WCF-Endpunkt zu senden. Versuchen Sie, Basic Auth mit einem nicht Windows-Benutzernamen auszuführen. Versuchen Sie, einen Fehler zurückzugeben, der nicht die Standard-HTML-Seite ist. –

1

Ich habe nicht wirklich versucht, aber this article könnte haben, was Sie wollen. Er schuf eine wickelte Nachricht, indem Sie diese:

private void ConsumeWcfRest() 
    { 
     string url = "http://something/MyWebsite/tagservice"; 

     Tag tag1 = new Tag() { ID = 1, TagName = "test1" }; 
     Tag tag2 = new Tag() { ID = 2, TagName = "test2" }; 

     HttpWebRequest req = HttpWebRequest.Create(url + "/tags/wrapped/1") as HttpWebRequest; 
     req.Method = "POST"; 
     string content = "<DoSomethingWrapped xmlns='http://mytagservice'>"; 
     content = content + DoSerialize(tag1, "tag1"); 
     content = content + DoSerialize(tag2, "tag2"); 
     content = content + "</DoSomethingWrapped>"; 

     // ..... 
    } 

    private string DoSerialize(object obj, string rootName) 
    { 
     System.Runtime.Serialization.DataContractSerializer se; 
     if (string.IsNullOrEmpty(rootName)) 
      se = new System.Runtime.Serialization.DataContractSerializer(obj.GetType()); 
     else 
      se = new System.Runtime.Serialization.DataContractSerializer(obj.GetType(), rootName, ""); 

     System.IO.MemoryStream ms = new System.IO.MemoryStream(); 
     se.WriteObject(ms, obj); 
     ms.Position = 0; 
     byte[] arr = new byte[ms.Length]; 
     ms.Read(arr, 0, Convert.ToInt32(ms.Length)); 
     return new System.Text.UTF8Encoding().GetString(arr); 
    } 

Also im Grunde ist er die normale DataContractSerializer unter Verwendung jedes Argument serialisiert werden, dann setzen manuell XML-Tags um die. Es scheint ein wenig hacky, aber es könnte funktionieren ...

Sie möchten mit der Dekompilierung der WCF-Bibliotheken beginnen und sehen, ob Sie herausfinden können, wie WCF es in erster Linie tut.

Verwandte Themen