小编Pet*_*ano的帖子

ASP.NET Core 禁用响应缓冲

我正在尝试将动态构建的大型 JSON 文件流式传输到客户端(可能是 500 MB+)。由于各种原因,我试图禁用响应缓冲,但主要是为了提高内存效率。

我试过直接写入,HttpContext.Response.BodyWriter但响应似乎在写入输出之前缓冲在内存中。此方法的返回类型是Task

HttpContext.Response.ContentType = "application/json";
HttpContext.Response.ContentLength = null;
await HttpContext.Response.StartAsync(cancellationToken);
var bodyStream = HttpContext.Response.BodyWriter.AsStream(true);
await bodyStream.WriteAsync(Encoding.UTF8.GetBytes("["), cancellationToken);
await foreach (var item in cursor.WithCancellation(cancellationToken)
    .ConfigureAwait(false))
{
    await bodyStream.WriteAsync(JsonSerializer.SerializeToUtf8Bytes(item, DefaultSettings.JsonSerializerOptions), cancellationToken);
    await bodyStream.WriteAsync(Encoding.UTF8.GetBytes(","), cancellationToken);
    
    await bodyStream.FlushAsync(cancellationToken);
    await Task.Delay(100,cancellationToken);
}
await bodyStream.WriteAsync(Encoding.UTF8.GetBytes("]"), cancellationToken);
bodyStream.Close();
await HttpContext.Response.CompleteAsync().ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)

注意:我意识到这段代码很hacky,试图让它工作,然后清理它

我正在使用Task.Delay来验证在本地测试时响应没有被缓冲,因为我没有完整的生产数据。我也试过IAsyncEnumerableand yield return,但失败了,因为响应太大以至于 Kestrel 认为可枚举是无限的。

我试过了

  1. KestrelServerLimits.MaxResponseBufferSize设置为一个较小的数字,甚至 0;
  2. 写作 HttpContext.Response.WriteAsync
  3. 写作 HttpContext.Response.BodyWriter.AsStream()
  4. 用管道作家模式写作和 HttpContext.Response.BodyWriter
  5. 删除所有中间件
  6. 删除呼叫 IApplicationBuilder.UseResponseCompression

更新

  1. 尝试在设置之前禁用响应缓冲ContentType(因此在任何写入响应之前)没有效果 …

c# asp.net asp.net-web-api asp.net-core asp.net-core-webapi

12
推荐指数
1
解决办法
3904
查看次数

HttpClient和HttpRequestHeaders.Range

我正在尝试使用HttpClient仅下载文件的一部分(在此示例中,来自SEC网站).

如果我将RangeHeaderValue设置为> = 4200,我得到文件的一部分(虽然response.Content.Headers.ContentLength说大小是32628字节,这可能是由于压缩).如果我在Fiddler看到请求,我会看到下面Range: bytes=0-4200的标题Miscellaneous.所以我相当自信我正确设置了标题.我无法弄清楚的是2倍,为什么将最大长度设置RangeHeaderValue为小于~4200导致a ContentLength为0(在Fiddler中确认)以及为什么不ContentLength匹配到所请求的范围?

我已经确认(通过查看标题)SEC服务器支持范围(Accept-Ranges: bytes).示例代码如下.

var client = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip });
var request = new HttpRequestMessage { RequestUri = new Uri("http://www.sec.gov/Archives/edgar/full-index/2013/QTR1/company.idx") };
request.Headers.Range = new RangeHeaderValue(0, 1000);

Console.WriteLine(request.Headers.Range.Ranges);
var response = await client.SendAsync(request);
Console.WriteLine(response.Headers);
Console.WriteLine(response.Content.Headers.ContentLength);
Console.WriteLine(response.RequestMessage);
Run Code Online (Sandbox Code Playgroud)

OutputFromProgram

c# httpclient http-headers

6
推荐指数
1
解决办法
3527
查看次数

测试未观察到的异常

我有一个C#Extension方法,可以与任务一起使用,以确保抛出的任何异常都是在最低限度观察到的,以免崩溃托管进程.在.NET4.5中,行为略有改变,因此不会发生这种情况,但仍会触发未观察到的异常事件.我在这里的挑战是编写一个测试来证明扩展方法是有效的.我正在使用NUnit Test Framework,ReSharper是测试运行者.

我试过了:

var wasUnobservedException = false;
TaskScheduler.UnobservedTaskException += (s, args) => wasUnobservedException = true;
var res = TaskEx.Run(() =>
                          {
                              throw new NaiveTimeoutException();
                              return new DateTime?();
                          });
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.IsTrue(wasUnobservedException);
Run Code Online (Sandbox Code Playgroud)

测试总是失败的Assert.IsTrue.当我手动运行此测试时,在LINQPad之类的东西中,我得到了预期的wasUnobservedException回复行为true.

我猜测测试框架正在捕获异常并观察它,以至于TaskScheduler.UnobservedTaskException永远不会被触发.

我尝试修改代码如下:

var wasUnobservedException = false;
TaskScheduler.UnobservedTaskException += (s, args) => wasUnobservedException = true;
var res = TaskEx.Run(async () =>
                          {
                              await TaskEx.Delay(5000).WithTimeout(1000).Wait();
                              return new DateTime?();
                          });
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.IsTrue(wasUnobservedException);
Run Code Online (Sandbox Code Playgroud)

我在此代码中进行的尝试是在抛出异常之前使任务获得GC'd,以便终结器将看到未捕获的,未观察到的异常.然而,这导致了上述相同的故障.

事实上,是否存在某种由测试框架连接的异常处理程序?如果是这样,有办法吗?或者我只是把事情弄得一团糟,有更好/更容易/更清洁的方法吗?

c# extension-methods nunit exception unobserved-exception

6
推荐指数
2
解决办法
863
查看次数

Buffer.BlockCopy与Array.Copy的好奇心

我一直在使用一些.NET功能(即管道,内存和数组池)来进行高速文件读取/解析.我碰到的东西,而与玩弄有趣的Array.Copy,Buffer.BlockCopyReadOnlySequence.CopyTo.IO Pipeline将数据读取为,byte并且我正在尝试有效地将其转换为char.

在玩弄时Array.Copy我发现我能够从中复制byte[]char[]编译器(和运行时)非常乐意这样做.

char[] outputBuffer = ArrayPool<char>.Shared.Rent(inputBuffer.Length);
Array.Copy(buffer, 0, outputBuffer, 0, buffer.Length);
Run Code Online (Sandbox Code Playgroud)

这段代码按预期运行,但我确信这里没有正确处理一些UTF边缘情况.

我的好奇心随之而来 Buffer.BlockCopy

char[] outputBuffer = ArrayPool<char>.Shared.Rent(inputBuffer.Length);
Buffer.BlockCopy(buffer, 0, outputBuffer, 0, buffer.Length);
Run Code Online (Sandbox Code Playgroud)

由此产生的内容outputBuffer是垃圾.例如,使用bufferas 的示例内容

{ 50, 48, 49, 56, 45 }
Run Code Online (Sandbox Code Playgroud)

outputBuffer复制后的内容是

{ 12338, 14385, 12333, 11575, 14385 }
Run Code Online (Sandbox Code Playgroud)

我只是好奇CLR内部正在发生的事情,导致这两个命令输出这些不同的结果.

c#

5
推荐指数
1
解决办法
406
查看次数

使用continue在循环中使用

给出以下示例代码:

var count = 0;
while (count < 5)
{
    using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
    using (var response = await StaticHttpClient.Client.SendAsync(request))
    {
        if (!response.IsSuccessStatusCode)
        {
            switch ((int)response.StatusCode)
            {
                case 500:
                case 504:
                    continue;
            }
        }
        else
        {  ... }
    }

    count++;
}
Run Code Online (Sandbox Code Playgroud)

这些IDisposable对象是否会在此方法中泄漏内存,还是会正确调用Dispose方法?(交换机中缺少许多情况,我并不关心那里的效率).

c# performance idisposable continue while-loop

3
推荐指数
1
解决办法
753
查看次数