代码之家  ›  专栏  ›  技术社区  ›  Matt W

指定页面的绝对路径

  •  1
  • Matt W  · 技术社区  · 5 年前

    我读过这样的文章 "" 在尝试编写一个完全独立的控制台应用程序以将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
    
    0 回复  |  直到 5 年前