2009-08-17 4 views
16

Wie greife ich auf den HTTP-POST-Anfragetext in einem WCF-REST-Dienst zu?Zugriffsanforderungshauptteil in einem WCF-RESTful-Dienst

Hier ist die Service-Definition:

[ServiceContract] 
public interface ITestService 
{ 
    [OperationContract] 
    [WebInvoke(Method = "POST", UriTemplate = "EntryPoint")] 
    MyData GetData(); 
} 

Hier ist die Umsetzung:

public MyData GetData() 
{ 
    return new MyData(); 
} 

ich allerdings den folgenden Code für die Verwendung der HTTP-Anforderung für den Zugriff auf:

IncomingWebRequestContext context = WebOperationContext.Current.IncomingRequest; 

Aber Der IncomingWebRequestContext gibt nur Zugriff auf die Header, nicht auf den Hauptteil.

Danke.

Antwort

0

Ich entschuldige mich für die vorherige Antwort, ich nahm dummerweise an, dass ich gerade WebOperationContext gecastet habe, um den OperationContext zu bekommen, leider ist die wirkliche Antwort viel hässlicher.

Lassen Sie mich dies vorwegnehmen, es muss einen besseren Weg geben!

Zuerst erstellte ich mein eigenes Kontextobjekt, das an das vorhandene OperationContext-Objekt angefügt werden konnte.

public class TMRequestContext : IExtension<OperationContext> { 

    private OperationContext _Owner; 

     public void Attach(OperationContext owner) { 
      _Owner = owner; 
     } 

    public void Detach(OperationContext owner) { 
      _Owner = null; 
     } 

    public static TMRequestContext Current { 
      get { 
       if (OperationContext.Current != null) { 
        return OperationContext.Current.Extensions.Find<TMRequestContext>(); 
       } else { 
        return null; 
       } 
      } 
     } 
} 

Um dieses neue Kontext-Objekt zugreifen zu können, müssen Sie es als eine Erweiterung des aktuellen hinzuzufügen. Ich habe das getan, indem ich eine Nachrichteninspektorklasse erstellt habe.

public class TMMessageInspector : IDispatchMessageInspector { 

     public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { 

      OperationContext.Current.Extensions.Add(new TMRequestContext()); 
      return null; 
     } 
} 

Damit der Nachrichteninspektor funktioniert, müssen Sie ein neues "Verhalten" erstellen. Ich habe dies mit dem folgenden Code gemacht. einen neuen Host durch das Erstellen und Hinzufügen des Verhaltens Objekt manuell in der OnOpening Methode

public class TMServerBehavior : IServiceBehavior { 

     public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { 
      //Do nothing 
     } 

     public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase) { 

      foreach (ChannelDispatcher chDisp in serviceHostBase.ChannelDispatchers) { 

       foreach (EndpointDispatcher epDisp in chDisp.Endpoints) { 
        epDisp.DispatchRuntime.MessageInspectors.Add(new TMMessageInspector()); 
       } 
      } 

     } 
} 

Das Verhalten, das Sie sollten in der Config-Datei hinzufügen können, obwohl ich es tat. Ich benutzte diese Klasse für viel mehr als nur den Zugriff auf das OperationContext-Objekt. Ich benutzte sie zum Loggen und Überschreiben der Fehlerbehandlung und des Zugriffs auf das http - Anfrageobjekt usw. Also, es ist nicht ganz so lächerlich wie es scheint. Fast, aber nicht ganz!

Ich kann mich wirklich nicht erinnern, warum ich nicht direkt auf OperationContext.Current zugreifen konnte. Ich habe eine schwache Erinnerung daran, dass es immer leer war und dieser eklige Prozess die einzige Möglichkeit war, eine Instanz zu erhalten, die tatsächlich gültige Daten enthielt.

+0

Hallo Darrel, Ich versuchte Ihren Vorschlag und stieß auf ein paar Probleme. Wenn ich Ihren genauen Code verwendet habe, habe ich diesen Fehler (zur Kompilierzeit): Kann 'System.ServiceModel.Web.WebOperationContext' nicht in 'System.ServiceModel.OperationContext' konvertieren Und wenn ich es in diesen Code geändert: Zeichenfolge body = OperationContext.Current.RequestContext.RequestMessage.ToString(); Der Körper war zur Laufzeit eine leere Zeichenfolge. Irgendwelche Ideen? Danke, Uri – urini

10

bester Weg, ich denke, ist nicht mit WebOperationContext

[OperationContract] 
[WebInvoke(Method = "POST", UriTemplate = "EntryPoint", BodyStyle = WebMessageBodyStyle.Bare)] 
MyData GetData(System.IO.Stream pStream); 
+0

Der 'BodyStyle' ist standardmäßig auf' WebMessageBodyStyle.Bare' voreingestellt. –

+0

Hmm dies wird nicht funktionieren, wenn URITemplate '{parameter}' – LamonteCristo

+0

dies funktioniert, auch wenn urltemplate params hat. Für mich funktioniert das für rohe XML-Post-Anfrage, aber Lösung mit OperationContext.Current.RequestContext.RequestMessage.ToString() - funktioniert nicht (Ergebnis "... Stream ...") – SalientBrain

1

Es scheint, dass da WCF konzipiert Transportprotokoll unabhängig zu sein, eine Service-Methode keinen Zugang bieten zu HTTP-spezifischen Informationen standardmäßig. Ich bin jedoch auf einen netten Artikel gestoßen, der den "ASP.Net Compatibility Mode" beschreibt, mit dem Sie im Wesentlichen festlegen können, dass Ihr Dienst tatsächlich über HTTP verfügbar gemacht werden soll.

http://blogs.msdn.com/b/wenlong/archive/2006/01/23/516041.aspx

Hinzufügen der aspNetCompatibilityEnabled Konfiguration Web.config, kombiniert mit dem AspNetCompatibilityRequirements Attribut auf den gewünschten Service-Operationen, sollte es tun. Ich werde es selbst versuchen.

Haw-Bin

+0

Wahr, aber es nimmt das Selbst-Hosting weg Fähigkeiten des Dienstes. –

10

Verwenden

OperationContext.Current.RequestContext.RequestMessage

+5

Es gibt Ihnen Nachricht xml und nicht POST body –

1

Die oben genannten Antworten hat mir geholfen, mit dieser Lösung. Ich empfange JSON mit Name/Wert-Paaren. { "P1": 7514, "p2": 3412, "p3": "Joe Smith" ...}

[OperationBehavior(Impersonation = ImpersonationOption.Allowed)] 
    [WebInvoke(Method = "POST", 
     BodyStyle = WebMessageBodyStyle.Bare, 
     RequestFormat = WebMessageFormat.Json 
     )] 

public Stream getJsonRequest() 
    { 

     // Get the raw json POST content. .Net has this in XML string.. 
     string JSONstring = OperationContext.Current.RequestContext.RequestMessage.ToString(); 

     // Parse the XML string into a XML document 
     XmlDocument doc = new XmlDocument(); 
     doc.LoadXml(JSONstring); 

     foreach (XmlNode node in doc.DocumentElement.ChildNodes) 
     { 
       node.Name // has key 
       node.InnerText; // has value 
+0

für xml post Anfrage gibt es mir "... Stream ...", Encoding.UTF8.GetString (OperationContext.Current.RequestContext.RequestMessage.GetBody ()) doesn Ich arbeite auch nicht. Für mich funktioniert [Kasthor] Lösung oder das folgende: var inputStream = OperationContext.Current.RequestContext.RequestMessage.GetBody (); \t \t \t var sr = neuer StreamReader (inputStream, Encoding.UTF8); \t \t \t var str = sr.ReadToEnd(); – SalientBrain

+0

Anstatt über die Knoten zu iterieren, können Sie einen XmlNodeReader aus dem Dokument erstellen und ihn dann in DataContractJsonSerializer.ReadObject() einspeisen, das einen XmlReader akzeptiert. Auf diese Weise sind die Werte, die keine Zeichenfolgen sind, wie z. B. Zahlen und Boolesche Werte, vom richtigen Typ! –

6

Sorry für die späte Antwort, aber ich dachte, ich würde hinzufügen, was mit UriTemplate Parametern arbeitet zu bekommen der Anfragetext.

[ServiceContract] 
public class Service 
{   
    [OperationContract] 
    [WebInvoke(UriTemplate = "{param0}/{param1}", Method = "POST")] 
    public Stream TestPost(string param0, string param1) 
    { 

     string body = Encoding.UTF8.GetString(OperationContext.Current.RequestContext.RequestMessage.GetBody<byte[]>()); 

     return ...; 
    } 
} 

body ist eine Zeichenfolge aus den rohen Bytes des Nachrichtenkörpers zugeordnet.

Verwandte Themen