Обязательные зависимости для Resolver или ServiceProvider для использования ICompositeViewEngine

Я пытаюсь использовать ICompositeViewEngine в ASP.NET Core MVC для замены ViewEngine из System.Web.Mvc, поскольку он больше не доступен в .NET Core. Я обычно пытаюсь перенести веб-форму из ASP.NET в ASP.NET Core в этом проекте.

Я нашел следующее решение:Где находятся свойства ControllerContext и ViewEngines в MVC 6 Controller? и я верю, что это может решить мою проблему. Я также нашел аналогичное создание движка с ServiceProvider в вопросе github:https://github.com/aspnet/Mvc/issues/3091

Тем не менее, я не уверен, какие зависимости или структуры мне могут не хватать, так как я очень новичок в .NET. У меня есть следующие пространства имен:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.DependencyInjection;

Я верю, что это может быть связано с моей проблемой.

Мой оригинальный код:

    public static string RenderPartialToString(Controller controller, string viewName, object model)
    {
        controller.ViewData.Model = model;

        using (StringWriter sw = new StringWriter())
        {
            ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
            ViewContext viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
            viewResult.View.Render(viewContext, sw);

            return "document.write('" + sw.GetStringBuilder().Replace('\n', ' ').Replace('\r', ' ').Replace("'","\\'").ToString() + "');";
        }
    }

И теперь я пытаюсь использовать одно из следующих:

 var engine = Resolver.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
 var engine2 = IServiceProvider.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;

Я на правильном пути, чтобы это исправить? Есть ли более простой способ заменить System.Web.Mvc ViewEngines в .NET Core? Что мне нужно исправить "не существует в текущем контексте"ошибки для Resolver и / или ServiceProvider?

Благодарю. Я надеюсь, что смог следовать принципам вопроса.

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

Ответы на вопрос(1)

Решение Вопроса

Вы в основном на правильном пути. ASP.NET Core избавился от многих статических объектов, поэтому вы не можете делать такие вещи, какResolver.GetService. Resolver не существует Вместо этого используйтевнедрение зависимости система.

Если вам просто нужно получить доступICompositeViewEngine из контроллера вставьте его в конструктор:

public MyController(ICompositeViewEngine viewEngine)
{
    // save a reference to viewEngine
}

Если вы хотите иметь отдельный сервис, который обрабатывает рендеринг Razor-to-string, вам нужно зарегистрировать его при запуске:

public void ConfigureServices(IServiceCollection services)
{
    // (Other code...)

    services.AddTransient<IViewRenderingService, ViewRenderingService>();

    services.AddMvc();
}

Сам сервис будет выглядеть так:

using System;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;

public interface IViewRenderingService
{
    string RenderPartialView(ActionContext context, string name, object model = null);
}

public class ViewRenderingService : IViewRenderingService
{
    private readonly ICompositeViewEngine _viewEngine;
    private readonly ITempDataProvider _tempDataProvider;

    public ViewRenderingService(ICompositeViewEngine viewEngine, ITempDataProvider tempDataProvider)
    {
        _viewEngine = viewEngine;
        _tempDataProvider = tempDataProvider;
    }

    public string RenderPartialView(ActionContext context, string name, object model)
    {
        var viewEngineResult = _viewEngine.FindView(context, name, false);

        if (!viewEngineResult.Success)
        {
            throw new InvalidOperationException(string.Format("Couldn't find view '{0}'", name));
        }

        var view = viewEngineResult.View;

        using (var output = new StringWriter())
        {
            var viewContext = new ViewContext(
                context,
                view,
                new ViewDataDictionary(
                    new EmptyModelMetadataProvider(),
                    new ModelStateDictionary())
                {
                    Model = model
                },
                new TempDataDictionary(
                    context.HttpContext,
                    _tempDataProvider),
                output,
                new HtmlHelperOptions());

            view.RenderAsync(viewContext).GetAwaiter().GetResult();

            return output.ToString();
        }
    }
}

Чтобы использовать его из контроллера, введите и вызовите его:

public class HomeController : Controller
{
    private readonly IViewRenderingService _viewRenderingService;

    public HomeController(IViewRenderingService viewRenderingService)
    {
        _viewRenderingService = viewRenderingService;
    }

    public IActionResult Index()
    {
        var result = _viewRenderingService.RenderPartialView(ControllerContext, "PartialViewName", model: null);
        // do something with the string

        return View();
    }
}

Если вы хотите использовать Razor вне MVC полностью, см.этот ответ.

 Sven15 июн. 2018 г., 14:38
Странно, что это не работает с Razor Pages - модель является нулевой в представлении. Я думаю, что обработка в Razor Pages отличается от стандартной MVC
 Kemal Tezer Dilsiz05 авг. 2016 г., 20:21
Проблема в том, что я использую ViewEngine в общедоступном статическом классе. Он называется Utils и имеет два метода, RenderPartialToString, который я пытаюсь изменить. Если бы это был не статический конструктор, я уверен, что это сработало бы. Какие-либо предложения? Должен ли я попытаться реструктурировать свой проект?
 Kemal Tezer Dilsiz08 авг. 2016 г., 15:43
Да, я вызываю метод RenderPartialToString из контроллеров. Могу ли я реализовать IViewEngineInterface для моего статического класса для прямой ссылки? (Пример использования:return Utils.RenderPartialToString(this, "ContactUsForm", new ContactUs());) (это контроллер, а ContactUs - модель, в которой хранятся некоторые значения из сгенерированной таблицы)
 Nate Barbettini05 авг. 2016 г., 21:59
@KemalTezerDilsiz Да, я думаю, что вы должны реструктурировать эту часть вашего проекта. Наличие статического класса, на который ссылается ваш веб-код, считается антипаттерном для ASP.NET Core. Где вы вызываете RenderPartialToString? С контроллеров?
 Nate Barbettini04 авг. 2016 г., 22:50
@KemalTezerDilsiz Добавлены пространства имен в пример кода службы. Это помогает?
 Kemal Tezer Dilsiz04 авг. 2016 г., 22:36
Я очень благодарен за ваш ответ, но какие ссылки / пространства имен я должен использовать для этих классов / методов?
 Kemal Tezer Dilsiz17 авг. 2016 г., 19:36
Я нашел ту часть, где это создает проблему: я задам новый вопрос и поделюсь ссылкой здесь на случай, если у кого-то возникнет такая же проблема
 Kemal Tezer Dilsiz17 авг. 2016 г., 17:51
Я получаю сообщение об ошибке «Исключение типа« System.InvalidOperationException »возникло в System.Private.CoreLib.ni.dll, но не было обработано в коде пользователя // Дополнительная информация: элемент ViewData, имеющий ключ« InvestorTypeId », имеет вид типа 'System.Int32', но должен иметь тип 'IEnumerable <SelectListItem>'. " вview.RenderAsync(viewContext).GetAwaiter().GetResult(); часть
 Nate Barbettini08 авг. 2016 г., 19:54
Возможно, вы сможете, но это гораздо лучший способ полностью избавиться от статического класса, если вы можете. Вы можете достичь той же функциональности, используя класс обслуживания (такой, как я продемонстрировал выше), где вы вводитеIViewRenderingService в контроллер, а затем назвать его какreturn _viewRenderingService.RenderPartialToString(...)

Ваш ответ на вопрос