【问题标题】:Sending cshtml view mails with mailkit使用 mailkit 发送 cshtml 查看邮件
【发布时间】:2020-04-19 08:25:48
【问题描述】:

我正在使用 ASP.NET Core 和 Mailkit 发送电子邮件。采取以下(基本)代码:

            var bodyBuilder = new BodyBuilder();
            bodyBuilder.HtmlBody = GetBody();

            var m = new MimeMessage();
            m.To.Add(new MailboxAddress("gurdip.sira@gmail.com"));
            m.From.Add(new MailboxAddress("Sender Name", "gurdip.sira@gmail.com"));

            string s = GetBody();

            // m.Body = bodyBuilder.ToMessageBody();
            m.Body = new TextPart(MimeKit.Text.TextFormat.Html) {Text = s};


            using (var smtp = new MailKit.Net.Smtp.SmtpClient())
            {
                smtp.Connect("smtp.gmail.com", 587);
                smtp.AuthenticationMechanisms.Remove("XOAUTH2");
                smtp.Authenticate("gurdip.sira@gmail.com", "December5!");


                smtp.Send(m);
            }

GetBody() 方法只是读取一个 html 文档(streamreader)。

我想做的是使用 razor 视图和 cshtml,因为我的电子邮件可能包含动态内容(例如,某些项目的大小未知的集合)。

我似乎无法找到有关如何执行此操作的权威文档。这个想法是然后将 cshtml 视图作为纯 html 读取,但解析 razor 语法和模型变量。

有人做过这样的事吗?

【问题讨论】:

    标签: asp.net-core mailkit


    【解决方案1】:

    一种解决方案是从您的控制器传递内容。

    public void TestAction(){
         var content = PartialView("your_partial_view").ToString();
         your_SendEmailFunction(content)
    }
    

    所以基本上你使用局部视图作为你作为内容传递给你的方法的字符串。

    【讨论】:

    • 并且大概 tostring() 方法调用会返回 html 并解析模型变量?我可以试试。
    • 会的。您只需渲染视图并获得一个对象作为回报。所以是的,您可以将其用作普通的局部视图
    【解决方案2】:

    这是一个基于jmal73's comment in Paris Polyzos' blog 的简单演示,如下所示:

    1.自定义界面:

    public interface IViewRenderService
    {
        Task<string> RenderToStringAsync(string viewName, object model);
    }
    

    2.实现接口:

    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;
    
    public class ViewRenderService : IViewRenderService
    {
        private readonly IRazorViewEngine _razorViewEngine;
        private readonly ITempDataProvider _tempDataProvider;
        private readonly HttpContext _httpContext;
    
    
        public ViewRenderService(IRazorViewEngine razorViewEngine,
            ITempDataProvider tempDataProvider,
            IHttpContextAccessor httpContextAccessor)
        {
            _razorViewEngine = razorViewEngine;
            _tempDataProvider = tempDataProvider;
            _httpContext = httpContextAccessor.HttpContext;
        }
    
    
        public async Task<string> RenderToStringAsync(string viewName, object model)
        {
    
            var actionContext = new ActionContext(_httpContext, new RouteData(), new ActionDescriptor());
            var viewEngineResult = _razorViewEngine.FindView(actionContext, viewName, false);
    
            if (viewEngineResult.View == null || (!viewEngineResult.Success))
            {
                throw new ArgumentNullException($"Unable to find view '{viewName}'");
            }
    
            var view = viewEngineResult.View;
    
    
            using (var sw = new StringWriter())
            {
                var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary());
                viewDictionary.Model = model;
    
                var tempData = new TempDataDictionary(_httpContext, _tempDataProvider);
    
                var viewContext = new ViewContext(actionContext, view, viewDictionary, tempData, sw, new HtmlHelperOptions());
    
                viewContext.RouteData = _httpContext.GetRouteData();   //set route data here
    
                await view.RenderAsync(viewContext);
    
                return sw.ToString();
            }
        }
    
    }
    

    3.读取.cshtml文件并返回字符串:

    public class HomeController : Controller
    {
        private readonly IViewRenderService _viewRenderService;
        public HomeController(IViewRenderService viewRenderService)
        {
            _viewRenderService = viewRenderService;
        }
        public IActionResult Index()
        {
            var data = new Users()
            {
                UserId = 1
            };
            return View(data);
        }
        public async Task<IActionResult> Privacy()
        {
            var data = new Users()
            {
                UserId = 1
            };
            var result = await _viewRenderService.RenderToStringAsync("Home/Index", data); 
            return Content(result);           
        }
    

    4.Index.cshtml:

    @model Users
    <form>
        <label asp-for="UserId"></label>
        <br />
        <input asp-for="UserId" class="form-control" maxlength="4" />
        <span asp-validation-for="UserId" class="text-danger"></span>
        <input type="submit" value="create" />
    </form>
    

    5.注册服务:

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    services.AddScoped<IViewRenderService, ViewRenderService>();
    

    【讨论】:

    • 如果您在 Core 3.0+ 上使用端点路由,这将不起作用,因为在您执行 new ActionContext() 时没有任何 IRouter 与请求关联。
    猜你喜欢
    • 2023-03-18
    • 1970-01-01
    • 2017-02-17
    • 1970-01-01
    • 2018-12-07
    • 1970-01-01
    • 2021-03-13
    • 2020-01-17
    • 2019-10-14
    相关资源
    最近更新 更多