【发布时间】:2018-07-27 14:00:55
【问题描述】:
对于我的项目,我目前为我的 asp.net 核心应用程序实现了 ViewRender。它在没有控制器的情况下生成 html 视图,使用以下代码可以正常工作:
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/
如果不重新启动应用程序本身,则不会更新使用此渲染器的视图所做的更改。深入研究,视图被缓存。源中的评论提到使用_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,据推测视图缓存所在的位置。
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 中为视图完成缓存和清除特定视图/集合的内容并不多。基本上,出于性能原因,我想找到一种方法如何将整个缓存视图选择刷新为命令。
编辑 13-04-2018
按照 K Finley 的建议,我尝试按照建议清空 ViewLookupCache。简而言之就是代码;
在我的 startup.cs ConfigureServices 中(不完全确定这是否是自定义视图引擎的注册方式)。
services.AddSingleton<IRazorViewEngine, CustomViewEngine>();
services.AddSingleton<IViewRenderService, ViewRenderService>();
自定义视图引擎:
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。但是它仍然没有正确更新我的观点。我必须注意视图没有自己的控制器。
【问题讨论】:
-
您是否确认该条目实际上已从集合中删除?我怀疑不是。我的经验是您不能使用简单的构造函数 (new ViewLocationCacheKey(viewName, isLayout);),因为它不会填充键中的其他项。 ViewLocationCacheKey 上的 ControllerName、IsMainPage、ViewLocationExpanderValue 等值必须设置为与 RenderViewEngine 加载和缓存视图时添加到缓存的键相匹配。
-
我可以确认 base.ViewLookupCache 已清空。我没有检查当我在同一个调用中第二次调用该方法时会发生什么。我注册 CustomViewEngine 的方式怎么样,是它应该发生的方式吗?
标签: c# asp.net-mvc caching asp.net-core .net-core