Захватите все запросы к Web Api 2.0, независимо от того, сопоставлены они или нет.

У меня есть Web API 2.0, работающий на localhost:4512, и я хочу перехватывать все запросы, сделанные к домену localhost:4512, независимо от того, обрабатываются они по определенному маршруту или нет. Например, я хочу зафиксировать запросы, сделанные localhost:4512/abc.dfsada или localhost:4512/meh/abc.js.

Я пробовал это с помощью DelegatingHandler, но к сожалению это перехватывает только запросы к обработанным маршрутам:

public class ProxyHandler : DelegatingHandler
{
    private async Task<HttpResponseMessage> RedirectRequest(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var redirectLocation = "http://localhost:54957/";
        var localPath = request.RequestUri.LocalPath;
        var client = new HttpClient();
        var clonedRequest = await request.Clone();
        clonedRequest.RequestUri = new Uri(redirectLocation + localPath);

        return await client.SendAsync(clonedRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return RedirectRequest(request, cancellationToken);
    }
}

и в WebConfig.cs:

 config.MessageHandlers.Add(new ProxyHandler());
 config.MapHttpAttributeRoutes();
 config.Routes.MapHttpRoute(
      name: "DefaultApi",
      routeTemplate: "api/{controller}/{id}",
      defaults: new {id = RouteParameter.Optional});

person Tamas Ionut    schedule 07.06.2018    source источник
comment
Вы используете Овин?   -  person Daniel Gimenez    schedule 07.06.2018
comment
Нет, я не использую Owin.   -  person Tamas Ionut    schedule 07.06.2018


Ответы (2)


Вы можете использовать метод Application_BeginRequest в классе Global.asax. Он будет вызываться первым, когда приложение получит запрос

Вот пример:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    var request = ((System.Web.HttpApplication) sender).Request;
}
person Marcus Höglund    schedule 07.06.2018
comment
Это прекрасно работает! Есть ли способ сделать там некоторую обработку и вернуть ответ, если выполняются некоторые условия? - не отправлять запрос дальше по конвейеру? - person Tamas Ionut; 08.06.2018
comment
Однако запрос GET к localhost:54957/app.js не обрабатывается Application_BeginRequest. Есть ли способ перехватить эти запросы? - person Tamas Ionut; 08.06.2018
comment
@TamasIonut хорошо, по умолчанию запросы статических файлов не включены. Проверьте этот ответ для решения stackoverflow. ком/вопросы/27940320/ - person Marcus Höglund; 08.06.2018

Я обнаружил, что лучший способ сделать то, что вы хотите, — использовать промежуточное ПО для перехвата всех запросов и ответов.

public class RequestResponseLoggingMiddleware
{
    private readonly RequestDelegate _next;

    public RequestResponseLoggingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        //First, get the incoming request
        var request = await FormatRequest(context.Request);

        //Copy a pointer to the original response body stream
        var originalBodyStream = context.Response.Body;

        //Create a new memory stream...
        using (var responseBody = new MemoryStream())
        {
            //...and use that for the temporary response body
            context.Response.Body = responseBody;

            //Continue down the Middleware pipeline, eventually returning to this class
            await _next(context);

            //Format the response from the server
            var response = await FormatResponse(context.Response);

            //TODO: Save log to chosen datastore

            //Copy the contents of the new memory stream (which contains the response) to the original stream, which is then returned to the client.
            await responseBody.CopyToAsync(originalBodyStream);
        }
    }

    private async Task<string> FormatRequest(HttpRequest request)
    {
        var body = request.Body;

        //This line allows us to set the reader for the request back at the beginning of its stream.
        request.EnableRewind();

        //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...
        var bodyAsText = Encoding.UTF8.GetString(buffer);

        //..and finally, assign the read body back to the request body, which is allowed because of EnableRewind()
        request.Body = body;

        return $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {bodyAsText}";
    }

    private async Task<string> FormatResponse(HttpResponse response)
    {
        //We need to read the response stream from the beginning...
        response.Body.Seek(0, SeekOrigin.Begin);

        //...and copy it into a string
        string text = await new StreamReader(response.Body).ReadToEndAsync();

        //We need to reset the reader for the response so that the client can read it.
        response.Body.Seek(0, SeekOrigin.Begin);

        //Return the string for the response, including the status code (e.g. 200, 404, 401, etc.)
        return $"{response.StatusCode}: {text}";
    }

Не забудьте использовать промежуточное ПО в файле startup.cs.

 public void Configure(IApplicationBuilder app, IHostingEnvironment env )
    {

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }
        app.UseMiddleware<RequestResponseLoggingMiddleware>();
        app.UseHttpsRedirection();
        app.UseMvc();
    }
person mavi    schedule 24.12.2018