主頁 > .NET開發 > API服務介面簽名代碼與設計,如果你的介面不走SSL的話?

API服務介面簽名代碼與設計,如果你的介面不走SSL的話?

2021-01-29 06:04:11 .NET開發

在看下面文章之前,我們先問幾個問題

  • rest 服務為什么需要簽名?
  • 簽名的幾種方式?
  • 我認為的比較方便的快捷的簽名方式(如果有大神持不同意見,可以交流!)?
  • 怎么實作驗簽程序 ?
  • 開放式open api sign怎么設計 (openkey 和 openid 的設計) ?
  • 在一個服務中,有些介面不需要簽名,介面怎么濾過簽名 ?

我認為好的簽名設計,應該要解決以上問題,

 

  一: Rest 服務為什么需要簽名?

    在介紹簽名之前,我們先對服務進行分一分,我們的服務從內網以及外網角度分為:內網服務以及開放型外網服務兩大類

  1.     內網服務,我們認為它是可靠安全,受局域網的防火墻保護,內網型的服務,我們不開放出INTERNET 訪問,
  2.     暴露在外網型的服務,我們認為是它本質是提供到INTERNET 網路允許訪問的服務,我們認為它是不可靠的,不安全的,

外網型的服務,我們通常面臨兩個問題:收到惡意請求和資料安全(如果你不是通過SSL走的話) 的問題,

在惡意請求方面,又涉及到惡意高頻請求以及資料攔截竄篡改請求,

資料安全方面涉及到,網路傳輸的資料如果被攔截,涉及到客戶隱私資料被竊取等相關問題,

因此,為了解決上述問題,偉大的 服務 “簽名” 就誕生了, 你可以這么認為:簽名 就是 請求當前業務介面的 前提鑰匙,通過軟實施實作,

 

簽名如何解決上述問題:

  1. 惡意請求: 我們知道,簽名在設計上面具有防篡改性質,如果這一點沒有實作,那么就會失去簽名的意義,被攔截的請求,修改請求報文后,再次發送,將會被服務端 驗簽 程序中 檢測到,直接打回--我們通常說是驗簽失敗
  2. 客戶隱私:客戶隱私資料的保護,加簽后的介面,只能請求當前的相同請求報文的請求,而不能嘗試請求被篡改后報文的請求,如果資料被攔截,也只能是當前此條資料客戶隱私被泄露,因此,如果要絕對的保護客戶隱私的話,還有對報文資料進行加密,這樣,我們就可以做到資料安全級別較高的介面,下面的文章將對具體實作程序展開,
  3. 高頻請求的保護,如果簽名產生的uuid 加上 時間戳,就可以解決高頻請求的容錯限流等問題.

 

因此簽名尤其變為重要,

我上面的標題,如果你的介面不走SSL的話,你的外網介面就需要走上述這些事情,為了你介面安全而考慮,

 

二:簽名的幾種方式

   簽名的幾種方式:我們通常見到的有 SHA 加密簽名,MD5 簽名,我個人比較推崇的是 MD5 加簽簽名,

原因:簡單,易懂,跨語言平臺型強,通用性強,尤其是.NET 與 JAVA 跨語言的的介面簽名對接時,因為JAVA 的 SHA  版本有很多中,而更甚的是,有些 SHA 在某些銀行還被改過,形成自己私有的版本,如果:

你要對接他們的 他們的介面,你必須使用JAVA 語言.   然而 MD5 的演算法比較統一,只要 確認 對方的最簡單的 字串 123 MD5  值跟 你 這邊的 MD5 值一樣,就可以保證 底層演算法 的一致 性,就 可以采用上述的加簽方式,

 

 

MD5 加簽原理:

我們假設有這么一個統一入參結構的請求報文

請求物件協議結構

型別

說明

object

object

說明:請求的業務引數(包裝物件),各介面不同的引數

二:包裝物件中物體中特殊業務欄位中的具體格式要求:

① 如果業務物件引數是時間型別的, 將時間引數轉成時間戳(當前時間與'1970-01-01'精確到毫秒,型別Long)

② 業務中的浮點型使用字串定義傳送(避免不同跨語言造成序列化形成的浮點位數不一致性)

time

long

當前時間的時間戳:datekong(當前時間與'1970-01-01'相對值,精確到毫秒)

sign

string

sign=MD5(openkey+ time+ JsonConvert.SerializeObject(object))

備注:OpenKey: 分配給呼叫方的key值,此值無需暴露在網路中傳輸,

 

 

在我們構建傳送報文的時候,我們看到有一個欄位: sign 是 由 服務方分配給客戶端一個 秘鑰字串 再加上 報文中 ( time 時間戳+ objcet 業務參序列化)相加后的字串 后 MD5值, 

我們這里 sign 的形成有兩個關鍵點:

第一: sign  值形成的演算法,我這邊演算法暫時是 :sign= MD5(openkey+ time+ JsonConvert.SerializeObject(object))

第二: sign 分配給客戶端的秘鑰值—openkey

 

如下加簽請求偽代碼:

  1 namespace T.API
  2 {
  3 
  4 
  5     /// <summary>
  6     /// 請求的報文物件
  7     /// </summary>
  8     public class SendObject
  9     {
 10         /// <summary>
 11         /// 發送物體物件
 12         /// </summary>
 13         public object @object { get; set; }
 14 
 15         /// <summary>
 16         /// 簽名
 17         /// </summary>
 18 
 19         public string sign { get; set; }
 20         /// <summary>
 21         /// 當前請求的時間戳
 22         /// </summary>
 23         public long? time { get; set; }
 24 
 25         /// <summary>
 26         /// 用戶id
 27         /// </summary>
 28         public int userId { get; set; }
 29     }
 30 
 31     /// <summary>
 32     /// 接收到的報文物件
 33     /// </summary>
 34     public class ReciveObject
 35     {
 36         /// <summary>
 37         /// 發送物體物件
 38         /// </summary>
 39         public object @object { get; set; }
 40 
 41         /// <summary>
 42         /// 服務請求回應值 code 為 1:請求成功 ,請求無例外  
 43         /// 當code 為 "1" 的情況下,下面的RevRep 物件中的 message 欄位 90% 的場景為空,
 44         /// 如果有必要賦值視雙方業務場景而定;
 45         /// code為 0:我方程式例外/業務性質失敗/介面引數校驗失敗,
 46         /// 當 code 為 "0"的情況下,下面message欄位包裝了例外/失敗資訊,
 47         /// </summary>
 48 
 49         public int code { get; set; }
 50         
 51 
 52         /// <summary>
 53         /// 請求回應的錯誤訊息/或者其他業務場景回應提示資訊
 54         /// </summary>
 55         public int message { get; set; }
 56     }
 57 
 58 
 59     /// <summary>
 60     /// 上面 Req 物件中的object 封裝欄位具體物體定義
 61     /// </summary>
 62     public class ObjectEntity
 63     {
 64 
 65         public string orderNum { get; set; }
 66 
 67         /// <summary>
 68         /// 如果引數是浮點型,在物體中定義成字串型別.
 69         /// </summary>
 70         public string orderMoney { get; set; }
 71 
 72         /// <summary>
 73         /// 如果引數是時間型別的,在物體中定義成long 時間戳型別
 74         /// </summary>
 75         public long? orderTime { get; set; }
 76     }
 77 
 78 
 79 
 80 
 81     /// <summary>
 82     /// 請求示例代碼
 83     /// </summary>
 84     public class RequestDemo
 85     {
 86 
 87         /// <summary>
 88         /// 請求示例,呼叫方請求
 89         /// </summary>
 90 
 91         public static void Request()
 92         {
 93 
 94             //服務端分配給呼叫方:openkey
 95             string openKey = "455853655-7dff-5585545-a1c3-7778887"; //
 96 
 97             //定義發送物件
 98             SendObject sendobject = new SendObject();
 99             //定義請求時間戳
100             long? reqtime= DateTime.Now.ToSafeDateTime().ToSafeDataLong();// 賦值
101             sendobject.time = reqtime;
102             try
103             {
104                 //定義以及賦值業務物體
105                 ObjectEntity objectEntity = new ObjectEntity();
106                 objectEntity.orderNum = "20200506071001";
107                 objectEntity.orderTime = DateTime.Now.ToSafeDateTime().ToSafeDataLong();
108                 objectEntity.orderMoney = "526.00";
109 
110                 //將定義好的業務物體塞入SendObject的object欄位中.
111                 sendobject.@object = objectEntity;
112 
113                 //加簽并且賦值簽名
114                 sendobject.sign = sign(reqtime, openkey,JsonConvert.SerializeObject(sendobject.@object));
115 
116 
117                 RestRequest rq = new RestRequest(Method.POST);
118              
119                 rq.Method = Method.POST; //請求設定為POST
120                 
121                 rq.AddHeader(" Content-Type", "application/json;charset=utf-8"); //頭部塞入Content-Type
122                 rq.AddParameter("application/json", JsonConvert.SerializeObject(sendobject), ParameterType.RequestBody);
123 
124 
125                 RestClient restclient = new RestClient { BaseUrl = new Uri("http://xx.xx.xx.xx:5021") }; //呼叫地址
126                 TaskCompletionSource<IRestResponse> tcs = new TaskCompletionSource<IRestResponse>();
127                 restclient.ExecuteAsync(rq, r =>
128                 {
129                     tcs.SetResult(r);
130                 });
131                 IRestResponse respones = tcs.Task.Result; // 請求回傳的資料
132 
133                 //如果請求狀態正常
134                 if ((int)respones.StatusCode == 200)
135                 {
136                     ReciveObject recive = JsonConvert.DeserializeObject<ReciveObject>(respones.Content);
137                     if (recive.code == 1)
138                     {
139                          //處理業務
140                     }
141                     else
142                     {
143                         //處理業務
144                     }
145 
146 
147 
148                 }
149                 else
150                 {
151                     throw new Exception("呼叫例外通訊狀態:${respones.StatusCode}");
152                    
153                 }
154              
155 
156 
157 
158 
159 
160             }
161             catch (Exception ex)
162             {
163                
164             }
165            
166         }
167 
168 
169         /// <summary>
170         /// Md5 方法
171         /// </summary>
172         public static string MD5(string md5orgincontent)
173         {
174 
175             string md5result = string.Empty;
176             if (string.IsNullOrEmpty(md5result)) return md5result;
177             StringBuilder sb = new StringBuilder();
178 
179             MD5 md5 = new MD5CryptoServiceProvider();
180             byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(md5orgincontent));
181             md5.Clear();
182             for (int i = 0; i < s.Length; i++)
183             {
184                 sb.Append(s[i].ToString("x2"));
185             }
186             md5result=sb.ToString();
187            return md5result;
188 
189 
190         }
191       
192         
193         /// <summary>
194         /// 加簽
195         /// </summary>
196         /// <param name="time">時間戳</param>
197         /// <param name="openkey">服務端分配給呼叫方:openkey</param>
198         /// <param name="szobject">參與加簽的object的json序列化字串</param>
199         /// <returns></returns>
200         public static string sign(long? time, string openkey, string szobject)
201         {
202 
203            
204             string signresult = string.Empty;
205             var signcontent = openkey+time.ToSafeString()+szobject;
206             signresult = MD5(signcontent);
207             return signresult;
208 
209         }
210 
211 
212 
213 
214     }
215 
216 }
View Code

 

服務端驗簽原理:

服務端通過  服務端定義介面攔截器或者全域過攔截器, 介面接收到的報文是上述表格的報文結構后,做如下事情

  1: 同樣:接攔截器中,做同樣的事情: 秘鑰字串 再加上 報文傳送過來的 ( time 時間戳+ objcet 業務參序列化)相加后的字串 MD5值 ,我將此值 為 service_sign

2:將服務端的  service_sign 值跟 報文中的 sign 進行比對,如果發現不匹配(假設在雙方演算法一直,openkey 一致的情況下):報文被篡改,簽名驗證不通過

我在這里貼出服務端驗簽 C# 代碼:其他語言可以參考:

  • 服務端先定義一個接收報文的物件:
     1 [JsonObject(MemberSerialization.OptIn)]
     2     public class ResultRequset : BaseRequestEntity
     3     {
     4         [JsonProperty]
     5         public object @object { get; set; }
     6         public virtual string openKey{ get; set; }
     7       /// <summary>
     8         /// 服務端加簽:此值將于傳送過來的 sign 值最終進行比對/// </summary>
     9         public override string checkedSign
    10         {
    11             get
    12             {
    13                 var orgin =this.time.ToString() + openKey+ JsonConvert.SerializeObject(@object);
    14                 return EntitySign.To32Md5(orgin);
    15             }
    16         }
    17 
    18      /// <summary>
    19         /// 簽名驗證
    20         /// </summary>
    21         /// <returns></returns>
    22         public Result CheckedSign()
    23         {
    24             Result r = new Result();
    25             if (this.sign == checkedSign)
    26             {
    27                 r.code = 1;
    28                 return r;
    29             }
    30             else
    31             {
    32                 r.code = 0;
    33                 r.message = "延簽失敗!";
    34             }
    35             return r;
    36         }
    View Code
  • 然后構建一個攔截器,攔截器的作業如下所示 NETFramework 代碼,其他語言可以參考:
     1 public class OpenSignAttribute : ActionFilterAttribute
     2     {
     3         public Type RequestType { get; set; }
     4 
     5         public override void OnActionExecuting(HttpActionContext actionContext)
     6         {
     7             HttpContent content = actionContext.Request.Content;
     8             var gloablkey = string.Empty; 
     9             ResultRequset resultRequset = new ResultRequset();
    10        foreach (KeyValuePair<string, object> obj in actionContext.ActionArguments)
    11                 {
    12 
    13                     resultRequset = (ResultRequset)obj.Value; //第一步:獲取報文資料,強制轉換到 上面定義的 ResultRequset 報文接收物件
    14                 }
    15  Result re = resultRequset.CheckedSign(); //第二步: 服務端進行加簽并且驗簽
    16                 if (re.code == 1)
    17                 {
    18                     base.OnActionExecuting(actionContext);
    19                 }
    20                 else
    21                 {
    22                     actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, re);
    23                 }
    24             }
    25         }
    View Code

     

  • 我們看一下介面定義- 給 介面 打上  OpenSign  標簽,并且使用  ResultRequset 來接收對方過來的報文資料,
    1 [HttpPost]
    2 
    3 [OpenSign]
    4  public ResultRequset test([FromBody]ResultRequset obj)
    5  {
    6 
    7  }
    View Code

     

上述我們基本上形成了 MD5 加簽和驗簽的邏輯程序,那么上述的這這個程序還是有個缺陷,就是文章一開頭要解決的一個問題,開放式open api sign怎么設計 (openkey 和 openid 的設計) ?

也就是說:上述的 demo 的openkey 在是死的,如果我們想 服務端分配給每個呼叫方的openkey 都不一樣,怎么辦?

其實原理很簡單:我們在增加一個 openid 概念:openid 是服務端分配給對呼叫方的唯一標識,openkey 是我們分配呼叫方參與加簽的 鑰匙,

怎么做呢:

 1:呼叫方: openid 一定要讓對方 放入 HTTP HEADER  里面 傳送到服務端,openkey  是參與加密,不需要傳送,

2:服務端:在接收到 呼叫方 傳送過來的 openid后,通過查庫或者其他方式 查出 openid 對應的 openkey, 然后將查到的openkey 參與服務端驗簽演算法,

上述原理,也就是我們通常看到的ALI,騰訊,或者其他第三方提供出來的 API  為什么需要分配一個OPENID,OPENKEY 的原因,或許有些廠商不是這種叫法,但是原理都是這樣,

 

在貼出改造代碼之前,我們還需要解決一個問題:就是 服務端在“接收到 呼叫方 傳送過來的 openid后,通過查庫或者其他方式 查出 openid 對應的 openkey, 然后將查到的openkey 參與服務端驗簽演算法” 這里的藍色字體標注的具體怎么查,這對

openid,openkey 配置對 怎么配置在服務端(有可能存庫,有可能放在組態檔中)可能每個服務端都不太一樣,我們把這層也抽象出來,讓介面標簽指定,

我們代碼再次改造,如下所示:

  • 我們先定義一個查找方式的介面:
    1 public interface ISingSecret
    2     {
    3         string OpenId(Microsoft.AspNetCore.Http.HttpRequest request =null);
    4         
    5         string OpenKey(string OpenId);
    6     }
    View Code
  • 服務端接收物件改造:
     1 [JsonObject(MemberSerialization.OptIn)]
     2     public class ResultRequset
     3     {
     4         [JsonProperty]
     5         public object @object { get; set; }
     6 
     7 
     8         /// <summary>
     9         /// 可以覆寫此KEY的方式
    10         /// </summary>
    11         public virtual string openKey{ get; set; }
    12       /// <summary>
    13         /// 開放平臺所使用的分配給客戶的OPENID
    14         /// </summary>
    15         [JsonProperty]
    16         public string openId
    17         {
    18 
    19             get;
    20 
    21             set;
    22         }
    23         /// <summary>
    24         /// 獲取簽名
    25         /// </summary>
    26         public override string checkedSign
    27         {
    28             get
    29             {
    30                 var orgin = singContent;
    31                
    32                 return EntitySign.To32Md5(orgin);
    33             }
    34         }
    35 
    36 
    37         /// <summary>
    38         /// 用戶ID 登入人ID
    39         /// </summary>
    40         [JsonIgnore]
    41         public string singContent
    42         {
    43             get { return  openKey+ this.time.ToString() + JsonConvert.SerializeObject(@object); }
    44         }/// <summary>
    45         /// 簽名驗證
    46         /// </summary>
    47         /// <returns></returns>
    48         public Result CheckedSign()
    49         {
    50             Result r = new Result();
    51            
    52         if (this.sign == checkedSign)
    53             {
    54                 r.code = 1;
    55                 return r;
    56             }
    57             else
    58             {
    59                 r.code = 0;
    60                
    61                 r.message = "簽名驗證失敗!";
    62                 LogService.Default.Debug("簽名驗證失敗---"+"框架簽名" + checkedSign.ToSafeString("")+"-------網路簽名:"+ sign.ToSafeString("") + "--------簽名資訊:" + singContent);
    63             }
    64             return r;
    65         }
    66     }
    View Code
  • 服務端攔截器改造
     1 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
     2     public class CentralSign: ActionFilterAttribute
     3     {
     4 
     5 
     6 
     7         private Type ISingRealization { get; set; }
     8 
     9         private ISingSecret singRealization { get; set; } //關鍵代碼:由服務端實作通過openid 查出openkey 的具體邏輯.
    10 
    11         public CentralSign(Type ISingSecret) // 關鍵代碼: 定義帶建構式的 介面標簽屬性 . 
    12         {
    13             this.ISingRealization = ISingSecret;
    14             if (ISingRealization != null)
    15             {
    16                 //獲取類的初始化引數資訊
    17                 ConstructorInfo obj = ISingRealization.GetConstructor(System.Type.EmptyTypes);
    18                 singRealization = (ISingSecret)Activator.CreateInstance(ISingRealization); //實體化物件
    19 
    20             }
    21         }
    22 
    23         public override void OnActionExecuting(ActionExecutingContext actionContext)
    24         {
    25             var content = actionContext.HttpContext.Request;
    26             var gloablkey = string.Empty;
    27 
    28                  ResultRequset resultRequset = new ResultRequset();
    29                 foreach (KeyValuePair<string, object> obj in actionContext.ActionArguments)
    30                 {
    31                     resultRequset = (ResultRequset)obj.Value;
    32                 }
    33 
    34 
    35                 Result re = new Result();
    36                 if (resultRequset == null)
    37                 {
    38                     re.code = 0;
    39                     re.message = "傳值不能為空";
    40                     actionContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
    41                     actionContext.HttpContext.Response.WriteAsync(JsonConvert.SerializeObject(re));
    42 
    43                 }
    44                 else
    45                 {
    46                     if (singRealization != null)
    47                     {
    48                         var openId = singRealization.OpenId(actionContext.HttpContext.Request); // 關鍵代碼: 通過 ISingSecret.OpenId() 方法,獲取到對應呼叫方傳送過來的 openid
    49 
    50                         resultRequset.publicApikey = singRealization.OpenKey(openId); // 關鍵代碼: 通過 ISingSecret.OpenId() 方法,獲取到對應呼叫方傳送過來的 openid
    51 
    52                     }
    53                     re = resultRequset.CheckedSign();
    54                     if (re.code == 1)
    55                     {
    56                         base.OnActionExecuting(actionContext);
    57                     }
    58                     else
    59                     {
    60 
    61                         HandleUnauthorizedRequest(actionContext);
    62 
    63                     }
    64                 }
    65 
    66             
    67         }
    68 
    69         protected void HandleUnauthorizedRequest(ActionExecutingContext actionContext)
    70         {
    71             var r = new JsonResult("簽名失敗,訪問受限.");
    72 
    73             r.StatusCode = (int)HttpStatusCode.BadRequest;
    74             actionContext.Result =r;
    75             return;
    76         }
    77     }
    View Code
  • 服務端介面定義改造:
    1 [HttpPost]
    2 [CentralSign(typeof(OpenSign))]
    3 public Result SignatureSample([FromBody]ResultRequset result)
    4   {
    5             var str = [email protected]("");
    6              Result re = new Result() { code = 1,message="簽名驗證成功!"};
    7             re.@object = str;
    8             return re;
    9  }
    View Code

    上面介面定義 打上了  [CentralSign(typeof(OpenSign))] 標簽,CentralSign 接收了一個 OpenSign Type  物件型別,根據上面的代碼,我們知道,OpenSign 實作了  ISingSecret 邏輯,我們具體看下 OpenSign  具體實作:

  • OpenSign  實作 ISingSecret 邏輯代碼:
     1 public class OpenSign : ISingSecret
     2     {
     3         public string OpenId(HttpRequest request)
     4         {
     5             return Header.GetHeaderValue(request,"openId");
     6         } 
     7 
     8         public string OpenKey(string OpenId)
     9         {
    10             return ConfigManage.JsonConfigMange.GetInstance().AppSettings[OpenId];
    11         }
    12     }
    View Code

這樣我們就整體上完成了我們所需要的 框架性 服務介面簽名認證代碼, 上面的代碼 在Bitter.Frame 框架 服務簽名模塊中有, Bitter.Frame 代碼還在整理中 ,后續會貼出來給大家,

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/253748.html

標籤:.NET Core

上一篇:到底該不該使用存盤程序

下一篇:一、基于workflow-core強勢開發審批流【已成功流轉50W筆單據】

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more