入门Vue+.NET 8 Web Api记录(一)
做自己感觉有意思的或者能解决自己需求的项目作为入门,我觉得是有帮助的,不会觉得那么无聊。
一个最简单的前后端分离项目应该是怎么样的?
我觉得就是前端有个按钮,点击向后端发送一个get请求,获取到数据后,将数据显示在前端上。
结合最近感兴趣的SemanticKernel,有了做这样的Demo学习的想法,用户点击按钮,返回一句夸人的话。
Vue:

前后端分离的一个很明显的好处就是,你可以使用多个前端使用同一个后端服务,比如我也用Avalona做了一个这样的客户端应用,也可以共用这个后端服务,如下所示:

开始使用.NET 8 Web Api
选择Web Api模板:

其他信息:

这里有几点可以注意:
配置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:

现在想一下自己想添加什么服务,想法是使用SemanticKernel接入大语言模型,当我们请求的时候让它返回一句夸人的话。
SemanticKernel现在就知道它是为了让LLM快速集成进我们的应用的就行了。
安装SemanticKernel:

在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给我们回复。
现在项目结构如下所示:

现在将构造的这个服务,添加到依赖注入容器中:

更规范的做法应该是传入一个接口和一个实现类,本次入门直接传入实现类即可。
现在来看看控制器怎么写?
先看看模板自带的一个控制器:
[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:

可以在上面调试写的接口,试试刚刚创建的Get请求:

我们刚刚写的
_logger.LogInformation($"执行Praise请求 时间:{DateTime.Now}");
在调用接口的时候,就可以看到信息输出在控制台上了,如下所示:

到时候为了让我们能够通过局域网访问,在Program中添加:

到时候前端访问还需要解决一下跨域的问题,在Program中添加:

即可。
到这里为止,我们就已经使用.NET 8 Web Api构建了一个简单的只有一个Get请求的后端服务了。
下期分享Vue与Avalonia中的部分。
入门Vue+.NET 8 Web Api记录(一)的更多相关文章
- Spring Boot入门(四):开发Web Api接口常用注解总结
本系列博客记录自己学习Spring Boot的历程,如帮助到你,不胜荣幸,如有错误,欢迎指正! 在程序员的日常工作中,Web开发应该是占比很重的一部分,至少我工作以来,开发的系统基本都是Web端访问的 ...
- abp学习(四)——根据入门教程(aspnetMVC Web API进一步学习)
Introduction With AspNet MVC Web API EntityFramework and AngularJS 地址:https://aspnetboilerplate.com/ ...
- ASP.NET Web API 记录请求响应数据到日志的一个方法
原文:http://blog.bossma.cn/dotnet/asp-net-web-api-log-request-response/ ASP.NET Web API 记录请求响应数据到日志的一个 ...
- 《ASP.NET Core跨平台开发从入门到实战》Web API自定义格式化protobuf
<ASP.NET Core跨平台开发从入门到实战>样章节 Web API自定义格式化protobuf. 样章 Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于 ...
- OData services入门----使用ASP.NET Web API描述
http://www.cnblogs.com/muyoushui/archive/2013/01/27/2878844.html ODate 是一种应用层协议,设计它的目的在于提供一组通过HTTP的交 ...
- Web API 2 入门——使用ASP.NET Web API和Angular.js构建单页应用程序(SPA)(谷歌翻译)
在这篇文章中 概观 演习 概要 由网络营 下载网络营训练包 在传统的Web应用程序中,客户机(浏览器)通过请求页面启动与服务器的通信.然后,服务器处理请求,并将页面的HTML发送给客户端.在与页面的后 ...
- Web API 2 入门——创建ASP.NET Web API的帮助页面(谷歌翻译)
在这篇文章中 创建API帮助页面 将帮助页面添加到现有项目 添加API文档 在敞篷下 下一步 作者:Mike Wasson 创建Web API时,创建帮助页面通常很有用,以便其他开发人员知道如何调用A ...
- web api 记录部署IIS获取服务器地址的类型
获取服务器地址类型分多种,以下记录 1.HttpContext.Current.Server.MapPath("~/File") 返回的值为 D:\3Project\Code\Mo ...
- YoyoGo微服务框架入门系列-快速编写WEB API
前言 YoyoGo是一个使用Golang编写的一个简单.轻量.快速.基于依赖注入的微服务框架,目前依然在研发阶段,欢迎Star以及一起参与到框架的研发 GitHub地址:https://github. ...
- .net core 3.0 web api 重点设置,主要为了解决axios post不到参数问题
这两天研究.net core 3.0升级,前端vue+axios 后端web api.测试过程中发现post的时候,由于提交的是json对象,后端web api获取不到数据. 今天贴了下解决过程.主要 ...
随机推荐
- golang kmp算法实现
// 不多逼逼直接上代码.原理的话可以参考下面的链接.讲的非常清晰package main import "fmt" func genNext(s string) []int { ...
- Yii框架Ar操作
1.$admin=Admin::model()->findAll($condition,$params); 该方法是根据一个条件查询一个集合,如: findAll("u ...
- python 如何判断一组数呈上升还是下降趋势
1. python 判断一组数呈上升还是下降趋势的方法 要判断一组数(数列)是呈上升趋势.下降趋势还是无明显趋势,我们可以比较数列中相邻元素的差值.如果大部分差值都是正数,则数列呈上升趋势:如果大部分 ...
- (十)selenium实现微博高级搜索信息爬取
1.selenium模拟登陆 2.定位进入高级搜索页面 3.对高级搜索进行定位,设置. 4.代码实现 import time from selenium import webdriver from l ...
- onreadystatechange 属性
onreadystatechange 属性是 XMLHttpRequest 对象的一个事件处理器,用于在 XMLHttpRequest 对象的 readyState 属性发生变化时触发.这个属性通常用 ...
- 关于java时间类型和格式化到微秒问题
常规的问题此处略,因为网络上到处都是,这里主要讨论三个问题: 1.数据库的时间戳类型(含微秒)对应java的什么类型 java的常见时间类型比较多: java.util.Date java.sql.D ...
- Vim编辑的小技巧
Vim编辑的小技巧 如何快速纠错 Ctrl + h 删除上一个字符, Ctrl + w 删除上一个单词, Ctrl + u 删除当前行. 从编辑模式快速切换到Nornal模式 1.Esc 2.Ctrl ...
- VSCode因网络问题导致下载更新/扩展出错
VSCode因网络问题导致下载更新/扩展出错 可尝试方法: 问题0: VSCode出现网络问题排查方法? 法1: 启动时加上选项 --log-net-log=netlog.json ...
- 集成学习与随机森林(二)Bagging与Pasting
Bagging 与Pasting 我们之前提到过,其中一个获取一组不同分类器的方法是使用完全不同的训练算法.另一个方法是为每个预测器使用同样的训练算法,但是在训练集的不同的随机子集上进行训练.在数据抽 ...
- Linux 内核:设备驱动模型(2)driver-bus-device与probe
Linux 内核:设备驱动模型(2)driver-bus-device与probe 系列:Linux 内核:设备驱动模型 学习总结 参考: https://blog.csdn.net/lizuobin ...