经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C# » 查看文章
webapi开发框架实践
来源:cnblogs  作者:星仔007  时间:2023/9/13 15:40:09  对本文有异议

项目链接以及目录结构

liuzhixin405/efcore-template (github.com)

这是一个纯webapi的开发框架。

1、支持的orm有efcore6、dapper,可以灵活切换数据库。

  1. using Microsoft.CodeAnalysis.CSharp.Syntax;
  2. using Microsoft.CodeAnalysis.Elfie.Model;
  3. using Microsoft.EntityFrameworkCore;
  4. using project.Context;
  5. using project.Repositories;
  6. using project.Services;
  7. using RepositoryComponent.DbFactories;
  8. namespace project.Extensions
  9. {
  10. public static partial class TheExtensions
  11. {
  12. public static void AddDatabase(this WebApplicationBuilder builder)
  13. {
  14. ///sqlserver
  15. if (builder.Configuration["DbType"]?.ToLower() == "sqlserver")
  16. {
  17. builder.Services.AddDbContext<ReadProductDbContext>(options => options.UseSqlServer(builder.Configuration["ConnectionStrings:SqlServer:ReadConnection"]), ServiceLifetime.Scoped);
  18. builder.Services.AddDbContext<WriteProductDbContext>(options => options.UseSqlServer(builder.Configuration["ConnectionStrings:SqlServer:WriteConnection"]), ServiceLifetime.Scoped);
  19. }
  20. ///mysql
  21. else if (builder.Configuration["DbType"]?.ToLower() == "mysql")
  22. {
  23. builder.Services.AddDbContext<ReadProductDbContext>(options => options.UseMySQL(builder.Configuration["ConnectionStrings:MySql:ReadConnection"]), ServiceLifetime.Scoped);
  24. builder.Services.AddDbContext<WriteProductDbContext>(options => options.UseMySQL(builder.Configuration["ConnectionStrings:MySql:WriteConnection"]), ServiceLifetime.Scoped);
  25. }
  26. else
  27. {
  28. //throw new ArgumentNullException("δ???????????????");
  29. builder.Services.AddDbContext<ReadProductDbContext>(options => options.UseInMemoryDatabase("test_inmemory_db"), ServiceLifetime.Scoped);
  30. builder.Services.AddDbContext<WriteProductDbContext>(options => options.UseInMemoryDatabase("test_inmemory_db"), ServiceLifetime.Scoped);
  31. }
  32. builder.Services.AddScoped<Func<ReadProductDbContext>>(provider => () => provider.GetService<ReadProductDbContext>() ?? throw new ArgumentNullException("ReadProductDbContext is not inject to program"));
  33. builder.Services.AddScoped<Func<WriteProductDbContext>>(provider => () => provider.GetService<WriteProductDbContext>() ?? throw new ArgumentNullException("WriteProductDbContext is not inject to program"));
  34. builder.Services.AddScoped<DbFactory<WriteProductDbContext>>();
  35. builder.Services.AddScoped<DbFactory<ReadProductDbContext>>();
  36. builder.Services.AddTransient<IReadProductRepository, ProductReadRepository>();
  37. builder.Services.AddTransient<IWriteProductRepository, ProductWriteRepository>();
  38. builder.Services.AddTransient<IProductService, ProductService>();
  39. builder.Services.AddTransient<ICustomerService, CustomerService>();
  40. }
  41. }
  42. }

2、至于消息中间件有rabbitmq、kafka,也是通过配置文件来指定哪一个实现。

  1. using MessageMiddleware.Factory;
  2. using MessageMiddleware.RabbitMQ;
  3. namespace project.Extensions
  4. {
  5. public static partial class TheExtensions
  6. {
  7. public static void AddMq(this WebApplicationBuilder builder)
  8. {
  9. var rabbitMqSetting = new RabbitMQSetting
  10. {
  11. ConnectionString = builder.Configuration["MqSetting:RabbitMq:ConnectionString"].Split(';'),
  12. Password = builder.Configuration["MqSetting:RabbitMq:PassWord"],
  13. Port = int.Parse(builder.Configuration["MqSetting:RabbitMq:Port"]),
  14. SslEnabled = bool.Parse(builder.Configuration["MqSetting:RabbitMq:SslEnabled"]),
  15. UserName = builder.Configuration["MqSetting:RabbitMq:UserName"],
  16. };
  17. var kafkaSetting = new MessageMiddleware.Kafka.Producers.ProducerOptions
  18. {
  19. BootstrapServers = builder.Configuration["MqSetting:Kafka:BootstrapServers"],
  20. SaslUsername = builder.Configuration["MqSetting:Kafka:SaslUserName"],
  21. SaslPassword = builder.Configuration["MqSetting:Kafka:SaslPassWord"],
  22. Key = builder.Configuration["MqSetting:Kafka:Key"]
  23. };
  24. var mqConfig = new MQConfig
  25. {
  26. ConsumerLog = bool.Parse(builder.Configuration["MqSetting:ConsumerLog"]),
  27. PublishLog = bool.Parse(builder.Configuration["MqSetting:PublishLog"]),
  28. Rabbit = rabbitMqSetting,
  29. Use = int.Parse(builder.Configuration["MqSetting:Use"]),
  30. Kafka = kafkaSetting
  31. };
  32. builder.Services.AddSingleton<MQConfig>(sp => mqConfig);
  33. builder.Services.AddMQ(mqConfig);
  34. }
  35. }
  36. }

3、该项目还集成了mongodb和elasticsearch,在project项目中没有写实现案例,实现起来也很简单。

4、下面是分布式雪花id的实现,先注入代码,使用的时候直接使用distributedid即可。

  1. builder.Services.AddDistributedLock(x =>
  2. {
  3. x.LockType = LockType.InMemory;
  4. x.RedisEndPoints = new string[] { builder.Configuration["DistributedRedis:ConnectionString"] ?? throw new Exception("$未能获取distributedredis连接字符串")};
  5. }).AddCache(new CacheOptions
  6. {
  7. CacheType = CacheTypes.Redis,
  8. RedisConnectionString = builder.Configuration["DistributedRedis:ConnectionString"] ?? throw new Exception("$未能获取distributedredis连接字符串")
  9. }).AddDistributedId(new DistributedIdOptions
  10. {
  11. Distributed = true
  12. });
  1. newProduct.Id = _distributedId.NewLongId().ToString();

5、缓存使用的是分布式缓存和内存缓存,其中分布式缓存有一般实现和指定序列化格式的实现。

  1. using System.Text;
  2. using System.Text.Json.Serialization;
  3. using MessagePack;
  4. using StackExchange.Redis.Extensions.Core;
  5. using StackExchange.Redis.Extensions.Core.Abstractions;
  6. using StackExchange.Redis.Extensions.Core.Configuration;
  7. using StackExchange.Redis.Extensions.Core.Implementations;
  8. namespace project.Utility.Helper
  9. {
  10. public class CacheHelper
  11. {
  12. private static IRedisClientFactory _factory_with_msgpack;
  13. private static IRedisDatabase _redis_with_msgpack => _factory_with_msgpack.GetDefaultRedisDatabase();
  14. private static IRedisClientFactory _factory;
  15. private static IRedisDatabase _redis => _factory.GetDefaultRedisDatabase();
  16. public static void Init(IConfiguration configuration)
  17. {
  18. var config = configuration.GetSection("Redis").Get<RedisConfiguration>();
  19. _factory = new RedisClientFactory(new[] { config }, null, new RedisSerializer());
  20. _factory_with_msgpack = new RedisClientFactory(new[] { config }, null, new RedisMessagepackSerializer());
  21. }
  22. static CacheHelper() { }
  23. public static T Get<T>(string key)
  24. {
  25. return _redis.GetAsync<T>(key).GetAwaiter().GetResult();
  26. }
  27. public static async Task<T> GetAsync<T>(string key)
  28. {
  29. return await _redis.GetAsync<T>(key);
  30. }
  31. public static async Task<T> GetAsync_With_Msgpack<T>(string key)
  32. {
  33. return await _redis_with_msgpack.GetAsync<T>(key);
  34. }
  35. public static string Get(string key)
  36. {
  37. return _redis.GetAsync<string>(key).GetAwaiter().GetResult();
  38. }
  39. public static bool Set(string key, object value, TimeSpan expiresIn)
  40. {
  41. return _redis.AddAsync(key, value, expiresIn).GetAwaiter().GetResult();
  42. }
  43. public static async Task<bool> SetAsync(string key, object value, TimeSpan expiresIn)
  44. {
  45. return await _redis.AddAsync(key, value, expiresIn);
  46. }
  47. public static async Task<bool> SetAsync_With_Msgpack(string key, object value, TimeSpan expiresIn)
  48. {
  49. return await _redis_with_msgpack.AddAsync(key, value, expiresIn);
  50. }
  51. /// <summary>
  52. /// 以秒为单位,返回给定 key 的剩余生存时间
  53. /// </summary>
  54.  
  55. public static long GetExpirin(string key)
  56. {
  57. var timespan = _redis.Database.KeyTimeToLive(key);
  58. if (timespan == null) { return 0; }
  59. return (long)timespan.Value.TotalSeconds;
  60. }
  61. public static bool KeyExpire(string key, TimeSpan expiresIn)
  62. {
  63. return _redis.Database.KeyExpire(key, expiresIn);
  64. }
  65. public static async Task<bool> RemoveKeyAsync(string key)
  66. {
  67. return await _redis.Database.KeyDeleteAsync(key);
  68. }
  69. public static long RemoveKey(string key)
  70. {
  71. var result = _redis.Database.KeyDelete(key);
  72. return result ? 1 : 0;
  73. }
  74. }
  75. public class RedisSerializer : ISerializer
  76. {
  77. public T? Deserialize<T>(byte[] serializedObject)
  78. {
  79. var data = Encoding.UTF8.GetString(serializedObject);
  80. return System.Text.Json.JsonSerializer.Deserialize<T>(data);
  81. }
  82. public byte[] Serialize<T>(T? item)
  83. {
  84. var data = System.Text.Json.JsonSerializer.Serialize(item);
  85. return Encoding.UTF8.GetBytes(data);
  86. }
  87. }
  88. public class RedisMessagepackSerializer : ISerializer
  89. {
  90. private MessagePackSerializerOptions _options;
  91. public RedisMessagepackSerializer()
  92. {
  93. _options = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.Lz4BlockArray);
  94. }
  95. public T? Deserialize<T>(byte[] serializedObject)
  96. {
  97. return MessagePackSerializer.Deserialize<T>(serializedObject, _options);
  98. }
  99. public byte[] Serialize<T>(T? item)
  100. {
  101. return MessagePackSerializer.Serialize(item, _options);
  102. }
  103. }
  104. }

6、单元测试、集成测试没有写。

更细节的需要自己看代码,这应该是一个基本的开发具备的功能。

该项目下载下来可以直接运行。

原文链接:https://www.cnblogs.com/morec/p/17696164.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号