Article directory
- Target
- Create WebApi
-
- 1. Create a database
-
- 1. Data table composition
- 2. SQL script
- 2. Link EFCore and perform dependency injection
- 3. Code explanation
-
- 1. Rewrite the controller base class
- 2. Create the controller
- 3. Return value Models class
- 4. Config
-
- (1).Config.cs
- (2). Model class of Config
- (3).platform.json
- 5. External WebApi call
-
- (1).ExternWebApiBase.cs
- (2).Address class
- 6.Mail Platform
-
- (1).MailBuilder
- (2).Mail Platform
- 7. Global reference (NET6.0)
- 3. Packages that need to be imported
- Project file download
- EMail-API service
Goal
Send a letter to the request mailbox through SMTP, the sending mailbox is created by the API creator, and the permissions are set
Create WebApi
1. Create a database
1. Data table composition
TB_RequestLog
column name | type | feature | remark |
---|---|---|---|
Index | int | Primary key automatically grows non-null | Number |
Region | nchar(32) | not empty | controller name |
Action | nchar(32) | not empty | function name |
Arguments | varchar (max) | not empty | parameter set |
IP | nchar(16) | Requester IP | |
Address | nchar(32) | Requester location | |
Identity | nchar(11) | Requester authentication | |
LogTime | datetime | not null | log time |
TB_Mail
column name | type | feature | remark |
---|---|---|---|
Guid | nchar(16) | Non-empty primary key | Unique UID |
Address | nchar(32) | Not empty | Current mailbox |
Title | nvarchar(max) | not empty | Title |
Body | nvarchar (max) | not empty | body |
Allocated | nchar(32) | Not Null | Assigned Subject Number |
SendTime | datetimt | Not Null | Time of occurrence |
2.SQL script
USE [db_spaceserver] go SET ANSI_NULLS ON go SET QUOTED_IDENTIFIER ON go CREATE TABLE [dbo].[TB_Mail]( [Guid] [nchar](16) NOT NULL, [Address] [nchar](32) NOT NULL, [Title] [nvarchar](max) NOT NULL, [Body] [nvarchar](max) NOT NULL, [Allocated] [nchar](32) NOT NULL, [SendTime] [datetime] NOT NULL, CONSTRAINT [PK_TB_Mail] PRIMARY KEY CLUSTERED ( [Guid] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] go SET ANSI_NULLS ON go SET QUOTED_IDENTIFIER ON go CREATE TABLE [dbo].[TB_RequestLog]( [Index] [int] IDENTITY(1,1) NOT NULL, [Region] [nchar](32) NOT NULL, [Action] [nchar](32) NOT NULL, [Arguments] [varchar](max) NULL, [IP][nchar](16) NULL, [Address] [nchar](32) NULL, [Identity] [nchar](11) NULL, [LogTime] [datetime] NOT NULL, CONSTRAINT [PK_TB_RequestLog] PRIMARY KEY CLUSTERED ( [Index] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] go
2. Link EFCore and perform dependency injection
The process refers to the previous steps to connect EFCore
EFCore’s link generation context and model
Dependency injection after completion
(The author uses the environment of .NET6.0, the configuration items are in Program.cs
, if you use the previous version, the configuration items are in Startup.cs
)
builder.Services.AddSqlServer<Db_SpaceserverContext>(builder.Configuration.GetConnectionString("DB_SpaceServer"));
Remember to configure the link string in advance in appsettings.json
Then make the following configuration
builder.Services.AddControllersWithViews().AddJsonOptions(options => {<!-- --> options.JsonSerializerOptions.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All); }); builder.Services.AddRouting(options => options.LowercaseUrls = true);
The first configuration above can make Json serialization without encoding errors, and the second one can make the URL all lowercase
3. Code explanation
1. Override the controller base class
First of all, we inherit a controller base class to replace ControllerBase, because we need to use many specific methods, and the base class can provide a lot of convenience for programming
public class ControllerBaseEx : ControllerBase, IDisposable {<!-- --> protected Db_SpaceserverContext DBContext {<!-- --> set; get; } protected string RequestIP {<!-- --> get {<!-- --> var ip = HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault(); if (string. IsNullOrEmpty(ip)) {<!-- --> ip = HttpContext.Connection.RemoteIpAddress.ToString(); } return ip; } } protected Config Config {<!-- --> get; } = new Config(); protected List<Task> WaitTasks = new List<Task>(); protected ControllerBaseEx(Db_SpaceserverContext context) {<!-- --> DBContext = context; } void IDisposable. Dispose() {<!-- --> //Wait for all tasks to be executed foreach (var c in WaitTasks) c. Wait(); } protected void Log(object args, string identity = "") {<!-- --> Address address = new(); string region = (ControllerContext.RouteData.Values["controller"] "NULL").ToString(); string action = (ControllerContext.RouteData.Values["action"] "NULL").ToString(); var log = new TbRequestLog() {<!-- --> Action = action, Region = region, Ip = RequestIP.Length < 5 ? "" : RequestIP, Address = RequestIP.Length < 5 ? "" : address.GetAddress(RequestIP), LogTime = DateTime. Now, Identity = identity, Arguments = JsonConvert. SerializeObject(args) }; DBContext.TbRequestLog.Add(log); DBContext. SaveChanges(); } protected void Log(string args, string identity = "") {<!-- --> Address address = new(); string region = (ControllerContext.RouteData.Values["controller"] "NULL").ToString(); string action = (ControllerContext.RouteData.Values["action"] "NULL").ToString(); var log = new TbRequestLog() {<!-- --> Action = action, Region = region, Ip = RequestIP.Length < 5 ? "" : RequestIP, Address = RequestIP.Length < 5 ? "" : address.GetAddress(RequestIP), LogTime = DateTime. Now, Identity = identity, Arguments = args }; DBContext.TbRequestLog.Add(log); DBContext. SaveChanges(); } protected string JsonString(object args) => JsonConvert.SerializeObject(args); protected ActionResult Json(object args) => new JsonResult(args); protected BadRequestObjectResult Error(string result) => BadRequest(new {<!-- --> code = 400, result = result }); protected string Random(int length, string dic = "") {<!-- --> dic = dic == "" ? "qwertyuiopasdfghjklzxcvbnm0123456789QWERTYUIOPASDFGHJKLZXCVBNM" : dic == "-1" ? "0123456789" : dic; string data = "";Random rand = new Random(); for(int i= 0; i < length; i ++ ) {<!-- --> data + = dic[rand. Next(dic. Length)]; } return data; } }
field value
DBContext
EFCore context object, initialized with injection object after inheritance
RequestIP
Request IP, actually get the X-Forwarded-For
field in the header, if the local request, this value is ‘:::’
Config
is used to get other configuration files
WaitTasks
is used to save all asynchronous tasks
function
protected ControllerBaseEx(Db_SpaceserverContext context)
parameter name | type | description |
---|---|---|
context | Db_SpaceserverContext | used to initialize DBContext properties |
initialization function
void IDisposable. Dispose()
Used to wait for all task objects when the object is released
protected void Log(object args, string identity = “”)
parameter name | type | description |
---|---|---|
args | object | parameter object object |
identity | string | Requester Authentication |
protected void Log(string args, string identity = “”)
parameter name | type | description |
---|---|---|
args | string | Serialized parameter set |
identity | string | Requester Authentication |
Used to record LOG information
protected string JsonString(object args)
parameter name | type | description |
---|---|---|
args | object | Data to be converted |
for serializing objects
protected ActionResult Json(object args)
parameter name | type | description |
---|---|---|
args | object | returned json object |
Used to return JsonResult
protected BadRequestObjectResult Error(string result)
parameter name | type | description |
---|---|---|
result | string | Error reason |
Used to return BadRequest
protected string Random(int length, string dic = “”)
parameter name | type | description |
---|---|---|
length | int | generated length |
dic | string | generated Dictionary |
It is used to generate a random sequence of a specified length. If dic is empty, it will be selected from the full dictionary. If it is -1, a digital set will be generated, and the others will be specified sets
2. Create a controller
ControllerNameMailCodeController.cs
[Route("api/[controller]/[action]")] [ApiController] public class MailCodeController : ControllerBaseEx {<!-- --> private ILogger<MailCodeController> _logger; private MailPlatformSetting_setting; public MailCodeController(Db_SpaceserverContext context, ILogger<MailCodeController> logger) : base(context) {<!-- --> _logger = logger; _setting = Config.GetSetting<MailPlatformSetting>("platform.json"); } [HttpGet] public async Task<IActionResult> SendCode(string code,string office,string address) {<!-- --> try {<!-- --> //write to log object log = new {<!-- --> code, office, address }; Log(JsonString(log), "SYSTEM"); //judgment information if (code.Length > 10) throw new Exception("exceeds the maximum content length, 10 characters"); if (office.Length > 16) throw new Exception("exceeds the maximum signature length, 16 bits"); //Check if the email address matches Regex regex = new(@"^[A-Za-z0-9\\一-\\龥] + @[a-zA-Z0-9_-] + (\.[a-zA-Z0-9_ -] + ) + $"); if (!regex.IsMatch(address)) throw new Exception("Email address does not match"); //Generate GUID and time string guid = Random(16); DateTime time = DateTime. Now; //Create a platform MailPlatform platform = new(_setting. Platform. ToArray()); //Create information MailBuilder builder = new MailBuilder(); builder.Address.Add(address); builder.Subject = $"Verification code from {office}"; builder.Body = $"Your verification code is: {code}, the sender is: {office}, and the sending time is: {time}"; //send email var task = platform.SendMailAsync(builder.Build()); WaitTasks. Add(task); //write record TbMail mail = new TbMail() {<!-- --> Address = address, Allocated = platform.LastAllocatedMail, Body = builder.Body, Title = builder. Subject, Guid = guid, SendTime = time, }; //Save to database DBContext.TbMail.Add(mail); DBContext. SaveChanges(); //Generate return set MailCodeModel model = new() {<!-- --> Address = address, Content = $"-H {builder.Subject} -B {builder.Body}", Guid = guid, DateTime = time, }; return Json(model); } catch(Exception ex) {<!-- --> return Error(ex. Message); } } }
field value
_logger
WebApi comes with log object
_setting
MailPlatform setting object
function
public MailCodeController(Db_SpaceserverContext context, ILogger logger)
parameter name | type | description |
---|---|---|
context | Db_SpaceserverContext | Injection context object |
logger | ILogger | Inject log object |
initialization function
[HttpGet]
public async Task SendCode(string code, string office, string address)
parameter name | type | description |
---|---|---|
code | string | Verification code |
office | string | company name |
address | string | target mailbox |
Verification code sending function
3. Return value Models class
public class MailCodeModel {<!-- --> public string Guid {<!-- --> set; get; } public string Address {<!-- --> set; get; } public string Content {<!-- --> set; get; } public DateTime DateTime {<!-- --> set; get; } }
field value
Guid
The unique Uid of the sending mark
Address
target mailbox
Content
content
DateTime
Sending time
4.Config
(1).Config.cs
public class Config {<!-- --> public T GetSetting<T>(string path) where T:class {<!-- --> StreamReader reader = new(path); var data = reader. ReadToEnd(); reader. Close(); return JsonConvert. DeserializeObject<T>(data); } }
function
public T GetSetting(string path) where T:class
parameter name | type | description |
---|---|---|
path | string | json file address |
T | T | Profile Model |
Get the configuration file and turn it into a .NET object
(2).Model class of Config
public class MailPlatformSetting {<!-- --> public List<EMailSetting> Platform {<!-- --> get; set; } public int Count => Platform. Count; } public class EMailSetting {<!-- --> public string EMail {<!-- --> get; set; } public string Key {<!-- --> get; set; } }
(3).platform.json
{<!-- --> "Platform": [ {<!-- --> "EMail": "Mailbox", "Key": "Authorization Code" }, {<!-- --> "EMail": "Mailbox", "Key": "Authorization Code" }, {<!-- --> "EMail": "Mailbox", "Key": "Authorization Code" } ] }
5. External WebApi call
(1).ExternWebApiBase.cs
public class ExternWebApiBase {<!-- --> protected string RequestByGet(string baseurl, params string[] args) {<!-- --> string url = baseurl + "?"; url + = string.Join(' &', args); HttpClient client = new HttpClient(); HttpRequestMessage request = new HttpRequestMessage(HttpMethod. Get, url); HttpResponseMessage response = client.Send(request); return response.Content.ReadAsStringAsync().Result; } protected T RequestByGet<T>(string baseurl, params string[] args) {<!-- --> string url = baseurl + "?"; url + = string.Join(' &', args); HttpClient client = new HttpClient(); HttpRequestMessage request = new HttpRequestMessage(HttpMethod. Get, url); HttpResponseMessage response = client.Send(request); return JsonConvert. DeserializeObject<T>(response. Content. ReadAsStringAsync(). Result); } protected string RequestByPost(string baseurl, object args) {<!-- --> string url = baseurl; HttpClient client = new HttpClient(); HttpRequestMessage request = new HttpRequestMessage(HttpMethod. Post, url); //Piece together json JsonContent content = JsonContent. Create(args); request.Content = content; HttpResponseMessage response = client.Send(request); return response.Content.ReadAsStringAsync().Result; } protected T RequestByPost<T>(string baseurl, object args) {<!-- --> string url = baseurl; HttpClient client = new HttpClient(); HttpRequestMessage request = new HttpRequestMessage(HttpMethod. Post, url); //Piece together json JsonContent content = JsonContent. Create(args); request.Content = content; HttpResponseMessage response = client.Send(request); return JsonConvert. DeserializeObject<T>(response. Content. ReadAsStringAsync(). Result); } }
(2).Address class
public class Address: ExternWebApiBase {<!-- --> public string GetAddress(string ip) {<!-- --> string url = "http://whois.pconline.com.cn/ip.jsp"; string data = RequestByGet(url, $"ip={ip}", $"level=3" ); return data; } }
6. MailPlatform
Implementation of MailPlatform
But it is different from the above blog, we have to change it a little bit
(1).MailBuilder
public class MailBuilder {<!-- --> public MailBuilder() {<!-- --> } public List<string>? Address {<!-- --> set; get; } = new List<string>(); public string? Body {<!-- --> set; get; } = string.Empty; public Encoding? Encoding {<!-- --> set; get; } = Encoding.UTF8; public bool? IsHtml {<!-- --> set; get; } = true; public string? Subject {<!-- --> set; get; } = string.Empty; public List<string>? Attachments {<!-- --> set; get; } = new List<string>(); public MailMessage Build() {<!-- --> var message = new MailMessage(); if (Address?.Count == 0) throw new Exception("The sender cannot be empty"); foreach (var c in Address) {<!-- --> message.To.Add(c); } message.Subject = Subject; message.Body = Body; message.IsBodyHtml = IsHtml true; message.BodyEncoding = Encoding; message.Priority = MailPriority.Normal; message.SubjectEncoding = Encoding; foreach(var c in Attachments) {<!-- --> if (!File.Exists(c)) throw new Exception("The attachment file does not exist"); var data = new Attachment(c, MediaTypeNames.Application.Octet);//instantiate the attachment data.ContentDisposition.CreationDate = File.GetCreationTime(c); data.ContentDisposition.ModificationDate = File.GetLastAccessTime(c); data.ContentDisposition.ReadDate = DateTime.Now; message.Attachments.Add(data);//Add to the attachment } return message; } public Task<MailMessage> BuildAsync() {<!-- --> Task<MailMessage> message = new Task<MailMessage>(() => {<!-- --> var message = new MailMessage(); if (Address?.Count == 0) throw new Exception("The sender cannot be empty"); foreach (var c in Address) {<!-- --> message.To.Add(c); } message.Subject = Subject; message.Body = Body; message.IsBodyHtml = IsHtml true; message.BodyEncoding = Encoding; message.Priority = MailPriority.Normal; message.SubjectEncoding = Encoding; foreach (var c in Attachments) {<!-- --> if (!File.Exists(c)) throw new Exception("The attachment file does not exist"); var data = new Attachment(c, MediaTypeNames.Application.Octet);//instantiate the attachment data.ContentDisposition.CreationDate = File.GetCreationTime(c); data.ContentDisposition.ModificationDate = File.GetLastAccessTime(c); data.ContentDisposition.ReadDate = DateTime.Now; message.Attachments.Add(data);//Add to the attachment } return message; }); message. Start(); return message; } }
(2).MailPlatform
public class MailPlatform {<!-- --> private string _last; public string LastAllocatedMail {<!-- --> get => _last; } private List<(MailAddress, string)>? _mailinformation; public MailPlatform(params (MailAddress, string)[]? pairs) {<!-- --> _mailinformation = pairs.ToList() throw new Exception("Wrong initialization"); } public MailPlatform(params EMailSetting[]? pairs) {<!-- --> _mailinformation = new List<(MailAddress, string)>(); foreach(var c in pairs) {<!-- --> (MailAddress, string) data = (new MailAddress(c.EMail), c.Key); _mailinformation. Add(data); } if (_mailinformation.Count == 0) throw new Exception("Wrong initialization"); } public void SendMail(MailMessage message) {<!-- --> var random = new Random(); var info = _mailinformation?.OrderBy(s => Guid.NewGuid()).FirstOrDefault() throw new Exception("No settings have been initialized"); _last = info.Item1.Address; message.From = info.Item1; var client = new SmtpClient() {<!-- --> EnableSsl = true, UseDefaultCredentials = false, Credentials = new System.Net.NetworkCredential(info.Item1.Address, info.Item2), DeliveryMethod = SmtpDeliveryMethod. Network, Host = "smtp." + info.Item1.Host }; client.Send(message); } public void SendMailAsync(MailMessage message, SendCompletedEventHandler CompletedMethod, object args) {<!-- --> var random = new Random(); var info = _mailinformation?.OrderBy(s => Guid.NewGuid()).FirstOrDefault() throw new Exception("No settings have been initialized"); _last = info.Item1.Address; message.From = info.Item1; var client = new SmtpClient() {<!-- --> EnableSsl = true, UseDefaultCredentials = false, Credentials = new System.Net.NetworkCredential(info.Item1.Address, info.Item2), DeliveryMethod = SmtpDeliveryMethod. Network, Host = "smtp." + info.Item1.Host }; client.SendCompleted += new SendCompletedEventHandler(CompletedMethod); client.SendAsync(message, args); } public Task SendMailAsync(MailMessage message) {<!-- --> var random = new Random(); var info = _mailinformation?.OrderBy(s => Guid.NewGuid()).FirstOrDefault() throw new Exception("No settings have been initialized"); _last = info.Item1.Address; Task task = new Task(() => {<!-- --> message.From = info.Item1; var client = new SmtpClient() {<!-- --> EnableSsl = true, UseDefaultCredentials = false, Credentials = new System.Net.NetworkCredential(info.Item1.Address, info.Item2), DeliveryMethod = SmtpDeliveryMethod. Network, Host = "smtp." + info.Item1.Host }; client.Send(message); }); task. Start(); return task; } }
Because to get the Allocate information, you need to call the LastAllocatedMail
property
7. Global reference (NET6.0)
GlobalUsing.cs
//SpaceServer function global using SpaceServer. EFCore; global using SpaceServer. EFCore. Models; global using SpaceServer. Programs. Mail; global using SpaceServer. Programs. Address; global using SpaceServer. Programs. Config; global using SpaceServer.Programs.Config.Models; global using SpaceServer.Models; //Mincrosoft function global using Microsoft.AspNetCore.Mvc; global using Microsoft.AspNetCore.Http; //System function global using System.Net; global using System.IO; global using System. Text; global using System.Text.RegularExpressions; //external function global using Newtonsoft.Json; global using Newtonsoft.Json.Linq;
3. Packages that need to be imported
Project file download
Project file download
EMail-API service
This API can only be used for verification code testing, not for other aspects, all problems have nothing to do with the author
Request address: api.spaceserver.cloud/api/mailcode/sendcode?
Request method: GET
parameter set
parameter name | type | description |
---|---|---|
code | string | Verification code sent |
office | string | Company name |
address | string | Target email address |
parameter name | type | description |
---|---|---|
Guid | string | Unique Identifier |
Address | string | Target Email Address |
Content | string | Content |
DateTime | DateTime | Send time |
error set
parameter name | type | description |
---|---|---|
code | int | error code |
result | string | error Reason |