主頁 > .NET開發 > [翻譯] 使用 Serverless 和 .NET Core 構建飛速發展的架構

[翻譯] 使用 Serverless 和 .NET Core 構建飛速發展的架構

2020-09-20 09:49:30 .NET開發

原文:Fast growing architectures with serverless and .NET Core
作者:Samuele Resca

Serverless 技術為開發人員提供了一種快速而獨立的方式將實作投入生產,這種技術在企業的技術堆疊中日益流行,自 2017 年以來,它一直是 ThoughtWorks 技術雷達的實驗級別的技術[譯注:技術雷達是 ThoughtWorks 每半年發布的前沿技術決議],

本篇文章的第一部分介紹了有關 Serverless 計算的基本概念,第二部分展示了如何構建 .NET Core 的 Lambda 函式,其中使用了 AWS 的 Serverless 框架,

Serverless 計算的好處

Serverless 技術是 FaaS(功能即服務)技術體系的一部分,隨著云計算的采用,這些技術變得越來越受歡迎,如今,serverless 實作被提升為云計算提供商的首選技術,無論是私有云還是公有云,

此外,典型的軟體服務和系統會通過在記憶體中保留大量資料并在復雜資料源中寫入成批資料來完成操作,
然而一般而言,像 Serverless 一樣的 FaaS 技術旨在通過盡可能快地處理許多小請求和事件,來使我們的系統保持快速回應,Serverless 組件通常與運行它們的云服務商所提供的事件緊密耦合:一個通知、一個佇列調度的事件或者一個來自 API 網關的請求,都被視為此組件中包含的一小部分計算的觸發器,這也就是云服務商的定價系統基于請求數而不是基于計算時間的主要原因,

再者,serverless 組件通常在執行時間上有一些限制,與每種技術一樣,serverless 并不適合每一個解決方案和系統,但是事實上,它確實簡化了軟體工程師的一些作業,lambda 部署周期通常很快,開發人員只需要做少量作業就可以快速將新功能投入生產,此外,使用 serverless 技術構建組件意味著開發人員無需擔心擴展問題或故障,讓云提供商去關心這些問題吧,

最后,我們還應該知道 serverless 函式是無狀態的,因此,基于此技術構建的每個系統都更加模塊化和松耦合,

Serverless 的痛點

但是這種能力和敏捷性卻不是沒有代價的,首先,serverless 函式是在云上執行的,它們通常由與云提供商緊密耦合的事件觸發,因此除錯它們并不容易,這就是為什么要使它的作用域保持盡可能小,并且始終將函式的核心邏輯與外部組件和事件分隔開的原因,此外,用單元測驗和集成測驗覆寫 serverless 代碼非常重要,

其次,就像微服務架構一樣,它具有大量的服務,但是關注的范圍很小,因此很難對 serverless 的組件進行監控,某些問題也很難檢測,總之,很難對不同的 serverless 組件之間的體系結構和依賴性有一個全面的認識,因此,云提服務商和第三方公司都在提供監控和系統分析功能的一體式工具上投入了大量資金,

體驗一下 serverless 計算

現如今,根據業務需求快速進化的架構以往任何時候都更為重要,資料驅動的體驗是這個程序的一部分,此外,在發布新功能之前,我們應該實作MVP(譯注:最小可行化產品)并在部分客戶群上測驗它,如果實驗結果是肯定的,則值得在MVP上進行投資,以將其轉化為我們產品的功能,

是的,serverless 計算提供了這樣一種方法,可以在不考慮基礎設施的情況下快速進化我們的架構,Serverless 輕量級開銷提供了一種實作一次性 MVP 的方法,用于試驗新功能和新特性,此外,它們還可以很容易地啟動和關閉,

使用 .NET Core 來實作 AWS Lambda 函式

這一節將介紹使用 .NET Core 的一些 AWS Lambdas 的簡單實作,該例子涉及三個關鍵技術:

  • AWS 是承載我們 serverless 功能的云服務商;
  • serverless 框架,它是將 Lambdas 放入 AWS 的非常有用的工具,作為一個通用的框架,它兼容所有主要的云服務商;
  • .NET Core 是微軟提供的開源的、跨平臺的框架;

我們將要討論的示例也放在了 GitHub 上,URL 如下: serverless/examples/aws-dotnet-rest-api-with-dynamodb,該示例是 serverless 框架提供的一些模板專案的一部分,

AWS Lambda 專案遵循以下功能架構:

總結一下,該功能實作了對資料的一些讀取/寫入操作,客戶端通過API網關發出HTTP請求,lambda 專案定義了三個函式:GetItem、InsertItem 和 UpdateItem,它們都對 DynamoDB 表進行操作,

專案結構

我們將要實作的解決方案具有以下專案結構:

  • src/DotNetServerless.Application 該專案包含了由 Serverless 執行的核心邏輯;
  • src/DotNetServerless.Lambda 該專案包含了 Serverless 函式的入口點以及所有與 AWS 緊密耦合的組件;
  • tests/DotNetServerless.Tests 該專案包含了 Serverless 功能的單元測驗和集成測驗;

領域專案

讓我們從 application 層開始分析,專案的核心物體是 Item 類,它表示 DynamoDB(譯注:AWS的一種資料庫) 表中存盤的物體:

using Amazon.DynamoDBv2.DataModel;

namespace DotNetServerless.Application.Entity
{
  public class Item
  {
    [DynamoDBHashKey]
    public string Id { get; set; }
    [DynamoDBRangeKey]
    public string Code { get; set; }
    [DynamoDBProperty]
    public string Description { get; set; }
    [DynamoDBProperty]
    public bool IsChecked { get; set; }
  }
}

物體的欄位使用了一些特性進行修飾,以便使用 DynamoDb 存盤模型映射它們,Item 物體被 IItemsRepository 介面參考,該介面定義用于存盤資料的操作:

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.DynamoDBv2.DocumentModel;
using DotNetServerless.Application.Entities;
using DotNetServerless.Application.Infrastructure.Configs;

namespace DotNetServerless.Application.Infrastructure.Repositories
{
  public interface IItemRepository
  {
    Task<IEnumerable<T>> GetById<T>(string id, CancellationToken cancellationToken);

    Task Save(Item item, CancellationToken cancellationToken);
  }

  public class ItemDynamoRepository : IItemRepository
  {
    private readonly AmazonDynamoDBClient _client;
    private readonly DynamoDBOperationConfig _configuration;

    public ItemDynamoRepository(DynamoDbConfiguration configuration,
      IAwsClientFactory<AmazonDynamoDBClient> clientFactory)
    {
      _client = clientFactory.GetAwsClient();
      _configuration = new DynamoDBOperationConfig
      {
        OverrideTableName = configuration.TableName,
        SkipVersionCheck = true
      };
    }

    public async Task Save(Item item, CancellationToken cancellationToken)
    {
      using (var context = new DynamoDBContext(_client))
      {
        await context.SaveAsync(item, _configuration, cancellationToken);
      }
    }

    public async Task<IEnumerable<T>> GetById<T>(string id, CancellationToken cancellationToken)
    {
      var resultList = new List<T>();
      using (var context = new DynamoDBContext(_client))
      {
        var scanCondition = new ScanCondition(nameof(Item.Id), ScanOperator.Equal, id);
        var search = context.ScanAsync<T>(new[] {scanCondition}, _configuration);

        while (!search.IsDone)
        {
          var entities = await search.GetNextSetAsync(cancellationToken);
          resultList.AddRange(entities);
        }
      }

      return resultList;
    }
  }
}

IItemRepository 的實作定義了兩個基本操作:

  • Save,允許呼叫者插入和更新物體;
  • GetById,根據 ID 回傳物件;

最后,DotNetServerless.Application 的頂層是 Handler 部分,并且
,整個 application 專案都基于中介模式,以保證 AWS 函式和核心邏輯之間的松散耦合,讓我們以創建專案處理程式的定義為例:

using System;
using System.Threading;
using System.Threading.Tasks;
using DotNetServerless.Application.Entities;
using DotNetServerless.Application.Infrastructure.Repositories;
using DotNetServerless.Application.Requests;
using MediatR;

namespace DotNetServerless.Application.Handlers
{
  public class CreateItemHandler : IRequestHandler<CreateItemRequest, Item>
  {
    private readonly IItemRepository _itemRepository;

    public CreateItemHandler(IItemRepository itemRepository)
    {
      _itemRepository = itemRepository;
    }

    public async Task<Item> Handle(CreateItemRequest request, CancellationToken cancellationToken)
    {
      var item = request.Map();
      item.Id = Guid.NewGuid().ToString();

      await _itemRepository.Save(item, cancellationToken);

      return item;
    }
  }
}

如您所見,代碼非常簡單,CreateItemHandler 實作了 IRequestHandler,它使用內置的依賴注入來決議 IItemRepository 介面,處理程式的 Handler 方法僅將傳入的請求與Item物體映射,并呼叫IItemRepository介面提供的Save方法,

函式專案

函式專案包含 lambda 功能的入口點,它定義了三個函式類,它們表示 AWS 的 lambda:CreateItemFunction, GetItemFunction 和 UpdateItemFunction; 稍后我們將看到,每個函式都將使用 API 網關的特定路由進行映射,

讓我們以 CreateItem 函式為例,對函式定義進行一些深入探討:

using System;
using System.Threading.Tasks;
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
using DotNetServerless.Application.Requests;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;

namespace DotNetServerless.Lambda.Functions
{
  public class CreateItemFunction
  {
    private readonly IServiceProvider _serviceProvider;

    public CreateItemFunction() : this(Startup
      .BuildContainer()
      .BuildServiceProvider())
    {
    }

    public CreateItemFunction(IServiceProvider serviceProvider)
    {
      _serviceProvider = serviceProvider;
    }

    [LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
    public async Task<APIGatewayProxyResponse> Run(APIGatewayProxyRequest request)
    {
      var requestModel = JsonConvert.DeserializeObject<CreateItemRequest>(request.Body);
      var mediator = _serviceProvider.GetService<IMediator>();
      
      var result = await mediator.Send(requestModel);

      return new APIGatewayProxyResponse { StatusCode =  201,  Body = JsonConvert.SerializeObject(result)};
    }
  }
}

上面提到的代碼定義了函式的入口點,首先,它宣告一個建構式,并使用Startup類公開的BuildContainer和BuildServiceProvider方法,稍后我們將看到,這些方法是為初始化依賴項注入容器而提供的,CreateItem 函式的 Run 方法使用 Lambda 序列器屬性進行修飾,這意味著它是函式的入口點,此外,運行函式使用 APIGatewayProxyRequest 請求和 APIGatewayProxyReposne 作為 lambda 計算的輸入和輸出,

依賴注入

該專案使用了 .NET Core 內置的依賴注入,Startup 類定義了 BuildContainer 靜態方法,該方法回傳一個新的 ServiceCollection,其中包含物體之間的依賴關系映射:

using System.IO;
using DotNetServerless.Application.Infrastructure;
using DotNetServerless.Application.Infrastructure.Configs;
using DotNetServerless.Application.Infrastructure.Repositories;
using DotNetServerless.Lambda.Extensions;
using MediatR;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace DotNetServerless.Lambda
{
  public class Startup
  {
    public static IServiceCollection BuildContainer()
    {
      var configuration = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddEnvironmentVariables()
        .Build();

      return ConfigureServices(configuration);
    }


    private static IServiceCollection ConfigureServices(IConfigurationRoot configurationRoot)
    {
      var services = new ServiceCollection();

      services
        .AddMediatR()
        .AddTransient(typeof(IAwsClientFactory<>), typeof(AwsClientFactory<>))
        .AddTransient<IItemRepository, ItemDynamoRepository>()
        .BindAndConfigure(configurationRoot.GetSection("DynamoDbConfiguration"), new DynamoDbConfiguration())
        .BindAndConfigure(configurationRoot.GetSection("AwsBasicConfiguration"), new AwsBasicConfiguration());

      return services;
    }
  }
}

Startup使用ConfigureServices初始化新的ServiceCollection并與其一起解決依賴關系,此外,它還使用 BindAndConfigure 方法創建一些配置物件,BuildContainer方法將由函式呼叫,以解決依賴項,

測驗我們的代碼

如前所述,測驗一下我們的代碼,對于持續集成和交付是非常重要的,尤其是在lambda專案中,在這種情況下,測驗將覆寫 IMediator 介面和處理程式之間的集成,此外,它們還覆寫了依賴項注入部分,讓我們看看 CreateItemFunctionTests 的實作:

using System.Threading;
using System.Threading.Tasks;
using Amazon.Lambda.APIGatewayEvents;
using DotNetServerless.Application.Entities;
using DotNetServerless.Application.Infrastructure.Repositories;
using DotNetServerless.Application.Requests;
using DotNetServerless.Lambda;
using DotNetServerless.Lambda.Functions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Moq;
using Newtonsoft.Json;
using Xunit;

namespace DotNetServerless.Tests.Functions
{
  public class CreateItemFunctionTests
  {
    public CreateItemFunctionTests()
    {
      _mockRepository = new Mock<IItemRepository>();
      _mockRepository.Setup(_ => _.Save(It.IsAny<Item>(), It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);

      var serviceCollection = Startup.BuildContainer();

      serviceCollection.Replace(new ServiceDescriptor(typeof(IItemRepository), _ => _mockRepository.Object,
        ServiceLifetime.Transient));

      _sut = new CreateItemFunction(serviceCollection.BuildServiceProvider());
    }

    private readonly CreateItemFunction _sut;
    private readonly Mock<IItemRepository> _mockRepository;

    [Fact]
    public async Task run_should_trigger_mediator_handler_and_repository()
    {
      await _sut.Run(new APIGatewayProxyRequest {Body = JsonConvert.SerializeObject(new CreateItemRequest())});
      _mockRepository.Verify(_ => _.Save(It.IsAny<Item>(), It.IsAny<CancellationToken>()), Times.Once);
    }
    
    [Theory]
    [InlineData(201)]
    public async Task run_should_return_201_created(int statusCode)
    {
      var result = await _sut.Run(new APIGatewayProxyRequest {Body = JsonConvert.SerializeObject(new CreateItemRequest())});
      Assert.Equal(result.StatusCode, statusCode);
    }
  }
}

如您所見,上述代碼執行了我們的函式,并且對已注入的依賴項執行一些驗證,并驗證 IItemRepository 公開的 Save 方法是否被呼叫,因為一些原因,測驗類并沒有覆寫 DynamoDb 的特性,此外,當我們將復雜的物體和操作結合在一起時,可以使用 Docker 容器通過一些集成測驗來覆寫資料庫部分,對了,提到 .NET Core 和 AWS 的話題,.NET AWS 團隊有一個很好的工具來改進 lambda 的測驗:LambdaTestTool

部署專案

讓我們來看看如何將專案匯入AWS,為此,我們將使用 serverless 框架,該框架的定義是:

serverless 框架是一個 CLI 工具,允許用戶構建和部署自動縮放、按執行付費、事件驅動的函式,

為了把 serverless 添加我們的專案,我們應該執行以下命令:

npm install serverless --save-dev

定義基礎架構

默認情況下,基礎架構的定義將放在 serverless.yml 檔案中,該檔案看起來像這樣:

service: ${file(env.configs.yml):feature}

frameworkVersion: ">=1.6.0 <2.1.0"

provider:
  name: aws
  stackName: ${file(env.configs.yml):feature}-${file(env.configs.yml):environment}
  runtime: dotnetcore2.1
  region: ${file(env.configs.yml):region}
  accountId: ${file(env.configs.yml):accountId}
  environment:
    DynamoDbConfiguration__TableName: ${file(env.configs.yml):dynamoTable}
    
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:*
      Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.DynamoDbConfiguration__TableName}"

package:
  artifact: bin/release/netcoreapp2.1/deploy-package.zip
  
functions:
  create:
    handler: DotNetServerless.Lambda::DotNetServerless.Lambda.Functions.CreateItemFunction::Run
    events:
      - http:
          path: items
          method: post
          cors: true

  get:
    handler: DotNetServerless.Lambda::DotNetServerless.Lambda.Functions.GetItemFunction::Run
    events:
      - http:
          path: items/{id}
          method: get
          cors: true

  update:
    handler: DotNetServerless.Lambda::DotNetServerless.Lambda.Functions.UpdateItemFunction::Run
    events:
      - http:
          path: items
          method: put
          cors: true

resources:
  Resources:
    ItemsDynamoDbTable:
      Type: 'AWS::DynamoDB::Table'
      DeletionPolicy: Retain
      Properties:
        AttributeDefinitions:
          - AttributeName: Id
            AttributeType: S
          - AttributeName: Code
            AttributeType: S
        KeySchema:
          - AttributeName: Id
            KeyType: HASH
          - AttributeName: Code
            KeyType: RANGE
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TableName: ${self:provider.environment.DynamoDbConfiguration__TableName}

以上代碼使用 AWS 的 cloud formation 對基礎架構進行一些操作,provider 節點定義了有關 lambda 的某些資訊,例如堆疊名稱、運行時以及有關AWS賬戶的一些資訊,此外,它還描述了 lambda 的角色和授權,例如,應該允許 lambda 對 DynamoDb 表執行操作, functions 節點定義了不同的 lambda 函式,并將其與特定的 HTTP 路徑進行映射,最后,resources 節點用于設定 DynamoDB 表模式,

組態檔

serverless.yml 定義通常與另一個 YAML 檔案結合使用,該檔案僅定義與環境相關的配置,例如,DynamoDbConfiguration__TableName 節點就是這種情況,該節點使用以下語法從另一個 YAML 檔案獲取資訊:${file(env.configs.yml):dynamoTable},以下代碼段顯示了 env.config.yml 檔案的一個示例:

feature: <feature_name>
version: 1.0.0.0
region: <aws_region>
environment: <environment>
accountId: <aws_account_id>
dynamoTable: <dynamo_table_name>

最后的想法

這篇文章涵蓋了一些關于 serverless 計算的理論主題,以及 .Net Core 實現 lambda 函式的例子,著重講解了如何使用 serverless 計算來快速推進我們的架構,此外,勇于嘗試是一個不斷發展的產品很關鍵的一方面,它對于快速適應業務的變化是很重要的,

最后,您可以在以下存盤庫中找到一些 serverless 的 lambda 示例,
serverless/examples/aws-dotnet-rest-api-with-dynamodb

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

標籤:.NET Core

上一篇:.net core 上傳檔案Demo

下一篇:netcore發布Linux相關問題記錄

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