经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
用最清爽的方式开发dotNet
来源:cnblogs  作者:君宁天下  时间:2023/12/8 11:48:36  对本文有异议

用最清爽的方式开发dotNet

不管是官方自带模板还是其他开源搞的,总是一来一大堆,如果你也嫌弃这些过于臃肿,不如看看我这个方式

前提

假设我要做一个简单的api

方式

想到清爽,那肯定是简单方便,脑袋第一个念头就是.Net6 推出的miniapi了

官方路子

两篇官方文档足以,按照文档step by step 就ok了,其他的需要就加

我的野路子

官方是官方,官方走的路子当然还是基于它最标准的搞法,我的路子则是基于国内实际情况
总体思路就是用控制台改api

模拟前提场景

搞一个普通企业官网的api,那么要求就是以下几点

  • 需要数据库操作
  • 需要授权鉴权
  • 需要swagger文档
  • 需要上传文件

根据这些要求,我需要引入最基本的就几个:

  • Swashbuckle.AspNetCore (swagger相关)
  • SqlSugarCore (sqlsugar Orm) (用啥都可以,例如还有freesql)
  • Microsoft.AspNetCore.Authentication.JwtBearer (授权鉴权这里用简单的jwt)
  • Mapster (dto和entity互转)

如果有其他需求,再自己加,一点也不冗余

注意:需要先右键控制台项目,将 <Project Sdk="Microsoft.NET.Sdk"> 改为 <Project Sdk="Microsoft.NET.Sdk.Web"> 其原因可以去官网翻找资料感悟一下

代码

dotNet 几忘了,反正很早就是通用主机了,如果你同时还要搞blazor server啥的,把这一坨封装一下即可,通用的

Program.cs 里面直接无脑写下以下代码

  1. var builder = WebApplication.CreateBuilder(args);
  2. #region 基本设置
  3. builder.Services.AddMemoryCache();
  4. builder.Services.AddControllers();
  5. builder.Services.Configure<FormOptions>(options =>
  6. {
  7. // 设置上传大小限制256MB
  8. options.MultipartBodyLengthLimit = 268435456;
  9. });
  10. builder.Services.AddSingleton<SqlSugarMemoryCacheService>();
  11. #endregion
  12. #region 授权鉴权
  13. // 添加身份验证和授权中间件
  14. builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  15. .AddJwtBearer(options =>
  16. {
  17. options.TokenValidationParameters = new TokenValidationParameters
  18. {
  19. ValidateIssuer = true,
  20. ValidateAudience = true,
  21. ValidateLifetime = true,
  22. ValidateIssuerSigningKey = true,
  23. ValidIssuer = "ningissuer",
  24. ValidAudience = "wr",
  25. IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("sdfsdfsrty45634kkhxxhtdgdfss345t678xx"))
  26. };
  27. });
  28. builder.Services.AddAuthorization(options =>
  29. {
  30. options.AddPolicy("AdminOnly", policy =>
  31. {
  32. policy.RequireClaim("role", "admin");
  33. });
  34. });
  35. #endregion
  36. #region swagger
  37. builder.Services.AddEndpointsApiExplorer();
  38. builder.Services.AddSwaggerGen(c =>
  39. {
  40. c.SwaggerDoc("v1", new OpenApiInfo { Title = "企业官网Api", Version = "v1" });
  41. // 添加身份验证
  42. c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
  43. {
  44. Description = "JWT Authorization header using the Bearer scheme",
  45. Name = "Authorization",
  46. In = ParameterLocation.Header,
  47. Type = SecuritySchemeType.ApiKey
  48. });
  49. // 添加授权要求
  50. c.AddSecurityRequirement(new OpenApiSecurityRequirement
  51. {
  52. {
  53. new OpenApiSecurityScheme
  54. {
  55. Reference = new OpenApiReference
  56. {
  57. Type = ReferenceType.SecurityScheme,
  58. Id = "Bearer"
  59. }
  60. },
  61. new string[] {}
  62. }
  63. });
  64. // 设置 XML 注释文件的路径
  65. var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
  66. var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
  67. c.IncludeXmlComments(xmlPath);
  68. });
  69. #endregion
  70. var app = builder.Build();
  71. app.UseSwagger();
  72. app.UseStaticFiles();
  73. // 启用身份验证和授权中间件
  74. app.UseAuthentication();
  75. app.UseRouting();
  76. app.UseAuthorization();
  77. app.UseEndpoints(endpoints =>
  78. {
  79. endpoints.MapControllers(); // 这里配置了使用控制器的路由
  80. });
  81. app.UseSwaggerUI(c =>
  82. {
  83. c.SwaggerEndpoint("/swagger/v1/swagger.json", "企业官网Api");
  84. c.RoutePrefix = string.Empty; // 将 Swagger UI 设置为应用程序的根路径
  85. });
  86. ServiceLocator.Instance = app.Services;
  87. ServiceLocator.ApplicationBuilder = app;
  88. var db = SqlSugarHelper.Db;
  89. //数据库初始化
  90. app.MapGet("/seed", async () =>
  91. {
  92. db.CodeFirst.InitTables<SysUserEntity>();
  93. string name = "op";
  94. string pwd = "op";
  95. var loginResult = await db.Queryable<SysUserEntity>().Where(a => !a.IsBan && a.UsePwd == pwd && a.UserName == name).AnyAsync();
  96. if (!loginResult)
  97. {
  98. await db.Insertable<SysUserEntity>(new SysUserEntity { IsBan = false, UsePwd = pwd, UserName = name }).ExecuteCommandAsync();
  99. }
  100. db.CodeFirst.InitTables<FileSourceEntity>();
  101. db.CodeFirst.InitTables<ArticleEntity>();
  102. });
  103. app.MapGet("/health", () => "1024");
  104. app.Run();

接口就“勉为其难”的新建个api文件夹然后

  1. /// <summary>
  2. /// 系统用户
  3. /// </summary>
  4. [Route("api/[controller]/[action]")]
  5. [ApiController]
  6. public class SysUserController : BaseApi
  7. {
  8. public SysUserController()
  9. {
  10. }
  11. /// <summary>
  12. /// 检测Token信息
  13. /// </summary>
  14. /// <returns></returns>
  15. [HttpGet]
  16. [Authorize]
  17. public ApiResult CheckToken()
  18. {
  19. var httpContext = HttpContext;
  20. // 从请求头中获取 Authorization 标头的值
  21. var authorizationHeader = httpContext.Request.Headers["Authorization"].FirstOrDefault();
  22. if (!string.IsNullOrEmpty(authorizationHeader) && authorizationHeader.StartsWith("Bearer "))
  23. {
  24. // 提取令牌字符串(去除 "Bearer " 前缀)
  25. var token = authorizationHeader.Substring(7);
  26. var tokenHandler = new JwtSecurityTokenHandler();
  27. var jwtToken = tokenHandler.ReadJwtToken(token);
  28. // 获取 ClaimTypes.Name 的值
  29. var username = jwtToken.Claims.FirstOrDefault(claim => claim.Type == "name")?.Value;
  30. // 在这里使用 username 进行其他操作
  31. return Success($"当前Token用户是:{username}");
  32. }
  33. return Error("Toekn信息解析失败");
  34. }
  35. /// <summary>
  36. /// 登录
  37. /// </summary>
  38. /// <param name="model"></param>
  39. /// <returns></returns>
  40. [AllowAnonymous]
  41. [HttpPost]
  42. public async Task<ApiResult> Login(SysUserEntity model)
  43. {
  44. string secretKey = "sdfsdfsrty45634kkhxxhtdgdfss345t678xx";
  45. var loginResult = await db.Queryable<SysUserEntity>().Where(a => !a.IsBan && a.UsePwd == model.UsePwd && a.UserName == model.UserName).AnyAsync();
  46. // 验证用户名和密码
  47. if (!loginResult)
  48. {
  49. return Error("账号密码错误");
  50. }
  51. // 生成 JWT 令牌
  52. var tokenHandler = new JwtSecurityTokenHandler();
  53. var key = Encoding.ASCII.GetBytes(secretKey);
  54. var tokenDescriptor = new SecurityTokenDescriptor
  55. {
  56. Subject = new ClaimsIdentity(new List<Claim>
  57. {
  58. new Claim(ClaimTypes.Name, model.UserName),
  59. new Claim(JwtRegisteredClaimNames.Jti, model.Id.ToString()),
  60. new Claim(JwtRegisteredClaimNames.Iat, DateTime.Now.ToString()),
  61. new Claim(ClaimTypes.Expiration, DateTime.Now.AddHours(10).ToString())
  62. }),
  63. Expires = DateTime.UtcNow.AddDays(7),
  64. SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
  65. Issuer = "ningissuer",
  66. Audience = "wr",
  67. };
  68. var token = tokenHandler.CreateToken(tokenDescriptor);
  69. var tokenString = tokenHandler.WriteToken(token);
  70. // 返回 JWT 令牌
  71. return Success(new { token = "Bearer " + tokenString });
  72. }
  73. }

到这里,基本上已经结束了,剩下的无非加加业务,或者加一些更丰富的组件,什么autofac啦,nacos啦,yarp啦,seq啦

总结

对项目而言

其实这种方式已经足够适用绝大多数中小公司的普通项目需求了,如果你还要加些限流或者什么中间件的话,也是可以很直观的去加,而不是像某些框架封装一坨又一坨,你在哪加个什么东西要翻找半天,毁坏了原本dotNet自身的生态(指官方文档)

这样出来对的项目也很直观,物尽其才,只要后续开发定好一个规范管理,就不会像你公司那破框架一堆密密麻麻的东西都没使用过的情况出现

对新手而言

同时呢,这样构建一个项目框架,也方便新手学习,因为十分的直观,不会对莫名其妙出现的东西感觉到匪夷所思,根本不知道拿来做什么的,像这样需要什么加什么,就对所有加的东西包括nuget包,中间件,或者封装啥的都有个很清晰的认知

对转行到.Net的人而言

dotnet官方本身已经是一个大封装了,不要把别的语言思维带到这里,做什么破功能都要自己写,写又写不好,写好了又没文档,人走了之后又坑公司又坑其他.net开发者

结语,给所有中小公司和个人的开发建议

马上2024了,.Net的生态已经算是十分丰富了,请不要再试图自行造轮子

举个例子假如你要
对接微信(企业微信,小程序,公众号)/字节用这个:https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat

别在那自己瞎琢磨封装,对个人而言你瞎封装有什么用对你也没什么好处费时费力,还封装不好,你能保证自己封装完了还会提供详细的文档?

一句很重要的话,我在一线开发从curd干到框架,我觉得很多人都没意识到的一点就是:
企业的项目,技术方面所有都要为了实际业务而做出努力,而不是为了技术而技术。

就刚才这封装的例子,如果你是自己封装,随便有点变动你是不是要抛下业务需求不管去维护?
一切的代码和封装前提思想就是不要为了写代码而去写代码,唉,忍不吐槽一下,这其实是码农基本素养,但还是看的太多太心累

代码文件补充

SqlSugarHelper

  1. public class SqlSugarHelper
  2. {
  3. public static readonly SqlSugarScope Db = new SqlSugarScope(new ConnectionConfig()
  4. {
  5. ConnectionString = "server=xxx;Database=xxx;Uid=root;Pwd=xxx;Port=6607;Allow User Variables=True;",//连接符字串
  6. DbType = DbType.MySql,
  7. IsAutoCloseConnection = true,
  8. }, db =>
  9. {
  10. ExternalServicesSetting(db);
  11. db.Aop.OnLogExecuting = (sql, pars) =>
  12. {
  13. Console.WriteLine(sql);
  14. };
  15. });
  16. /// <summary>
  17. /// 拓展配置
  18. /// </summary>
  19. /// <param name="db"></param>
  20. /// <param name="config"></param>
  21. private static void ExternalServicesSetting(SqlSugarClient db)
  22. {
  23. var cache = ServiceLocator.Instance.GetService<SqlSugarMemoryCacheService>();
  24. db.CurrentConnectionConfig.ConfigureExternalServices = new ConfigureExternalServices
  25. {
  26. DataInfoCacheService = cache,
  27. };
  28. }
  29. }

原文链接:https://www.cnblogs.com/ncellit/p/17881779.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号