Frage

Ich schreibe einen Web-Service (mit ASP.NET MVC) und für Support-Zwecke würden wir in der Lage sein wie die Anforderungen und Antwort in so nah wie möglich an das rohen, on-the-Wire-Format einzuloggen ( dh einschließlich HTTP-Methode, Pfad, alle Überschriften und der Körper) in einer Datenbank.

Was ich bin mir nicht sicher ist, wie in dem am wenigsten ‚verstümmelten‘ Art und Weise halten, diese Daten zu erhalten. Ich kann wieder bilden das, was ich die Anfrage glauben, sieht aus wie durch alle Eigenschaften des HttpRequest Objekt Inspektion und eine Zeichenfolge von ihnen bauen (und in ähnlicher Weise für die Antwort), aber ich würde wirklich halten, die eigentliche Request / Response-Daten erhalten möchte das ist auf dem Draht gesendet.

Ich bin glücklich, jeden Abhörmechanismus zu verwenden, wie zum Beispiel Filter, Module, usw., und die Lösung kann auf IIS7 spezifisch sein. Ich würde jedoch lieber nur in verwaltetem Code zu halten.

Jede Empfehlungen?

Edit: Ich nehme zur Kenntnis, dass HttpRequest eine hat SaveAs Verfahren, das die Anforderung auf dem Datenträger speichern kann, aber diese rekonstruiert die Anforderung vom internen Zustand einer Last von internen Hilfsmethoden verwenden, das nicht öffentlich zugänglich ist (ganz, warum dies darf nicht zu einer Einsparung Benutzer bereitgestellte Strom ich weiß nicht). Also es fängt an zu schauen, wie ich mein Bestes werde tun müssen, um die Anfrage / Antworttext von den Objekten zu rekonstruieren ... stöhnen.

Edit 2: Bitte beachten Sie, dass ich sagte, die ganz Anfrage einschließlich Verfahren, Pfad, Header usw. Die aktuellen Reaktionen an den Körperströmen aussehen, das nicht nur diese enthält Informationen.

Bearbeiten 3: niemand Fragen lesen Ist hier? Fünf Antworten bisher und noch nicht ein deuten sogar auf eine Art und Weise die ganze rohe on-the-Wire-Anfrage zu bekommen. Ja, ich weiß, ich kann die Ausgangsströme und die Header erfassen und die URL und die ganze Zeug aus dem Request-Objekt. Ich sagte bereits, dass in der Frage finden Sie unter:

  

Ich kann neu konstituieren, was ich die Anfrage glauben, sieht aus wie durch alle Eigenschaften des Httprequest-Objekt Inspektion und eine Zeichenfolge von ihnen bauen (und in ähnlicher Weise für die Antwort), aber ich würde wirklich halten, die eigentliche Anfrage bekommen / Antwort-Daten, die auf dem Draht gesendet wird.

Wenn Sie wissen, die vollständig Rohdaten (einschließlich Header, URL, HTTP-Methode, etc.) können nicht einfach dann abgerufen werden, die nützlich sein würde wissen. Ebenso, wenn Sie wissen, wie es alle im RAW-Format zu erhalten (ja, ich meine immer noch einschließlich Header, URL, HTTP-Methode, etc.), ohne sie zu rekonstruieren ist, das ist, was ich gefragt, dann wäre das sehr nützlich sein. Aber mir zu sagen, dass ich es von den HttpRequest / HttpResponse Objekten rekonstruieren kann, ist nicht sinnvoll. Ich weiß das. Ich sagte es schon.


Bitte beachten Sie: Bevor Sie beginnt jemand sagen, das ist eine schlechte Idee, oder wird die Skalierbarkeit begrenzen usw., werden wir auch Drosselung, sequenzielle Lieferung werden die Implementierung und Anti-Replay-Mechanismen in einer verteilten Umgebung, so Datenbank Protokollierung ist ohnehin erforderlich. Ich bin nicht auf der Suche für eine Diskussion, ob dies eine gute Idee, ich suche, wie es getan werden kann.

War es hilfreich?

Lösung 7

OK, so dass es wie die Antwort aussieht, ist „nein Sie nicht die Rohdaten erhalten können, haben Sie die Anfrage / Antwort von den Eigenschaften der analysierten Objekte zu rekonstruieren“. Na ja, ich habe den Wiederaufbau getan.

Andere Tipps

Auf jeden Fall ein IHttpModule verwenden und die BeginRequest und EndRequest Ereignisse implementieren.

Alle der „rohen“ Daten vorhanden ist zwischen HttpRequest und HttpResponse, es ist einfach nicht in einem einzigen RAW-Format. Hier werden die benötigten Teile Fiddler-style-Dumps (etwa so nah an rohen HTTP wie es geht) zu bauen:

request.HttpMethod + " " + request.RawUrl + " " + request.ServerVariables["SERVER_PROTOCOL"]
request.Headers // loop through these "key: value"
request.InputStream // make sure to reset the Position after reading or later reads may fail

Für die Antwort:

"HTTP/1.1 " + response.Status
response.Headers // loop through these "key: value"

Beachten Sie, dass Sie können nicht die Antwort Strom lesen, so dass Sie einen Filter auf den Output Stream hinzuzufügen und eine Kopie zu erfassen.

In Ihrem BeginRequest, müssen Sie eine Antwort Filter hinzuzufügen:

HttpResponse response = HttpContext.Current.Response;
OutputFilterStream filter = new OutputFilterStream(response.Filter);
response.Filter = filter;

Shop filter, wo Sie es in dem EndRequest Handler zu bekommen. Ich schlage vor, in HttpContext.Items. Es kann dann die volle Antwortdaten in filter.ReadStream() erhalten.

Dann implementieren OutputFilterStream die Dekorierermuster als Wrapper um einen Strom mit:

/// <summary>
/// A stream which keeps an in-memory copy as it passes the bytes through
/// </summary>
public class OutputFilterStream : Stream
{
    private readonly Stream InnerStream;
    private readonly MemoryStream CopyStream;

    public OutputFilterStream(Stream inner)
    {
        this.InnerStream = inner;
        this.CopyStream = new MemoryStream();
    }

    public string ReadStream()
    {
        lock (this.InnerStream)
        {
            if (this.CopyStream.Length <= 0L ||
                !this.CopyStream.CanRead ||
                !this.CopyStream.CanSeek)
            {
                return String.Empty;
            }

            long pos = this.CopyStream.Position;
            this.CopyStream.Position = 0L;
            try
            {
                return new StreamReader(this.CopyStream).ReadToEnd();
            }
            finally
            {
                try
                {
                    this.CopyStream.Position = pos;
                }
                catch { }
            }
        }
    }


    public override bool CanRead
    {
        get { return this.InnerStream.CanRead; }
    }

    public override bool CanSeek
    {
        get { return this.InnerStream.CanSeek; }
    }

    public override bool CanWrite
    {
        get { return this.InnerStream.CanWrite; }
    }

    public override void Flush()
    {
        this.InnerStream.Flush();
    }

    public override long Length
    {
        get { return this.InnerStream.Length; }
    }

    public override long Position
    {
        get { return this.InnerStream.Position; }
        set { this.CopyStream.Position = this.InnerStream.Position = value; }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        return this.InnerStream.Read(buffer, offset, count);
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        this.CopyStream.Seek(offset, origin);
        return this.InnerStream.Seek(offset, origin);
    }

    public override void SetLength(long value)
    {
        this.CopyStream.SetLength(value);
        this.InnerStream.SetLength(value);
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        this.CopyStream.Write(buffer, offset, count);
        this.InnerStream.Write(buffer, offset, count);
    }
}

Die folgende Erweiterungsmethode auf Httprequest wird eine Zeichenfolge erstellen, die in Fiedler und wiederholt eingefügt werden können.

namespace System.Web
{
    using System.IO;

    /// <summary>
    /// Extension methods for HTTP Request.
    /// <remarks>
    /// See the HTTP 1.1 specification http://www.w3.org/Protocols/rfc2616/rfc2616.html
    /// for details of implementation decisions.
    /// </remarks>
    /// </summary>
    public static class HttpRequestExtensions
    {
        /// <summary>
        /// Dump the raw http request to a string. 
        /// </summary>
        /// <param name="request">The <see cref="HttpRequest"/> that should be dumped.       </param>
        /// <returns>The raw HTTP request.</returns>
        public static string ToRaw(this HttpRequest request)
        {
            StringWriter writer = new StringWriter();

            WriteStartLine(request, writer);
            WriteHeaders(request, writer);
            WriteBody(request, writer);

            return writer.ToString();
        }

        private static void WriteStartLine(HttpRequest request, StringWriter writer)
        {
            const string SPACE = " ";

            writer.Write(request.HttpMethod);
            writer.Write(SPACE + request.Url);
            writer.WriteLine(SPACE + request.ServerVariables["SERVER_PROTOCOL"]);
        }

        private static void WriteHeaders(HttpRequest request, StringWriter writer)
        {
            foreach (string key in request.Headers.AllKeys)
            {
                writer.WriteLine(string.Format("{0}: {1}", key, request.Headers[key]));
            }

            writer.WriteLine();
        }

        private static void WriteBody(HttpRequest request, StringWriter writer)
        {
            StreamReader reader = new StreamReader(request.InputStream);

            try
            {
                string body = reader.ReadToEnd();
                writer.WriteLine(body);
            }
            finally
            {
                reader.BaseStream.Position = 0;
            }
        }
    }
}

Sie die Variable ALL_RAW Server verwenden können, um die ursprünglichen HTTP-Header mit der Anfrage gesendet zu bekommen, dann können Sie die Input wie gewohnt erhalten:

string originalHeader = HttpHandler.Request.ServerVariables["ALL_RAW"];

check out: http://msdn.microsoft .com / en-us / library / ms524602% 28VS.90% 29.aspx

Nun, ich bin an einem Projekt arbeiten und tat, vielleicht auch nicht zu tief, ein Protokoll der Anfrage params mit:

Werfen Sie einen Blick:

public class LogAttribute : ActionFilterAttribute
{
    private void Log(string stageName, RouteData routeData, HttpContextBase httpContext)
    {
        //Use the request and route data objects to grab your data
        string userIP = httpContext.Request.UserHostAddress;
        string userName = httpContext.User.Identity.Name;
        string reqType = httpContext.Request.RequestType;
        string reqData = GetRequestData(httpContext);
        string controller = routeData["controller"];
        string action = routeData["action"];

        //TODO:Save data somewhere
    }

    //Aux method to grab request data
    private string GetRequestData(HttpContextBase context)
    {
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < context.Request.QueryString.Count; i++)
        {
            sb.AppendFormat("Key={0}, Value={1}<br/>", context.Request.QueryString.Keys[i], context.Request.QueryString[i]);
        }

        for (int i = 0; i < context.Request.Form.Count; i++)
        {
            sb.AppendFormat("Key={0}, Value={1}<br/>", context.Request.Form.Keys[i], context.Request.Form[i]);
        }

        return sb.ToString();
    }

Sie können Ihre Controller Klasse dekorieren für sie völlig log:

[Log]
public class TermoController : Controller {...}

oder melden Sie sich nur ein paar einzelne Aktionsmethoden

[Log]
public ActionResult LoggedAction(){...}

Gibt es Gründe, müssen Sie es in verwaltetem Code halten?

Es ist erwähnenswert, dass Sie

Ich ging mit McKAMEY Ansatz. Hier ist ein Modul Ich schrieb die Ihnen beim Einstieg und hoffentlich Sie etwas Zeit sparen. Sie müssen den Logger offensichtlich mit etwas stecken, das funktioniert für Sie:

public class CaptureTrafficModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(context_BeginRequest);
        context.EndRequest += new EventHandler(context_EndRequest);
    }

    void context_BeginRequest(object sender, EventArgs e)
    {
        HttpApplication app = sender as HttpApplication;

        OutputFilterStream filter = new OutputFilterStream(app.Response.Filter);
        app.Response.Filter = filter;

        StringBuilder request = new StringBuilder();
        request.Append(app.Request.HttpMethod + " " + app.Request.Url);
        request.Append("\n");
        foreach (string key in app.Request.Headers.Keys)
        {
            request.Append(key);
            request.Append(": ");
            request.Append(app.Request.Headers[key]);
            request.Append("\n");
        }
        request.Append("\n");

        byte[] bytes = app.Request.BinaryRead(app.Request.ContentLength);
        if (bytes.Count() > 0)
        {
            request.Append(Encoding.ASCII.GetString(bytes));
        }
        app.Request.InputStream.Position = 0;

        Logger.Debug(request.ToString());
    }

    void context_EndRequest(object sender, EventArgs e)
    {
        HttpApplication app = sender as HttpApplication;
        Logger.Debug(((OutputFilterStream)app.Response.Filter).ReadStream());
    }

    private ILogger _logger;
    public ILogger Logger
    {
        get
        {
            if (_logger == null)
                _logger = new Log4NetLogger();
            return _logger;
        }
    }

    public void Dispose()
    {
        //Does nothing
    }
}

Verwenden Sie ein IHttpModule :

    namespace Intercepts
{
    class Interceptor : IHttpModule
    {
        private readonly InterceptorEngine engine = new InterceptorEngine();

        #region IHttpModule Members

        void IHttpModule.Dispose()
        {
        }

        void IHttpModule.Init(HttpApplication application)
        {
            application.EndRequest += new EventHandler(engine.Application_EndRequest);
        }
        #endregion
    }
}

    class InterceptorEngine
    {       
        internal void Application_EndRequest(object sender, EventArgs e)
        {
            HttpApplication application = (HttpApplication)sender;

            HttpResponse response = application.Context.Response;
            ProcessResponse(response.OutputStream);
        }

        private void ProcessResponse(Stream stream)
        {
            Log("Hello");
            StreamReader sr = new StreamReader(stream);
            string content = sr.ReadToEnd();
            Log(content);
        }

        private void Log(string line)
        {
            Debugger.Log(0, null, String.Format("{0}\n", line));
        }
    }

, wenn für den gelegentlichen Gebrauch, bekommen eine enge Kurve um, wie wäre es etwas roh wie unten?

Public Function GetRawRequest() As String
    Dim str As String = ""
    Dim path As String = "C:\Temp\REQUEST_STREAM\A.txt"
    System.Web.HttpContext.Current.Request.SaveAs(path, True)
    str = System.IO.File.ReadAllText(path)
    Return str
End Function

Sie können dies in einem DelegatingHandler erreichen, ohne die OutputFilter in anderen Antworten in .NET 4.5 erwähnt mit dem Stream.CopyToAsync() Funktion.

Ich bin auf die Details nicht sicher, aber es nicht all die schlechten Dinge auslösen, die passieren, wenn Sie versuchen, direkt die Antwort Stream zu lesen.

Beispiel:

public class LoggingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        DoLoggingWithRequest(request);
        var response = await base.SendAsync(request, cancellationToken);
        await DoLoggingWithResponse(response);
        return response;
    }

    private async Task DologgingWithResponse(HttpResponseMessage response) {
        var stream = new MemoryStream();
        await response.Content.CopyToAsync(stream).ConfigureAwait(false);     
        DoLoggingWithResponseContent(Encoding.UTF8.GetString(stream.ToArray()));

        // The rest of this call, the implementation of the above method, 
        // and DoLoggingWithRequest is left as an exercise for the reader.
    }
}

Ich weiß, dass es nicht verwalteten Code, aber ich werde ein ISAPI-Filter suggerieren. Es ist ein paar Jahre her, dass ich das „Vergnügen“ meine eigene ISAPI habe aufrechtzuerhalten, aber von dem, was ich Sie daran erinnern, kann der Zugriff auf all diese Dinge zu bekommen, sowohl vor als auch nach ASP.Net getan hat es Sache.

http://msdn.microsoft.com/en-us/library /ms524610.aspx

Wenn ein Httpmodule ist nicht gut genug für das, was Sie brauchen, dann nur, ich glaube nicht, es gibt jeden verwaltete Weg, dies detailliert in der erforderlichen Menge zu tun. Es wird ein Schmerz sein, obwohl zu tun.

Ich stimme mit den anderen, verwenden Sie einen IHttpModule. Werfen Sie einen Blick auf die Antwort auf diese Frage, die fast die gleiche Sache tut, dass Sie fragen. Es protokolliert die Anfrage und Antwort, aber ohne Header.

Wie Script WebService-Anfragen verfolgen?

Es wäre am besten, diese außerhalb Ihrer Anwendung zu tun. Sie können ein Reverse-Proxy einrichten Dinge wie diese (und vieles mehr) zu tun. Ein Reverse-Proxy ist im Grunde ein Webserver, der im Serverraum sitzt und steht zwischen Ihrem Web-Server (n) und dem Client. Siehe http://en.wikipedia.org/wiki/Reverse_proxy

Vereinbaren Sie mit FigmentEngine, IHttpModule scheint der Weg zu sein, zu gehen.

Schauen Sie in httpworkerrequest, readentitybody und GetPreloadedEntityBody.

Um die httpworkerrequest erhalten Sie müssen dies tun:

(HttpWorkerRequest)inApp.Context.GetType().GetProperty("WorkerRequest", bindingFlags).GetValue(inApp.Context, null);

wo inApp ist das Httpapplication-Objekt.

HttpRequest und HttpResponse pre MVC verwendet, um ein GetInputStream() und GetOutputStream() zu haben, die zu diesem Zweck verwendet werden könnten. schauen nicht in jenen Teil in MVC so Ich bin nicht sicher, dass sie availavle sind aber könnte eine Idee sein:)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top