发送邮件的小功能(.net core 版)

前言:

使用.net core 开发有一段时间了,期间从.net core 2.0 preview1 到 preview2 又到core 1.1 现在2.0正式版出来了。又把项目升级至2.0了。目前正在用2.0进行开发。期间也遇到了不少问题。在这里进行总结一下。

最近工作内容就是job的迁移工作,从Framework迁移到.net Core上。体会到了两个框架的不同之处。以及使用过程中体会到的1.1和2.0的不同 以及Framework和Core的不同。首先说一下2.0和Framework的不同吧。刚开始用的preview1 用的时候感觉差异不是特别的大。有些方法2.0的实现方式和Framework实现的方式一样。命名空间也没有变,方法名也没有变。当然了有些东西还是不一样的。或者说有些方法没有实现。后来升级到preview2后。突然感觉那里不对。后来仔细观察了一下原来是类库变了。preview1类库是netcore2.0。preview2类库是.netstandard2.0。总体来说升级影响不是特别的大。后来降到1.1 差别就出来了。很多方法1.1没有实现。或者说用别的方法给实现了。最头疼的可能就是反射的那块了。几乎每次都要getRuntimeXXX一次。很是烦人。2.0的语法就和Framework反射的语法是一致的。很是方便。现在升级到2.0反射那块没有变,依旧可以用。应该是保留了1.1的那种过度的写法。或者说保留了那种写法。

内容:

内容比较乱吧。自己想到哪里就讲到哪里吧。

我有这么一个需求:将razor视图加载之后生成的html获取出来。我用的视图引擎,加载执行,之后将执行的结果进行返回过来。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
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 CNBlogs.Job.Web.Core.Utility
{
    public interface IViewRenderService
    {
        Task<string> RenderToStringAsync(string viewName, object model);
    }
    public class ViewRenderService : IViewRenderService
    {
        private readonly IRazorViewEngine _razorViewEngine;
        private readonly ITempDataProvider _tempDataProvider;
        private readonly IServiceProvider _serviceProvider;

        public ViewRenderService(IRazorViewEngine razorViewEngine,
            ITempDataProvider tempDataProvider,
            IServiceProvider serviceProvider)
        {
            _razorViewEngine = razorViewEngine;
            _tempDataProvider = tempDataProvider;
            _serviceProvider = serviceProvider;
        }

        public async Task<string> RenderToStringAsync(string viewName, object model)
        {
            var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
            var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

            using (var sw = new StringWriter())
            {
                var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);

                if (viewResult.View == null)
                {
                    throw new ArgumentNullException($"{viewName} does not match any available view");
                }

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

                var viewContext = new ViewContext(
                    actionContext,
                    viewResult.View,
                    viewDictionary,
                    new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
                    sw,
                    new HtmlHelperOptions()
                );

                await viewResult.View.RenderAsync(viewContext);
                return sw.ToString();
            }
        }
    }
}

IViewRenderService

用法呢:当然我需要进行依赖注入。services.AddScoped<IViewRenderService, ViewRenderService>();对于ViewRenderService需要的依赖注入,其实mvc框架中这些已经注入过了。直接拿来用就可以。

我是这么用的

 var userResumeAttachmentString = await _viewRenderService.RenderToStringAsync("_ResumeForEmail", resume);

说明一下: 传的第一参数是视图名称。或者视图文件所在路径也可以,第二参数是加载视图所需要的model。

说一下发邮件的问题。由于Core1.1没有system.net.mail 。发送邮件一时间成了难题。有难难题就有人解决,于是mailkit出现了,用法呢和Framework发送邮件的方式大致是一样的。

        /// <summary>
        ///发送邮件
        /// </summary>
        /// <param name="receive">接收人</param>
        /// <param name="sender">发送人</param>
        /// <param name="subject">标题</param>
        /// <param name="body">内容</param>
        /// <param name="attachments">附件</param>
        /// <returns></returns>
        public bool SendMail(string receive, string sender, string subject, string body, byte[] attachments = null)
        {
            string displayName = _configuration["Mail:Name"];
            string from = _configuration.GetSection("Mail").GetSection("Address").Value;
            var fromMailAddress = new MailboxAddress(displayName, from);
            var toMailAddress = new MailboxAddress(receive);
            var mailMessage = new MimeMessage();
            mailMessage.From.Add(fromMailAddress);
            mailMessage.To.Add(toMailAddress);
            if (!string.IsNullOrEmpty(sender))
            {
                var replyTo = new MailboxAddress(displayName, sender);
                mailMessage.ReplyTo.Add(replyTo);
            }
            var bodyBuilder = new BodyBuilder() { HtmlBody = body };
            mailMessage.Body = bodyBuilder.ToMessageBody();
            mailMessage.Subject = subject;
            return SendMail(mailMessage);

        }
        private bool SendMail(MimeMessage mailMessage)
        {
            try
            {
                var smtpClient = new SmtpClient();
                smtpClient.Timeout = 10 * 1000;   //设置超时时间
                string host = _configuration.GetSection("Mail").GetSection("Host").Value;
                int port = int.Parse(_configuration.GetSection("Mail").GetSection("Port").Value);
                string address = _configuration.GetSection("Mail").GetSection("Address").Value;
                string password = _configuration.GetSection("Mail").GetSection("Password").Value;
                smtpClient.Connect(host, port, MailKit.Security.SecureSocketOptions.None);//连接到远程smtp服务器
                smtpClient.Authenticate(address, password);
                smtpClient.Send(mailMessage);//发送邮件
                smtpClient.Disconnect(true);
                return true;

            }
            catch
            {
                return false;
            }

        }

发邮件这个问题解决了。可是还有一个需求,那就是发送邮件附件。当时查了国外的资料,也没有弄明白。后来自己慢慢的试出来了。具体做法就是将字符串转化为byte数组。然后借用bodyBuilder的一个方法进行附件的添加。

            if (attachments != null)
            {
                bodyBuilder.Attachments.Add("用户简历.pdf", attachments);
            }

这里有个坑,那就是添加附件的时候需要将附件的文件名和格式直接指定。

到这里基本已经完成了。我用单元测试进行测试了一番。关于在控制台进行依赖注入的用法,我能想到就是在单元测试中使用。很方便。比如有时候需要进行数据提交的测试。我们可以在单元测试中造假数据,然后向对应的action提交数据。获取返回结果。不用在界面的一次次的填充数据了。

 1         [Fact]
 2         public void TestSendEmail()
 3         {
 4             var builder = new ConfigurationBuilder()
 5                .SetBasePath(Directory.GetCurrentDirectory())
 6                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
 7             var k1 = Directory.GetCurrentDirectory();
 8             builder.AddEnvironmentVariables();
 9             var Configuration = builder.Build();
10             var serviceProvider = new ServiceCollection()
11                      .AddSingleton<IConfigurationRoot>(Configuration)
12                      .AddScoped<MsgServices, MsgServices>()
13                      .BuildServiceProvider();
14             var msgService = serviceProvider.GetService<MsgServices>();
15             var k = msgService.SendMail("[email protected]", "[email protected]", "测试", "你好我进行了测试");
16             Assert.True(k);
17         }

需要在单元测试项目的目录中添加appsetting.json文件。(我项目已经升到2.0了,但这些用法还是1.1的旧的用法。)

我的appsetting.json 文件 (敏感信息已删除)

1   "Mail": {
2     "Name": "博客园招聘频道",
3     "Address": "emailAddress",
4     "Host": "xxxxxxx",
5     "Port": 25,
6     "Password": "password"
7   }

单元测试显示效果:

发送附件的测试没有放在单元测试中,因为视图需要加载。显示一张截图吧

最后还有一个问题,还么有解决,就是HTML to PDF中文乱码的问题。我用的是node.js 参考的是微软官网的。英文没有问题,中文就乱码,乱码原因目前正在查找中。期间也尝试过用jspdf 但是中文乱码问题解决的方式并不是很理想。目前常见的解决方式是:获取指定元素所在块的内容,然后进行截图,截图分辨率很低,没有使用。也试过DinkToPdf 我看了一点源码,主要核心的的功能使用的wkhtmltopdf的一个类库,他是在这个类库上进行了一层封装。中文乱码问题解决了,但是不是特别的优雅。考虑到跨平台,也没有使用。目前没有合适的解决方案。正在找node.js中文乱码的原因。希望有人用过的给提点建议。很是头疼的中文乱码问题。

写了这么多的代码最终在界面上显示的功能就是一个小按钮。

时间: 2024-08-03 07:15:26

发送邮件的小功能(.net core 版)的相关文章

小鹤双拼飞扬版反查编码功能解释-by老随风

更新时间:2015-05-22 反查编码功能 文中例字均为(码maum) 关于知道编码也不知道为何这么拆,请明白鹤形是拆一个字首尾两部分的形码 ②ofi   (知道字怎么读,想知道该字是否有其他编码) ③ofi: (不知道字怎么读,但该字可以复制到剪贴板) ④:i   (查某字的详细信息:读音.笔画数.部首.笔顺.小鹤编码.释义) ⑤ozd  (打开候选窗字典功能) ⑥omb  (查码表,这个如果也查不出来的话,说明小鹤飞扬版词库没这个字或词) ⑦ohd  (这个专治笔顺和读音不对的亲们) 关于

学习笔记之小述Linux发行版

一.小述Linux发行版 由于Linux基于OpenOS的原则,任何人都可以获取源其内核源代码,因此也有了众多发行版,其中Linux最主要的三个分支分别是Debian.Slackware.RedHat. 下面分别介绍下三大主流发行版及其衍生版: 1.Debian:Debian Project诞生于1993年8月13日,它的目标是提供一个稳定容错的Linux版本.使用于任何环境,由于系统稳定,多用于服务器.支持Debian的不是某家公司,而是互联网上自发组织起来进行更新和发布的,是最为原汁原味的O

Visual Studio Debugger中七个鲜为人知的小功能

Visual Studio debugger是一个很棒的调试工具,可以帮助程序猿们快速地发现和解决问题.这里给大家简单介绍一下VS调试工具中的七个鲜为人知的小功能. 1.    一键跳转到指定语句 调试过程中经常需要拖拽黄箭头,使特定语句执行或者不执行.常规方法就是使用鼠标直接拖拽. 在Visual Studio 2017 15.3预览版中,有一个更简单地跳转到目标行的方法:在目标行盘旋鼠标指针,出现绿色竖线右箭头图标后,按住CTRL后鼠标左键点击,就把调试黄箭头移过去了,再点击调试下一步或者F

暴风雨中的 online :.net core 版博客站点遭遇的高并发问题进展

今天暴风雨袭击了杭州,而昨天暴风雨(高并发问题)席卷了园子,留下一片狼藉. 在前天傍晚,我们进行了 .net core 版博客站点的第二次发布尝试,在发布后通过 kestrel 直接监听取代 nginx 转发解决了高并发下的1秒延迟问题,成功地顶住了下班前的访问小高峰,但这只是一场大雨,第二天的上午和下午的暴风雨(访问高峰中的高并发)才是真正的考验. 昨天,面对暴风雨,我们哼都不敢哼一声“让暴风雨来得更猛烈些吧”,只是一直不停地默念“让暴风雨快点过去吧”,尤其在下午的暴风雨袭击下,跑在 dock

使用GO语言实现的日志集中查看的小功能.

程序分为站点端和中心端(相当于一个proxy). 这个小功能主要是解决,程序经常让我们去拖日志,特别烦.所以做个小程序.使程序可以自己去线上查看. 有个问题是,不能把游戏服务器暴露出来,还有就是不能占用业务机器的公网带宽. 这个小程序主要就是中心端(proxy)通过内网获取文件,然后转发给访问端. 中心端主要有两个文件,一个是程序文件.一个是我命名为json的文件(主要是根据ID来分辨分站) 主程序文件内容: package main import ( "encoding/json"

小功能——类似微信里,评论内容里面,点击每个人的用户名进入个人主页

项目里的朋友圈页面,每幅图片的评论内容里面,有不同的用户进行评论,起初想法是点击用户名直接进行回复,后来看微信都是点击评论内容进行回复评论的发起人,这个好做,把这个textview绑定一个监听器就ok了 后来再一想,如果要实现类似微信点击用户名就进入用户的主页,怎么让用户名可以点击呢? 现在父布局下面在new一个水平布局的linearlayout,然后根据把每个用户.包括评论内容都设置进textview里面,然后通过linearlayout的addview()方法,把这些textview添加进去

C#、Java中的一些小功能点总结(持续更新......)

前言:在项目中,有时候一些小的功能点,总是容易让人忽略,但是这些功能加在项目中往往十分的有用,因此笔者在这里总结项目中遇到的一些实用的小功能点,以备用,并持续更新...... 1.禁用DataGridView表头的排序功能 1 /// <summary> 2 /// 禁止点击列表头进行排序 3 /// </summary> 4 /// <param name="dgv">当前DataGridView控件</param> 5 private

用angular方法简单实现了吃了么搜索小功能,还不太完善,后续会继续添加新内容。

最近接触了Angular框架,今天用里面的http请求方法做了一个小的案例,是一个查询地名获取附近美食的小案例.还不太完善,后面面有时间会继续添加新的内容.这个小案例没有用到任何的jQuery与原生js方法. 先上HTML结构代码与HTML结构中的angular指令. <body ng-app="app"> <div ng-controller="con" id="con"> <h1>吃了么</h1>

Pascal小游戏 俄罗斯方块怀旧版

俄罗斯方块怀旧版(注释版) {$APPTYPE GUI}{$MODE DELPHI}program WinPiece; usesWindows; constAppName = 'WinPiece';pm = 25; vardc : hdc;AMessage : Msg;hWindow: HWnd;hPen ,hBrush : longword;intNextPiece, intCurPiece,intTempPiece : longint;BigMap : array [0..11,-4..20