我有以下由 Hangfire 执行的代码(没有 HttpContext),当我在本地运行时运行完美:
class FakeController : ControllerBase
{
protected override void ExecuteCore() { }
public static string RenderViewToString(string controllerName, string viewName, object viewData)
{
using (var writer = new StringWriter())
{
var routeData = new RouteData();
routeData.Values.Add("controller", controllerName);
var fakeControllerContext = new ControllerContext(
new HttpContextWrapper(
new HttpContext(new HttpRequest(null, "http://nopage.no", null)
, new HttpResponse(null))
),
routeData,
new FakeController()
);
var razorViewEngine = new RazorViewEngine();
var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false);
var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer);
razorViewResult.View.Render(viewContext, writer);
return writer.ToString();
}
}
}
Run Code Online (Sandbox Code Playgroud)
然而,我们设置应用程序的方式如下:
https://application.net <- 一个应用程序
https://application.net/admin <- 运行此代码的另一个应用程序。
当我在 上运行代码时https://application.net/admin,出现以下异常:
System.ArgumentException: The virtual path '/' maps to another application, which is not allowed.
Run Code Online (Sandbox Code Playgroud)
它发生在这一行:razorViewEngine.FindView(fakeControllerContext, viewName, "", false)。
我尝试创建自己的 RazorViewEngine 并覆盖了一些方法来查找视图,但无济于事。
class MyViewEngine : RazorViewEngine
{
protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
{
if (!base.FileExists(controllerContext, virtualPath))
return base.FileExists(controllerContext, "~/../admin" + virtualPath.TrimStart('~'));
return true;
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
var newViewPath = viewPath;
if (!base.FileExists(controllerContext, viewPath))
newViewPath = "~/../admin/" + viewPath.TrimStart('~');
return base.CreateView(controllerContext, newViewPath, masterPath);
}
}
Run Code Online (Sandbox Code Playgroud)
这失败了,因为它不想让我离开“目录树的最上层”。
是否有一个简单的解决方法,或者从剃刀视图创建字符串的替代方法?- 目的是创建电子邮件模板。会创建很多电子邮件,我不想使用 HttpClient 要求我自己的端点创建它。
经过多次尝试和失败后,我最终放弃了我的方法,转而使用Rick Strahl 的 WestWind.RazorHosting库。
这是我使用的文档中最重要的部分。
这是我的代码最终的结果。
class FakeController : IDisposable
{
private readonly RazorFolderHostContainer _host;
public FakeController()
{
_host = new RazorFolderHostContainer
{
TemplatePath = $@"{HostingEnvironment.ApplicationPhysicalPath}Views\EmailTemplate\"
};
_host.AddAssemblyFromType(typeof(Controller));
_host.AddAssemblyFromType(typeof(EmailTemplateController.TestViewModel));
_host.Start();
}
public string RenderViewToString(string viewName, object viewData)
{
return _host.RenderTemplate($@"~/{viewName}.cshtml", viewData);
}
public void Dispose()
{
_host.Stop();
}
}
Run Code Online (Sandbox Code Playgroud)
EmailTemplate这会在我的文件夹中查找视图Views,查找我想要使用的 *.cshtml 文件。由于它从文件夹中获取它们Views,我仍然能够在普通控制器中使用相同的视图,因此当我也在端点中使用视图时它也会工作。漂亮。