简体   繁体   中英

Return the result of View Component as a string in C#

I have a service which generates email messages and returns them a string. However, I have a view component which I usually call from my views and append the result with an already present string:

string result = @await Component.InvokeAsync("Widget", new { widgetZone = "stock_levels_summary_cart_price", additionalData = product.Id })
sb.AppendLine($"<td style=\"padding: 0.6em 0.4em;text-align: center;\">{result}</td>");

How can I call this view component in my service and pass the result into a string variable which I can use in my email message service?

I was able to implement this by creating a partial view for the view component.

In the partial view, I declared my view component:

@model int

@await Component.InvokeAsync("Widget", new { widgetZone = "stock_levels_summary_cart_price", additionalData = Model})

In my controller, I created an action as follows:

public virtual PartialViewResult OrderDetailsStocklevel(int productId)
{
    return PartialView("~/Views/Shared/_OrderDetailsStocklevel.cshtml", productId);
}

Then I implemented a service to render the partial view content and return the result:

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;

namespace Nop.Services.Helpers
    {

        public interface IViewRenderHelper
        {
            string RenderToString(string viewName, object model, string viewPath);
        }

    public class ViewRenderHelper : IViewRenderHelper
    {
        private readonly IServiceProvider _serviceProvider;

        public ViewRenderHelper(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public string RenderToString(string viewName, object model, string viewPath)
        {
            var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
            var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

            var engine = _serviceProvider.GetService(typeof(IRazorViewEngine)) as IRazorViewEngine;
            var tempDataProvider = _serviceProvider.GetService(typeof(ITempDataProvider)) as ITempDataProvider;

            if (engine == null)
            {
                throw new Exception("Can't find IRazorViewEngine");
            }


            var viewEngineResult = engine.FindView(actionContext, viewPath, false);

            if (!viewEngineResult.Success)
            {
                throw new InvalidOperationException($"Couldn't find view '{viewName}'");
            }

            var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
            {
                Model = model
            };


            using (var output = new StringWriter())
            {
                var viewContext = new ViewContext(actionContext, viewEngineResult.View,
                    viewDictionary, new TempDataDictionary(actionContext.HttpContext, tempDataProvider),
                    output, new HtmlHelperOptions());

                viewEngineResult.View.RenderAsync(viewContext).GetAwaiter().GetResult();

                return output.ToString();
            }



        }
    }
}

Then, to load the partial view that was created from a view component, I executed the method as follows:

var stockLevelLabel = _viewRenderService.RenderToString("stocklevel", orderItem.ProductId, "_OrderDetailsStocklevel");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM