Как заставить бритву находить виды из другой сборки в сервисе шаблонов - PullRequest
0 голосов
/ 05 октября 2018

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

Один из вариантов - использовать встроенные ресурсы, а затем подключить встроенный файловый провайдер к бритве.Я могу ошибаться, но я думаю, что это подход pre .net core 2.1.Насколько я понимаю, в 2.1 представления Razor компилируются во время сборки.Установка его как встроенного сохранит фактический файл, который будет полезен для более ранней компиляции во время выполнения.

// Add the embedded file provider to be used with razor view templates
var viewAssembly = typeof(CoreStartup).GetTypeInfo().Assembly;
var fileProvider = new EmbeddedFileProvider(viewAssembly);
services.Configure<RazorViewEngineOptions>(o => o.FileProviders.Add(fileProvider));
services.AddTransient<ITemplateService, TemplateService>();

Другой подход - поместить представления в папку областей.Я даже нашел пример проекта , который показывает, что вы можете сделать именно это!Тем не менее, мне не удалось найти способ получить те же результаты.

Для справки вот служба, которую я пытаюсь использовать для поиска и визуализации видов бритвы.Мне нужно получить вывод html, чтобы помочь создать шаблон html-письма.

namespace TestApp.Services
{
    using System;
    using System.IO;
    using System.Threading.Tasks;

    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.ViewFeatures;
    using Microsoft.AspNetCore.Routing;
    using Microsoft.Extensions.Options;

    using Serilog;

    public class TemplateService : ITemplateService
    {
        private readonly IServiceProvider _serviceProvider;
        private readonly ITempDataProvider _tempDataProvider;
        private readonly IRazorViewEngine _viewEngine;

        public TemplateService(
            IServiceProvider serviceProvider,
            ITempDataProvider tempDataProvider,
            IRazorViewEngine viewEngine)
        {
            this._serviceProvider = serviceProvider;
            this._tempDataProvider = tempDataProvider;
            this._viewEngine = viewEngine;
        }

        public async Task<string> RenderTemplateAsync<TViewModel>(string viewPath, TViewModel viewModel)
        {
            var httpContext = new DefaultHttpContext
                                  {
                                      RequestServices = this._serviceProvider
                                  };

            return await RenderTemplateAsync(httpContext, viewPath, viewModel);
        }

        public async Task<string> RenderTemplateAsync<TViewModel>(HttpContext httpContext, string viewPath, TViewModel viewModel)
        {
            var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

            var viewResult = this._viewEngine.FindView(actionContext, viewPath, false);
            if (!viewResult.Success)
            {
                Log.Error("Failed to render template {@viewPath} because it was not found.", viewPath);
                throw new FileNotFoundException($"Failed to render template {viewPath} because it was not found.");
            }

            var viewDictionary = new ViewDataDictionary<TViewModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary());
            var tempDataDictionary = new TempDataDictionary(httpContext, this._tempDataProvider);

            using (var outputWriter = new StringWriter())
            {
                try
                {
                    var viewContext = new ViewContext(
                        actionContext, 
                        viewResult.View, 
                        viewDictionary,
                        tempDataDictionary, 
                        outputWriter, 
                        new HtmlHelperOptions());
                    viewContext.ViewData.Model = viewModel;

                    await viewResult.View.RenderAsync(viewContext);
                }
                catch (Exception ex)
                {
                    Log.Error(ex, "Failed to render template due to a razor engine failure");
                    throw;
                }

                return outputWriter.ToString().Replace("\r\n", string.Empty);
            }
        }
    }
}

Я звоню в службу следующим образом.Я пробовал каждую возможную строку в маршруте, чтобы попытаться заставить ее работать.Проблема в том, что я не уверен, какой именно формат использовать для поиска области.Поэтому я не уверен, что маршрут неправильный или не подключен правильно.

var body = await _templateService.RenderTemplateAsync(HttpContext, "Common/EmailDetails", emailModel);

Сейчас я пытаюсь получить общий вид EmailDetails.cshtml.

/Areas
    /Common
        /Views
            /Shared
                -EmailDetails.cshtml

Ответы [ 2 ]

0 голосов
/ 09 августа 2019

Проверьте это, пожалуйста. Это работает только для поиска представлений в каталоге приложения:

public class MyViewLocationExpander : IViewLocationExpander
{

    public void PopulateValues(ViewLocationExpanderContext context)
    {

    }

    public virtual IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
    {
        return viewLocations.Select(f => f.Replace("/Views/", "/Areas/Common/Views/")); 
    }

}

И в классе запуска:

services.Configure<RazorViewEngineOptions>(options =>
        {                
            options.ViewLocationExpanders.Add( new MyViewLocationExpander());                
        });

Если вам нужно загрузить представление «снаружи» изприложение, проверьте это: https://www.mikesdotnetting.com/article/301/loading-asp-net-core-mvc-views-from-a-database-or-other-location

0 голосов
/ 07 августа 2019

Вы можете использовать IViewLocationExpander.Пожалуйста, смотрите https://weblogs.asp.net/imranbaloch/view-location-expander-aspnet5-mvc6

...