Укажите абсолютный путь к странице бритвы - PullRequest
2 голосов
/ 12 марта 2019

Я читал подобные статьи "" , пытаясь написать полностью автономное консольное приложение для отображения страницы Razor в строку.

Мой уникальный (казалось бы) вариант использования состоит в том, что я также хочу предоставить страницу бритвы через строковый ввод, а не локальную папку /Views.

Пока у меня есть готовое репо , у меня возникают проблемы с указанием где для загрузки файлов *.cshtml, так как я хочу предоставить их в определенном месте.

Допустим, ради аргумента, что они (по крайней мере, во время разработки) находятся в папке над папкой консольного проекта, например:

/sln
  sln.sln
  /console
    console.csproj
    Program.cs
  /razor
    /views
      MyView.cshtml

Если я выгружаю весь соответствующий код из репозитория, я могу запустить программу, но я получаю ошибку при выполнении страницы бритвы:

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

Я предполагаю, что это потому, что страница находится за пределами папки проекта приложения, поэтому вопрос в том, как мне обойти это? Можно ли динамически создать страницу бритвы и разрешить ее загрузку для выполнения?

Проще говоря, как я могу указать расположение бритвенных страниц за пределами папки решения или проекта? Или можно загрузить страницу бритвы в виде строки и передать ее в память двигателя?

Код, который у меня (почти) работает, следующий (сильно сжатый из различных репозиториев и статей, которые я нашел):

Program.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());
        }
    }
}

MyView.cshtml:

@model Razor2Pdf.MyModel

Testing
...