c# - 将 View 渲染为字符串缓存问题

标签 c# asp.net-mvc caching asp.net-core .net-core

对于我的项目,我目前为我的 asp.net 核心应用程序实现了一个 ViewRender。它生成没有 Controller 到 html 的 View ,使用以下代码可以正常工作:

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());
        string viewgerendered = "";
        try
        {
            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);

                viewgerendered = sw.ToString();
                return viewgerendered;
            }
        }
        catch (Exception e)
        {
            object temp = e.Message + " - " + e.StackTrace;
            return temp.ToString();
        }
    }

    public Task RenderToStringAsync(string v)
    {
        throw new NotImplementedException();
    }
}

来源:https://ppolyzos.com/2016/09/09/asp-net-core-render-view-to-string/

对使用此渲染器的 View 所做的更改不会在不重新启动应用程序本身的情况下更新。深入研究, View 被缓存。来源中的评论提到使用 _razorViewEngine.GetView方法应该摆脱我的缓存问题。然而这行不通。

我得到了什么,试图找出一种注册新 ViewRender 的方法,并对 ViewRenderService 稍作修改。
//Seems not to be available on asp.net core 2.0...
services.AddMvc().Configure<MvcViewOptions>(options =>
            {
                options.ViewEngines.Clear();
                options.ViewEngines.Add(typeof(CustomViewEngine));
            });

并重载 RazorViewEngine 以公开 ViewLookupCache,据称 View 缓存所在的位置。
  public class CustomViewEngine : RazorViewEngine
    {
        public CustomViewEngine(
            IRazorPageFactoryProvider pageFactory, 
            IRazorPageActivator pageActivator,
            HtmlEncoder htmlEncoder, 
            IOptions<RazorViewEngineOptions> optionsAccessor, 
            Microsoft.AspNetCore.Razor.Language.RazorProject razorProject, 
            ILoggerFactory loggerFactory, 
            System.Diagnostics.DiagnosticSource diagnosticSource) : 
            base(pageFactory, pageActivator, htmlEncoder, optionsAccessor,razorProject,loggerFactory, diagnosticSource){ }

        public void RemoveCachedView(string view)
        { 
            this.ViewLookupCache.Remove(view);
        }
    }

关于如何在 asp.net core 2.0 中为 View 完成缓存和清除特定 View /集的内容并不多。基本上,出于性能原因,我想找到一种方法,如何将整个缓存 View 选择刷新为命令。

编辑 13-04-2018

正如 K Finley 所建议的,我尝试按照建议清空 ViewLookupCache。代码简而言之;

在我的 startup.cs ConfigureServices (不完全确定这是否是自定义 View 引擎的注册方式)。
    services.AddSingleton<IRazorViewEngine, CustomViewEngine>();
    services.AddSingleton<IViewRenderService, ViewRenderService>();

自定义 View 引擎:
public class CustomViewEngine : RazorViewEngine
{
    public CustomViewEngine(
        IRazorPageFactoryProvider pageFactory,
        IRazorPageActivator pageActivator,
        HtmlEncoder htmlEncoder,
        IOptions<RazorViewEngineOptions> optionsAccessor,
        Microsoft.AspNetCore.Razor.Language.RazorProject razorProject,
        ILoggerFactory loggerFactory,
        System.Diagnostics.DiagnosticSource diagnosticSource) :
        base(pageFactory, pageActivator, htmlEncoder, optionsAccessor, razorProject, loggerFactory, diagnosticSource)
    { }


    public void RemoveViewFromCache(string viewName, string controller, bool isLayout, bool isPartial = false, string pageName = null, string areaName = null)
    {   
        var key = new ViewLocationCacheKey(viewName, controller, areaName, pageName, !isLayout | !isPartial, isLayout ? null : new Dictionary<string, string>(StringComparer.Ordinal));        
        base.ViewLookupCache.Remove(key);
    }

    public void RemoveViewFromCache(string viewName, bool isLayout)
    {
        //Code uses this one
        var key = new ViewLocationCacheKey(viewName, isLayout);  
        base.ViewLookupCache.Remove(key);    
    }
}

并修改了原来的ViewRenderService...
    public class ViewRenderService : IViewRenderService
    {
        private CustomViewEngine _razorViewEngine;
        private ITempDataProvider _tempDataProvider;
        private IServiceProvider _serviceProvider;
        private IHostingEnvironment _hostingEnvironment;


        public ViewRenderService(IRazorViewEngine razorViewEngine,
            ITempDataProvider tempDataProvider,
            IServiceProvider serviceProvider, 
            IHostingEnvironment hostingEnvironment)
        {
            _razorViewEngine = (CustomViewEngine)razorViewEngine;
...

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

这些修改确实使用第二种方法删除了 ViewLookupCache。但是它仍然没有正确更新我的观点。我必须注意 View 没有自己的 Controller 。

最佳答案

您需要启用文件观察器:
添加环境变量DOTNET_USE_POLLING_FILE_WATCHER=trueENV DOTNET_USE_POLLING_FILE_WATCHER=true在 Dockerfile 中。

关于c# - 将 View 渲染为字符串缓存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48830519/

相关文章:

c# - WCF 服务无法返回 1/1/0001 DateTime

c# - 为什么我需要在一种情况下将位图转换为图像,而在另一种情况下不需要?

docker - 在提交时自动更新我的 package.json 是否会禁用 docker build 以重用缓存?

postgresql - 内存中数据的典型大小与数据库元组中数据的典型大小是多少?

java - 配置缓存 (Java/MySQL)

c# - NuGet 包应支持哪些 .NET 版本以最大限度地提高其可用性和功能?

c# - 更好的收藏或更好的字典搜索方式

asp.net-mvc - C# razor url 参数 View

c# - MVC EF 不断寻找 userId,这很昂贵

c# - 为什么用户必须输入正确的凭据两次?