将视图渲染为字符串:ArgumentOutOfRangeException

时间:2017-06-08 19:01:30

标签: c# asp.net asp.net-mvc asp.net-core razorengine

我有一个asp.net核心应用程序,我有一个名为ViewRenderService的服务,它将视图转换为字符串,以便我根据正在发出的请求呈现某些视图。

ViewRenderService:

public class ViewRenderService : IViewRenderService
    {
        private readonly IRazorViewEngine _razorViewEngine;
        private readonly ITempDataProvider _tempDataProvider;
        private readonly IServiceProvider _serviceProvider;

        public ViewRenderService(IRazorViewEngine razorViewEngine,
            ITempDataProvider tempDataProvider,
            IServiceProvider serviceProvider)
        {
            _razorViewEngine = razorViewEngine;
            _tempDataProvider = tempDataProvider;
            _serviceProvider = serviceProvider;
        }

        public async Task<string> RenderToStringAsync(string viewName, object model)
        {
            var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
            var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

            using (var sw = new StringWriter())
            {
                var viewResult = _razorViewEngine.GetView(viewName, viewName, false);

                if (viewResult.View == null)
                {
                    throw new ArgumentNullException($"{viewName} does not match any available view");
                }

                var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
                {
                    Model = model
                };

                var viewContext = new ViewContext(
                    actionContext,
                    viewResult.View,
                    viewDictionary,
                    new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
                    sw,
                    new HtmlHelperOptions()
                );

                await viewResult.View.RenderAsync(viewContext);
                return sw.GetStringBuilder().ToString();
            }
        }
    }

该行:

await viewResult.View.RenderAsync

引发

  

&#34; System.ArgumentOutOfRangeException:索引超出范围。一定是   非负数且小于集合的大小。参数名称:   索引&#34;

在某些模型/视图

视图和模型它会抛出异常:

VerifyCodeViewModel:

public class VerifyCodeViewModel
    {
        [Required (ErrorMessage = "Please enter verification code that was sent via email")]
        public string Code { get; set; }
        public string ReturnUrl { get; set; }
    }

Verify.cshtml

@model VerifyCodeViewModel


<div class="row">
    <div class="col s12 m5 l5 push-m3 push-l3 center">
        <div class="center">
            <br />
            <form method="post" asp-action="Verify">
                <div class="card">
                    <div class="card-content">
                        <div class="red-text text-bold" asp-validation-summary="ModelOnly"></div>
                        <div class="row">
                            <div class="col 12 m12 l12">
                                <h4 class="text-bold header caption-uppercase">Verification Token Required</h4>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col s12 m12 l12">
                                <p class="center-align">
                                    An email that contains a token have been sent to you. Please enter token below.
                                </p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="input-field col 12 m12 l12">
                                <i class="mdi-communication-vpn-key prefix"></i>
                                <input type="text" asp-for="Code" placeholder="Enter token here"/>
                                <span asp-validation-for="Code"></span>
                                <span class="text-bold red-text">@ViewBag.Message</span>
                            </div>
                        </div>
                    </div>
                    <div class="card-action">
                        <button type="submit" class="btn btn-danger">Verify</button>
                    </div>
                </div>
            </form>
        </div>
    </div>
</div>

@section Scripts {
    @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}

指导我,因为它适用于某些观点,但不适用于上述观点。

1 个答案:

答案 0 :(得分:4)

我遇到了同样的问题,通过检查我的调用堆栈找到了答案。我身边的问题是:

at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) 
at System.Collections.Generic.List`1.get_Item(Int32 index)
at Microsoft.AspNetCore.Mvc.Routing.UrlHelper.get_Router()
at Microsoft.AspNetCore.Mvc.Routing.UrlHelper.GetVirtualPathData(String routeName, RouteValueDictionary values)
at Microsoft.AspNetCore.Mvc.Routing.UrlHelper.Action(UrlActionContext actionContext)

因此路由器丢失了,并且通过将代码更改为以下内容来解决此问题:

public class ViewRenderService : IViewRenderService
{
    private readonly IRazorViewEngine _razorViewEngine;
    private readonly ITempDataProvider _tempDataProvider;
    private readonly IServiceProvider _serviceProvider;
    private readonly HttpContext _context;

    public ViewRenderService(IRazorViewEngine razorViewEngine,
        ITempDataProvider tempDataProvider,
        IServiceProvider serviceProvider,
        IHttpContextAccessor accessor)
    {
        _razorViewEngine = razorViewEngine;
        _tempDataProvider = tempDataProvider;
        _serviceProvider = serviceProvider;
        _context = accessor.HttpContext;
    }

    public async Task<string> RenderToStringAsync(string viewName, object model)
    {
        var actionContext = new ActionContext(_context, new RouteData(), new ActionDescriptor());

        using (var sw = new StringWriter())
        {
            var viewResult = _razorViewEngine.GetView(viewName, viewName, false);

            if (viewResult.View == null)
            {
                throw new ArgumentNullException($"{viewName} does not match any available view");
            }

            var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
            {
                Model = model
            };

            var viewContext = new ViewContext(
                actionContext,
                viewResult.View,
                viewDictionary,
                new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
                sw,
                new HtmlHelperOptions()
            );
            viewContext.RouteData = _context.GetRouteData();

            await viewResult.View.RenderAsync(viewContext);
            return sw.GetStringBuilder().ToString();
        }
    }
}

实际帮助的是将上下文从新的ActionContext更改为注入的ActionContext。通过更改此设置然后设置RouteData,问题得以解决。

        viewContext.RouteData = _context.GetRouteData();