主頁 > .NET開發 > (3)ASP.NET Core3.1 Ocelot認證

(3)ASP.NET Core3.1 Ocelot認證

2020-11-09 19:52:44 .NET開發

1.認證

當客戶端通過Ocelot訪問下游服務的時候,為了保護下游資源服務器會進行認證鑒權,這時候需要在Ocelot添加認證服務,添加認證服務后,隨后使用Ocelot基于宣告的任何功能,例如授權或使用Token中的值修改請求,用戶必須像往常一樣在其Startup.cs中注冊身份驗證服務,但是他們為每次注冊提供一個方案(身份驗證提供者密鑰),例如:

public void ConfigureServices(IServiceCollection services)
{
    var authenticationProviderKey = "TestKey";
    services.AddAuthentication()
        .AddJwtBearer(authenticationProviderKey, x =>
        {
        });
}

在此Ocelot認證專案示例中,TestKey是已注冊此提供程式的方案,然后我們將其映射到配置中的Routes路由,例如:

{
    "Routes": [
        {
            "DownstreamPathTemplate": "/api/customers",
            "DownstreamScheme": "http",
            "DownstreamHost": "localhost",
            "DownstreamPort": 9001,
            "UpstreamPathTemplate": "/customers",
            "UpstreamHttpMethod": [ "Get" ],
            "AuthenticationOptions": {
                "AuthenticationProviderKey": "TestKey",
                "AllowedScopes": []
            }
        }
    ]
}

Ocelot運行時,它將查看Routes.AuthenticationOptions.AuthenticationProviderKey并檢查是否存在使用給定密鑰注冊的身份驗證提供程式,如果不存在,則Ocelot將不會啟動,如果存在,則Routes將在執行時使用該提供程式,如果對路由進行身份驗證,Ocelot將在執行身份驗證中間件時呼叫與之關聯的任何方案,如果請求通過身份驗證失敗,Ocelot將回傳http狀態代碼401,

2.JWT Tokens Bearer認證

Json Web Token (JWT),是為了在網路應用環境間傳遞宣告而執行的一種基于JSON的開放標準(RFC 7519),該token被設計為緊湊且安全的,特別適用于分布式站點的單點登錄(SSO)場景,JWT的宣告一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份資訊,以便于從資源服務器獲取資源,也可以增加一些額外的其它業務邏輯所必須的宣告資訊,該token也可直接被用于認證,也可被加密,

2.1JWT令牌結構

在緊湊的形式中,JSON Web Tokens由dot(.)分隔的三個部分組成,它們是:Header頭、Payload有效載荷、Signature簽名,因此,JWT通常如下所示:xxxxx.yyyyy.zzzzz(Header.Payload.Signature),

2.1.1Header頭

標頭通常由兩部分組成:令牌的型別,即JWT,以及正在使用的簽名演算法,例如HMAC SHA256或RSA,例如:

{
  "alg": "HS256",
  "typ": "JWT"
}

然后,這個JSON被編碼為Base64Url,形成JWT的第一部分,

2.1.2Payload有效載荷

Payload部分也是一個JSON物件,用來存放實際需要傳遞的資料,JWT規定了7個官方欄位,供選用,
iss (issuer):簽發人
exp (expiration time):過期時間
sub (subject):主題
aud (audience):受眾
nbf (Not Before):生效時間
iat (Issued At):簽發時間
jti (JWT ID):編號
除了官方欄位,你還可以在這個部分定義私有欄位,下面就是一個例子,例如:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

注意,JWT默認是不加密的,任何人都可以讀到,所以不要把秘密資訊放在這個部分,這個JSON物件也要使用Base64URL演算法轉成字串,

2.1.3.Signature簽名

Signature部分是前兩部分的簽名,防止資料篡改,首先,需要指定一個密鑰(secret),這個密鑰只有服務器才知道,不能泄露給用戶,然后,使用Header里面指定的簽名演算法(默認是HMAC SHA256),按照下面的公式產生簽名:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

簽名用于驗證訊息在此程序中未被更改,并且,在使用私鑰簽名的令牌的情況下,它還可以驗證JWT的發件人是否是它所聲稱的人,把他們三個全部放在一起,輸出是三個由點分隔的Base64-URL字串,可以在HTML和HTTP環境中輕松傳遞,而與基于XML的標準(如SAML)相比更加緊湊,下面顯示了一個JWT,它具有先前的頭和有效負載編碼,并使用機密簽名:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoid3prNzAzIiwibmJmIjoiMTU5MjE0MzkzNyIsImV4cCI6MTU5MjE0Mzk5OCwiaXNzIjoiYXV0aC5qd3QuY2MiLCJhdWQiOiJkZW5nd3V8MjAyMC82LzE0IDIyOjEyOjE5In0
.4RiwhRy0rQkZjclOFWyTpmW7v0AMaL3aeve1L-eWIz0

其實一般發送用戶名和密碼獲取token那是由Identity4來完成的,包括驗證用戶,生成JwtToken,但是專案這里是由System.IdentityModel.Tokens類別庫來生成JwtToken,最后回傳jwt令牌token給用戶,JwtToken解碼可以通過https://jwt.io/中進行查看,

3.專案演示

3.1APIGateway專案

在該專案中啟用身份認證來保護下游api服務,使用JwtBearer認證,將默認的身份驗證方案設定為TestKey,在appsettings.json檔案中配置認證中密鑰(Secret)跟受眾(Aud)資訊:

{
    "Audience": {
        "Secret": "Y2F0Y2hlciUyMHdvbmclMjBsb3ZlJTIwLm5ldA==",
        "Iss": "http://www.c-sharpcorner.com/members/catcher-wong",
        "Aud": "Catcher Wong"
    }
}

Startup添加身份認證代碼如下:

public void ConfigureServices(IServiceCollection services)
{
    //獲取appsettings.json檔案中配置認證中密鑰(Secret)跟受眾(Aud)資訊
    var audienceConfig = Configuration.GetSection("Audience");
    //獲取安全秘鑰
    var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(audienceConfig["Secret"]));
    //token要驗證的引數集合
    var tokenValidationParameters = new TokenValidationParameters
    {
        //必須驗證安全秘鑰
        ValidateIssuerSigningKey = true,
        //賦值安全秘鑰
        IssuerSigningKey = signingKey,
        //必須驗證簽發人
        ValidateIssuer = true,
        //賦值簽發人
        ValidIssuer = audienceConfig["Iss"],
        //必須驗證受眾
        ValidateAudience = true,
        //賦值受眾
        ValidAudience = audienceConfig["Aud"],
        //是否驗證Token有效期,使用當前時間與Token的Claims中的NotBefore和Expires對比
        ValidateLifetime = true,
        //允許的服務器時間偏移量
        ClockSkew = TimeSpan.Zero,
        //是否要求Token的Claims中必須包含Expires
        RequireExpirationTime = true,
    };
    //添加服務驗證,方案為TestKey
    services.AddAuthentication(o =>
    {
        o.DefaultAuthenticateScheme = "TestKey";
    })
    .AddJwtBearer("TestKey", x =>
        {
            x.RequireHttpsMetadata = false;
            //在JwtBearerOptions配置中,IssuerSigningKey(簽名秘鑰)、ValidIssuer(Token頒發機構)、ValidAudience(頒發給誰)三個引數是必須的,
            x.TokenValidationParameters = tokenValidationParameters;
        });
    //添加Ocelot網關服務時,包括Secret秘鑰、Iss簽發人、Aud受眾
    services.AddOcelot(Configuration);
}
public async void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    //使用認證服務
    app.UseAuthentication();
    //使用Ocelot中間件
    await app.UseOcelot();
}
3.1.1Identity Server承載JWT Token

在第二小節介紹JWT Token認證時候,我們都知道一般發送用戶名和密碼獲取Token那是由Identity4來完成的,包括驗證用戶,生成JWT Token,也就是說Identity Server承載了JWT Token認證功能,為了使用IdentityServer承載Token,請像往常一樣在ConfigureServices中使用方案(密鑰)注冊IdentityServer服務,如果您不知道如何執行此操作,請查閱IdentityServer檔案,

public void ConfigureServices(IServiceCollection services)
{
    var authenticationProviderKey = "TestKey";
    Action<IdentityServerAuthenticationOptions> options = o =>
        {
            o.Authority = "https://whereyouridentityserverlives.com";
            o.ApiName = "api";
            o.SupportedTokens = SupportedTokens.Both;
            o.ApiSecret = "secret";
        };
    services.AddAuthentication()
        .AddIdentityServerAuthentication(authenticationProviderKey, options);
    services.AddOcelot();
}

在Identity4中是由Authority引數指定OIDC服務地址,OIDC可以自動發現Issuer, IssuerSigningKey等配置,而o.Audience與x.TokenValidationParameters = new TokenValidationParameters { ValidAudience = "api" }是等效的,

3.2AuthServer專案

此服務主要用于客戶端請求受保護的資源服務器時,認證后產生客戶端需要的JWT Token,生成JWT Token關鍵代碼如下:

[Route("api/[controller]")]
public class AuthController : Controller
{
    private IOptions<Audience> _settings;
    public AuthController(IOptions<Audience> settings)
    {
        this._settings = settings;
    }
    /// <summary>
    ///用戶使用 用戶名密碼 來請求服務器
    ///服務器進行驗證用戶的資訊
    ///服務器通過驗證發送給用戶一個token
    ///客戶端存盤token,并在每次請求時附送上這個token值, headers: {'Authorization': 'Bearer ' + token}
    ///服務端驗證token值,并回傳資料
    /// </summary>
    /// <param name="name"></param>
    /// <param name="pwd"></param>
    /// <returns></returns>
    [HttpGet]
    public IActionResult Get(string name, string pwd)
    {
        //驗證登錄用戶名和密碼
        if (name == "catcher" && pwd == "123")
        {
            var now = DateTime.UtcNow;
            //添加用戶的資訊,轉成一組宣告,還可以寫入更多用戶資訊宣告
            var claims = new Claim[]
            {
                //宣告主題
                new Claim(JwtRegisteredClaimNames.Sub, name),
                    //JWT ID 唯一識別符號
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                    //發布時間戳 issued timestamp
                new Claim(JwtRegisteredClaimNames.Iat, now.ToUniversalTime().ToString(), ClaimValueTypes.Integer64)
            };
            //下面使用 Microsoft.IdentityModel.Tokens幫助庫下的類來創建JwtToken

            //安全秘鑰
            var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_settings.Value.Secret));

            //宣告jwt驗證引數
            var tokenValidationParameters = new TokenValidationParameters
            {
                //必須驗證安全秘鑰
                ValidateIssuerSigningKey = true,
                //賦值安全秘鑰
                IssuerSigningKey = signingKey,
                //必須驗證簽發人
                ValidateIssuer = true,
                //賦值簽發人
                ValidIssuer = _settings.Value.Iss,
                //必須驗證受眾
                ValidateAudience = true,
                //賦值受眾
                ValidAudience = _settings.Value.Aud,
                //是否驗證Token有效期,使用當前時間與Token的Claims中的NotBefore和Expires對比
                ValidateLifetime = true,
                //允許的服務器時間偏移量
                ClockSkew = TimeSpan.Zero,
                //是否要求Token的Claims中必須包含Expires
                RequireExpirationTime = true,
            };
            var jwt = new JwtSecurityToken(
                //jwt簽發人
                issuer: _settings.Value.Iss,
                //jwt受眾
                audience: _settings.Value.Aud,
                //jwt一組宣告
                claims: claims,
                notBefore: now,
                //jwt令牌過期時間
                expires: now.Add(TimeSpan.FromMinutes(2)),
                //簽名憑證: 安全密鑰、簽名演算法
                signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
            );
            //生成jwt令牌(json web token)
            var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
            var responseJson = new
            {
                access_token = encodedJwt,
                expires_in = (int)TimeSpan.FromMinutes(2).TotalSeconds
            };
            return Json(responseJson);
        }
        else
        {
            return Json("");
        }
    }
}
public class Audience
{
    public string Secret { get; set; }
    public string Iss { get; set; }
    public string Aud { get; set; }
}

appsettings.json檔案中配置認證中密鑰(Secret)跟受眾(Aud)資訊:

{
    "Audience": {
        "Secret": "Y2F0Y2hlciUyMHdvbmclMjBsb3ZlJTIwLm5ldA==",
        "Iss": "http://www.c-sharpcorner.com/members/catcher-wong",
        "Aud": "Catcher Wong"
    }
}

3.3CustomerAPIServices專案

該專案跟APIGateway專案是一樣的,為了保護下游api服務,使用JwtBearer認證,將默認的身份驗證方案設定為TestKey,在appsettings.json檔案中配置認證中密鑰(Secret)跟受眾(Aud)資訊:

{
    "Audience": {
        "Secret": "Y2F0Y2hlciUyMHdvbmclMjBsb3ZlJTIwLm5ldA==",
        "Iss": "http://www.c-sharpcorner.com/members/catcher-wong",
        "Aud": "Catcher Wong"
    }
}

Startup添加身份認證代碼如下:

public void ConfigureServices(IServiceCollection services)
{
    //獲取appsettings.json檔案中配置認證中密鑰(Secret)跟受眾(Aud)資訊
    var audienceConfig = Configuration.GetSection("Audience");
    //獲取安全秘鑰
    var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(audienceConfig["Secret"]));
    //token要驗證的引數集合
    var tokenValidationParameters = new TokenValidationParameters
    {
        //必須驗證安全秘鑰
        ValidateIssuerSigningKey = true,
        //賦值安全秘鑰
        IssuerSigningKey = signingKey,
        //必須驗證簽發人
        ValidateIssuer = true,
        //賦值簽發人
        ValidIssuer = audienceConfig["Iss"],
        //必須驗證受眾
        ValidateAudience = true,
        //賦值受眾
        ValidAudience = audienceConfig["Aud"],
        //是否驗證Token有效期,使用當前時間與Token的Claims中的NotBefore和Expires對比
        ValidateLifetime = true,
        //允許的服務器時間偏移量
        ClockSkew = TimeSpan.Zero,
        //是否要求Token的Claims中必須包含Expires
        RequireExpirationTime = true,
    };
    //添加服務驗證,方案為TestKey
    services.AddAuthentication(o =>
    {
        o.DefaultAuthenticateScheme = "TestKey";
    })
    .AddJwtBearer("TestKey", x =>
        {
            x.RequireHttpsMetadata = false;
            //在JwtBearerOptions配置中,IssuerSigningKey(簽名秘鑰)、ValidIssuer(Token頒發機構)、ValidAudience(頒發給誰)三個引數是必須的,
            x.TokenValidationParameters = tokenValidationParameters;
        });

    services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
    //使用認證服務
    app.UseAuthentication();
    app.UseMvc();
}

在CustomersController下添加一個需要認證方法,一個不需要認證方法:

[Route("api/[controller]")]
public class CustomersController : Controller
{
    //添加認證屬性
    [Authorize]
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "Catcher Wong", "James Li" };
    }
    [HttpGet("{id}")]
    public string Get(int id)
    {
        return $"Catcher Wong - {id}";
    }
}

3.4ClientApp專案

該專案是用來模擬客戶端訪問資源服務器整個認證流程測驗專案,在Program主程式可以看到如下代碼:

class Program
{
    static void Main(string[] args)
    {
        HttpClient client = new HttpClient();

        client.DefaultRequestHeaders.Clear();
        client.BaseAddress = new Uri("http://localhost:9000");

        // 1. without access_token will not access the service
        //    and return 401 .
        var resWithoutToken = client.GetAsync("/customers").Result;

        Console.WriteLine($"Sending Request to /customers , without token.");
        Console.WriteLine($"Result : {resWithoutToken.StatusCode}");

        //2. with access_token will access the service
        //   and return result.
        client.DefaultRequestHeaders.Clear();
        Console.WriteLine("\nBegin Auth....");
        var jwt = GetJwt();
        Console.WriteLine("End Auth....");
        Console.WriteLine($"\nToken={jwt}");

        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwt}");
        var resWithToken = client.GetAsync("/customers").Result;

        Console.WriteLine($"\nSend Request to /customers , with token.");
        Console.WriteLine($"Result : {resWithToken.StatusCode}");
        Console.WriteLine(resWithToken.Content.ReadAsStringAsync().Result);

        //3. visit no auth service
        Console.WriteLine("\nNo Auth Service Here ");
        client.DefaultRequestHeaders.Clear();
        var res = client.GetAsync("/customers/1").Result;

        Console.WriteLine($"Send Request to /customers/1");
        Console.WriteLine($"Result : {res.StatusCode}");
        Console.WriteLine(res.Content.ReadAsStringAsync().Result);

        Console.Read();
    }
    private static string GetJwt()
    {
        HttpClient client = new HttpClient();

        client.BaseAddress = new Uri( "http://localhost:9000");
        client.DefaultRequestHeaders.Clear();

        var res2 = client.GetAsync("/api/auth?name=catcher&pwd=123").Result;

        dynamic jwt = JsonConvert.DeserializeObject(res2.Content.ReadAsStringAsync().Result);

        return jwt.access_token;
    }
}

運行專案看看測驗結果:

結合代碼,我們能看到當客戶端通過Ocelot網關訪問下游服務http://localhost:9000/api/Customers/Get方法時候,因為該方法是需要通過認證才回傳處理結果的,所以會進行JWT Token認證,如果發現沒有Token,Ocelot則回傳http狀態代碼401拒絕訪問,如果我們通過GetJwt方法在AuthServer服務上登錄認證獲取到授權Token,然后再訪問該資源服務器介面,立即就會回傳處理結果,通過跟而未加認證屬性的http://localhost:9000/api/Customers/Get/{id}方法對比,我們就知道,Ocelot認證已經成功了!

4.總結

該章節只是結合demo專案簡單介紹在Ocelot中如何使用JWT Token認證,其實正式環境中,Ocelot是應該集成IdentityServer認證授權的,同樣的通過重寫Ocelot中間件我們還可以把configuration.json的配置資訊存盤到資料庫或者快取到Redis中,

參考文獻:
Ocelot官網

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

標籤:.NET Core

上一篇:說說 C# 9 新特性的實際運用

下一篇:(3)ASP.NET Core3.1 Ocelot認證

標籤雲
其他(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