WCF + REST:请求数据在哪里?

发布于 2024-08-14 01:10:24 字数 256 浏览 2 评论 0原文

我目前正在开发 WCF RESTful 服务。在 POST 数据的验证中,如果请求 XML 不符合我们的业务规则,我将抛出异常。

目标是如果收到的请求被视为无效,则向相应的工作人员发送电子邮件。但是,除了传入的请求标头、方法和 URI 之外,我还想发送已发布的 XML。

我一直无法找到访问这些数据的方法。在我有机会访问请求正文/数据之前,WCF 实际上是否已销毁它,或者我是否丢失了某些内容?

感谢您的帮助,因为我对为什么无法访问请求数据感到困惑。

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.

The goal is to send an e-mail to the appropriate staff if a request comes in that considered invalid. But, along with the incoming request headers, method and URI, I'd like to also send the XML that was posted.

I have not been able to find a way to access this data. Is WCF actually destroying the request body/data before I have a chance to access it or am I missing something?

Your help is appreciated as I'm confused as to why I can't access the request data.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

姐不稀罕 2024-08-21 01:10:25

下面介绍了如何在不进行反射的情况下执行此操作:

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

如果读取器是 HttpStreamXmlDictionaryReader(就像我的情况一样),则类的方法 ReadContentAsBase64(byte[] buffer, int index, int count) 只需将这些参数传递给 Stream.Read 方法即可。

一旦我有了 byte[],我就会通过 ASCII 编码将字节转换为字符串。为了正确实施,您可以使用内容类型和内容类型。根据 HTTP 规范对消息标头进行编码。

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.

苍白女子 2024-08-21 01:10:25

您可以在 WCF 服务的自定义 HttpModule 中捕获 HttpApplication.Request.InputStrea,读取流并再次在自定义 HttpModule 的事件处理程序中将其位置设置为 0。然后将其存储在会话中并在实际的OperationContract中进一步访问它。

例如:

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;
    }
 }

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;
    }
 }
沉鱼一梦 2024-08-21 01:10:24

不幸的是,这不受支持——我们有类似的需求,并通过反思调用内部成员来做到这一点。我们只是在错误处理程序中使用它(这样我们就可以转储原始请求),但它工作正常。我不会推荐它用于您不拥有和操作的系统(例如,不要将此代码发送给客户),因为它可以随时通过服务包或其他方式进行更改。

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;
}

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;
}
杀手六號 2024-08-21 01:10:24

因此,如果您声明的合同类似于:(

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

您可以使用 XML 代替)
StreamOfData 应该是 HTTP POST 的主体。您可以使用类似的方法反序列化它:

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

至少对我们来说它是这样工作的。您可能想要使用不同的方法将字符串放入 XMLDocument 或其他内容中。这适用于我们的 JSON 帖子。可能不是最优雅的解决方案,但它确实有效。

我希望这有帮助。

格伦

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

烂柯人 2024-08-21 01:10:24

试试这个,

OperationContext.Current.RequestContext.RequestMessage

Try this,

OperationContext.Current.RequestContext.RequestMessage
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文