Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Dotnetcore 3.1中间件HttpContext。在内存测试服务器集成测试期间中间件运行之前,请求已为null_C#_.net Core_Asp.net Core Webapi_Asp.net Core Middleware - Fatal编程技术网

C# Dotnetcore 3.1中间件HttpContext。在内存测试服务器集成测试期间中间件运行之前,请求已为null

C# Dotnetcore 3.1中间件HttpContext。在内存测试服务器集成测试期间中间件运行之前,请求已为null,c#,.net-core,asp.net-core-webapi,asp.net-core-middleware,C#,.net Core,Asp.net Core Webapi,Asp.net Core Middleware,我有一个dotnetcore 3.1 API项目,它接收HTTP请求,将相关数据传递给服务层,然后服务层执行业务逻辑并将数据写入数据库。相当标准的东西。此外,我有一个自定义中间件类,它使用秒表来分析传入请求的执行时间,并将URI、时间戳、经过的时间、请求头/正文、响应状态代码和响应头/正文记录到我的数据库中,以便进行分析和调试 当我在IIS中使用API并使用Postman发布带有给定JSON主体的请求时,一切都正常工作;中间件记录请求,并按预期将数据写入数据库。但是,只有在使用.net中的内存内

我有一个dotnetcore 3.1 API项目,它接收HTTP请求,将相关数据传递给服务层,然后服务层执行业务逻辑并将数据写入数据库。相当标准的东西。此外,我有一个自定义中间件类,它使用秒表来分析传入请求的执行时间,并将URI、时间戳、经过的时间、请求头/正文、响应状态代码和响应头/正文记录到我的数据库中,以便进行分析和调试

当我在IIS中使用API并使用Postman发布带有给定JSON主体的请求时,一切都正常工作;中间件记录请求,并按预期将数据写入数据库。但是,只有在使用.net中的内存内TestServer运行我的集成测试套件时,POST请求才会由于请求正文为空而失败(它是一个空字符串,甚至不是一个空JSON对象)

我怀疑这是由于在中间件读取请求流之后错误地重置了请求流,但令人困惑的是HttpContext。在中间件运行之前,请求已经是空的。在逐步阅读代码时,我已经确认HttpRequestMessage内容设置正确,JSON正确,并且测试在中间件未被使用时通过,因此测试逻辑就我所知不是问题所在。在中间件InvokeAsync中设置断点并检查pHttpContext的值表明内容已经为null

下面是我的控制器代码的简化版本,以及集成测试方法和中间件的代码。任何协助都将不胜感激


控制器方法:

[HttpPost]
public IActionResult Create([FromBody] Widget pWidget)
{
    _WidgetService.CreateWidget(new CreateWidget()
    {
        WidgetNo = pWidget.WidgetNo,
        StatusId = pWidget.StatusId,
        WidgetTypeId = pWidget.WidgetTypeId,
        CreatedBy = pWidget.CreatedBy
    });
    return Ok();
}
试验方法:

[Theory]
[InlineData("/api/v1/widget")]
public async Task PostCreatesWidget(String pUrl)
{
    // Arrange
    List<SelectWidget> originalWidgets = _widgetService.GetAllWidgets().ToList();
    Widget createdWidget = _widgetGenerator.GenerateModel();
    String json = JsonConvert.SerializeObject(createdWidget);
    Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    HttpRequestMessage request = new HttpRequestMessage()
    {
        RequestUri = new Uri(pUrl, UriKind.Relative),
        Content = new StringContent(json, Encoding.UTF8, "application/json"),
        Method = HttpMethod.Post,
    };

    // Act
    HttpResponseMessage response = await Client.SendAsync(request);
    String responseContent = await response.Content.ReadAsStringAsync();

    // Assert
    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
    List<SelectWidget> newWidgets = _widgetService.GetAllWidgets().ToList();
    Assert.True(newWidgets.Count == originalWidgets.Count + 1);
}
[理论]
[InlineData(“/api/v1/widget”)]
公共异步任务PostCreatesWidget(字符串pUrl)
{
//安排
List originalWidgets=_widgetService.GetAllWidgets().ToList();
Widget createdWidget=\u widgetGenerator.GenerateModel();
字符串json=JsonConvert.SerializeObject(createdWidget);
Client.DefaultRequestHeaders.Accept.Add(新的MediaTypeWithQualityHeaderValue(“应用程序/json”);
HttpRequestMessage请求=新建HttpRequestMessage()
{
RequestUri=新Uri(pUrl,UriKind.Relative),
Content=newstringcontent(json,Encoding.UTF8,“application/json”),
方法=HttpMethod.Post,
};
//表演
HttpResponseMessage response=等待客户端.SendAsync(请求);
String responseContent=await response.Content.ReadAsStringAsync();
//断言
Assert.Equal(HttpStatusCode.OK,response.StatusCode);
List newWidgets=_widgetService.GetAllWidgets().ToList();
True(newWidgets.Count==originalWidgets.Count+1);
}
中间件:

public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IRequestLoggingService _requestLoggingService;

    public RequestLoggingMiddleware(RequestDelegate pNext, IRequestLoggingService pRequestLoggingService)
    {
        _next = pNext;
        _requestLoggingService = pRequestLoggingService;
    }

    public async Task InvokeAsync(HttpContext pHttpContext)
    {
        try
        {
            HttpRequest request = pHttpContext.Request;

            if (request.Path.StartsWithSegments(new PathString("/api")))
            {
                Stopwatch stopwatch = Stopwatch.StartNew();
                DateTime requestTime = DateTime.UtcNow;
                String requestBodyContent = await ReadRequestBody(request);
                Stream bodyStream = pHttpContext.Response.Body;

                using (MemoryStream responseBody = new MemoryStream())
                {
                    HttpResponse response = pHttpContext.Response;
                    response.Body = responseBody;
                    await _next(pHttpContext);
                    stopwatch.Stop();

                    String responseBodyContent = null;
                    responseBodyContent = await ReadResponseBody(response);
                    await responseBody.CopyToAsync(bodyStream);

                    await _requestLoggingService.LogRequest(new InsertRequestLog()
                    {
                        DateRequested = requestTime,
                        ResponseDuration = stopwatch.ElapsedMilliseconds,
                        StatusCode = response.StatusCode,
                        Method = request.Method,
                        Path = request.Path,
                        QueryString = request.QueryString.ToString(),
                        RequestBody = requestBodyContent,
                        ResponseBody = responseBodyContent
                    });
                }
            }
            else
            {
                await _next(pHttpContext);
            }
        }
        catch (Exception)
        {
            await _next(pHttpContext);
        }
    }

    private async Task<String> ReadRequestBody(HttpRequest pRequest)
    {
        pRequest.EnableBuffering();

        Byte[] buffer = new Byte[Convert.ToInt32(pRequest.ContentLength)];
        await pRequest.Body.ReadAsync(buffer, 0, buffer.Length);
        String bodyAsText = Encoding.UTF8.GetString(buffer);
        pRequest.Body.Seek(0, SeekOrigin.Begin);

        return bodyAsText;
    }

    private async Task<String> ReadResponseBody(HttpResponse pResponse)
    {
        pResponse.Body.Seek(0, SeekOrigin.Begin);
        String bodyAsText = await new StreamReader(pResponse.Body).ReadToEndAsync();
        pResponse.Body.Seek(0, SeekOrigin.Begin);

        return bodyAsText;
    }
}
公共类requestLogging中间件
{
private readonly RequestDelegate\u next;
专用只读IRequestLoggingService _requestLoggingService;
公共RequestLogging中间件(RequestDelegate pNext、IRequestLoggingService pRequestLoggingService)
{
_next=pNext;
_requestLoggingService=pRequestLoggingService;
}
公共异步任务InvokeAsync(HttpContext pHttpContext)
{
尝试
{
HttpRequest请求=pHttpContext.request;
if(request.Path.StartsWithSegments(新路径字符串(“/api”))
{
秒表秒表=Stopwatch.StartNew();
DateTime requestTime=DateTime.UtcNow;
字符串requestBodyContent=等待ReadRequestBody(请求);
Stream bodyStream=pHttpContext.Response.Body;
使用(MemoryStream responseBody=new MemoryStream())
{
HttpResponse response=pHttpContext.response;
response.Body=responseBody;
等待下一步(pHttpContext);
秒表;
字符串responseByContent=null;
responseBodyContent=等待ReadResponseBody(响应);
wait responseBody.CopyToAsync(bodyStream);
wait_requestLoggingService.LogRequest(新的InsertRequestLog()
{
DateRequested=requestTime,
ResponseDuration=stopwatch.ElapsedMilliseconds,
StatusCode=response.StatusCode,
Method=request.Method,
Path=request.Path,
QueryString=request.QueryString.ToString(),
RequestBody=requestBodyContent,
ResponseBody=responseBodyContent
});
}
}
其他的
{
等待下一步(pHttpContext);
}
}
捕获(例外)
{
等待下一步(pHttpContext);
}
}
私有异步任务ReadRequestBody(HttpRequest pRequest)
{
pRequest.enableBuffer();
Byte[]buffer=新字节[Convert.ToInt32(pRequest.ContentLength)];
wait pRequest.Body.ReadAsync(buffer,0,buffer.Length);
字符串bodyAsText=Encoding.UTF8.GetString(缓冲区);
pRequest.Body.Seek(0,SeekOrigin.Begin);
返回bodyAsText;
}
专用异步任务ReadResponseBody(HttpResponse-pResponse)
{
preponse.Body.Seek(0,SeekOrigin.Begin);
String bodyAsText=等待新的StreamReader(pResponse.Body).ReadToEndAsync();
preponse.Body.Seek(0,SeekOrigin.Begin);
返回bodyAsText;
}
}

我最后回到日志中间件的绘图板上。基于此,我实现了一个更简单的解决方案。此代码在部署和集成测试时都有效

新的中间件代码:

公共类requestLogging中间件
{
私有只读Re