经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
基于.NetCore开发博客项目 StarBlog - (28) 开发友情链接相关接口
来源:cnblogs  作者:程序设计实验室  时间:2023/5/30 11:46:13  对本文有异议

前言

之前介绍的友情链接功能,只实现了友情链接的展示和管理接口。

还缺失友情链接申请、审核管理、通知,现在把这块功能补全。

Model 什么的之前那篇文章都有,本文直接补全逻辑代码~

详见: 基于.NetCore开发博客项目 StarBlog - (13) 加入友情链接功能

先看效果

友情链接申请页面

邮件通知

实现一个简单的通知功能,申请通过之后,给申请友链的邮箱发通知。

使用 MimeKit 这个库可以很方便的实现发邮件功能

为了更方便使用,我封装了一个 EmailUtils 放在 StarBlog.Share.Utils 里面

  1. public class EmailAccountConfig {
  2. public string Host { get; set; }
  3. public int Port { get; set; }
  4. public string FromUsername { get; set; }
  5. public string FromPassword { get; set; }
  6. public string FromAddress { get; set; }
  7. }
  8. public static class EmailUtils {
  9. public static async Task<MessageSentEventArgs> SendEmailAsync(
  10. EmailAccountConfig config,
  11. string subject,
  12. string htmlBody,
  13. string toName,
  14. string toAddress,
  15. string fromName = "StarBlog"
  16. ) {
  17. return await SendEmailAsync(
  18. config,
  19. new MimeMessage {
  20. Subject = subject,
  21. From = {new MailboxAddress(fromName, config.FromAddress)},
  22. To = {new MailboxAddress(toName, toAddress)},
  23. Body = new BodyBuilder {
  24. HtmlBody = htmlBody
  25. }.ToMessageBody()
  26. }
  27. );
  28. }
  29. public static async Task<MessageSentEventArgs> SendEmailAsync(EmailAccountConfig config, MimeMessage message,
  30. HttpProxyClient? proxyClient = null) {
  31. MessageSentEventArgs result = null;
  32. using var client = new SmtpClient {
  33. ServerCertificateValidationCallback = (s, c, h, e) => true,
  34. };
  35. if (proxyClient != null) {
  36. client.ProxyClient = proxyClient;
  37. }
  38. client.AuthenticationMechanisms.Remove("XOAUTH2");
  39. client.MessageSent += (sender, args) => { result = args; };
  40. await client.ConnectAsync(config.Host, config.Port, SecureSocketOptions.Auto);
  41. await client.AuthenticateAsync(config.FromUsername, config.FromPassword);
  42. await client.SendAsync(message);
  43. await client.DisconnectAsync(true);
  44. return result;
  45. }
  46. }

使用比较简单,传入邮箱配置和邮件主题、内容、收件地址就行。

具体的可以接着看下面的代码。

友链申请管理

管理友情链接申请记录的逻辑,同样也是有增删改查,这部分代码跟上面的一样,省略了

构造方法通过依赖注入,从配置系统里读取了邮箱配置,读者可以自行将邮箱配置添加到 appsettings.json 中,这里给出一个outlook邮箱的配置

  1. "EmailAccountConfig": {
  2. "Host": "smtp-mail.outlook.com",
  3. "Port": 587,
  4. "FromUsername": "邮箱地址@outlook.com",
  5. "FromPassword": "邮箱密码",
  6. "FromAddress": "邮箱地址@outlook.com"
  7. }

下面开始是 service 的代码

这里只贴设置是否验证发邮件通知 的代码

  1. public class LinkExchangeService {
  2. private readonly IBaseRepository<LinkExchange> _repo;
  3. private readonly LinkService _linkService;
  4. private readonly EmailAccountConfig _emailAccountConfig;
  5. public LinkExchangeService(IBaseRepository<LinkExchange> repo, LinkService linkService, IOptions<EmailAccountConfig> options) {
  6. _repo = repo;
  7. _linkService = linkService;
  8. _emailAccountConfig = options.Value;
  9. }
  10. public async Task<LinkExchange?> SetVerifyStatus(int id, bool status, string? reason = null) {
  11. var item = await GetById(id);
  12. if (item == null) return null;
  13. item.Verified = status;
  14. item.Reason = reason;
  15. await _repo.UpdateAsync(item);
  16. var link = await _linkService.GetByName(item.Name);
  17. if (status) {
  18. await SendEmailOnAccept(item);
  19. if (link == null) {
  20. await _linkService.AddOrUpdate(new Link {
  21. Name = item.Name,
  22. Description = item.Description,
  23. Url = item.Url,
  24. Visible = true
  25. });
  26. }
  27. else {
  28. await _linkService.SetVisibility(link.Id, true);
  29. }
  30. }
  31. else {
  32. await SendEmailOnReject(item);
  33. if (link != null) await _linkService.DeleteById(link.Id);
  34. }
  35. return await GetById(id);
  36. }
  37. // 本文仅贴上申请通过的代码,其他的也是类似的写法
  38. public async Task SendEmailOnAccept(LinkExchange item) {
  39. const string starblogLink = "<a href=\"https://deali.cn\">StarBlog</a>";
  40. var sb = new StringBuilder();
  41. sb.AppendLine($"<p>您好,友链申请已通过!感谢支持,欢迎互访哦~</p>");
  42. sb.AppendLine($"<br>");
  43. sb.AppendLine($"<p>以下是您申请的友链信息:</p>");
  44. sb.AppendLine($"<p>网站名称:{item.Name}</p>");
  45. sb.AppendLine($"<p>介绍:{item.Description}</p>");
  46. sb.AppendLine($"<p>网址:{item.Url}</p>");
  47. sb.AppendLine($"<p>站长:{item.WebMaster}</p>");
  48. sb.AppendLine($"<p>补充信息:{item.Reason}</p>");
  49. sb.AppendLine($"<br>");
  50. sb.AppendLine($"<br>");
  51. sb.AppendLine($"<br>");
  52. sb.AppendLine($"<p>本消息由 {starblogLink} 自动发送,无需回复。</p>");
  53. await EmailUtils.SendEmailAsync(
  54. _emailAccountConfig,
  55. "[StarBlog]友链申请结果反馈",
  56. sb.ToString(),
  57. item.WebMaster,
  58. item.Email
  59. );
  60. }
  61. }

在设置是否验证的方法中,实现了:

  • 设置一个申请为已验证,自动将该申请的链接添加到友情链接中
  • 设置一个申请为未验证,则自动将对应的友情链接删除(如果存在的话)

其他地方就跟上面的友情链接一样了。

写完之后别忘了注册服务

  1. builder.Services.AddScoped<LinkExchangeService>();
  2. builder.Services.AddScoped<LinkService>();

友链申请

展示功能做完了,还得接着做友链申请的功能,以方便路过的站长申请互换友链~

添加 StarBlog.Web/ViewModels/LinkExchange/LinkExchangeAddViewModel.cs 文件

我们使用 AspNetCore MVC 框架提供的表单验证功能

  1. public class LinkExchangeAddViewModel {
  2. /// <summary>
  3. /// 网站名称
  4. /// </summary>
  5. [Display(Name = "网站名称")]
  6. [Required(ErrorMessage = "必须填写网站名称")]
  7. public string Name { get; set; }
  8. /// <summary>
  9. /// 介绍
  10. /// </summary>
  11. [Display(Name = "介绍")]
  12. public string? Description { get; set; }
  13. /// <summary>
  14. /// 网址
  15. /// </summary>
  16. [Display(Name = "网址")]
  17. [Required(ErrorMessage = "必须填写网址")]
  18. [DataType(DataType.Url)]
  19. public string Url { get; set; }
  20. /// <summary>
  21. /// 站长
  22. /// </summary>
  23. [Display(Name = "站长名称")]
  24. [Required(ErrorMessage = "必须填写站长名称")]
  25. public string WebMaster { get; set; }
  26. /// <summary>
  27. /// 联系邮箱
  28. /// </summary>
  29. [Display(Name = "联系邮箱")]
  30. [Required(ErrorMessage = "必须填写联系邮箱")]
  31. [DataType(DataType.EmailAddress)]
  32. public string Email { get; set; }
  33. }

接着写一下页面 StarBlog.Web/Views/LinkExchange/Add.cshtml

  1. @model StarBlog.Web.ViewModels.LinkExchange.LinkExchangeAddViewModel
  2. @{
  3. ViewData["Title"] = "申请友链";
  4. }
  5. <div class="container px-4 py-3">
  6. <h2 class="d-flex w-100 justify-content-between pb-2 mb-3 border-bottom">
  7. <div>申请友链</div>
  8. <div>Link Exchange</div>
  9. </h2>
  10. <div class="card px-1 py-3">
  11. <form enctype="multipart/form-data" class="card-body row" asp-controller="LinkExchange" asp-action="Add" method="post">
  12. <div class="col-xl-6">
  13. <div class="mb-4">
  14. <h4 class="card-title">友链信息</h4>
  15. <h6 class="card-subtitle mb-3 text-muted">请输入您的网站信息,方便后续联系</h6>
  16. </div>
  17. <div class="mb-3">
  18. <label asp-for="Name" class="form-label"></label>
  19. <input asp-for="Name" class="form-control">
  20. <span asp-validation-for="Name" class="form-text text-danger"></span>
  21. </div>
  22. <div class="mb-3">
  23. <label asp-for="Description" class="form-label"></label>
  24. <input asp-for="Description" class="form-control">
  25. <span asp-validation-for="Description" class="form-text text-danger"></span>
  26. </div>
  27. <div class="mb-3">
  28. <label asp-for="Url" class="form-label"></label>
  29. <input asp-for="Url" class="form-control">
  30. <span asp-validation-for="Url" class="form-text text-danger"></span>
  31. </div>
  32. <div class="mb-3">
  33. <label asp-for="WebMaster" class="form-label"></label>
  34. <input asp-for="WebMaster" class="form-control">
  35. <span asp-validation-for="WebMaster" class="form-text text-danger"></span>
  36. </div>
  37. <div class="mb-3">
  38. <label asp-for="Email" class="form-label"></label>
  39. <input asp-for="Email" class="form-control">
  40. <span asp-validation-for="Email" class="form-text text-danger"></span>
  41. </div>
  42. </div>
  43. <div class="col-xl-6">
  44. <div class="ms-3 mb-4">
  45. <h4 class="card-title">注意事项</h4>
  46. <h6 class="card-subtitle mb-3 text-muted">申请友情链接需符合以下几点要求</h6>
  47. </div>
  48. <ul class="list-group list-group-flush list-group-numbered">
  49. <li class="list-group-item d-flex justify-content-between align-items-start">
  50. <div class="ms-2 me-auto">
  51. <div class="fw-bold">相互性</div>
  52. 请先在您的网站添加本站链接,再进行友链申请
  53. </div>
  54. </li>
  55. <li class="list-group-item d-flex justify-content-between align-items-start">
  56. <div class="ms-2 me-auto">
  57. <div class="fw-bold">内容类别</div>
  58. 本站优先招同类原创、内容相近的博客或网站
  59. </div>
  60. </li>
  61. <li class="list-group-item d-flex justify-content-between align-items-start">
  62. <div class="ms-2 me-auto">
  63. <div class="fw-bold">SEO</div>
  64. BaiduGoogle有正常收录,有近期快照的网站优先
  65. </div>
  66. </li>
  67. <li class="list-group-item d-flex justify-content-between align-items-start">
  68. <div class="ms-2 me-auto">
  69. <div class="fw-bold">合法性</div>
  70. 不含有违反相关国家法律内容的合法网站,不接受TB客等垃圾站的链接
  71. </div>
  72. </li>
  73. <li class="list-group-item d-flex justify-content-between align-items-start">
  74. <div class="ms-2 me-auto">
  75. <div class="fw-bold">更新及时性</div>
  76. 不接受原创内容很少,且长期不更新的网站
  77. </div>
  78. </li>
  79. <li class="list-group-item d-flex justify-content-between align-items-start">
  80. <div class="ms-2 me-auto">
  81. <div class="fw-bold">可访问性</div>
  82. 如您的网站无法访问,将会暂时撤销友情链接,如需恢复请联系站长处理
  83. </div>
  84. </li>
  85. </ul>
  86. </div>
  87. <div class="form-group">
  88. <button type="submit" class="btn btn-outline-primary">提交</button>
  89. <button type="reset" class="btn btn-outline-warning">重置</button>
  90. </div>
  91. </form>
  92. </div>
  93. </div>

最后是Controller,添加 StarBlog.Web/Controllers/LinkExchangeController.cs 文件

代码如下

  1. public class LinkExchangeController : Controller {
  2. private readonly ILogger<LinkExchangeController> _logger;
  3. private readonly LinkExchangeService _service;
  4. private readonly IMapper _mapper;
  5. private readonly Messages _messages;
  6. public LinkExchangeController(
  7. ILogger<LinkExchangeController> logger, LinkExchangeService service, IMapper mapper,
  8. Messages messages) {
  9. _logger = logger;
  10. _service = service;
  11. _mapper = mapper;
  12. _messages = messages;
  13. }
  14. [HttpGet]
  15. public IActionResult Add() {
  16. return View();
  17. }
  18. [HttpPost]
  19. public async Task<IActionResult> Add(LinkExchangeAddViewModel vm) {
  20. if (!ModelState.IsValid) return View();
  21. if (await _service.HasUrl(vm.Url)) {
  22. _messages.Error("相同网址的友链申请已提交!");
  23. return View();
  24. }
  25. var item = _mapper.Map<LinkExchange>(vm);
  26. item = await _service.AddOrUpdate(item);
  27. // 发送邮件通知
  28. await _service.SendEmailOnAdd(item);
  29. _messages.Info("友链申请已提交,正在处理中,请及时关注邮件通知~");
  30. return RedirectToAction("Index", "Home");
  31. }
  32. }

搞定~

一切就绪

欢迎各位站长大佬来交换友链~!

原文链接:https://www.cnblogs.com/deali/p/starblog-28.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号