基于.NetCore開發博客項目 StarBlog - (28) 開發友情鏈接相關接口
前言
之前介紹的友情鏈接功能,只實現了友情鏈接的展示和管理接口。
還缺失友情鏈接申請、審核管理、通知,現在把這塊功能補全。
Model 什么的之前那篇文章都有,本文直接補全邏輯代碼~
詳見: 基于.NetCore開發博客項目 StarBlog - (13) 加入友情鏈接功能
先看效果
友情鏈接申請頁面

郵件通知
實現一個簡單的通知功能,申請通過之后,給申請友鏈的郵箱發通知。
使用 MimeKit 這個庫可以很方便的實現發郵件功能
為了更方便使用,我封裝了一個 EmailUtils 放在 StarBlog.Share.Utils 里面
public class EmailAccountConfig {
public string Host { get; set; }
public int Port { get; set; }
public string FromUsername { get; set; }
public string FromPassword { get; set; }
public string FromAddress { get; set; }
}
public static class EmailUtils {
public static async Task<MessageSentEventArgs> SendEmailAsync(
EmailAccountConfig config,
string subject,
string htmlBody,
string toName,
string toAddress,
string fromName = "StarBlog"
) {
return await SendEmailAsync(
config,
new MimeMessage {
Subject = subject,
From = {new MailboxAddress(fromName, config.FromAddress)},
To = {new MailboxAddress(toName, toAddress)},
Body = new BodyBuilder {
HtmlBody = htmlBody
}.ToMessageBody()
}
);
}
public static async Task<MessageSentEventArgs> SendEmailAsync(EmailAccountConfig config, MimeMessage message,
HttpProxyClient? proxyClient = null) {
MessageSentEventArgs result = null;
using var client = new SmtpClient {
ServerCertificateValidationCallback = (s, c, h, e) => true,
};
if (proxyClient != null) {
client.ProxyClient = proxyClient;
}
client.AuthenticationMechanisms.Remove("XOAUTH2");
client.MessageSent += (sender, args) => { result = args; };
await client.ConnectAsync(config.Host, config.Port, SecureSocketOptions.Auto);
await client.AuthenticateAsync(config.FromUsername, config.FromPassword);
await client.SendAsync(message);
await client.DisconnectAsync(true);
return result;
}
}
使用比較簡單,傳入郵箱配置和郵件主題、內容、收件地址就行。
具體的可以接著看下面的代碼。
友鏈申請管理
管理友情鏈接申請記錄的邏輯,同樣也是有增刪改查,這部分代碼跟上面的一樣,省略了
構造方法通過依賴注入,從配置系統里讀取了郵箱配置,讀者可以自行將郵箱配置添加到 appsettings.json 中,這里給出一個outlook郵箱的配置
"EmailAccountConfig": {
"Host": "smtp-mail.outlook.com",
"Port": 587,
"FromUsername": "郵箱地址@outlook.com",
"FromPassword": "郵箱密碼",
"FromAddress": "郵箱地址@outlook.com"
}
下面開始是 service 的代碼
這里只貼設置是否驗證 和 發郵件通知 的代碼
public class LinkExchangeService {
private readonly IBaseRepository<LinkExchange> _repo;
private readonly LinkService _linkService;
private readonly EmailAccountConfig _emailAccountConfig;
public LinkExchangeService(IBaseRepository<LinkExchange> repo, LinkService linkService, IOptions<EmailAccountConfig> options) {
_repo = repo;
_linkService = linkService;
_emailAccountConfig = options.Value;
}
public async Task<LinkExchange?> SetVerifyStatus(int id, bool status, string? reason = null) {
var item = await GetById(id);
if (item == null) return null;
item.Verified = status;
item.Reason = reason;
await _repo.UpdateAsync(item);
var link = await _linkService.GetByName(item.Name);
if (status) {
await SendEmailOnAccept(item);
if (link == null) {
await _linkService.AddOrUpdate(new Link {
Name = item.Name,
Description = item.Description,
Url = item.Url,
Visible = true
});
}
else {
await _linkService.SetVisibility(link.Id, true);
}
}
else {
await SendEmailOnReject(item);
if (link != null) await _linkService.DeleteById(link.Id);
}
return await GetById(id);
}
// 本文僅貼上申請通過的代碼,其他的也是類似的寫法
public async Task SendEmailOnAccept(LinkExchange item) {
const string starblogLink = "<a href=\"https://deali.cn\">StarBlog</a>";
var sb = new StringBuilder();
sb.AppendLine($"<p>您好,友鏈申請已通過!感謝支持,歡迎互訪哦~</p>");
sb.AppendLine($"<br>");
sb.AppendLine($"<p>以下是您申請的友鏈信息:</p>");
sb.AppendLine($"<p>網站名稱:{item.Name}</p>");
sb.AppendLine($"<p>介紹:{item.Description}</p>");
sb.AppendLine($"<p>網址:{item.Url}</p>");
sb.AppendLine($"<p>站長:{item.WebMaster}</p>");
sb.AppendLine($"<p>補充信息:{item.Reason}</p>");
sb.AppendLine($"<br>");
sb.AppendLine($"<br>");
sb.AppendLine($"<br>");
sb.AppendLine($"<p>本消息由 {starblogLink} 自動發送,無需回復。</p>");
await EmailUtils.SendEmailAsync(
_emailAccountConfig,
"[StarBlog]友鏈申請結果反饋",
sb.ToString(),
item.WebMaster,
item.Email
);
}
}
在設置是否驗證的方法中,實現了:
- 設置一個申請為已驗證,自動將該申請的鏈接添加到友情鏈接中
- 設置一個申請為未驗證,則自動將對應的友情鏈接刪除(如果存在的話)
其他地方就跟上面的友情鏈接一樣了。
寫完之后別忘了注冊服務
builder.Services.AddScoped<LinkExchangeService>();
builder.Services.AddScoped<LinkService>();
友鏈申請
展示功能做完了,還得接著做友鏈申請的功能,以方便路過的站長申請互換友鏈~
添加 StarBlog.Web/ViewModels/LinkExchange/LinkExchangeAddViewModel.cs 文件
我們使用 AspNetCore MVC 框架提供的表單驗證功能
public class LinkExchangeAddViewModel {
/// <summary>
/// 網站名稱
/// </summary>
[Display(Name = "網站名稱")]
[Required(ErrorMessage = "必須填寫網站名稱")]
public string Name { get; set; }
/// <summary>
/// 介紹
/// </summary>
[Display(Name = "介紹")]
public string? Description { get; set; }
/// <summary>
/// 網址
/// </summary>
[Display(Name = "網址")]
[Required(ErrorMessage = "必須填寫網址")]
[DataType(DataType.Url)]
public string Url { get; set; }
/// <summary>
/// 站長
/// </summary>
[Display(Name = "站長名稱")]
[Required(ErrorMessage = "必須填寫站長名稱")]
public string WebMaster { get; set; }
/// <summary>
/// 聯系郵箱
/// </summary>
[Display(Name = "聯系郵箱")]
[Required(ErrorMessage = "必須填寫聯系郵箱")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
}
接著寫一下頁面 StarBlog.Web/Views/LinkExchange/Add.cshtml
@model StarBlog.Web.ViewModels.LinkExchange.LinkExchangeAddViewModel
@{
ViewData["Title"] = "申請友鏈";
}
<div class="container px-4 py-3">
<h2 class="d-flex w-100 justify-content-between pb-2 mb-3 border-bottom">
<div>申請友鏈</div>
<div>Link Exchange</div>
</h2>
<div class="card px-1 py-3">
<form enctype="multipart/form-data" class="card-body row" asp-controller="LinkExchange" asp-action="Add" method="post">
<div class="col-xl-6">
<div class="mb-4">
<h4 class="card-title">友鏈信息</h4>
<h6 class="card-subtitle mb-3 text-muted">請輸入您的網站信息,方便后續聯系</h6>
</div>
<div class="mb-3">
<label asp-for="Name" class="form-label"></label>
<input asp-for="Name" class="form-control">
<span asp-validation-for="Name" class="form-text text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="Description" class="form-label"></label>
<input asp-for="Description" class="form-control">
<span asp-validation-for="Description" class="form-text text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="Url" class="form-label"></label>
<input asp-for="Url" class="form-control">
<span asp-validation-for="Url" class="form-text text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="WebMaster" class="form-label"></label>
<input asp-for="WebMaster" class="form-control">
<span asp-validation-for="WebMaster" class="form-text text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="Email" class="form-label"></label>
<input asp-for="Email" class="form-control">
<span asp-validation-for="Email" class="form-text text-danger"></span>
</div>
</div>
<div class="col-xl-6">
<div class="ms-3 mb-4">
<h4 class="card-title">注意事項</h4>
<h6 class="card-subtitle mb-3 text-muted">申請友情鏈接需符合以下幾點要求</h6>
</div>
<ul class="list-group list-group-flush list-group-numbered">
<li class="list-group-item d-flex justify-content-between align-items-start">
<div class="ms-2 me-auto">
<div class="fw-bold">相互性</div>
請先在您的網站添加本站鏈接,再進行友鏈申請
</div>
</li>
<li class="list-group-item d-flex justify-content-between align-items-start">
<div class="ms-2 me-auto">
<div class="fw-bold">內容類別</div>
本站優先招同類原創、內容相近的博客或網站
</div>
</li>
<li class="list-group-item d-flex justify-content-between align-items-start">
<div class="ms-2 me-auto">
<div class="fw-bold">SEO</div>
Baidu和Google有正常收錄,有近期快照的網站優先
</div>
</li>
<li class="list-group-item d-flex justify-content-between align-items-start">
<div class="ms-2 me-auto">
<div class="fw-bold">合法性</div>
不含有違反相關國家法律內容的合法網站,不接受TB客等垃圾站的鏈接
</div>
</li>
<li class="list-group-item d-flex justify-content-between align-items-start">
<div class="ms-2 me-auto">
<div class="fw-bold">更新及時性</div>
不接受原創內容很少,且長期不更新的網站
</div>
</li>
<li class="list-group-item d-flex justify-content-between align-items-start">
<div class="ms-2 me-auto">
<div class="fw-bold">可訪問性</div>
如您的網站無法訪問,將會暫時撤銷友情鏈接,如需恢復請聯系站長處理
</div>
</li>
</ul>
</div>
<div class="form-group">
<button type="submit" class="btn btn-outline-primary">提交</button>
<button type="reset" class="btn btn-outline-warning">重置</button>
</div>
</form>
</div>
</div>
最后是Controller,添加 StarBlog.Web/Controllers/LinkExchangeController.cs 文件
代碼如下
public class LinkExchangeController : Controller {
private readonly ILogger<LinkExchangeController> _logger;
private readonly LinkExchangeService _service;
private readonly IMapper _mapper;
private readonly Messages _messages;
public LinkExchangeController(
ILogger<LinkExchangeController> logger, LinkExchangeService service, IMapper mapper,
Messages messages) {
_logger = logger;
_service = service;
_mapper = mapper;
_messages = messages;
}
[HttpGet]
public IActionResult Add() {
return View();
}
[HttpPost]
public async Task<IActionResult> Add(LinkExchangeAddViewModel vm) {
if (!ModelState.IsValid) return View();
if (await _service.HasUrl(vm.Url)) {
_messages.Error("相同網址的友鏈申請已提交!");
return View();
}
var item = _mapper.Map<LinkExchange>(vm);
item = await _service.AddOrUpdate(item);
// 發送郵件通知
await _service.SendEmailOnAdd(item);
_messages.Info("友鏈申請已提交,正在處理中,請及時關注郵件通知~");
return RedirectToAction("Index", "Home");
}
}
搞定~
一切就緒
歡迎各位站長大佬來交換友鏈~!

浙公網安備 33010602011771號