入門Vue+.NET 8 Web Api記錄(一)

mingupupup發表於2024-07-25

做自己感覺有意思的或者能解決自己需求的專案作為入門,我覺得是有幫助的,不會覺得那麼無聊。

一個最簡單的前後端分離專案應該是怎麼樣的?

我覺得就是前端有個按鈕,點選向後端傳送一個get請求,獲取到資料後,將資料顯示在前端上。

結合最近感興趣的SemanticKernel,有了做這樣的Demo學習的想法,使用者點選按鈕,返回一句夸人的話。

Vue:

前後端分離的一個很明顯的好處就是,你可以使用多個前端使用同一個後端服務,比如我也用Avalona做了一個這樣的客戶端應用,也可以共用這個後端服務,如下所示:

開始使用.NET 8 Web Api

選擇Web Api模板:

image-20240725092622106

其他資訊:

image-20240725093117690

這裡有幾點可以注意:

配置https是什麼意思?

配置HTTPS是指在網路伺服器上設定和啟用安全超文字傳輸協議(HTTPS)。HTTPS是HTTP的安全版本,它在HTTP協議的基礎上新增了SSL/TLS加密層,以確保資料在客戶端和伺服器之間的傳輸過程中是加密的,從而保護資料的機密性和完整性。

啟用OpenAPI支援是什麼意思?

OpenAPI(以前稱為Swagger規範)是一種用於描述、生成、消費和視覺化RESTful Web服務的規範。它允許開發者定義API的各個方面,包括路徑、操作、請求引數、響應和認證方法。透過使用OpenAPI規範,開發者可以更容易地建立、維護和使用API文件,從而提高開發效率和API的可理解性。

啟用OpenAPI支援是指在軟體專案中整合和配置OpenAPI規範,以便能夠生成、使用和展示符合OpenAPI標準的API文件。這意味著專案將能夠利用OpenAPI的各種工具和生態系統來簡化API的設計、開發、文件編寫和測試過程。

不使用頂級語句是什麼意思?

在C#中,"不使用頂級語句"(Not using top-level statements)是指在編寫程式碼時不採用C# 9.0引入的頂級語句特性。

使用控制器是什麼意思?

控制器是MVC(Model-View-Controller)中的Controller,在Web API開發中,"使用控制器"(Using Controllers)是指採用一種設計模式,其中API的邏輯被組織到稱為"控制器"的類中。控制器負責處理HTTP請求、執行相應的業務邏輯,並返回HTTP響應。

為了維護方便與規範化,自己再加上一層Model、一層Services:

image-20240725130842155

現在想一下自己想新增什麼服務,想法是使用SemanticKernel接入大語言模型,當我們請求的時候讓它返回一句夸人的話。

SemanticKernel現在就知道它是為了讓LLM快速整合進我們的應用的就行了。

安裝SemanticKernel:

image-20240725131101780

在Services中新增SemanticKernelService:

 public class SemanticKernelService
 {
     private readonly Kernel _kernel;
     public SemanticKernelService()
     {
         var handler = new OpenAIHttpClientHandler();
         var builder = Kernel.CreateBuilder()
        .AddOpenAIChatCompletion(
           modelId: "Qwen/Qwen2-7B-Instruct",
           apiKey: "你的apikey",
           httpClient: new HttpClient(handler));
         _kernel = builder.Build();
     }

     public async Task<string> Praiseyuzai()
     {
         var skPrompt = """                           
                       你是一個夸人的專家,回覆一句話夸人。                         
                       你的回覆應該是一句話,不要太長,也不要太短。                               
                       """;
         var result = await _kernel.InvokePromptAsync(skPrompt);
         var str = result.ToString();
         return str;
     }

 }

可能很多人看SemanticKernel的介紹會覺得只能用OpenAI的模型,其實只要相容了OpenAI格式的線上模型都可以的,本地大模型的話也是可以透過實現介面實現接入的,本文選擇的平臺是矽基流動下的Qwen/Qwen2-7B-Instruct模型,免費使用。

由於不是OpenAI需要將請求轉發到矽基流動提供的Api上,需要在模型中新增OpenAIHttpClientHandler類如下所示:

 public class OpenAIHttpClientHandler : HttpClientHandler
 {
     protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
     {
         UriBuilder uriBuilder;
         switch (request.RequestUri?.LocalPath)
         {
             case "/v1/chat/completions":
                 uriBuilder = new UriBuilder(request.RequestUri)
                 {
                     // 這裡是你要修改的 URL
                     Scheme = "https",
                     Host = "api.siliconflow.cn",
                     Path = "v1/chat/completions",
                 };
                 request.RequestUri = uriBuilder.Uri;
                 break;
         }

         HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

         return response;
     }

我們與大語言模型聊天,就是在提供一個Prompt,這裡我們的Prompt如下:

  var skPrompt = """                           
                       你是一個夸人的專家,回覆一句話夸人。                         
                       你的回覆應該是一句話,不要太長,也不要太短。                               
                       """;

大語言模型會根據這個Prompt給我們回覆。

現在專案結構如下所示:

image-20240725131839064

現在將構造的這個服務,新增到依賴注入容器中:

image-20240725131923106

更規範的做法應該是傳入一個介面和一個實現類,本次入門直接傳入實現類即可。

現在來看看控制器怎麼寫?

先看看模板自帶的一個控制器:

 [ApiController]
 [Route("[controller]")]
 public class WeatherForecastController : ControllerBase
 {
     private static readonly string[] Summaries = new[]
     {
         "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
     };

     private readonly ILogger<WeatherForecastController> _logger;

     public WeatherForecastController(ILogger<WeatherForecastController> logger)
     {
         _logger = logger;
     }

     [HttpGet(Name = "GetWeatherForecast")]
     public IEnumerable<WeatherForecast> Get()
     {
         return Enumerable.Range(1, 5).Select(index => new WeatherForecast
         {
             Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
             TemperatureC = Random.Shared.Next(-20, 55),
             Summary = Summaries[Random.Shared.Next(Summaries.Length)]
         })
         .ToArray();
     }
 }

模仿它的樣子寫一個控制器:

[ApiController]
[Route("[controller]")]
public class SemantickernelController : ControllerBase
{
    private readonly ILogger<SemantickernelController> _logger;
    private readonly SemanticKernelService _semanticKernelService;
    
    public SemantickernelController(ILogger<SemantickernelController> logger,SemanticKernelService semanticKernelService)
    {
        _logger = logger;
        _semanticKernelService = semanticKernelService;
    }

    [HttpGet]
    public async Task<string> Get()
    {
        _logger.LogInformation($"執行Praise請求 時間:{DateTime.Now}");
        var str = await _semanticKernelService.Praise();
        return str;
    }
 
}

在建構函式中注入了我們剛剛註冊的服務類。

[HttpGet]
public async Task<string> Get()
{
   _logger.LogInformation($"執行Praise請求 時間:{DateTime.Now}");
   var str = await _semanticKernelService.Praise();
   return str;
}

這個的寫法其實也不規範,後面可以使用ActionResult<T>替代,現在先不用管,能用就行。

現在啟動專案,會跳出Swagger UI:

image-20240725132604898

可以在上面除錯寫的介面,試試剛剛建立的Get請求:

image-20240725132824604

我們剛剛寫的

 _logger.LogInformation($"執行Praise請求 時間:{DateTime.Now}");

在呼叫介面的時候,就可以看到資訊輸出在控制檯上了,如下所示:

image-20240725133048007

到時候為了讓我們能夠透過區域網訪問,在Program中新增:

image-20240725133156224

到時候前端訪問還需要解決一下跨域的問題,在Program中新增:

image-20240725133235285

即可。

到這裡為止,我們就已經使用.NET 8 Web Api構建了一個簡單的只有一個Get請求的後端服務了。

下期分享Vue與Avalonia中的部分。

相關文章