• .net core mvc利用razor模板引擎开发邮件模板功能


      前言:模板引擎渲染HTML的技术有很多,这里仅说明一下利用.net core下的mvc框架里的razor引擎怎么去做模板渲染功能。 在介绍之前,首先感谢磊哥的技术分享,得以让这篇文章成型。

      核心参考文章:

      Walkthrough: Creating an HTML Email Template with Razor and Razor Class Libraries

      https://github.com/scottsauber/RazorHtmlEmails

      a-razor引擎渲染HTML核心代码:

    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 System;
    using System.IO;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace MeShop.CRM.Domain.Services.Vip.Helper
    {
        // Code from: https://github.com/aspnet/Entropy/blob/master/samples/Mvc.RenderViewToString/RazorViewToStringRenderer.cs
        public class RazorViewToStringRenderer : IRazorViewToStringRenderer
        {
            private IRazorViewEngine _viewEngine;
            private ITempDataProvider _tempDataProvider;
            private IServiceProvider _serviceProvider;
    
            public RazorViewToStringRenderer(
                IRazorViewEngine viewEngine,
                ITempDataProvider tempDataProvider,
                IServiceProvider serviceProvider)
            {
                _viewEngine = viewEngine;
                _tempDataProvider = tempDataProvider;
                _serviceProvider = serviceProvider;
            }
    
            public async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model)
            {
                var actionContext = GetActionContext();
                var view = FindView(actionContext, viewName);
    
                using (var output = new StringWriter())
                {
                    var viewContext = new ViewContext(
                        actionContext,
                        view,
                        new ViewDataDictionary<TModel>(
                            metadataProvider: new EmptyModelMetadataProvider(),
                            modelState: new ModelStateDictionary())
                        {
                            Model = model
                        },
                        new TempDataDictionary(
                            actionContext.HttpContext,
                            _tempDataProvider),
                        output,
                        new HtmlHelperOptions());
    
                    await view.RenderAsync(viewContext);
    
                    return output.ToString();
                }
            }
    
            private IView FindView(ActionContext actionContext, string viewName)
            {
                var getViewResult = _viewEngine.GetView(executingFilePath: null, viewPath: viewName, isMainPage: true);
                if (getViewResult.Success)
                {
                    return getViewResult.View;
                }
    
                var findViewResult = _viewEngine.FindView(actionContext, viewName, isMainPage: 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 '{viewName}'. The following locations were searched:" }.Concat(searchedLocations)); ;
    
                throw new InvalidOperationException(errorMessage);
            }
    
            private ActionContext GetActionContext()
            {
                var httpContext = new DefaultHttpContext();
                httpContext.RequestServices = _serviceProvider;
                return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
            }
    
        }
        public interface IRazorViewToStringRenderer
        {
            Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model);
        }
    }
    View Code

      

      b-邮件模板模块:

      需要注意的是:邮件模板模块,必须放在mvc项目的Views目录下,主要是利用Razor寻找页面元素位置的机制(或者可以自定义寻找视图位置)

      TemplateShopExpired实体示例:

    namespace MeShop.Module.Model.CRM.EmailTemplate
    {
        /// <summary>
        /// 邮件模板类-店铺过期
        /// </summary>
        public class TemplateShopExpired
        {
            public string ShopHost { get; set; }
            public string ShopHostAdmin { get; set; }
            public string ShopSaveDays { get; set; }
            public string ShopCloseDate { get; set; }
            public string CdnHost { get; set; }
        }
    }
    View Code

      EmailTemplateShopExpired.cshtml文件示例:

    @model MeShop.Module.Model.CRM.EmailTemplate.TemplateShopExpired
    @{
        Layout = null;
    }
    <!DOCTYPE HTML>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title></title>
    </head>
    <body>
        <table width="650" border="0" align="center" cellpadding="0" cellspacing="0" style="border: 1px solid #ccc;">
            <tbody>
                <tr>
                    <td valign="top" width="335">
                        <span class="edit-emai-text" style="font-size:20px;color:#000;font-weight: bold;font-family: arial;display:block;padding:20px 0 20px 20px;">
                            <span class="edit-email-child">欢迎来到meshop</span>
                        </span>
                    </td>
                </tr>
                <tr>
                    <td valign="top" width="335">
                        <span class="edit-emai-text" style="font-size:15px;color:#000;font-weight:bold;font-family: arial;display:block;padding:20px 20px 15px 20px;">
                            <span class="edit-email-child">您的店铺<a href="@(Model.ShopHost)/admin/home">@(Model.ShopHostAdmin)</a>已经到期, 我们将为您保留@ShopSaveDays@天的店铺配置数据,@(Model.ShopCloseDate)(UTC)后我们将清除店铺的配置数据,只保留店铺注册信息。</span>
                        </span>
                    </td>
                </tr>
                <tr>
                    <td valign="top" width="335">
                        <span class="edit-emai-text" style="font-size:16px;color:#000;font-weight:bold;font-family: arial;display:block;padding:20px 0 15px 20px;">
                            <a class="edit-emai-link" href="@(Model.ShopHost)/admin/home" title="" style="border:1px solid #ccc;font-size:14px;border-radius: 3px; padding:5px 3px; color:#000; text-decoration:none"><span class="edit-email-child"> 立即续费 </span></a>
                        </span>
                    </td>
                </tr>
            </tbody>
        </table>
        <TABLE style="PADDING-BOTTOM: 10px; FONT-FAMILY: Arial; MARGIN-BOTTOM: 10px; MARGIN-LEFT: auto; FONT-SIZE: 12px; MARGIN-RIGHT: auto; PADDING-TOP: 15px" border=0 cellSpacing=0 cellPadding=0 width=650 bgColor=#ffffff align=center>
            <TBODY>
                <TR>
                    <TD vAlign=center width=650 align=middle>
                        <SPAN class="edit-emai-text" style="PADDING-BOTTOM:15px; DISPLAY: inline-block;vertical-align: middle;">
                            <img src="@(Model.CdnHost)/admin/favicon.ico" style="display:inline-block;40px;height:auto; vertical-align: middle;">
                            <span class="edit-emai-text" style=" DISPLAY: inline-block;FONT-SIZE:20px;font-weight:bold;">meshop</span>
                        </SPAN>
                    </TD>
                </TR>
            </TBODY>
        </TABLE>
    </body>
    </html>
    View Code

      c-使用示例:

    /// <summary>
    /// 3-发送店铺过期邮件
    /// </summary>
    /// <param name="shopID">店铺ID</param>
    /// <param name="times">次数</param>
    public async Task SendShopExpiredEmail(long shopID, int times)
    {
        ShopInfo shopInfo = base.ShopInfoRepository.Get(shopID);
        if (shopInfo != null)
        {
            string shopSsoHost = PayCommonHelper.GetSsoHost(shopInfo.HostAdmin);
    
            //生成店铺过期时间执行SouceValue(店铺ID+过期时间+次数)
            string shopExpiredSourceValue = $"{shopID}_{shopInfo.ExpiredTime.ToString_yyyyMMddHHmmss()}_{times}";
    
            TemplateShopExpired templateShopExpired = new TemplateShopExpired
            {
                ShopHostAdmin = shopInfo.HostAdmin,
                ShopHost = shopSsoHost,
                ShopSaveDays = (shopInfo.BufferTime - shopInfo.ExpiredTime).Days.ToString(),
                ShopCloseDate = shopInfo.BufferTime.ToString_yyyyMMddHHmmss(),
                CdnHost = PayCommonHelper.GetCdnHost(this._config)
            };
    
            string emailTemplateContent = await this._razorViewToStringRenderer.RenderViewToStringAsync(this._emailTmplateShopExpiredRazorPath, templateShopExpired);
        }
    }
    View Code
    *感谢您的阅读。喜欢的、有用的就请大哥大嫂们高抬贵手“推荐一下”吧!你的精神 支持是博主强大的写作动力。欢迎转载!
    *博主的文章是自己平时开发总结的经验,由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。
    *我的博客: http://www.cnblogs.com/lxhbky/
  • 相关阅读:
    机器学习实践笔记3(树和随机森林)
    Cocos2d-x3.1回调函数具体解释
    base 64 编解码器
    HDU 4915 Parenthese sequence _(:зゝ∠)_ 哈哈
    跟我extjs5(03--在项目过程中加载文件)
    备份和还原数据库
    Android学习–Android app 语言切换功能
    Android app内语言环境切换
    Android学习–Android app 语言切换功能
    swift:自定义UICollectionViewFlowLayout
  • 原文地址:https://www.cnblogs.com/lxhbky/p/14639334.html
Copyright © 2020-2023  润新知