我读过这样的文章
""
在尝试编写一个完全独立的控制台应用程序以将Razor页面呈现为字符串时。
我的独特(似乎)用例是,我还希望通过字符串输入而不是本地输入来提供razor页面
/Views
文件夹。
当我有
off-the-shelf
repo
工作中,我很难具体说明
哪里
加载
*.cshtml
来自的文件,因为我想在特定位置提供它们。
为了便于论证,假设它们(至少在开发过程中)位于控制台项目文件夹上方的文件夹中,例如:
/sln
sln.sln
/console
console.csproj
Program.cs
/razor
/views
MyView.cshtml
如果我从repo中转储所有相关代码,我可以运行该程序,但在执行razor页面时出现错误:
One or more compilation failures occurred:
bkrmmc1j.kzc(4,20): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(5,19): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(4,82): error CS0518: Predefined type 'System.Type' is not defined or imported
bkrmmc1j.kzc(4,116): error CS0518: Predefined type 'System.String' is not defined or imported
bkrmmc1j.kzc(4,133): error CS0518: Predefined type 'System.String' is not defined or imported
bkrmmc1j.kzc(5,81): error CS0518: Predefined type 'System.String' is not defined or imported
bkrmmc1j.kzc(5,106): error CS0518: Predefined type 'System.Type' is not defined or imported
bkrmmc1j.kzc(9,11): error CS0246: The type or namespace name 'System' could not be found (are you missing a using directive or an assembly reference?)
bkrmmc1j.kzc(10,11): error CS0246: The type or namespace name 'System' could not be found (are you missing a using directive or an assembly reference?)
bkrmmc1j.kzc(11,11): error CS0246: The type or namespace name 'System' could not be found (are you missing a using directive or an assembly reference?)
bkrmmc1j.kzc(12,11): error CS0246: The type or namespace name 'System' could not be found (are you missing a using directive or an assembly reference?)
bkrmmc1j.kzc(13,11): error CS0246: The type or namespace name 'Microsoft' could not be found (are you missing a using directive or an assembly reference?)
bkrmmc1j.kzc(14,11): error CS0246: The type or namespace name 'Microsoft' could not be found (are you missing a using directive or an assembly reference?)
bkrmmc1j.kzc(15,11): error CS0246: The type or namespace name 'Microsoft' could not be found (are you missing a using directive or an assembly reference?)
bkrmmc1j.kzc(16,14): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(16,78): error CS0518: Predefined type 'System.String' is not defined or imported
bkrmmc1j.kzc(16,87): error CS0518: Predefined type 'System.String' is not defined or imported
bkrmmc1j.kzc(16,132): error CS0518: Predefined type 'System.String' is not defined or imported
bkrmmc1j.kzc(17,42): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(20,67): error CS1983: The return type of an async method must be void, Task or Task<T>
bkrmmc1j.kzc(20,39): error CS0400: The type or namespace name 'System' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(28,24): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(28,118): error CS0518: Predefined type 'System.Void' is not defined or imported
bkrmmc1j.kzc(30,24): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(30,71): error CS0518: Predefined type 'System.Void' is not defined or imported
bkrmmc1j.kzc(32,24): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(32,87): error CS0518: Predefined type 'System.Void' is not defined or imported
bkrmmc1j.kzc(34,24): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(34,83): error CS0518: Predefined type 'System.Void' is not defined or imported
bkrmmc1j.kzc(36,24): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(36,71): error CS0518: Predefined type 'System.Object' is not defined or imported
bkrmmc1j.kzc(36,102): error CS0518: Predefined type 'System.Void' is not defined or imported
bkrmmc1j.kzc(20,67): error CS0115: '_Views_MyView.ExecuteAsync()': no suitable method found to override
bkrmmc1j.kzc(27,18): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(29,18): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(31,18): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(33,18): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(35,18): error CS0400: The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?)
bkrmmc1j.kzc(22,13): error CS0518: Predefined type 'System.Object' is not defined or imported
bkrmmc1j.kzc(22,13): error CS0103: The name 'BeginContext' does not exist in the current context
bkrmmc1j.kzc(22,26): error CS0518: Predefined type 'System.Int32' is not defined or imported
bkrmmc1j.kzc(22,30): error CS0518: Predefined type 'System.Int32' is not defined or imported
bkrmmc1j.kzc(22,33): error CS0518: Predefined type 'System.Boolean' is not defined or imported
bkrmmc1j.kzc(23,13): error CS0518: Predefined type 'System.Object' is not defined or imported
bkrmmc1j.kzc(23,13): error CS0103: The name 'WriteLiteral' does not exist in the current context
bkrmmc1j.kzc(23,26): error CS0518: Predefined type 'System.String' is not defined or imported
bkrmmc1j.kzc(24,13): error CS0518: Predefined type 'System.Object' is not defined or imported
bkrmmc1j.kzc(24,13): error CS0103: The name 'EndContext' does not exist in the current context
bkrmmc1j.kzc(20,67): error CS0161: '_Views_MyView.ExecuteAsync()': not all code paths return a value
我假设这是因为页面在应用程序项目文件夹之外,所以问题是如何绕过这个问题?是否可以动态创建razor页面并允许加载以执行?
更简单地说,如何将razor页面的位置指定在解决方案或项目文件夹之外?或者可以将razor页面作为字符串加载并提供给内存中的引擎?
我(几乎)使用的代码是这样的(从我发现的各种回购协议和文章中大量压缩):
程序.cs:
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Internal;
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.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.ObjectPool;
using Microsoft.Extensions.PlatformAbstractions;
namespace Razor2Pdf
{
public class Program
{
public static void Main(string[] args)
{
var str = RazorRenderer.DoHtml();
}
}
public class MyModel { }
public class RazorRenderer
{
public static string DoHtml()
{
var slnpath = $@"{Directory.GetCurrentDirectory()}\..\..\..\..";
var razorpath = $@"{slnpath}\RazorPages";
var viewname = "MyView";
var renderer = GetRenderer();
var html = renderer.RenderViewToString(razorpath, viewname, new MyModel());
return html;
}
private static RazorViewToStringRenderer GetRenderer()
{
var services = new ServiceCollection();
var applicationEnvironment = PlatformServices.Default.Application;
services.AddSingleton(applicationEnvironment);
var appDirectory = Directory.GetCurrentDirectory();
var environment = new HostingEnvironment
{
ApplicationName = Assembly.GetEntryAssembly().GetName().Name
};
services.AddSingleton<IHostingEnvironment>(environment);
services.Configure<RazorViewEngineOptions>(options =>
{
options.FileProviders.Clear();
options.FileProviders.Add(new PhysicalFileProvider(appDirectory));
options.FileProviders.Add(new PhysicalFileProvider($@"{appDirectory}\..\..\..\..\RazorPages"));
});
services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore");
services.AddSingleton<DiagnosticSource>(diagnosticSource);
services.AddLogging();
services.AddMvc();
services.AddSingleton<RazorViewToStringRenderer>();
var provider = services.BuildServiceProvider();
return provider.GetRequiredService<RazorViewToStringRenderer>();
}
}
public class RazorViewToStringRenderer
{
private IRazorViewEngine _viewEngine;
private ITempDataProvider _tempDataProvider;
private IServiceProvider _serviceProvider;
public RazorViewToStringRenderer(
IRazorViewEngine viewEngine,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
{
_viewEngine = viewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
public string RenderViewToString<TModel>(string razorpath, string viewName, TModel model)
{
var actionContext = GetActionContext();
var view = FindView(actionContext, razorpath, viewName);
using (var output = new StringWriter())
{
var viewContext = new ViewContext(
actionContext,
view,
new ViewDataDictionary<TModel>(
metadataProvider: new EmptyModelMetadataProvider(),
modelState: new ModelStateDictionary())
{
Model = model
},
new TempDataDictionary(
actionContext.HttpContext,
_tempDataProvider),
output,
new HtmlHelperOptions());
view.RenderAsync(viewContext);
return output.ToString();
}
}
private IView FindView(ActionContext actionContext, string razorpath, string viewName)
{
var getViewResult = _viewEngine.GetView(executingFilePath: null, viewPath: viewName, isMainPage: true);
if (getViewResult.Success)
{
return getViewResult.View;
}
var findViewResult = _viewEngine.FindView(actionContext, viewName, isMainPage: false);
if (findViewResult.Success)
{
return findViewResult.View;
}
var searchedLocations = getViewResult.SearchedLocations.Concat(findViewResult.SearchedLocations);
var errorMessage = string.Join(
Environment.NewLine,
new[] { $"Unable to find view '{viewName}'. The following locations were searched:" }.Concat(searchedLocations)); ;
throw new InvalidOperationException(errorMessage);
}
private ActionContext GetActionContext()
{
var dict = new RouteValueDictionary();
dict.Add("razor", @"C:\git\Dink2Pdf\ConsoleApp1\RazorPages");
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = _serviceProvider;
return new ActionContext(httpContext, new RouteData(dict), new ActionDescriptor());
}
}
}
我的视图.cshtml:
@model Razor2Pdf.MyModel
Testing