用最清爽的方式开发dotNet
用最清爽的方式开发dotNet
不管是官方自带模板还是其他开源搞的,总是一来一大堆,如果你也嫌弃这些过于臃肿,不如看看我这个方式
前提
假设我要做一个简单的api
方式
想到清爽,那肯定是简单方便,脑袋第一个念头就是.Net6 推出的miniapi了
官方路子
两篇官方文档足以,按照文档step by step 就ok了,其他的需要就加
我的野路子
官方是官方,官方走的路子当然还是基于它最标准的搞法,我的路子则是基于国内实际情况
总体思路就是用控制台改api
模拟前提场景
搞一个普通企业官网的api,那么要求就是以下几点
- 需要数据库操作
- 需要授权鉴权
- 需要swagger文档
- 需要上传文件
根据这些要求,我需要引入最基本的就几个:
- Swashbuckle.AspNetCore (swagger相关)
- SqlSugarCore (sqlsugar Orm)
- Microsoft.AspNetCore.Authentication.JwtBearer (授权鉴权这里用简单的jwt)
- Mapster (dto和entity互转)
如果有其他需求,再自己加,一点也不冗余
代码
Program.cs
里面直接无脑写下以下代码
var builder = WebApplication.CreateBuilder(args);
> dotNet 几忘了,反正很早就是通用主机了,如果你同时还要搞blazor server啥的,把这一坨封装一下即可,通用的
var builder = WebApplication.CreateBuilder(args);
#region 基本设置
builder.Services.AddMemoryCache();
builder.Services.AddControllers();
builder.Services.Configure<FormOptions>(options =>
{
// 设置上传大小限制256MB
options.MultipartBodyLengthLimit = 268435456;
});
builder.Services.AddSingleton<SqlSugarMemoryCacheService>();
#endregion
#region 授权鉴权
// 添加身份验证和授权中间件
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "ningissuer",
ValidAudience = "wr",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("sdfsdfsrty45634kkhxxhtdgdfss345t678xx"))
};
});
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy =>
{
policy.RequireClaim("role", "admin");
});
});
#endregion
#region swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "企业官网Api", Version = "v1" });
// 添加身份验证
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});
// 添加授权要求
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] {}
}
});
// 设置 XML 注释文件的路径
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
#endregion
var app = builder.Build();
app.UseSwagger();
app.UseStaticFiles();
// 启用身份验证和授权中间件
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers(); // 这里配置了使用控制器的路由
});
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "企业官网Api");
c.RoutePrefix = string.Empty; // 将 Swagger UI 设置为应用程序的根路径
});
ServiceLocator.Instance = app.Services;
ServiceLocator.ApplicationBuilder = app;
var db = SqlSugarHelper.Db;
//数据库初始化
app.MapGet("/seed", async () =>
{
db.CodeFirst.InitTables<SysUserEntity>();
string name = "op";
string pwd = "op";
var loginResult = await db.Queryable<SysUserEntity>().Where(a => !a.IsBan && a.UsePwd == pwd && a.UserName == name).AnyAsync();
if (!loginResult)
{
await db.Insertable<SysUserEntity>(new SysUserEntity { IsBan = false, UsePwd = pwd, UserName = name }).ExecuteCommandAsync();
}
db.CodeFirst.InitTables<FileSourceEntity>();
db.CodeFirst.InitTables<ArticleEntity>();
});
app.MapGet("/health", () => "1024");
app.Run();
接口就“勉为其难”的新建个api文件夹然后
/// <summary>
/// 系统用户
/// </summary>
[Route("api/[controller]/[action]")]
[ApiController]
public class SysUserController : BaseApi
{
public SysUserController()
{
}
/// <summary>
/// 检测Token信息
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize]
public ApiResult CheckToken()
{
var httpContext = HttpContext;
// 从请求头中获取 Authorization 标头的值
var authorizationHeader = httpContext.Request.Headers["Authorization"].FirstOrDefault();
if (!string.IsNullOrEmpty(authorizationHeader) && authorizationHeader.StartsWith("Bearer "))
{
// 提取令牌字符串(去除 "Bearer " 前缀)
var token = authorizationHeader.Substring(7);
var tokenHandler = new JwtSecurityTokenHandler();
var jwtToken = tokenHandler.ReadJwtToken(token);
// 获取 ClaimTypes.Name 的值
var username = jwtToken.Claims.FirstOrDefault(claim => claim.Type == "name")?.Value;
// 在这里使用 username 进行其他操作
return Success($"当前Token用户是:{username}");
}
return Error("Toekn信息解析失败");
}
/// <summary>
/// 登录
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpPost]
public async Task<ApiResult> Login(SysUserEntity model)
{
string secretKey = "sdfsdfsrty45634kkhxxhtdgdfss345t678xx";
var loginResult = await db.Queryable<SysUserEntity>().Where(a => !a.IsBan && a.UsePwd == model.UsePwd && a.UserName == model.UserName).AnyAsync();
// 验证用户名和密码
if (!loginResult)
{
return Error("账号密码错误");
}
// 生成 JWT 令牌
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(secretKey);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new List<Claim>
{
new Claim(ClaimTypes.Name, model.UserName),
new Claim(JwtRegisteredClaimNames.Jti, model.Id.ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTime.Now.ToString()),
new Claim(ClaimTypes.Expiration, DateTime.Now.AddHours(10).ToString())
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
Issuer = "ningissuer",
Audience = "wr",
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
// 返回 JWT 令牌
return Success(new { token = "Bearer " + tokenString });
}
}
到这里,基本上已经结束了
总结
对项目而言
其实这种方式已经足够适用绝大多数中小公司的普通项目需求了,如果你还要加些限流或者什么中间件的话,也是可以很直观的去加,而不是像某些框架封装一坨又一坨,你在哪加个什么东西要翻找半天,毁坏了原本dotNet自身的生态(指官方文档)
这样出来对的项目也很直观,物尽其才,只要后续开发定好一个规范管理,就不会像你公司那破框架一堆密密麻麻的东西都没使用过的情况出现
对新手而言
同时呢,这样构建一个项目框架,也方便新手学习,因为十分的直观,不会对莫名其妙出现的东西感觉到匪夷所思,根本不知道拿来做什么的,像这样需要什么加什么,就对所有加的东西包括nuget包,中间件,或者封装啥的都有个很清晰的认知
对转行到.Net的人而言
dotnet官方本身已经是一个大封装了,不要把别的语言思维带到这里,做什么破功能都要自己写,写又写不好,写好了又没文档,人走了之后又坑公司又坑其他.net开发者
结语,给所有中小公司和个人的开发建议
马上2024了,.Net的生态已经算是十分丰富了,请不要再试图自行造轮子
举个例子假如你要
对接微信(企业微信,小程序,公众号)/字节用这个:https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat
别在那自己瞎琢磨封装,对个人而言你瞎封装有什么用对你也没什么好处费时费力,还封装不好,你能保证自己封装完了还会提供详细的文档?
一句很重要的话,我在一线开发从curd干到框架,我觉得很多人都没意思到的一点就是:
企业的项目,技术方面所有都要为了实际业务而做出努力,而不是为了技术而技术。
就刚才这封装的例子,如果你是自己封装,随便有点变动你是不是要抛下业务需求不管去维护?
一切的代码和封装前提思想就是不要为了写代码而去写代码,唉,忍不吐槽一下,这其实是码农基本素养,但还是看的太多太心累
用最清爽的方式开发dotNet的更多相关文章
- VS 2010 WebSite网站 使用CodeBehide 方式开发[Web应用程序项目转Web网站]
由于生成Web应用程序的文件非常大,100M左右,上传到香港太慢,对于运维工作很不现实, 所以只能改用单个源代码文件上传方式,也就是Web网站方式,但VS2010中只提供Web网站转Web应用程序功能 ...
- mapper代理方式开发
使用mapper代理方式开发: 需要编写mapper接口,UserMapper.java需要编写映射文件,UserMapper.xml需要遵循一些开发规范,mybatis便可以自动生成mapper接口 ...
- Mybatis进阶学习笔记——动态代理方式开发Dao接口、Dao层(推荐第二种)
1.原始方法开发Dao Dao接口 package cn.sm1234.dao; import java.util.List; import cn.sm1234.domain.Customer; pu ...
- mybatis入门--mapper代理方式开发
不使用代理开发 之前,我们说了如何搭建mybatis框架以及我们使用mybatis进行简单的增删改查.现在,我们一起来构建一个dao层的完整代码.并用@test来模拟service层对dao层进行一下 ...
- 从零开始学JAVA(09)-使用SpringMVC4 + Mybatis + MySql 例子(注解方式开发)
项目需要,继续学习springmvc,这里加入Mybatis对数据库的访问,并写下一个简单的例子便于以后学习,希望对看的人有帮助.上一篇被移出博客主页,这一篇努力排版整齐,更原创,希望不要再被移出主页 ...
- 《开源框架那点事儿23》:採用TinyDB组件方式开发
採用TinyDB组件方式开发 步骤 Icon 前文介绍四则运算的流程编程开发时,说过流程编排在开发反复功能时.能够利用已有的组件库高速开发.对于开发者而言仅仅须要简单配置流程就能够完毕工作了.开发增删 ...
- BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第11章节--为Office和SP解决方式开发集成Apps Office新的App模型
BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第11章节--为Office和SP解决方式开发集成Apps Office新的App模型 Office 2 ...
- BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第11章节--为Office和SP解决方式开发集成Apps Office的JavaScript对象模型
BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第11章节--为Office和SP解决方式开发集成Apps Office的JavaScript对象模型 ...
- BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第11章节--为Office和SP解决方式开发集成Apps 集成SP和Office App
BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第11章节--为Office和SP解决方式开发集成Apps 集成SP和Office App 你能够用两种 ...
- 使用goroutine+channel和java多线程+queue队列的方式开发各有什么优缺点?
我感觉很多项目使用java或者c的多线程库+线程安全的queue数据结构基本上可以实现goroutine+channel开发能达到的需求,所以请问一下为什么说golang更适合并发服务端的开发呢?使用 ...
随机推荐
- Programming abstractions in C阅读笔记:p91-p106
<Programming Abstractions In C>学习第45天,p91-p102,完成第二章内容学习.总结如下: 一.技术总结 1.垃圾回收 p91,"Some la ...
- Nginx 文件名逻辑漏洞(CVE-2013-4547)(Vulhub)
Nginx 文件名逻辑漏洞(CVE-2013-4547)(Vulhub) 漏洞简介 在Nginx 0.8.41 ~ 1.4.3 / 1.5.0 ~ 1.5.7版本中存在错误解析用户请求的url信息,从 ...
- 手写RISC-V处理器(1)
由来 由于去年工作变动,有幸进入了芯片行业,但主要工作内容为基于RISC-V的嵌入式应用软件开发,几乎接触不到芯片设计的相关知识,然而随着工作的深入,越来越想探究一下运行在软件之下的CPU的世界,于是 ...
- 浅谈基于QT的截图工具的设计与实现
本人一直在做属于自己的一款跨平台的截图软件(w4ngzhen/capi(github.com)),在软件编写的过程中有一些心得体会,所以有了本文.其实这篇文章酝酿了很久,现在这款软件有了雏形,也有空梳 ...
- k8s 入门到实战--部署应用到 k8s
背景 最近这这段时间更新了一些 k8s 相关的博客和视频,也收到了一些反馈:大概分为这几类: 公司已经经历过服务化改造了,但还未接触过云原生. 公司部分应用进行了云原生改造,但大部分工作是由基础架构和 ...
- HTML网页/KRPano项目一键打包EXE工具(HTML网页打包成单个windows可执行文件exe)
HTML一键打包EXE工具使用说明 工具简介 HTML一键打包EXE工具(HTML封装EXE,桌件)能把任意HTML项目(网址)一键打包为单个EXE文件,可以脱离浏览器和服务器,直接双击即可运行.支持 ...
- 聊聊数据库事务内嵌TCP连接
最近再看项目代码,发现很多的service里面,喜欢在事务内部再去调用HTTP请求,简单分析下此种方式的利弊与解决策略. 概述 在数据库内部嵌套TCP连接(一般是HTTP调用或是RPC远程调用). @ ...
- 在线问诊 Python、FastAPI、Neo4j — 构建问题分类器
目录 构建字典数据 构建 Trie 字典树 按实体组装字典 问题分析 将问题进行分析,和系统已有的分类进行关联 构建字典数据 将构建的知识图片字典化, 用于后面对问题的解析,下图为症状的字典,其它字典 ...
- open与fopen的区别
1. 来源 从来源的角度看,两者能很好的区分开,这也是两者最显而易见的区别: open是UNIX系统调用函数(包括LINUX等),返回的是文件描述符(File Descriptor),它是文件在文件描 ...
- 分布式事务 —— SpringCloud Alibaba Seata
Seata 简介 传统的单体应用中,业务操作使用同一条连接操作不同的数据表,一旦出现异常就可以整体回滚.随着公司的快速发展.业务需求的变化,单体应用被拆分成微服务应用,原来的单体应用被拆分成多个独立的 ...