Как можно RenderPartialToString в asp.net Core 2? - PullRequest
0 голосов
/ 15 мая 2018

Мне нужно визуализировать некоторый частичный вид в виде строки в ядре 2?

Кто-нибудь может помочь мне создать это?

1 Ответ

0 голосов
/ 15 мая 2018

Как-то так?

Интерфейс

using System.Threading.Tasks;

namespace DL.SO.Framework.Mvc.ViewEngine
{
    public interface IRazorViewRenderer
    {
        Task<string> RenderToStringAsync<T>(T model, string viewPath);
    }
}

Реализация

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.Options;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace DL.SO.Framework.Mvc.ViewEngine
{
    public class SimpleRazorViewRenderer : IRazorViewRenderer
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IRazorViewEngine _razorViewEngine;
        private readonly ITempDataProvider _tempDataProvider;
        private readonly IServiceProvider _serviceProvider;
        private readonly IOptions<MvcViewOptions> _viewOptions;

        public SimpleRazorViewRenderer(IHttpContextAccessor httpContextAccessor,
            IRazorViewEngine razorViewEngine,
            ITempDataProvider tempDataProvider,
            IServiceProvider serviceProvider,
            IOptions<MvcViewOptions> viewOptions)
        {
            _httpContextAccessor = httpContextAccessor;
            _razorViewEngine = razorViewEngine;
            _tempDataProvider = tempDataProvider;
            _serviceProvider = serviceProvider;
            _viewOptions = viewOptions;
        }

        public async Task<string> RenderToStringAsync<T>(T model, string viewPath)
        {
            var actionContext = GetActionContext();
            var view = FindView(actionContext, viewPath);

            using (var sw = new StringWriter())
            {
                var viewContext = new ViewContext(
                    actionContext,
                    view,
                    new ViewDataDictionary<T>(new EmptyModelMetadataProvider(), new ModelStateDictionary())
                    {
                        Model = model
                    },
                    new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
                    sw,
                    _viewOptions.Value.HtmlHelperOptions
                );

                await view.RenderAsync(viewContext);

                return sw.ToString();
            }
        }

        private IView FindView(ActionContext actionContext, string viewPath)
        {
            var getViewResult = _razorViewEngine.GetView(null, viewPath, true);
            if (getViewResult.Success)
            {
                return getViewResult.View;
            }

            var findViewResult = _razorViewEngine.FindView(actionContext, viewPath, true);
            if (findViewResult.Success)
            {
                return findViewResult.View;
            }

            var searchedLocations = getViewResult.SearchedLocations.Concat(findViewResult.SearchedLocations);
            var errorMessage = String.Join(
                Environment.NewLine,
                new[] { $"Unable to find view '{ viewPath }'. The following locations were searched:" }.Concat(searchedLocations)); ;

            throw new InvalidOperationException(errorMessage);
        }

        private ActionContext GetActionContext()
        {
            var httpContext = _httpContextAccessor.HttpContext;
            var routingFeature = httpContext.Features.Get<IRoutingFeature>();

            return new ActionContext(
                httpContext,
                routingFeature.RouteData,
                new ActionDescriptor());
        }
    }
}

Регистрация при запуске

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddScoped<IRazorViewRenderer, SimpleRazorViewRenderer>();

    ...
}

Как это использовать

namespace DL.SO.Web.UI.Controllers
{
    public class HomeController : Controller
    {
        private readonly IEmailService _emailService;
        private readonly IRazorViewRenderer _viewRenderer;

        public HomeController(IEmailService emailService,
            IRazorViewRenderer viewRenderer)
        {
            _emailService = emailService;
            _viewRenderer = viewRenderer;
        }

        public IActionResult Contact()
        {
            return View();
        }

        [HttpPost]
        public async Task<IActionResult> Contact(ContactViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return Json(new {
                    Status = false,
                    Message = "Something wrong"
                });
            }

            // I have the template/partial view under Shared/EmailTemplates folder
            // but you can put it right in the Shared folder too
            const string emailTemplatePath = "EmailTemplates/_ContactEmail";

            var emailModel = new ContactEmailModel
            {
                VisitorFullName = model.FullName,
                VisitorEmail = model.Email,
                Company = model.Company,
                Message = model.Message
            };

            // Calling the view renderer to parse the partial view into
            // string
            var emailContent = await _viewRenderer.RenderToStringAsync(
                emailModel, emailTemplatePath);

            // Send out email with my custom email service
            _emailService.SendAsync("Customer Message", emailContent, 
                model.Email, "to@sample.com");

            return Json(new {
                Status = true,
                Message = @"Your message is sent and you should receive
                    a confirmation email."
            });
        }
    }
}

Частичное представление / Шаблон _ContactEmail.cshtml

@model DL.SO.Web.UI.EmailModels.Contact.ContactEmailModel
@{
    Layout = null;
}

<p>Hello @Model.VisitorFullName,</p>
<p>
    Thanks for contacting us. We have received your message and will 
    try to response to you as soon as possible.
</p>
<p>
    Below is your message summary:
</p>
<ul>
    <li><small>Your name: </small> @Model.VisitorFullName</li>
    <li><small>Email: </small> @Model.VisitorEmail</li>
    @if (!String.IsNullOrEmpty(Model.Company))
    {
        <li><small>Company: </small> @Model.Company</li>
    }
    <li><small>Message: </small> @Model.Message</li>
</ul>
<p>
    Thank you,<br />
    David Liang
</p>
...