邮件服务是一般的系统都会拥有和需要的功能,但是对于.NET项目来说,邮件服务的创建和使用会较为的麻烦。.NET对于邮件功能提供了System.Net.Mail用于创建邮件服务,该基础服务提供邮件的基础操作,并且使用也较为的简单。对于真正将该功能使用于项目的人,就会慢慢发现其中的优缺点,甚至有些时候不能忍受其中的问题。在这里介绍一种微软用于替代System.Net.Mail的邮件服务组件MailKit和MimeKit,官网地址:http://www.mimekit.net/。GitHub地址:https://github.com/jstedfast/MimeKit。下面就具体的介绍一下。

  一.MailKit和MimeKit基础概述:

MailKit组件的支持的客户端类型比较多,例如SMTP客户端、POP3客户端、IMAP4客户端。该组件是一个跨平台的Email组件,该组件支持.NET 4.0,.NET 4.5,Xamarin.Android,Xamarin.iOS,Windows Phone 8.1等等平台。

MimeKit提供了一个MIME解析器,组件具备的解析特性灵活、性能高、很好的处理各种各样的破碎的MIME格式化。MimeKit的性能实际上与GMime相当。

该组件在安全性的还是比较高的,处理安全的方式较多,SASL认证、支持S / MIME v3.2、支持OpenPGP、支持DKIM签名等等方式。Mailkit组件可以通过CancellationToken取消对应的操作,CancellationToken传播应取消操作的通知,一个的CancellationToken使线程,线程池工作项目之间,或取消合作任务的对象。过实例化CancellationTokenSource对象来创建取消令牌,该对象管理从其CancellationTokenSource.Token属性检索的取消令牌。然后,将取消令牌传递到应该收到取消通知的任意数量的线程,任务或操作。令牌不能用于启动取消。

MailKit组件支持异步操作,在内部编写的有关I/O异步操作的类。

  二.创建基础邮件服务:

介绍过MailKit和MimeKit组建的基础信息,接下来就介绍一下如何使用两个组件的基本功能,在这里我将基本操作做了一个简单的封装,一般的项目可以直接引用封装好的类,大家可以根据实际的情况对该组件进行扩展。

1.邮件发送基础服务API

/// <summary>

/// 邮件服务API

/// </summary>

public static class MailServiceApi

{

/// <summary>

/// 发送邮件

/// </summary>

/// <param name="mailBodyEntity">邮件基础信息</param>

/// <param name="sendServerConfiguration">发件人基础信息</param>

public static SendResultEntity SendMail(MailBodyEntity mailBodyEntity,

SendServerConfigurationEntity sendServerConfiguration)

{

if (sendServerConfiguration == null)

{

throw new ArgumentNullException();

}

if (sendServerConfiguration == null)

{

throw new ArgumentNullException();

}

var sendResultEntity = new SendResultEntity();

using (var client = new SmtpClient(new ProtocolLogger(CreateMailLog())))

{

client.ServerCertificateValidationCallback = (s, c, h, e) => true;

Connection(mailBodyEntity, sendServerConfiguration, client, sendResultEntity);

if (sendResultEntity.ResultStatus == false)

{

return sendResultEntity;

}

SmtpClientBaseMessage(client);

Authenticate(mailBodyEntity, sendServerConfiguration, client, sendResultEntity);

if (sendResultEntity.ResultStatus == false)

{

return sendResultEntity;

}

Send(mailBodyEntity, sendServerConfiguration, client, sendResultEntity);

if (sendResultEntity.ResultStatus == false)

{

return sendResultEntity;

}

client.Disconnect(true);

}

return sendResultEntity;

}

/// <summary>

/// 连接服务器

/// </summary>

/// <param name="mailBodyEntity">邮件内容</param>

/// <param name="sendServerConfiguration">发送配置</param>

/// <param name="client">客户端对象</param>

/// <param name="sendResultEntity">发送结果</param>

public static void Connection(MailBodyEntity mailBodyEntity, SendServerConfigurationEntity sendServerConfiguration,

SmtpClient client, SendResultEntity sendResultEntity)

{

try

{

client.Connect(sendServerConfiguration.SmtpHost, sendServerConfiguration.SmtpPort);

}

catch (SmtpCommandException ex)

{

sendResultEntity.ResultInformation = $"尝试连接时出错:{0}" + ex.Message;

sendResultEntity.ResultStatus = false;

}

catch (SmtpProtocolException ex)

{

sendResultEntity.ResultInformation = $"尝试连接时的协议错误:{0}" + ex.Message;

sendResultEntity.ResultStatus = false;

}

catch (Exception ex)

{

sendResultEntity.ResultInformation = $"服务器连接错误:{0}" + ex.Message;

sendResultEntity.ResultStatus = false;

}

}

/// <summary>

/// 账户认证

/// </summary>

/// <param name="mailBodyEntity">邮件内容</param>

/// <param name="sendServerConfiguration">发送配置</param>

/// <param name="client">客户端对象</param>

/// <param name="sendResultEntity">发送结果</param>

public static void Authenticate(MailBodyEntity mailBodyEntity, SendServerConfigurationEntity sendServerConfiguration,

SmtpClient client, SendResultEntity sendResultEntity)

{

try

{

client.Authenticate(sendServerConfiguration.SenderAccount, sendServerConfiguration.SenderPassword);

}

catch (AuthenticationException ex)

{

sendResultEntity.ResultInformation = $"无效的用户名或密码:{0}" + ex.Message;

sendResultEntity.ResultStatus = false;

}

catch (SmtpCommandException ex)

{

sendResultEntity.ResultInformation = $"尝试验证错误:{0}" + ex.Message;

sendResultEntity.ResultStatus = false;

}

catch (SmtpProtocolException ex)

{

sendResultEntity.ResultInformation = $"尝试验证时的协议错误:{0}" + ex.Message;

sendResultEntity.ResultStatus = false;

}

catch (Exception ex)

{

sendResultEntity.ResultInformation = $"账户认证错误:{0}" + ex.Message;

sendResultEntity.ResultStatus = false;

}

}

/// <summary>

/// 发送邮件

/// </summary>

/// <param name="mailBodyEntity">邮件内容</param>

/// <param name="sendServerConfiguration">发送配置</param>

/// <param name="client">客户端对象</param>

/// <param name="sendResultEntity">发送结果</param>

public static void Send(MailBodyEntity mailBodyEntity, SendServerConfigurationEntity sendServerConfiguration,

SmtpClient client, SendResultEntity sendResultEntity)

{

try

{

client.Send(MailMessage.AssemblyMailMessage(mailBodyEntity));

}

catch (SmtpCommandException ex)

{

switch (ex.ErrorCode)

{

case SmtpErrorCode.RecipientNotAccepted:

sendResultEntity.ResultInformation = $"收件人未被接受:{ex.Message}";

break;

case SmtpErrorCode.SenderNotAccepted:

sendResultEntity.ResultInformation = $"发件人未被接受:{ex.Message}";

break;

case SmtpErrorCode.MessageNotAccepted:

sendResultEntity.ResultInformation = $"消息未被接受:{ex.Message}";

break;

}

sendResultEntity.ResultStatus = false;

}

catch (SmtpProtocolException ex)

{

sendResultEntity.ResultInformation = $"发送消息时的协议错误:{ex.Message}";

sendResultEntity.ResultStatus = false;

}

catch (Exception ex)

{

sendResultEntity.ResultInformation = $"邮件接收失败:{ex.Message}";

sendResultEntity.ResultStatus = false;

}

}

/// <summary>

/// 获取SMTP基础信息

/// </summary>

/// <param name="client">客户端对象</param>

/// <returns></returns>

public static MailServerInformation SmtpClientBaseMessage(SmtpClient client)

{

var mailServerInformation = new MailServerInformation

{

Authentication = client.Capabilities.HasFlag(SmtpCapabilities.Authentication),

BinaryMime = client.Capabilities.HasFlag(SmtpCapabilities.BinaryMime),

Dsn = client.Capabilities.HasFlag(SmtpCapabilities.Dsn),

EightBitMime = client.Capabilities.HasFlag(SmtpCapabilities.EightBitMime),

Size = client.MaxSize

};

return mailServerInformation;

}

/// <summary>

/// 创建邮件日志文件

/// </summary>

/// <returns></returns>

public static string CreateMailLog()

{

var logPath = AppDomain.CurrentDomain.BaseDirectory + "/DocumentLog/" +

Guid.NewGuid() + ".txt";

if (File.Exists(logPath)) return logPath;

var fs = File.Create(logPath);

fs.Close();

return logPath;

}

}

2.组装邮件消息:

/// <summary>

/// 邮件信息

/// </summary>

public static class MailMessage

{

/// <summary>

/// 组装邮件文本/附件邮件信息

/// </summary>

/// <param name="mailBodyEntity">邮件消息实体</param>

/// <returns></returns>

public static MimeMessage AssemblyMailMessage(MailBodyEntity mailBodyEntity)

{

if (mailBodyEntity == null)

{

throw new ArgumentNullException(nameof(mailBodyEntity));

}

var message = new MimeMessage();

//设置邮件基本信息

SetMailBaseMessage(message, mailBodyEntity);

var multipart = new Multipart("mixed");

//插入文本消息

if (string.IsNullOrEmpty(mailBodyEntity.MailTextBody) == false)

{

var alternative = new MultipartAlternative

{

AssemblyMailTextMessage(mailBodyEntity.MailTextBody, mailBodyEntity.MailBodyType)

};

multipart.Add(alternative);

}

//插入附件

if (mailBodyEntity.MailFilePath != null && File.Exists(mailBodyEntity.MailFilePath) == false)

{

var mimePart = AssemblyMailAttachmentMessage(mailBodyEntity.MailFileType, mailBodyEntity.MailFileSubType,

mailBodyEntity.MailFilePath);

multipart.Add(mimePart);

}

//组合邮件内容

message.Body = multipart;

return message;

}

/// <summary>

/// 设置邮件基础信息

/// </summary>

/// <param name="minMessag"></param>

/// <param name="mailBodyEntity"></param>

/// <returns></returns>

public static MimeMessage SetMailBaseMessage(MimeMessage minMessag, MailBodyEntity mailBodyEntity)

{

if (minMessag == null)

{

throw new ArgumentNullException();

}

if (mailBodyEntity == null)

{

throw new ArgumentNullException();

}

//插入发件人

minMessag.From.Add(new MailboxAddress(mailBodyEntity.Sender, mailBodyEntity.SenderAddress));

//插入收件人

foreach (var recipients in mailBodyEntity.Recipients)

{

minMessag.To.Add(new MailboxAddress(recipients));

}

//插入抄送人

foreach (var cC in mailBodyEntity.Cc)

{

minMessag.Cc.Add(new MailboxAddress(cC));

}

//插入主题

minMessag.Subject = mailBodyEntity.Subject;

return minMessag;

}

/// <summary>

/// 组装邮件文本信息

/// </summary>

/// <param name="mailBody">邮件文本内容</param>

/// <param name="textPartType">邮件文本类型(plain,html,rtf,xml)</param>

/// <returns></returns>

public static TextPart AssemblyMailTextMessage(string mailBody, string textPartType)

{

if (string.IsNullOrEmpty(mailBody))

{

throw new ArgumentNullException();

}

if (string.IsNullOrEmpty(textPartType))

{

throw new ArgumentNullException();

}

var textBody = new TextPart(textPartType)

{

Text = mailBody

};

return textBody;

}

/// <summary>

/// 组装邮件附件信息

/// </summary>

/// <param name="fileAttachmentType">附件类型(image,application)</param>

/// <param name="fileAttachmentSubType">附件子类型 </param>

/// <param name="fileAttachmentPath">附件路径</param>

/// <returns></returns>

public static MimePart AssemblyMailAttachmentMessage(string fileAttachmentType, string fileAttachmentSubType, string fileAttachmentPath)

{

if (string.IsNullOrEmpty(fileAttachmentSubType))

{

throw new ArgumentNullException();

}

if (string.IsNullOrEmpty(fileAttachmentType))

{

throw new ArgumentNullException();

}

if (string.IsNullOrEmpty(fileAttachmentPath))

{

throw new ArgumentNullException();

}

var attachment = new MimePart(fileAttachmentType, fileAttachmentSubType)

{

Content = new MimeContent(File.OpenRead(fileAttachmentPath)),

ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),

ContentTransferEncoding = ContentEncoding.Base64,

FileName = Path.GetFileName(fileAttachmentPath)

};

return attachment;

}

}

3.邮件基础服务实体:

/// <summary>

/// 邮件内容实体

/// </summary>

public class MailBodyEntity

{

/// <summary>

/// 邮件文本内容

/// </summary>

public string MailTextBody { get; set; }

/// <summary>

/// 邮件内容类型

/// </summary>

public string MailBodyType { get; set; }

/// <summary>

/// 邮件附件文件类型

/// </summary>

public string MailFileType { get; set; }

/// <summary>

/// 邮件附件文件子类型

/// </summary>

public string MailFileSubType { get; set; }

/// <summary>

/// 邮件附件文件路径

/// </summary>

public string MailFilePath { get; set; }

/// <summary>

/// 收件人

/// </summary>

public List<string> Recipients { get; set; }

/// <summary>

/// 抄送

/// </summary>

public List<string> Cc { get; set; }

/// <summary>

/// 发件人

/// </summary>

public string Sender { get; set; }

/// <summary>

/// 发件人地址

/// </summary>

public string SenderAddress { get; set; }

/// <summary>

/// 邮件主题

/// </summary>

public string Subject { get; set; }

/// <summary>

/// 邮件内容

/// </summary>

public string Body { get; set; }

}

/// <summary>

/// 邮件服务器基础信息

/// </summary>

public class MailServerInformation

{

/// <summary>

/// SMTP服务器支持SASL机制类型

/// </summary>

public bool Authentication { get; set; }

/// <summary>

/// SMTP服务器对消息的大小

/// </summary>

public uint Size { get; set; }

/// <summary>

/// SMTP服务器支持传递状态通知

/// </summary>

public bool Dsn { get; set; }

/// <summary>

/// SMTP服务器支持Content-Transfer-Encoding

/// </summary>

public bool EightBitMime { get; set; }

/// <summary>

/// SMTP服务器支持Content-Transfer-Encoding

/// </summary>

public bool BinaryMime { get; set; }

/// <summary>

/// SMTP服务器在消息头中支持UTF-8

/// </summary>

public string UTF8 { get; set; }

}

/// <summary>

/// 邮件发送结果

/// </summary>

public class SendResultEntity

{

/// <summary>

/// 结果信息

/// </summary>

public string ResultInformation { get; set; } = "发送成功!";

/// <summary>

/// 结果状态

/// </summary>

public bool ResultStatus { get; set; } = true;

}

/// <summary>

/// 邮件发送服务器配置

/// </summary>

public class SendServerConfigurationEntity

{

/// <summary>

/// 邮箱SMTP服务器地址

/// </summary>

public string SmtpHost { get; set; }

/// <summary>

/// 邮箱SMTP服务器端口

/// </summary>

public int SmtpPort { get; set; }

/// <summary>

/// 是否启用IsSsl

/// </summary>

public bool IsSsl { get; set; }

/// <summary>

/// 邮件编码

/// </summary>

public string MailEncoding { get; set; }

/// <summary>

/// 发件人账号

/// </summary>

public string SenderAccount { get; set; }

/// <summary>

/// 发件人密码

/// </summary>

public string SenderPassword { get; set; }

}

上面提供了借助MailKit组建创建发送邮件服务,分别是创建邮件服务器连接,组装邮件基础信息,邮件基础实体。发送邮件的基础服务比较的多,下面介绍一下邮件的接收。

/// <summary>

/// 跟投邮件服务API

/// </summary>

public static class ReceiveEmailServiceApi

{

/// <summary>

/// 设置发件人信息

/// </summary>

/// <returns></returns>

public static SendServerConfigurationEntity SetSendMessage()

{

var sendServerConfiguration = new SendServerConfigurationEntity

{

SmtpHost = ConfigurationManager.AppSettings["SmtpServer"],

SmtpPort = int.Parse(ConfigurationManager.AppSettings["SmtpPort"]),

IsSsl = Convert.ToBoolean(ConfigurationManager.AppSettings["IsSsl"]),

MailEncoding = ConfigurationManager.AppSettings["MailEncoding"],

SenderAccount = ConfigurationManager.AppSettings["SenderAccount"],

SenderPassword = ConfigurationManager.AppSettings["SenderPassword"]

};

return sendServerConfiguration;

}

/// <summary>

/// 接收邮件

/// </summary>

public static void ReceiveEmail()

{

var sendServerConfiguration = SetSendMessage();

if (sendServerConfiguration == null)

{

throw new ArgumentNullException();

}

using (var client = new ImapClient(new ProtocolLogger(CreateMailLog())))

{

client.Connect(sendServerConfiguration.SmtpHost, sendServerConfiguration.SmtpPort,

SecureSocketOptions.SslOnConnect);

client.Authenticate(sendServerConfiguration.SenderAccount, sendServerConfiguration.SenderPassword);

client.Inbox.Open(FolderAccess.ReadOnly);

var uids = client.Inbox.Search(SearchQuery.All);

foreach (var uid in uids)

{

var message = client.Inbox.GetMessage(uid);

message.WriteTo($"{uid}.eml");

}

client.Disconnect(true);

}

}

/// <summary>

/// 下载邮件内容

/// </summary>

public static void DownloadBodyParts()

{

var sendServerConfiguration = SetSendMessage();

using (var client = new ImapClient())

{

client.Connect(sendServerConfiguration.SmtpHost, sendServerConfiguration.SmtpPort,

SecureSocketOptions.SslOnConnect);

client.Authenticate(sendServerConfiguration.SenderAccount, sendServerConfiguration.SenderPassword);

client.Inbox.Open(FolderAccess.ReadOnly);

// 搜索Subject标题包含“MimeKit”或“MailKit”的邮件

var query = SearchQuery.SubjectContains("MimeKit").Or(SearchQuery.SubjectContains("MailKit"));

var uids = client.Inbox.Search(query);

// 获取搜索结果的摘要信息(我们需要UID和BODYSTRUCTURE每条消息,以便我们可以提取文本正文和附件)

var items = client.Inbox.Fetch(uids, MessageSummaryItems.UniqueId | MessageSummaryItems.BodyStructure);

foreach (var item in items)

{

// 确定一个目录来保存内容

var directory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "/MailBody", item.UniqueId.ToString());

Directory.CreateDirectory(directory);

// IMessageSummary.TextBody是一个便利的属性,可以为我们找到“文本/纯文本”的正文部分

var bodyPart = item.TextBody;

// 下载'text / plain'正文部分

var body = (TextPart) client.Inbox.GetBodyPart(item.UniqueId, bodyPart);

// TextPart.Text是一个便利的属性,它解码内容并将结果转换为我们的字符串

var text = body.Text;

File.WriteAllText(Path.Combine(directory, "body.txt"), text);

// 现在遍历所有附件并将其保存到磁盘

foreach (var attachment in item.Attachments)

{

// 像我们对内容所做的那样下载附件

var entity = client.Inbox.GetBodyPart(item.UniqueId, attachment);

// 附件可以是message / rfc822部件或常规MIME部件

var messagePart = entity as MessagePart;

if (messagePart != null)

{

var rfc822 = messagePart;

var path = Path.Combine(directory, attachment.PartSpecifier + ".eml");

rfc822.Message.WriteTo(path);

}

else

{

var part = (MimePart) entity;

// 注意:这可能是空的,但大多数会指定一个文件名

var fileName = part.FileName;

var path = Path.Combine(directory, fileName);

// decode and save the content to a file

using (var stream = File.Create(path))

part.Content.DecodeTo(stream);

}

}

}

client.Disconnect(true);

}

}

/// <summary>

/// 创建邮件日志文件

/// </summary>

/// <returns></returns>

public static string CreateMailLog()

{

var logPath = AppDomain.CurrentDomain.BaseDirectory + "/DocumentLog/" +

DateTime.Now.ToUniversalTime().ToString(CultureInfo.InvariantCulture) + ".txt";

if (File.Exists(logPath)) return logPath;

var fs = File.Create(logPath);

fs.Close();

return logPath;

}

}

面只是简单的介绍了邮件的接收,如果需要更加深入的了解功能,可以进一步对组件源码进行解析,该组件的文档为较为的丰富。

  三.组件使用感悟:

MailKit和MimeKit组件在项目的使用中较为的便捷,基本包含了所有的基础邮件服务操作。组件提供的SmtpClient类提供的功能很丰富,例如连接邮件服务器,邮件账户认证,组装邮件消息,获取邮件服务器配置信息等等方法的提供,可以让我们在项目中快速的获取邮件服务的所有信息。

使用过邮件功能的项目 都会有困扰,客户端与邮件服务器的连接是否成功,以及邮件是否发送成功状态没有办法很快的获取,只能根据邮件服务器返回的一场状态进行判断。但是MailKit提供对应的方法和异常类,对邮件服务器返回的异常信息进行解析,客户端可以根据这些异常类获取邮件状态。

MailKit组件的提供了ProtocolLogger类,该类用于记录SMTP操作基础信息,该类作用为记录邮件服务日志。在邮件发送完毕后,需要及时的关闭连接,调用Disconnect(true)方法。

原文:https://www.cnblogs.com/pengze0902/p/8519715.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 

创建基于MailKit和MimeKit的.NET基础邮件服务相关推荐

  1. 邮件服务 php,PHP基础-邮件服务

    PHP mail() 函数 PHP mail() 函数用于从脚本中发送电子邮件. 语法 mail(to,subject,message,headers,parameters) 参数 描述 to 必需. ...

  2. MailKit和MimeKit 收发邮件

    新建项目,引用MailKit和MimeKit NuGet包 using CommonTool.MailKit; using System; using System.Collections.Gener ...

  3. 微信在计算机基础中的辅助作用,基于微信课后辅导在计算机基础教学中应用.doc...

    基于微信课后辅导在计算机基础教学中应用 基于微信课后辅导在计算机基础教学中应用 摘 要: 如今,计算机技术更新快与计算机教育资源少的矛盾,促使课后学习成为大学生获取知识的重要途径.课后辅导是大学生课后 ...

  4. 创建基于webpack打包的vue项目

    创建基于webpack打包的vue项目 结合win7.element-ui.vue(vue-router.vue-cli).webpack等技术,完成了项目的基础工作.难则不会,会则不难:贵在经验总结 ...

  5. 基于RxJava2+Retrofit2精心打造的Android基础框架

    代码地址如下: http://www.demodashi.com/demo/12132.html XSnow 基于RxJava2+Retrofit2精心打造的Android基础框架,包含网络.上传.下 ...

  6. 使用图形编辑框架GEF创建基于Eclipse的应用程序

    简介: 了解使用图形编辑框架(Graphical Editing Framework,GEF)创建基于 Eclipse 的应用程序涉及的最初步骤.此外,介绍了目前在 Eclipse 中引导创建图形编辑 ...

  7. 一个基于.Net Core 开源的物联网基础平台

    在智慧工厂领域,智慧城市领域,都需要对设备进行监控.比如工厂需要对周围环境温度.湿度.气压.电压,灯的开关进行监控.这时候就需要物联网平台来进行管理. 在智慧工厂领域,宝马集团通过英伟达的Omnive ...

  8. 基于SpringBoot搭建应用开发框架(一) —— 基础架构

    基于SpringBoot搭建应用开发框架(一) -- 基础架构 目录 Spring的简史 零.开发技术简介 一.创建项目 1.创建工程 2.创建Starter 3.启动项目 4.Spring Boot ...

  9. 基于CoreText的排版引擎:基础

    基于 CoreText 的排版引擎:基础 JUN 27TH, 2015 版权说明 原创文章,转载请保留以下信息: 本文节选自我的图书:<iOS 开发进阶 >. 本文涉及的 Demo 工程在 ...

最新文章

  1. [导入]决定进入J2EE一探究竟
  2. 招商银行的软件BUG
  3. App Store应用脱壳
  4. iOS SAX解析XML
  5. 关于网页授权的两种scope的区别说明
  6. GIT的Push和Pull,强制Pull覆盖本地命令
  7. ptmalloc,tcmalloc和jemalloc内存分配策略研究
  8. JavaScript历史与ECMAScript
  9. eclipce 快捷键
  10. mojang官方正版服务器,《我的世界》如果Mojang上线最新版本,你最想要的是哪种版本更新...
  11. oracle 定时备份数据库脚本
  12. 富文本编辑器CKEditor配置与使用
  13. Mysql错误:#1054 - Unknown column '字段名' in 'field list'
  14. 单片机课设波形发生器 产生方波、三角波、正弦波、锯齿波 波形幅度可调、频率可调
  15. thrift 编译报错 undefined reference
  16. 微博数据解析:综艺节目如何频上微博热搜?以《令人心动的offer》为例
  17. linux中常用的压缩命令,Linux中常用的压缩和解压缩命令汇总
  18. IT大侦“碳”:VxRail的可持续法宝
  19. 古魂魂之刃2电脑版用逍遥模拟器电脑上玩手机账号数据互通
  20. 隐马尔科夫模型java实现

热门文章

  1. NodeJS-queryString
  2. nat+端口转发,使得宿主机secureCRT可以访问vbox里linux虚拟机
  3. 128位加密SSL证书
  4. 介绍一款受欢迎的.NET 开源UI库
  5. C# 使用TCP创建HTTP客户程序
  6. Avalonia跨平台入门第二十二篇之人脸检测
  7. 如何判断当前请求的API类型
  8. 那些35岁的程序员都去哪了
  9. 在 ASP.NET Core 中使用 Serilog 使用 Fluentd 将日志写入 Elasticsearch
  10. .NET 6 即将到来的新特性 — 隐式命名空间引用