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.