简体   繁体   中英

WebApi get the post raw body inside a filter

I' creating a log and i need to retrieve the request body to save in db. i created a filter with HttpActionContext. I tried recover via filterContext.Request.Content.ReadAsStringAsync().Result; but it always return me an empty string.

LogFilter.cs

public override void OnActionExecuting(HttpActionContext filterContext)
    {
        try
        {
            Task<string> content = filterContext.Request.Content.ReadAsStringAsync();
            string body = content.Result;

            logModel.RequestLog rl = new logModel.RequestLog();
            rl.IP = ((HttpContextWrapper)filterContext.Request.Properties["MS_HttpContext"]).Request.UserHostAddress;
            rl.Type = filterContext.ControllerContext.RouteData.Values["controller"].ToString().ToUpper();
            rl.URL = filterContext.Request.RequestUri.OriginalString;
            rl.Operation = filterContext.Request.Method.Method;
            rl.RequestDate = DateTime.Now;


            filterContext.ControllerContext.RouteData.Values.Add("reqID", new deviceLog.RequestLog().Add(rl).ID.ToString());
        }
        catch { }
        //return new deviceLog.RequestLog().Add(rl);
        base.OnActionExecuting(filterContext);
    }

Maybe request stream already reached to end. Try reset stream position to beginning:

public class MyAttribute:ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionContext actionContext)
    {
        string rawRequest;
        using (var stream = new StreamReader(actionContext.Request.Content.ReadAsStreamAsync().Result))
        {
            stream.BaseStream.Position = 0;
            rawRequest = stream.ReadToEnd();
        }
    }
}

almost 7 years late... I was tasked to create a filter for a legacy project - about 8 years old - with no patterns or architecture whatsoever.

I tried reading from stream with stream/string async but it doesn't let you read more than once, and it was already read before the action filter - Seek was false, position was readonly.

I tried reflection but it was too much for little gain and again I didn't like it.

I tried getting "MS_HttpContext" but it wasn't in the dictionary.

After 8 hours of research I compromised with getting all the action arguments from the request and just turn them into Json.

For 4.7 framework API:

private string requestBody = "";

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        requestBody = JsonConvert.SerializeObject(actionContext.ActionArguments);

        base.OnActionExecuting(actionContext);
    }

For .NET 5.0:

I use this on OnResultExecuted method. The stream is already read so you need to reposition the request body at 0.

private static async Task<string> FormatRequestBody(HttpRequest request)
        {
            // we set the stream position to 0 to reset the pointer. If this is not done, the read stream will be incorrect and the Body will be empty
            request.Body.Position = 0;
            // We now need to read the request stream.  First, we create a new byte[] with the same length as the request stream...
            var buffer = new byte[Convert.ToInt32(request.ContentLength)];
            //...Then we copy the entire request stream into the new buffer.
            await request.Body.ReadAsync(buffer, 0, buffer.Length);
            // We convert the byte[] into a string using UTF8 encoding...
            //... and send it back...
            return Encoding.UTF8.GetString(buffer);
        }

Hope this helps someone, because I stumbled on this post along with other 15 stackoverflow posts while doing my research.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM