You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6中RenderAsync调用IViewBufferScope时索引越界问题排查

问题:Razor视图渲染字符串时偶发索引越界异常

在.NET 6环境下,我通过IView将视图渲染为字符串作为邮件内容,99.9%的场景运行正常,但每日会出现3-4次索引越界异常。

相关实现代码

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;

namespace MyRazor.Namespace
{
    public class MyRazor : IMyRazor
    {
        private readonly IRazorViewEngine _viewEngine;
        private readonly ITempDataProvider _tempDataProvider;
        private readonly IServiceProvider _serviceProvider;

        public MyRazor(
            IRazorViewEngine viewEngine,
            ITempDataProvider tempDataProvider,
            IServiceProvider serviceProvider)
        {
            _viewEngine = viewEngine;
            _tempDataProvider = tempDataProvider;
            _serviceProvider = serviceProvider;
        }

        public async Task<string> RenderViewToStringAsync<TModel>(string viewPath, TModel model,
            Action<dynamic> initializeViewBag = null)
        {
            ActionContext actionContext = new ActionContext(new DefaultHttpContext 
                { 
                    RequestServices = _serviceProvider 
                }, 
                new RouteData(), 
                new ActionDescriptor());

            IView view = _viewEngine.FindView(actionContext, viewPath, isMainPage: false).View;

            using (StringWriter writer = new StringWriter())
            {
                ViewContext viewContext = new ViewContext(
                    actionContext,
                    view,
                    new ViewDataDictionary<TModel>(
                        metadataProvider: new EmptyModelMetadataProvider(),
                        modelState: new ModelStateDictionary())
                    {
                        Model = model,
                    },
                    new TempDataDictionary(
                        actionContext.HttpContext,
                        _tempDataProvider),
                    writer,
                    new HtmlHelperOptions());

                initializeViewBag?.Invoke(viewContext.ViewBag);
                await view.RenderAsync(viewContext);

                return writer.ToString();
            }
        }
    }
}

IMyRazor被注册为瞬态服务,触发的异常信息如下:

System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
at System.Collections.Generic.List`1.RemoveAt(Int32 index)
at Microsoft.AspNetCore.Mvc.ViewFeatures.Buffers.MemoryPoolViewBufferScope.GetPage(Int32 pageSize)
at Microsoft.AspNetCore.Mvc.ViewFeatures.Buffers.ViewBuffer.AppendNewPage()

我推测由于IViewBufferScope是作用域服务,当并行调用IMyRazor.RenderViewToStringAsync时,同一作用域下的多个视图上下文产生干扰导致异常,但无法通过测试复现该问题。请问如何复现上述异常?

测试代码

// xunit
[Fact]
public async Task TestFailure()
{
    using (IServiceScope scope = testFixture.TestServer.Host.Services.CreateScope())
    {
        // Microsoft.AspNetCore.Mvc.ViewFeatures.Buffers.IViewBufferScope is scoped
        // IMyRazor is transient 
        IMyRazor builder = scope.ServiceProvider.GetRequiredService<IMyRazor>();

        List<Task<string>> tasks = new List<Task<string>>();
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test", new { }));
        tasks.Add(builder.RenderViewToStringAsync("test2", payload));

        await Task.WhenAll(tasks);

        foreach (var task in tasks)
        {
            Assert.True(task.IsCompletedSuccessfully);
        }
    }
}

内容的提问来源于stack exchange,提问作者SilentTremor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 18:56:02