Укажите абсолютный путь к странице бритвы

Я читал такие статьи, как "", когда пытался написать полностью автономное консольное приложение для отображения страницы 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

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

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

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

Программа.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

Возможно, вы видели эту страницу, но она может оказаться полезной. antaris.github.io/RazorEngine

ibrahimozgon 12.03.2019 16:35

Да, пока не собираюсь идти по этому пути. Спасибо за ссылку.

Matt W 12.03.2019 19:43
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
2
434
0

Другие вопросы по теме