DotNet加密方式解析--非對稱加密

来源:http://www.cnblogs.com/pengze0902/archive/2017/02/04/6268705.html
-Advertisement-
Play Games

新年新氣象,也希望新年可以掙大錢。不管今年年底會不會跟去年一樣,滿懷抱負卻又壯志未酬。(不過沒事,我已為各位卜上一卦,卦象顯示各位都能掙錢...)。已經上班兩天了,公司大部分人還在休假,而我早已上班,估計今年我就是加班狗的命。(不說了,要堅強...) 以上扯淡已畢,下麵言歸正傳。 這次的.NET加密 ...


   新年新氣象,也希望新年可以掙大錢。不管今年年底會不會跟去年一樣,滿懷抱負卻又壯志未酬。(不過沒事,我已為各位卜上一卦,卦象顯示各位都能掙錢...)。已經上班兩天了,公司大部分人還在休假,而我早已上班,估計今年我就是加班狗的命。(不說了,要堅強...)

   以上扯淡已畢,下麵言歸正傳。

 

   這次的.NET加密解析系列中,前面已經講解了散列加密、對稱加密、數字簽名三種加密方式,在這篇博文種,將會主要講解非對稱加密的原理,以及非對稱加密在.NET種的應用。

一.非對稱加密概述:

     前面講解過對稱加密,對稱加密中加密和解密的密鑰是相同的,但是正因為如此,這會給協商過程帶來潛在的危險。所以產生了非對稱加密方式。

   1.非對稱加密原理概述:

       非對稱加密演算法需要兩個密鑰,分別是公鑰和私鑰。公鑰和私鑰是一對,如果公鑰對數據進行加密,只有使用私鑰才可以進行解密,反之亦然。對於非對稱加密的原理有如下圖:

   

      以上是大致說明瞭消息利用非對稱加密和解密的方式,解析來我們再來看一下如果生成密鑰對。非對稱加密演算法包含一個“密鑰生成”協議,用戶可以使用該協議生成密鑰對。有如下圖:

   

     在非對稱加密演算法中,使用兩個有關的函數,一個是加密函數,使用一個公鑰加密消息,加密函數只能加密數據;一個時解密函數,使用一個私鑰來解密被響應公鑰加密的消息。

    2.非對稱加密特點概述:

       非對稱加密演算法中,採用加密函數和解密函數,加密函數只能加密函數,解密函數只能解密函數。加密函數的單向性意味著一個發送者創建的消息不能被另一個發送者閱讀。非對稱加密相對於對稱加密來說,非對稱加密的速度非常慢,而且不適用於加密大量數據,公鑰加密(非對稱加密)是用來為對稱加密演算法解決密鑰協商的問題而產生的。RSA演算法中指定密鑰長度為最小的位數,這些位的個數使用二進位數表示密鑰繫數N的值。

    3.非對稱加密演算法分類概述:  

      對於非對稱加密演算法的種類,有如下圖:

    RSA演算法:此演算法是基於數論的非對稱密碼體制,採用分組加密方式。安全性是基於大整數因數分解的困難性,RSA演算法是第一個既能用於數據加密也能用與數字簽名的演算法。

    DSA演算法(數字簽名演算法):次演算法是基於證書有限域離散對數難題。

    ECC演算法(橢圓曲線密碼體制):橢圓曲線指的是由維爾斯特拉斯方程所確定的平面曲線。

    Diffie-Hellman演算法:該演算法本身限於密鑰交換的用途,目的在於使得兩個用戶安全地交換一個秘密密鑰以便用與以後的報文加密。該演算法依賴於計算離散對數的難度。

 以上是簡單介紹了一些演算法,沒有更加深入的介紹其演算法原理,由於涉及的知識面比較廣,分析起來比較的繁瑣,在這裡就不做講解,如果有興趣可以自行學習和瞭解。

二.DotNet非對稱加密核心對象解析:

     上面簡單敘述了非對稱加密的原理,在這裡主要介紹非對稱加密演算法在.NET種的應用,以及實現該演算法所創建的對象。在這裡主要介紹RSA演算法的核心對象。

   1.RSA加密和解密的方式:

     

    2.DotNet種RSA演算法核心對象概述:

       在.NET種對於非對稱加密演算法的結構體系有如下圖:

   3.AsymmetricAlgorithm類解析:

    (1).Create():創建用於執行非對稱演算法的預設加密對象。

  public static AsymmetricAlgorithm Create()
    {
      return AsymmetricAlgorithm.Create("System.Security.Cryptography.AsymmetricAlgorithm");
    }

   該方法返回新的 RSACryptoServiceProvider 實例,除非已使用 <cryptoClass> 元素更改預設設置。

public static AsymmetricAlgorithm Create(string algName)
    {
      return (AsymmetricAlgorithm) CryptoConfig.CreateFromName(algName);
    }

  該方法返回所指定的非對稱演算法實現的新實例。接收參數為要使用的非對稱演算法實現。CryptoConfig.CreateFromName()該方法在前面的加密方式中已經做過解析,這裡就不做介紹了。

   (2).KeySize:獲取或設置非對稱演算法所用密鑰模塊的大小(以位為單位)。

 public virtual int KeySize
    {
      get
      {
        return this.KeySizeValue;
      }
      set
      {
        for (int index = 0; index < this.LegalKeySizesValue.Length; ++index)
        {
          if (this.LegalKeySizesValue[index].SkipSize == 0)
          {
            if (this.LegalKeySizesValue[index].MinSize == value)
            {
              this.KeySizeValue = value;
              return;
            }
          }
          else
          {
            int minSize = this.LegalKeySizesValue[index].MinSize;
            while (minSize <= this.LegalKeySizesValue[index].MaxSize)
            {
              if (minSize == value)
              {
                this.KeySizeValue = value;
                return;
              }
              minSize += this.LegalKeySizesValue[index].SkipSize;
            }
          }
        }
        throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidKeySize"));
      }
    }

    由以上代碼可以發現,該屬性具有get和set兩個構造器,說明該屬性是可讀可寫的。該屬性返回非對稱演算法所用密鑰模塊的大小(以位為單位)。

  4.RSA類解析:

   (1).FromXmlString():通過 XML 字元串中的密鑰信息初始化Cryptography.RSA對象。

  public override void FromXmlString(string xmlString)
    {
      if (xmlString == null)
        throw new ArgumentNullException("xmlString");
      RSAParameters parameters = new RSAParameters();
      SecurityElement topElement = new Parser(xmlString).GetTopElement();
      string inputBuffer1 = topElement.SearchForTextOfLocalName("Modulus");
      if (inputBuffer1 == null)
      {
        string key = "Cryptography_InvalidFromXmlString";
        object[] objArray = new object[2];
        int index1 = 0;
        string str1 = "RSA";
        objArray[index1] = (object) str1;
        int index2 = 1;
        string str2 = "Modulus";
        objArray[index2] = (object) str2;
        throw new CryptographicException(Environment.GetResourceString(key, objArray));
      }
      parameters.Modulus = Convert.FromBase64String(Utils.DiscardWhiteSpaces(inputBuffer1));
      string inputBuffer2 = topElement.SearchForTextOfLocalName("Exponent");
      if (inputBuffer2 == null)
      {
        string key = "Cryptography_InvalidFromXmlString";
        object[] objArray = new object[2];
        int index1 = 0;
        string str1 = "RSA";
        objArray[index1] = (object) str1;
        int index2 = 1;
        string str2 = "Exponent";
        objArray[index2] = (object) str2;
        throw new CryptographicException(Environment.GetResourceString(key, objArray));
      }
      parameters.Exponent = Convert.FromBase64String(Utils.DiscardWhiteSpaces(inputBuffer2));
      string inputBuffer3 = topElement.SearchForTextOfLocalName("P");
      if (inputBuffer3 != null)
        parameters.P = Convert.FromBase64String(Utils.DiscardWhiteSpaces(inputBuffer3));
      string inputBuffer4 = topElement.SearchForTextOfLocalName("Q");
      if (inputBuffer4 != null)
        parameters.Q = Convert.FromBase64String(Utils.DiscardWhiteSpaces(inputBuffer4));
      string inputBuffer5 = topElement.SearchForTextOfLocalName("DP");
      if (inputBuffer5 != null)
        parameters.DP = Convert.FromBase64String(Utils.DiscardWhiteSpaces(inputBuffer5));
      string inputBuffer6 = topElement.SearchForTextOfLocalName("DQ");
      if (inputBuffer6 != null)
        parameters.DQ = Convert.FromBase64String(Utils.DiscardWhiteSpaces(inputBuffer6));
      string inputBuffer7 = topElement.SearchForTextOfLocalName("InverseQ");
      if (inputBuffer7 != null)
        parameters.InverseQ = Convert.FromBase64String(Utils.DiscardWhiteSpaces(inputBuffer7));
      string inputBuffer8 = topElement.SearchForTextOfLocalName("D");
      if (inputBuffer8 != null)
        parameters.D = Convert.FromBase64String(Utils.DiscardWhiteSpaces(inputBuffer8));
      this.ImportParameters(parameters);
    }

     該方法是繼承自AsymmetricAlgorithm類,在RSA類種被重寫,該方法接收參數包含 RSA 密鑰信息的 XML 字元串。SecurityElement類表示用於編碼安全對象的XML對象模型。

   (2).ToXmlString():創建並返回包含當前 RSA 對象的密鑰的 XML 字元串。

public override string ToXmlString(bool includePrivateParameters)
    {
      RSAParameters rsaParameters = this.ExportParameters(includePrivateParameters);
      StringBuilder stringBuilder = new StringBuilder();
      stringBuilder.Append("<RSAKeyValue>");
      stringBuilder.Append("<Modulus>" + Convert.ToBase64String(rsaParameters.Modulus) + "</Modulus>");
      stringBuilder.Append("<Exponent>" + Convert.ToBase64String(rsaParameters.Exponent) + "</Exponent>");
      if (includePrivateParameters)
      {
        stringBuilder.Append("<P>" + Convert.ToBase64String(rsaParameters.P) + "</P>");
        stringBuilder.Append("<Q>" + Convert.ToBase64String(rsaParameters.Q) + "</Q>");
        stringBuilder.Append("<DP>" + Convert.ToBase64String(rsaParameters.DP) + "</DP>");
        stringBuilder.Append("<DQ>" + Convert.ToBase64String(rsaParameters.DQ) + "</DQ>");
        stringBuilder.Append("<InverseQ>" + Convert.ToBase64String(rsaParameters.InverseQ) + "</InverseQ>");
        stringBuilder.Append("<D>" + Convert.ToBase64String(rsaParameters.D) + "</D>");
      }
      stringBuilder.Append("</RSAKeyValue>");
      return stringBuilder.ToString();
    }

    該方法同樣繼承自AsymmetricAlgorithm類,該方法接收一個布爾型的參數,true 表示同時包含 RSA 公鑰和私鑰;false 表示僅包含公鑰。該方法返回包含當前 RSA 對象的密鑰的 XML 字元串。RSAParameters為一個結構,表示System.Security.Cryptography.RSA演算法的標準參數。

   5.RSACryptoServiceProvider類解析:

    (1).Encrypt():使用 RSA演算法對數據進行加密。

 [SecuritySafeCritical]
    public byte[] Encrypt(byte[] rgb, bool fOAEP)
    {
      if (rgb == null)
        throw new ArgumentNullException("rgb");
      this.GetKeyPair();
      byte[] o = (byte[]) null;
      RSACryptoServiceProvider.EncryptKey(this._safeKeyHandle, rgb, rgb.Length, fOAEP, JitHelpers.GetObjectHandleOnStack<byte[]>(ref o));
      return o;
    }

   該方法接受兩個參數,要加密的數據。fOAEP如果為 true,則使用 OAEP 填充(僅在運行 Microsoft Windows XP 或更高版本的電腦上可用)執行直接的 RSA 加密;否則,如果為 false,則使用 PKCS#1 1.5 版填充。該方法返回一個已加密的數據,為一個位元組數組。

    (2).Decrypt():使用 RSA演算法對數據進行解密。

[SecuritySafeCritical]
    public byte[] Decrypt(byte[] rgb, bool fOAEP)
    {
      if (rgb == null)
        throw new ArgumentNullException("rgb");
      this.GetKeyPair();
      if (rgb.Length > this.KeySize / 8)
      {
        string key = "Cryptography_Padding_DecDataTooBig";
        object[] objArray = new object[1];
        int index = 0;
        // ISSUE: variable of a boxed type
        __Boxed<int> local = (ValueType) (this.KeySize / 8);
        objArray[index] = (object) local;
        throw new CryptographicException(Environment.GetResourceString(key, objArray));
      }
      if (!this.CspKeyContainerInfo.RandomlyGenerated && !CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
      {
        KeyContainerPermission containerPermission = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
        KeyContainerPermissionAccessEntry accessEntry = new KeyContainerPermissionAccessEntry(this._parameters, KeyContainerPermissionFlags.Decrypt);
        containerPermission.AccessEntries.Add(accessEntry);
        containerPermission.Demand();
      }
      byte[] o = (byte[]) null;
      RSACryptoServiceProvider.DecryptKey(this._safeKeyHandle, rgb, rgb.Length, fOAEP, JitHelpers.GetObjectHandleOnStack<byte[]>(ref o));
      return o;
    }

   該方法接受兩個參數,rgb要解密的數據。fOAEP如果為 true,則使用 OAEP 填充(僅在運行 Microsoft Windows XP 或更高版本的電腦上可用)執行直接的 <see cref="T:System.Security.Cryptography.RSA"/> 解密;否則,如果為 false,則使用 PKCS#1 1.5 版填充。該方法返回 已解密的數據,它是加密前的原始純文本。

三.應用實例:

   1.RsaHelper類:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace BasicMmethodExtensionClass.EncryptHelper
{
    /// <summary>
    /// 非對稱RSA加密類
    /// 需要BigInteger類來輔助
    /// </summary>
    public static class RsaHelper
    {
        /// <summary>
        /// RSA的容器 可以解密的源字元串長度為 DWKEYSIZE/8-11 
        /// </summary>
        public const int Dwkeysize = 1024;

        /// <summary>
        /// RSA加密的密匙結構  公鑰和私匙
        /// </summary>
        public struct RsaKey
        {
            public string PublicKey { get; set; }

            public string PrivateKey { get; set; }
        }

        /// <summary>
        /// 得到RSA的解謎的密匙對
        /// </summary>
        /// <returns></returns>
        public static RsaKey GetRasKey()
        {
            RSACryptoServiceProvider.UseMachineKeyStore = true;
            //聲明一個指定大小的RSA容器
            RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(Dwkeysize);
            //取得RSA容易里的各種參數
            RSAParameters p = rsaProvider.ExportParameters(true);

            return new RsaKey
            {
                PublicKey = ComponentKey(p.Exponent, p.Modulus),
                PrivateKey = ComponentKey(p.D, p.Modulus)
            };
        }

        /// <summary>
        /// 檢查明文的有效性 DWKEYSIZE/8-11 長度之內為有效 中英文都算一個字元
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool CheckSourceValidate(string source)
        {
            return (Dwkeysize / 8 - 11) >= source.Length;
        }

        /// <summary>
        /// 組合成密匙字元串
        /// </summary>
        /// <param name="b1"></param>
        /// <param name="b2"></param>
        /// <returns></returns>
        private static string ComponentKey(byte[] b1, byte[] b2)
        {
            var list = new List<byte>
            {
                (byte) b1.Length
            };
            list.AddRange(b1);
            list.AddRange(b2);
            var b = list.ToArray<byte>();
            return Convert.ToBase64String(b);
        }

        /// <summary>
        /// 解析密匙
        /// </summary>
        /// <param name="key">密匙</param>
        /// <param name="b1">RSA的相應參數1</param>
        /// <param name="b2">RSA的相應參數2</param>
        private static void ResolveKey(string key, out byte[] b1, out byte[] b2)
        {
            //從base64字元串 解析成原來的位元組數組
            byte[] b = Convert.FromBase64String(key);
            //初始化參數的數組長度
            b1 = new byte[b[0]];
            b2 = new byte[b.Length - b[0] - 1];
            //將相應位置是值放進相應的數組
            for (int n = 1, i = 0, j = 0; n < b.Length; n++)
            {
                if (n <= b[0])
                {
                    b1[i++] = b[n];
                }
                else
                {
                    b2[j++] = b[n];
                }
            }
        }

        /// <summary>
        /// 字元串加密
        /// </summary>
        /// <param name="source">源字元串 明文</param>
        /// <param name="key">密匙</param>
        /// <returns>加密遇到錯誤將會返回原字元串</returns>
        public static string EncryptString(string source, string key)
        {
            string encryptString;
            try
            {
                if (!CheckSourceValidate(source))
                {
                    throw new Exception("明文太長");
                }
                //解析這個密鑰
                byte[] d;
                byte[] n;
                ResolveKey(key, out d, out n);
                var biN = new BigInteger(n);
                var biD = new BigInteger(d);
                encryptString = EncryptString(source, biD, biN);
            }
            catch
            {
                encryptString = source;
            }
            return encryptString;
        }

        /// <summary>
        /// 字元串解密
        /// </summary>
        /// <param name="encryptString">密文</param>
        /// <param name="key">密鑰</param>
        /// <returns>遇到解密失敗將會返回原字元串</returns>
        public static string DecryptString(string encryptString, string key)
        {
            string source;
            try
            {
                //解析這個密鑰
                byte[] e;
                byte[] n;
                ResolveKey(key, out e, out n);
                var biE = new BigInteger(e);
                var biN = new BigInteger(n);
                source = DecryptString(encryptString, biE, biN);
            }
            catch
            {
                source = encryptString;
            }
            return source;
        }

        /// <summary>
        /// 用指定的密匙加密 
        /// </summary>
        /// <param name="source">明文</param>
        /// <param name="d">可以是RSACryptoServiceProvider生成的D</param>
        /// <param name="n">可以是RSACryptoServiceProvider生成的Modulus</param>
        /// <returns>返回密文</returns>
        private static string EncryptString(string source, BigInteger d, BigInteger n)
        {
            var len = source.Length;
            int len1;
            if ((len % 128) == 0)
                len1 = len / 128;
            else
                len1 = len / 128 + 1;
            var result = new StringBuilder();
            for (var i = 0; i < len1; i++)
            {
                var blockLen = len >= 128 ? 128 : len;
                var block = source.Substring(i * 128, blockLen);
                byte[] oText = Encoding.UTF8.GetBytes(block);
                var biText = new BigInteger(oText);
                var biEnText = biText.modPow(d, n);
                var temp = biEnText.ToHexString();
                result.Append(temp).Append("@");
                len -= blockLen;
            }
            return result.ToString().TrimEnd('@');
        }

        /// <summary>
        /// 用指定的密匙加密 
        /// </summary>
        /// <param name="encryptString"></param>
        /// <param name="e">可以是RSACryptoServiceProvider生成的Exponent</param>
        /// <param name="n">可以是RSACryptoServiceProvider生成的Modulus</param>
        /// <returns>返回明文</returns>
        private static string DecryptString(string encryptString, BigInteger e, BigInteger n)
        {
            var result = new StringBuilder();
            var strarr1 = encryptString.Split(new[] { '@' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var block in strarr1)
            {
                var biText = new BigInteger(block, 16);
                var biEnText = biText.modPow(e, n);
                var temp = Encoding.UTF8.GetString(biEnText.getBytes());
                result.Append(temp);
            }
            return result.ToString();
        }
    }
}

   2.BigInteger類:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BasicMmethodExtensionClass.EncryptHelper
{
    public class BigInteger
    {
        // maximum length of the BigInteger in uint (4 bytes)
        // change this to suit the required level of precision.

        private const int maxLength = 70;

        // primes smaller than 2000 to test the generated prime number

        public static readonly int[] primesBelow2000 = {
        2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
        101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
    211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293,
    307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397,
    401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499,
    503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599,
    601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691,
    701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797,
    809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887,
    907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,
    1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097,
    1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193,
    1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297,
    1301, 	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Xamarin寫Android程式時,通常要使用按中文首字母分組顯示(如通訊錄) 。 於是需要被迫包含CJK,不過包含後包肯定是會變大的,於是。。。。自己寫了一個硬枚舉的中文轉拼音的類。 原理是這樣的: 源碼: https://github.com/chsword/PinYinUtil/blob/m ...
  • 在本節中,您將創建一個新的MoviesController類,併在這個Controller類里編寫代碼來取得電影數據,並使用視圖模板將數據展示在瀏覽器里。 在開始下一步前,先Build一下應用程式(生成應用程式)(確保應用程式編譯沒有問題) 用滑鼠右鍵單擊Controller文件夾,並創建一個新的  ...
  • 前言 本節主要介紹非同步編程中Task、Async和Await的基礎知識。 什麼是非同步? 非同步處理不用阻塞當前線程來等待處理完成,而是允許後續操作,直至其它線程將處理完成,並回調通知此線程。 非同步和多線程 相同點:避免調用線程阻塞,從而提高軟體的可響應性。 不同點: 非同步操作無須額外的線程負擔,並且使 ...
  • asp.net程式開發,用戶根據角色訪問對應頁面以及功能。 項目結構如下圖: 根目錄 Web.config 代碼: admin文件夾中 Web.config 代碼: teacher文件夾中 Web.config 代碼: student文件夾中 Web.config 代碼: Login.aspx中登錄 ...
  • 寫在前面 全部手打,沒有多餘的話,全部乾貨,基本上用到的我就記錄了。 一、什麼是JSON JSON:JavaScript Object Notation,是一種輕量級的數據交互格式,主要用於數據傳輸。 二、JSON語法規則 1、數據由鍵值對(映射)關係表示,使用 “:” 表示; 例子:"name" ...
  • 創建型模式靜態工廠模式(Factory Pattern)靜態方法返回實例抽象工廠模式(Abstract Factory Pattern)介面方式返回實例建造者模式(Builder Pattern)每次返回多個實例單例模式(Singleton Pattern)類只有一個實例原型模式(Prototype ...
  • 使用MVC開發也有一段時間了,總結下無刷新部分視圖的使用、PagedList分頁控制項的使用。 @using PagedList @model StaticPagedList<T> <style type="text/css"> .tab-title { background-color: #efef ...
  • 在進行.netCore平臺後,由於它的版本在.net4.6,C#6之後,所以它的語法也有一些新的特性,主要表現在以下幾個方面 只讀屬性初始化 屬性初始化 字典初始化器 string.Format,後臺引入了$,而且支持智能提示 空對象判斷 空集合判斷 方法-單行實現 感謝各位的閱讀與支持! .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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...