如何让剃刀从模板服务中的另一个程序集中查找视图
How to have razor find views from another assembly in a template service
我正在尝试从另一个项目加载剃刀视图。我已经进入了几个不同的兔子洞,但到目前为止我还没有找到一种方法来完成这项工作。但是,根据我的研究,似乎有两种主要方法可以使它起作用。
一种选择是使用嵌入式资源,然后将嵌入式文件提供程序连接到 Razor。我可能是错的,但我认为这是 .net core 2.1 之前的方法。我的理解是,在 2.1 Razor 中,视图是在构建时编译的。将其设置为嵌入式将保存实际文件,这对旧的运行时编译很有用。
// Add the embedded file provider to be used with razor view templates
var viewAssembly = typeof(CoreStartup).GetTypeInfo().Assembly;
var fileProvider = new EmbeddedFileProvider(viewAssembly);
services.Configure<RazorViewEngineOptions>(o => o.FileProviders.Add(fileProvider));
services.AddTransient<ITemplateService, TemplateService>();
另一种方法是将视图放在区域文件夹中。我什至发现了一个 sample project 表明你可以做到这一点!但是,我一直无法找到获得相同结果的方法。
此处供参考的是我试图用来查找和呈现剃刀视图的服务。我需要从中获取 html 输出以帮助创建 html 电子邮件模板。
namespace TestApp.Services
{
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.ViewFeatures;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Options;
using Serilog;
public class TemplateService : ITemplateService
{
private readonly IServiceProvider _serviceProvider;
private readonly ITempDataProvider _tempDataProvider;
private readonly IRazorViewEngine _viewEngine;
public TemplateService(
IServiceProvider serviceProvider,
ITempDataProvider tempDataProvider,
IRazorViewEngine viewEngine)
{
this._serviceProvider = serviceProvider;
this._tempDataProvider = tempDataProvider;
this._viewEngine = viewEngine;
}
public async Task<string> RenderTemplateAsync<TViewModel>(string viewPath, TViewModel viewModel)
{
var httpContext = new DefaultHttpContext
{
RequestServices = this._serviceProvider
};
return await RenderTemplateAsync(httpContext, viewPath, viewModel);
}
public async Task<string> RenderTemplateAsync<TViewModel>(HttpContext httpContext, string viewPath, TViewModel viewModel)
{
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
var viewResult = this._viewEngine.FindView(actionContext, viewPath, false);
if (!viewResult.Success)
{
Log.Error("Failed to render template {@viewPath} because it was not found.", viewPath);
throw new FileNotFoundException($"Failed to render template {viewPath} because it was not found.");
}
var viewDictionary = new ViewDataDictionary<TViewModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary());
var tempDataDictionary = new TempDataDictionary(httpContext, this._tempDataProvider);
using (var outputWriter = new StringWriter())
{
try
{
var viewContext = new ViewContext(
actionContext,
viewResult.View,
viewDictionary,
tempDataDictionary,
outputWriter,
new HtmlHelperOptions());
viewContext.ViewData.Model = viewModel;
await viewResult.View.RenderAsync(viewContext);
}
catch (Exception ex)
{
Log.Error(ex, "Failed to render template due to a razor engine failure");
throw;
}
return outputWriter.ToString().Replace("\r\n", string.Empty);
}
}
}
}
我是这样调用服务的。我已经尝试了我能想到的所有可能的字符串来尝试让它工作。问题是我不确定用于查找区域视图的确切格式。所以不知道是不是路由错了还是没接好。
var body = await _templateService.RenderTemplateAsync(HttpContext, "Common/EmailDetails", emailModel);
现在我正在尝试获取 EmailDetails.cshtml 共享视图。
/Areas
/Common
/Views
/Shared
-EmailDetails.cshtml
您可以使用 IViewLocationExpander。请参阅 https://weblogs.asp.net/imranbaloch/view-location-expander-aspnet5-mvc6
请检查这个
这仅适用于在应用程序目录中搜索视图:
public class MyViewLocationExpander : IViewLocationExpander
{
public void PopulateValues(ViewLocationExpanderContext context)
{
}
public virtual IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
return viewLocations.Select(f => f.Replace("/Views/", "/Areas/Common/Views/"));
}
}
启动时 class:
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add( new MyViewLocationExpander());
});
如果您需要从应用的 "outside" 加载视图,请检查:https://www.mikesdotnetting.com/article/301/loading-asp-net-core-mvc-views-from-a-database-or-other-location
我正在尝试从另一个项目加载剃刀视图。我已经进入了几个不同的兔子洞,但到目前为止我还没有找到一种方法来完成这项工作。但是,根据我的研究,似乎有两种主要方法可以使它起作用。
一种选择是使用嵌入式资源,然后将嵌入式文件提供程序连接到 Razor。我可能是错的,但我认为这是 .net core 2.1 之前的方法。我的理解是,在 2.1 Razor 中,视图是在构建时编译的。将其设置为嵌入式将保存实际文件,这对旧的运行时编译很有用。
// Add the embedded file provider to be used with razor view templates
var viewAssembly = typeof(CoreStartup).GetTypeInfo().Assembly;
var fileProvider = new EmbeddedFileProvider(viewAssembly);
services.Configure<RazorViewEngineOptions>(o => o.FileProviders.Add(fileProvider));
services.AddTransient<ITemplateService, TemplateService>();
另一种方法是将视图放在区域文件夹中。我什至发现了一个 sample project 表明你可以做到这一点!但是,我一直无法找到获得相同结果的方法。
此处供参考的是我试图用来查找和呈现剃刀视图的服务。我需要从中获取 html 输出以帮助创建 html 电子邮件模板。
namespace TestApp.Services
{
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.ViewFeatures;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Options;
using Serilog;
public class TemplateService : ITemplateService
{
private readonly IServiceProvider _serviceProvider;
private readonly ITempDataProvider _tempDataProvider;
private readonly IRazorViewEngine _viewEngine;
public TemplateService(
IServiceProvider serviceProvider,
ITempDataProvider tempDataProvider,
IRazorViewEngine viewEngine)
{
this._serviceProvider = serviceProvider;
this._tempDataProvider = tempDataProvider;
this._viewEngine = viewEngine;
}
public async Task<string> RenderTemplateAsync<TViewModel>(string viewPath, TViewModel viewModel)
{
var httpContext = new DefaultHttpContext
{
RequestServices = this._serviceProvider
};
return await RenderTemplateAsync(httpContext, viewPath, viewModel);
}
public async Task<string> RenderTemplateAsync<TViewModel>(HttpContext httpContext, string viewPath, TViewModel viewModel)
{
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
var viewResult = this._viewEngine.FindView(actionContext, viewPath, false);
if (!viewResult.Success)
{
Log.Error("Failed to render template {@viewPath} because it was not found.", viewPath);
throw new FileNotFoundException($"Failed to render template {viewPath} because it was not found.");
}
var viewDictionary = new ViewDataDictionary<TViewModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary());
var tempDataDictionary = new TempDataDictionary(httpContext, this._tempDataProvider);
using (var outputWriter = new StringWriter())
{
try
{
var viewContext = new ViewContext(
actionContext,
viewResult.View,
viewDictionary,
tempDataDictionary,
outputWriter,
new HtmlHelperOptions());
viewContext.ViewData.Model = viewModel;
await viewResult.View.RenderAsync(viewContext);
}
catch (Exception ex)
{
Log.Error(ex, "Failed to render template due to a razor engine failure");
throw;
}
return outputWriter.ToString().Replace("\r\n", string.Empty);
}
}
}
}
我是这样调用服务的。我已经尝试了我能想到的所有可能的字符串来尝试让它工作。问题是我不确定用于查找区域视图的确切格式。所以不知道是不是路由错了还是没接好。
var body = await _templateService.RenderTemplateAsync(HttpContext, "Common/EmailDetails", emailModel);
现在我正在尝试获取 EmailDetails.cshtml 共享视图。
/Areas
/Common
/Views
/Shared
-EmailDetails.cshtml
您可以使用 IViewLocationExpander。请参阅 https://weblogs.asp.net/imranbaloch/view-location-expander-aspnet5-mvc6
请检查这个 这仅适用于在应用程序目录中搜索视图:
public class MyViewLocationExpander : IViewLocationExpander
{
public void PopulateValues(ViewLocationExpanderContext context)
{
}
public virtual IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
return viewLocations.Select(f => f.Replace("/Views/", "/Areas/Common/Views/"));
}
}
启动时 class:
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add( new MyViewLocationExpander());
});
如果您需要从应用的 "outside" 加载视图,请检查:https://www.mikesdotnetting.com/article/301/loading-asp-net-core-mvc-views-from-a-database-or-other-location