WCF + REST: Where is the request data?

前端 未结 5 1568
有刺的猬
有刺的猬 2020-12-01 11:23

I\'m currently developing a WCF RESTful service. Within the validation of the POST data, I am throwing exceptions if the request XML does not conform to our business rules.

相关标签:
5条回答
  • 2020-12-01 11:54

    Try this,

    OperationContext.Current.RequestContext.RequestMessage
    
    0 讨论(0)
  • 2020-12-01 11:59

    Here's how you do it without reflection:

    using (var reader = OperationContext.Current.RequestContext.RequestMessage.GetReaderAtBodyContents ()) {
        if (reader.Read ())
            return new string (Encoding.ASCII.GetChars (reader.ReadContentAsBase64 ()));
                    return result;
        }
    }
    

    If the reader is a HttpStreamXmlDictionaryReader (as it was in my case), the class's implementation of the method ReadContentAsBase64(byte[] buffer, int index, int count) simply passes these parameters to the Stream.Read method.

    Once I have the byte[] I convert the bytes to a string via ASCII encoding. For a proper implementation, you could use the content type & encoding from the message's headers to do per HTTP spec.

    0 讨论(0)
  • 2020-12-01 12:00

    You could arrest the HttpApplication.Request.InputStream in a custom HttpModule of the WCF Service, read the stream and again set its position to 0 in the custom HttpModule's event handler. Then store it in session and access it further in the actual OperationContract.

    For example:

    public class CustomModule : IHttpModule
    {
        public void Dispose()
        {
    
        }
    
        public void Init(HttpApplication context)
        {
            context.AcquireRequestState +=context_AcquireRequestState;
        }
    
        void context_AcquireRequestState(object sender, EventArgs e)
        {
            HttpApplication application = sender as HttpApplication;
            Stream str = application.Request.InputStream;
            StreamReader sr = new StreamReader(str);
            string req = sr.ReadToEnd();
            str.Position = 0;
            application.Session["CurrentRequest"] = req;
        }
     }
    
    0 讨论(0)
  • 2020-12-01 12:08

    This unfortunately isn't supported- we had a similar need, and did it by calling internal members with reflection. We just use it in an error handler (so we can dump the raw request), but it works OK. I wouldn't recommend it for a system you don't own and operate though (eg, don't ship this code to a customer), since it can change at any time with a service pack or whatever.

    public static string GetRequestBody()
    {
        OperationContext oc = OperationContext.Current;
    
        if (oc == null)
            throw new Exception("No ambient OperationContext.");
    
        MessageEncoder encoder = oc.IncomingMessageProperties.Encoder;
        string contentType = encoder.ContentType;
        Match match = re.Match(contentType);
    
        if (!match.Success)
            throw new Exception("Failed to extract character set from request content type: " + contentType);
    
        string characterSet = match.Groups[1].Value;
    
        object bufferedMessage = operationContextType.InvokeMember("request",
            BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField,
            null, oc, null);
    
        //TypeUtility.AssertType(bufferedMessageType, bufferedMessage);
    
        object messageData = bufferedMessageType.InvokeMember("MessageData",
            BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetProperty,
            null, bufferedMessage, null);
    
        //TypeUtility.AssertType(jsonBufferedMessageDataType, messageData);
    
        object buffer = jsonBufferedMessageDataType.InvokeMember("Buffer",
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty,
            null, messageData, null);
    
        ArraySegment<byte> arrayBuffer = (ArraySegment<byte>)buffer;
    
        Encoding encoding = Encoding.GetEncoding(characterSet);
    
        string requestMessage = encoding.GetString(arrayBuffer.Array, arrayBuffer.Offset, arrayBuffer.Count);
    
        return requestMessage;
    }
    
    0 讨论(0)
  • 2020-12-01 12:17

    So, if you declare your contract something like:

    [WebInvoke(Method = "POST", UriTemplate = "create", ResponseFormat=WebMessageFormat.Json)]
     int CreateItem(Stream streamOfData);
    

    (you can use XML instead) The streamOfData should be the body of an HTTP POST. You can deserialize it using something like:

     StreamReader reader = new StreamReader(streamId);
     String res = reader.ReadToEnd();
     NameValueCollection coll = HttpUtility.ParseQueryString(res);
    

    It's working like that for us, at least. You may want to use a different approach to get the string into an XMLDocument or something. This works for our JSON posts. Might not be the most elegant solution, but it is working.

    I hope this helps.

    Glenn

    0 讨论(0)
提交回复
热议问题