C# .NET更智能的資料庫操作的封裝

来源:http://www.cnblogs.com/jnxzk/archive/2017/02/25/6443192.html
-Advertisement-
Play Games

前述: 對資料庫操作的封裝,相信網路上已經有一大堆,ORM框架,或者是.NET本身的EF,都很好的支持資料庫操作。這篇文章是分享自己所思考的,對資料庫操作的簡單封裝。我對於這篇文章,認為被瀏覽者所關註重點的是怎麼分析設計資料庫操作封裝,代碼是其次。而且,這是我第一篇文章,為了想好怎麼實現花了些天,代 ...


前述:

  對資料庫操作的封裝,相信網路上已經有一大堆,ORM框架,或者是.NET本身的EF,都很好的支持資料庫操作。這篇文章是分享自己所思考的,對資料庫操作的簡單封裝。我對於這篇文章,認為被瀏覽者所關註重點的是怎麼分析設計資料庫操作封裝,代碼是其次。而且,這是我第一篇文章,為了想好怎麼實現花了些天,代碼是博客發表時現寫的。所以我想,使用可能還有bug,而且沒有try catch異常的設計。

  這個框架我理應做到對資料庫無關,無論是哪個資料庫都能夠使用。不過,重點在於分析,而不是代碼。所以,為了更好的闡述,我只做了對sql Server的封裝,對其他的話,瀏覽者可以自己設計;框架可支持鏈式寫法,我想,在許多編程語言,大家對鏈式寫法大不會陌生,所以我想,資料庫訪問也可以做成鏈式的模式。這個框架不需要寫sql語句,對任何的操作,都只需要簡單的傳所需的參數,封裝好對應的操作。

  在閱讀文章之前最好有些泛型、反射、Link的基礎,不然閱讀可能會有些費勁。

 

進入重點:

  框架的結構比較簡單,使用簡單工廠模式,因此筆者就不畫一張UML圖來解釋,而用文字對裡面方法進行描述。

  在設計工廠介面時候,應該考慮介面中應該含有鏈式寫法必須的三個階段(也稱部分):資料庫基本操作(打開,關閉,創建等)、資料庫的增刪改查、資料庫返回的數據(這裡我做為執行階段,估計大家會好奇為什麼不是上一階段,大家往下閱讀就知道)和不是必須的事務操作。

 

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Data;
  6 using System.Data.SqlClient;
  7 
  8 namespace Dal
  9 {
 10     public interface DbHelper
 11     {
 12         /// <summary>
 13         /// 創建資料庫連接
 14         /// </summary>
 15         /// <param name="connectionString">連接字元串</param>
 16         /// <returns></returns>
 17         DbHelper createConnection(string connectionString);
 18 
 19         /// <summary>
 20         /// 打開資料庫
 21         /// </summary>
 22         /// <returns></returns>
 23         DbHelper openConnection();
 24 
 25         /// <summary>
 26         /// 關閉資料庫
 27         /// </summary>
 28         /// <returns></returns>
 29         DbHelper closeConnection();
 30 
 31         /// <summary>
 32         /// 釋放sqlConnection對象
 33         /// </summary>
 34         void DisposedConnection();
 35 
 36         /// <summary>
 37         /// 釋放sqlCommand對象
 38         /// </summary>
 39         void DisposedCommand();
 40 
 41         /// <summary>
 42         /// 創建sqlCommand對象
 43         /// </summary>
 44         /// <returns></returns>
 45         DbHelper createCommand();
 46 
 47         /// <summary>
 48         /// 設置sqlCommand的類型
 49         /// </summary>
 50         /// <param name="type">CommandType枚舉類型</param>
 51         /// <returns></returns>
 52         DbHelper setCommandType(CommandType type);
 53         
 54         /// <summary>
 55         /// 要查詢的表(多表以逗號隔開)、存儲過程、視圖名
 56         /// </summary>
 57         /// <param name="Name"></param>
 58         /// <returns></returns>
 59         DbHelper FromName(string Name);
 60 
 61         /// <summary>
 62         /// 創建事務
 63         /// </summary>
 64         /// <returns></returns>
 65         DbHelper beginTransaction();
 66 
 67         /// <summary>
 68         /// 事務回滾
 69         /// </summary>
 70         /// <returns></returns>
 71         DbHelper TransactionRowBack();
 72 
 73         /// <summary>
 74         /// 事務提交
 75         /// </summary>
 76         /// <returns></returns>
 77         DbHelper TransactionCommit();
 78 
 79         /// <summary>
 80         /// 對多張表間的列進行聯繫
 81         /// </summary>
 82         /// <param name="Fields">表間聯繫的欄位</param>
 83         /// <returns></returns>
 84         DbHelper ForMulTable(string Fields);
 85 
 86         /// <summary>
 87         /// 查詢
 88         /// </summary>
 89         /// <param name="Fields">查詢欄位</param>
 90         /// <param name="Where">查詢條件字典</param>
 91         /// <param name="otherWhere">其他條件</param>
 92         /// <returns></returns>
 93         DbHelper Select(string Fields = "*", Dictionary<string, object> Where = null, string otherWhere = "");
 94 
 95         /// <summary>
 96         /// 更新
 97         /// </summary>
 98         /// <param name="model">需要更新的對象</param>
 99         /// <param name="Where">更新條件</param>
100         /// <param name="Fields">更新欄位</param>
101         /// <param name="otherWhere">其他條件</param>
102         /// <returns></returns>
103         DbHelper Update(object model, Dictionary<string, object> Where, string Fields = "", string otherWhere = "");
104 
105         /// <summary>
106         /// 插入
107         /// </summary>
108         /// <param name="model">需要插入的對象</param>
109         /// <param name="Fields">需要插入的欄位</param>
110         /// <returns></returns>
111         DbHelper Insert(object model, string Fields = "");
112 
113         /// <summary>
114         /// 刪除
115         /// </summary>
116         /// <param name="Where">刪除條件</param>
117         /// <param name="otherWhere">其他條件</param>
118         /// <returns></returns>
119         DbHelper Delete(Dictionary<string, object> Where, string otherWhere = "");
120 
121 
122         /// <summary>
123         /// 查詢返回List
124         /// </summary>
125         /// <typeparam name="T">模型</typeparam>
126         /// <returns></returns>
127         List<T> ToList<T>()
128             where T : class ,new();
129 
130         
131         /// <summary>
132         /// 查詢返回DataSet
133         /// </summary>
134         /// <param name="DatasetName"></param>
135         /// <returns></returns>
136         DataSet ToDataSet(string DatasetName);
137 
138         /// <summary>
139         /// 查詢返回DataTable
140         /// </summary>
141         /// <returns></returns>
142         DataTable ToDataTable();
143 
144         /// <summary>
145         /// 執行存儲過程
146         /// </summary>
147         /// <param name="Parameter">存儲過程參數</param>
148         /// <returns></returns>
149         DbHelper ExcuteProc(Dictionary<string, object> Parameter);
150 
151         /// <summary>
152         /// 執行返回查詢第一行第一列值
153         /// </summary>
154         /// <returns></returns>
155         object Result();
156 
157         /// <summary>
158         /// 返回執行的影響行數
159         /// </summary>
160         /// <returns></returns>
161         int ExcuteResult();
162 
163         /// <summary>
164         /// 用戶自定義sqlCommand
165         /// </summary>
166         /// <param name="fun">委托</param>
167         void UserDefineOperation(Action<dynamic> fun);
168     }
169 }

 

  好了,看完代碼,大家對具體實現應該還是一頭霧水,那,接下來一步步分析具體實現,是以sql Server來分析。

  在具體實現的類中SQLHelper,設計中所必須的欄位。在一開始設計時候,我在想怎麼給各個資料庫相容,因為它們使用的執行對象Command是不同的,所以為了能夠更好封裝的庫,將其設計sqlCommand不暴露給外部使用,而是在內部使用。暴露方法能夠設置com的屬性,以及ExcuteName就存放著執行數據的對象。

 

//連接字元串
        string ConnectionString;
        
        //資料庫連接對象
        private SqlConnection conn;

        //執行對象
        SqlCommand com;

        //表、存儲過程、視圖名稱
        string ExcuteName;

        //事務
        SqlTransaction tran;

        //sql語句
        StringBuilder sqlBuilderString;

        //參數
        SqlParameter[] paras;

 

 

 

 第一部分:資料庫基本操作

  createConnection方法:這個方法其實就是new sqlConnection,對其賦值connectionString,也採用了大家一般使用的單例模式,這樣也會在執行的時候比較安全。不過這個單例是指一個Helper對應一個sqlConnection,而不是設計為static,因為我覺得有些項目在訪問的資料庫有可能有多個。而且在創建時候,對其進行打開和關閉一次,為了檢查能否真的能使用。

 

public DbHelper createConnection(string connectionString)
        {
            if (!ConnectionCanUse())
            {
                this.ConnectionString = connectionString;
                conn = new SqlConnection(this.ConnectionString);
            }

            return this;
        }

        /// <summary>
        /// 檢查conn是否能用
        /// </summary>
        /// <returns></returns>
        public bool ConnectionCanUse()
        {
            if (conn == null)
                return false;
            try
            {
                conn.Open();
                conn.Close();
            }catch(Exception e)
            {
                return false;
            }
            
            return true;
        }

 

  打開、關閉、釋放connection和創建command就不作解釋了,因為裡面就一句話。

  關於基本操作,還有就是關於sqlCommandType的設置,因為存儲過程和普通的語句等操作字元串明顯是不同,因此要寫個方法來設置它。

 

  第二部分:增刪改查的操作 這裡就解釋為什麼sql語句不是在這個階段執行。我覺得,如果將具體的執行放在這個階段,那麼就會導致方法重載過多,為什麼?因為並不是所有人都能考慮到使用者要返回的類型,比如我想要List,或者DataSet等等,而且還會將這個方法的作用過重:在我設計的這些方法中,實操作的是對sql語句的生成,所以說為什麼不能在這邊執行,那麼就不能重用。是吧,這樣設計很靈活,將資料庫真正執行放在下個階段。而且這些方法都是鏈式的寫法,所以會對執行能夠很靈活的控制,最重要能夠重用,不需要寫別的重載方法,只需要一個方法。

  生成sql語句在這也是簡單的封裝,如果要做起真的框架,我覺得sql字元串的組合還應該創建一個類,來更智能的組合用戶的需求。

  自然,裡面使用到反射、Linq。不過筆者也一步步解釋,將怎麼設計分享給大家。

  大家看到Select、Insert、Update、Delete的介面都有Where的條件字典。沒錯,反射就在這裡使用。為了考慮到資料庫的安全,所以sql自然只是簡單的拼接,還應該使用參數。所以,反射就用在Where生成參數上。大家也許還看到別的otherWhere,這個怎麼不設計成參數,因為Where能夠實現的,其實就是賦值語句,也就是表內某欄位 = 值,所以需要。在otherWhere中,存放的是其他特殊的條件。前面說這裡設計的不完美,就因為如此,其實有些條件 like 或者 使用or ,雖然能夠寫在otherWhere中,但是沒辦法使用參數來控制。

  那麼接下來就是Fiels參數了,這個在各個方法充當不同的作用。Select是查詢的欄位,Update中是更新的欄位,在Insert中是插入的欄位,這樣就靈活的控制了。在這些欄位為空的時候,預設為全部,反射在這裡就使用了,遍歷模型對象中的屬性,然後將它們一個個填進sql語句中。在這裡比較註意的應該是插入,因為大家在寫sql語句時候是這樣的 insert tableName values(value,value....)這樣的格式,這樣是因為sql會自己對應值插入,而在程式中的模型類中,我想大家寫屬性可不是按順序的吧,所以在反射遍歷時候,就有可能將幾個本來待在某個列位置的值去換了位置的情況。所以,這裡在遍歷的時候,應該按插入的完全格式來設計,也就是 insert tableName(Field,Field...) values(value,value...)。

  在這幾個方法中,Delete最簡單。

 

public DbHelper Select(string Fields = "*",Dictionary<string,object> Where = null,string otherWhere = "")
        {
            sqlBuilderString = new StringBuilder();

            sqlBuilderString.AppendLine("select " + Fields + " from " + this.ExcuteName);
            List<SqlParameter> paras = new List<SqlParameter>();
            sqlBuilderString.AppendLine(" where 1 = 1 ");
            
            if (Where != null && Where.Count > 0)
            {
                paras = new List<SqlParameter>();
                //遍歷Where,將裡面的條件添加到sqlParamter和sql語句中
                Where.Keys.ToList().ForEach(o => {
                    sqlBuilderString.AppendLine(" and "+ o + " = @" + o);
                    paras.Add(new SqlParameter(o, Where[o]));
                });
            }

            if(!string.IsNullOrEmpty(otherWhere))
            {
                sqlBuilderString.AppendLine(otherWhere);
            }

            this.paras = paras.ToArray();
            return this;
        }

 

public DbHelper Update(object model,Dictionary<string, object> Where,string Fields = "", string otherWhere = "")
        {
            Type t = model.GetType();
            List<string> keys = Where.Keys.ToList();
            sqlBuilderString = new StringBuilder();
            bool firstnode = true;
            sqlBuilderString.AppendLine("update "+ExcuteName + " set ");
            List<SqlParameter> paras = new List<SqlParameter>();
            if(string.IsNullOrEmpty(Fields))
            {
                t.GetProperties().ToList().ForEach(o =>
                {
                    if (!firstnode)
                        sqlBuilderString.Append(",");
                    else
                        firstnode = false;
                    if(!keys.Contains(o.Name))
                    {
                        sqlBuilderString.AppendLine(o.Name + " = @"+o.Name);
                        paras.Add(new SqlParameter(o.Name,o.GetValue(model,null)));
                    }
                });
            }else
            {
                Fields.Split(',').ToList().ForEach(o =>
                {
                    sqlBuilderString.AppendLine(o + " = @" + o);
                    paras.Add(new SqlParameter(o, t.GetProperty(o).GetValue(model, null)));
                });
            }

            this.paras = paras.ToArray();
            return this;
        }
public DbHelper Insert(object model,string Fields = "")
        {
            List<SqlParameter> paras = new List<SqlParameter>();
            Type t = model.GetType();
            sqlBuilderString = new StringBuilder();
            sqlBuilderString.AppendLine("insert " + ExcuteName);
            if(string.IsNullOrEmpty(Fields))
            {
                string s = "";
                string s1="";
                t.GetProperties().ToList().ForEach(o =>
                {
                    s += o.Name + ",";
                    s1 += " @" + o.Name + ",";
                    paras.Add(new SqlParameter(o.Name, o.GetValue(model, null)));
                });
                s.Remove(s.LastIndexOf(','),1);
                s1.Remove(s.LastIndexOf(','), 1);
                sqlBuilderString.AppendLine("(" + s + ")");
                sqlBuilderString.AppendLine(" values(" + s1 + ")");
            }else
            {
                sqlBuilderString.AppendLine("(" + Fields + ")");
                string s = "";
                Fields.Split(',').ToList().ForEach(o =>
                {
                    s += " @" + o + ",";
                    paras.Add(new SqlParameter(o, t.GetProperty(o).GetValue(model, null)));
                });
                sqlBuilderString.AppendLine(" values(" + s + ")");
            }

            this.paras = paras.ToArray();
            return this;
        }
public DbHelper Delete(Dictionary<string,object> Where,string otherWhere = "")
        {
            sqlBuilderString = new StringBuilder();
            List<SqlParameter> paras = new List<SqlParameter>();
            sqlBuilderString.AppendLine("delete " + ExcuteName);
            sqlBuilderString.AppendLine(" where 1 = 1 ");

            Where.Keys.ToList().ForEach(o =>
            {
                sqlBuilderString.AppendLine(" and " + o + " = @" + o);
                paras.Add(new SqlParameter(o, Where[o]));
            });
            this.paras = paras.ToArray();
            return this;
        }

最後一個階段,那就是執行階段,這裡封裝了些執行的方法。

這個也是簡單,最重要的方法應該是setCommand,這個方法是對sqlCommand進行設置,執行的語句,以及添加參數。

 

private void setCommand()
        {
            if(com.CommandType== CommandType.StoredProcedure)
            {
                this.com.CommandText = ExcuteName;
            }else
            {
                this.com.CommandText = sqlBuilderString.ToString();
            }

            this.paras.ToList().ForEach(o =>
            {
                this.com.Parameters.Add(o);
            });
        }

 

其他就是執行的語句。

 

public List<T> ToList<T>()
            where T:class ,new()
        {
            List<T> list = new List<T>();
            setCommand();
            SqlDataReader reader = com.ExecuteReader();
            Type t = typeof(T);
            List<PropertyInfo> pros = t.GetProperties().ToList();

            while(reader.Read())
            {
                T model = new T();
                pros.ForEach(o =>
                {
                    o.SetValue(model, reader[o.Name], null);
                });
                list.Add(model);
            }
            reader.Dispose();
            return list;
        }

        public DataSet ToDataSet(string DatasetName = "")
        {
            DataSet ds = new DataSet();
            setCommand();
            SqlDataAdapter adapter = new SqlDataAdapter(com);

            adapter.Fill(ds, string.IsNullOrEmpty(DatasetName) ? this.ExcuteName.Replace(",", "_") : DatasetName);
            adapter.Dispose();
            return ds;
        }

        public DataTable ToDataTable()
        {
            DataTable dt = new DataTable();
            setCommand();
            SqlDataAdapter adapter = new SqlDataAdapter(com);
            adapter.Fill(dt);
            adapter.Dispose();
            return dt;
        }

        public object Result()
        {
            setCommand();
            return com.ExecuteScalar();
        }

        public int ExcuteResult()
        {
            setCommand();
            return com.ExecuteNonQuery();
        }

        public DbHelper ExcuteProc(Dictionary<string,object> Parameter)
        {
            List<SqlParameter> paras = new List<SqlParameter>();

            Parameter.Keys.ToList().ForEach(o =>
            {
                paras.Add(new SqlParameter(o, Parameter[o]));
            });
            return this;
        }

 

當然,還不能少了讓用戶自定義的方法,所以最後還留了個方法,參數是委托。委托裡面的參數還是動態類型,這就懂了吧,想用戶怎麼用,你就怎麼定義。

 

public void UserDefineOperation(Action<dynamic> fun)
        {
            fun(this.com);
        }

 

 

好了,設計也就到這裡,下麵就貼上SQLHelper完整的代碼。

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;

namespace Dal
{
    public class SQLHelper:DbHelper
    {
        //連接字元串
        string ConnectionString;
        
        //資料庫連接對象
        private SqlConnection conn;

        //執行對象
        SqlCommand com;

        //表、存儲過程、視圖名稱
        string ExcuteName;

        //事務
        SqlTransaction tran;

        //sql語句
        StringBuilder sqlBuilderString;

        //參數
        SqlParameter[] paras;

        private SQLHelper()
        {

        }

        /// <summary>
        /// 創建sqlHelper靜態方法
        /// </summary>
        /// <returns></returns>
        public static DbHelper getInstance()
        {
            return new SQLHelper();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="connectionString"></param>
        /// <returns></returns>
        public DbHelper createConnection(string connectionString)
        {
            if (!ConnectionCanUse())
            {
                this.ConnectionString = connectionString;
                conn = new SqlConnection(this.ConnectionString);
            }

            return this;
        }

        /// <summary>
        /// 檢查conn是否能用
        /// </summary>
        /// <returns></returns>
        public bool ConnectionCanUse()
        {
            if (conn == null)
                return false;
            try
            {
                conn.Open();
                conn.Close();
            }catch(Exception e)
            {
                return false;
            }
            
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public DbHelper openConnection()
        {
            if(conn.State != ConnectionState.Open)
            this.conn.Open();
            return this;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public DbHelper closeConnection()
        {
            if(conn.State != ConnectionState.Closed)
            this.conn.Close();
            return this;
        }

        /// <summary>
        /// 
        /// </summary>
        public void DisposedConnection()
        {
            if (!ConnectionBeUsed())
                this.conn.Dispose();
        }

        /// <summary>
        /// 檢查資料庫是否在被打開使用
        /// </summary>
        /// <returns></returns>
        
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 簡單的來理解,我所說的CNMP,不是CNM+P,而是CentOs+Nginx+MySql+PHP,也可以單純的理解為LNMP,但是系統是我們自己選的,雖說是Linux的一個分支,但我就喜歡CentOs的這個C。 好的,我們開搞伺服器。 工欲善其事,必先利其器,首先,你需要兩臺電腦,為了更好的去模擬。 ...
  • 0x00 CREELINKS平臺簡介 0x00 CREELINKS平臺簡介 CREELINKS(創e聯)是由大信科技有限公司研發,集合軟硬體、操作系統、數據云儲存、開發工具於一體,用於物聯網產品的設計、研發與生產的平臺。 平臺涉及智能硬體、車聯網、智能家居、可穿戴設備、工業控制等各個物聯網領域。旨在 ...
  • 作為一個Linux新手,在寫這篇博客之前,裝了幾次jdk,好多次都是環境變數配置錯誤,導致無法登錄系統。經過幾天的研究,今天新裝系統,從頭來完整配置一遍 系統版本:Ubuntu 16.04 JDK版本:jdk1.8.0_121 1.官網下載JDK文件jdk-8u121-linux-x64.tar.g ...
  • Linux 用戶管理2 添加修改和刪除用戶,必須是超級管理員root賬號才可以進行的操作,所以噹噹前賬號不是超級管理員root賬號時,首先要先切換為root賬號。 如圖,ylq為普通用戶,執行添加用戶時,會出現如圖的錯誤: 快捷切換為root用戶: 添加用戶 useradd命令 此時便可以執行添加用 ...
  • 隨著網路的發展,網路安全也越來越重要,對於網站來說,從Http升級到https也是我們要做的首要事情。要實現https,首先我們需要申請一張SSL證書,這篇文章我主要介紹下邊這幾個方面: 1. SSL簡單介紹 2. 免費Letencrypt證書部署 3. 安裝註意事項 一.SSL簡單介紹 ssl作為 ...
  • 在linux進行連接windows下的ftp伺服器 ftp://192.168.2.71 輸入用戶名和密碼登陸成功 當使用get把文件下載後,然後unzip進行解壓時,出現了問題 error [10201_database_linux32.zip]: start of central directo ...
  • 第一步:搭建apache伺服器,這在上篇博客中已經完成 http://www.cnblogs.com/sangmu/p/6422238.html 第二步:安裝ssl yum install mod_ssl -y iptables -I INPUT 1 -p tcp --dport 443 -j AC ...
  • 昨天Boss在公司微信群發了此張圖片,"哪個水槽先灌滿",Insus.NET今天早上才有時間來研究一下: 如果你對此話題有興趣,你可以繼續討論和補充...... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...