diff --git a/test/ShardingCore.Test50.MySql/Configs/DbConfig.json b/test/ShardingCore.Test50.MySql/Configs/DbConfig.json
index 4e353d58..3d754d6a 100644
--- a/test/ShardingCore.Test50.MySql/Configs/DbConfig.json
+++ b/test/ShardingCore.Test50.MySql/Configs/DbConfig.json
@@ -1,6 +1,6 @@
{
"MySql": {
- "ConnectionString": "server=localhost;port=3306;user=root;password=123456;database=ShardingCoreDB;sslMode=None;"
+ "ConnectionString": "server=127.0.0.1;port=3306;user=root;password=root;database=ShardingCoreDB;sslMode=None;"
}
}
\ No newline at end of file
diff --git a/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserMod.cs b/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserMod.cs
new file mode 100644
index 00000000..4883a53b
--- /dev/null
+++ b/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserMod.cs
@@ -0,0 +1,28 @@
+using ShardingCore.Core;
+
+namespace ShardingCore.Test50.MySql.Domain.Entities
+{
+/*
+* @Author: xjm
+* @Description:
+* @Date: Thursday, 14 January 2021 15:36:43
+* @Email: 326308290@qq.com
+*/
+ public class SysUserMod:IShardingEntity
+ {
+ ///
+ /// 用户Id用于分表
+ ///
+ [ShardingKey(TailPrefix = "_",AutoCreateTableOnStart = true)]
+ public string Id { get; set; }
+ ///
+ /// 用户名称
+ ///
+ public string Name { get; set; }
+ ///
+ /// 用户姓名
+ ///
+ public int Age { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserRange.cs b/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserRange.cs
new file mode 100644
index 00000000..6eeec2db
--- /dev/null
+++ b/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserRange.cs
@@ -0,0 +1,27 @@
+using ShardingCore.Core;
+
+namespace ShardingCore.Test50.MySql.Domain.Entities
+{
+/*
+* @Author: xjm
+* @Description:
+* @Date: Wednesday, 20 January 2021 10:43:19
+* @Email: 326308290@qq.com
+*/
+ public class SysUserRange:IShardingEntity
+ {
+ ///
+ /// 分表分库range切分
+ ///
+ [ShardingKey(TailPrefix = "_",AutoCreateTableOnStart = true)]
+ public string Id { get; set; }
+ ///
+ /// 姓名
+ ///
+ public string Name { get; set; }
+ ///
+ /// 年龄
+ ///
+ public int Age { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/test/ShardingCore.Test50.MySql/Domain/Entities/UserGroup.cs b/test/ShardingCore.Test50.MySql/Domain/Entities/UserGroup.cs
new file mode 100644
index 00000000..90d243e1
--- /dev/null
+++ b/test/ShardingCore.Test50.MySql/Domain/Entities/UserGroup.cs
@@ -0,0 +1,13 @@
+namespace ShardingCore.Test50.MySql.Domain.Entities
+{
+/*
+* @Author: xjm
+* @Description:
+* @Date: Friday, 22 January 2021 14:17:29
+* @Email: 326308290@qq.com
+*/
+ public class UserGroup
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/test/ShardingCore.Test50.MySql/Domain/Maps/SysUserModMap.cs b/test/ShardingCore.Test50.MySql/Domain/Maps/SysUserModMap.cs
new file mode 100644
index 00000000..efe4b7ad
--- /dev/null
+++ b/test/ShardingCore.Test50.MySql/Domain/Maps/SysUserModMap.cs
@@ -0,0 +1,23 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using ShardingCore.Test50.MySql.Domain.Entities;
+
+namespace ShardingCore.Test50.MySql.Domain.Maps
+{
+/*
+* @Author: xjm
+* @Description:
+* @Date: Thursday, 14 January 2021 15:37:33
+* @Email: 326308290@qq.com
+*/
+ public class SysUserModMap:IEntityTypeConfiguration
+ {
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasKey(o => o.Id);
+ builder.Property(o => o.Id).IsRequired().HasMaxLength(128);
+ builder.Property(o => o.Name).HasMaxLength(128);
+ builder.ToTable(nameof(SysUserMod));
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/ShardingCore.Test50.MySql/Domain/Maps/SysUserRangeMap.cs b/test/ShardingCore.Test50.MySql/Domain/Maps/SysUserRangeMap.cs
new file mode 100644
index 00000000..614472ae
--- /dev/null
+++ b/test/ShardingCore.Test50.MySql/Domain/Maps/SysUserRangeMap.cs
@@ -0,0 +1,23 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using ShardingCore.Test50.MySql.Domain.Entities;
+
+namespace ShardingCore.Test50.MySql.Domain.Maps
+{
+/*
+* @Author: xjm
+* @Description:
+* @Date: Wednesday, 20 January 2021 10:45:47
+* @Email: 326308290@qq.com
+*/
+ public class SysUserRangeMap:IEntityTypeConfiguration
+ {
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasKey(o => o.Id);
+ builder.Property(o => o.Id).IsRequired().HasMaxLength(128);
+ builder.Property(o => o.Name).HasMaxLength(128);
+ builder.ToTable(nameof(SysUserRange));
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/ShardingCore.Test50.MySql/ShardingCore.Test50.MySql.csproj b/test/ShardingCore.Test50.MySql/ShardingCore.Test50.MySql.csproj
index 229291ae..3fffdcd6 100644
--- a/test/ShardingCore.Test50.MySql/ShardingCore.Test50.MySql.csproj
+++ b/test/ShardingCore.Test50.MySql/ShardingCore.Test50.MySql.csproj
@@ -2,11 +2,8 @@
net5.0
- TRACE;DEBUG;EFCORE5MYSQL;
- ShardingCore.Test50
- ShardingCore.Test50
- ShardingCore.Test50
- ShardingCore.Test50
+ ShardingCore.Test50.MySql
+ ShardingCore.Test50.MySql
9.0
@@ -24,12 +21,6 @@
-
-
-
-
-
-
true
diff --git a/test/ShardingCore.Test50.MySql/ShardingTest.cs b/test/ShardingCore.Test50.MySql/ShardingTest.cs
new file mode 100644
index 00000000..d918055a
--- /dev/null
+++ b/test/ShardingCore.Test50.MySql/ShardingTest.cs
@@ -0,0 +1,146 @@
+using System.Linq;
+using System.Threading.Tasks;
+using ShardingCore.DbContexts.VirtualDbContexts;
+using ShardingCore.Extensions;
+using ShardingCore.Test50.MySql.Domain.Entities;
+using Xunit;
+
+namespace ShardingCore.Test50.MySql
+{
+/*
+* @Author: xjm
+* @Description:
+* @Date: Friday, 15 January 2021 17:22:10
+* @Email: 326308290@qq.com
+*/
+ public class ShardingTest
+ {
+ private readonly IVirtualDbContext _virtualDbContext;
+
+ public ShardingTest(IVirtualDbContext virtualDbContext)
+ {
+ _virtualDbContext = virtualDbContext;
+ }
+
+ [Fact]
+ public async Task ToList_All_Test()
+ {
+ var mods=await _virtualDbContext.Set().ToShardingListAsync();
+ Assert.Equal(100,mods.Count);
+ var ranges=await _virtualDbContext.Set().ToShardingListAsync();
+ Assert.Equal(1000,ranges.Count);
+ }
+ [Fact]
+ public async Task ToList_OrderBy_Asc_Desc_Test()
+ {
+ var modascs=await _virtualDbContext.Set().OrderBy(o=>o.Age).ToShardingListAsync();
+ Assert.Equal(100,modascs.Count);
+ Assert.Equal(100,modascs.Last().Age);
+ var moddescs=await _virtualDbContext.Set().OrderByDescending(o=>o.Age).ToShardingListAsync();
+ Assert.Equal(100,moddescs.Count);
+ Assert.Equal(1,moddescs.Last().Age);
+ }
+ [Fact]
+ public async Task ToList_Id_In_Test()
+ {
+ var ids = new[] {"1", "2", "3", "4"};
+ var sysUserMods=await _virtualDbContext.Set().Where(o=>ids.Contains(o.Id)).ToShardingListAsync();
+ var sysUserRanges=await _virtualDbContext.Set().Where(o=>ids.Contains(o.Id)).ToShardingListAsync();
+ foreach (var id in ids)
+ {
+ Assert.Contains(sysUserMods, o =>o.Id==id);
+ Assert.Contains(sysUserRanges, o =>o.Id==id);
+ }
+ }
+ [Fact]
+ public async Task ToList_Id_Eq_Test()
+ {
+ var mods=await _virtualDbContext.Set().Where(o=>o.Id=="3").ToShardingListAsync();
+ Assert.Single(mods);
+ Assert.Equal("3",mods[0].Id);
+ var ranges=await _virtualDbContext.Set().Where(o=>o.Id=="3").ToShardingListAsync();
+ Assert.Single(ranges);
+ Assert.Equal("3",ranges[0].Id);
+ }
+ [Fact]
+ public async Task ToList_Id_Not_Eq_Test()
+ {
+ var mods=await _virtualDbContext.Set().Where(o=>o.Id!="3").ToShardingListAsync();
+ Assert.Equal(99,mods.Count);
+ Assert.DoesNotContain(mods,o=>o.Id=="3");
+ var ranges=await _virtualDbContext.Set().Where(o=>o.Id!="3").ToShardingListAsync();
+ Assert.Equal(999,ranges.Count);
+ Assert.DoesNotContain(ranges,o=>o.Id=="3");
+ }
+ [Fact]
+ public async Task ToList_Name_Eq_Test()
+ {
+ var mods=await _virtualDbContext.Set().Where(o=>o.Name=="name_3").ToShardingListAsync();
+ Assert.Single(mods);
+ Assert.Equal("3",mods[0].Id);
+ var ranges=await _virtualDbContext.Set().Where(o=>o.Name=="name_range_3").ToShardingListAsync();
+ Assert.Single(ranges);
+ Assert.Equal("3",ranges[0].Id);
+ }
+ [Fact]
+ public async Task ToList_Id_Eq_Not_In_Db_Test()
+ {
+ var mods=await _virtualDbContext.Set().Where(o=>o.Id=="1001").ToShardingListAsync();
+ Assert.Empty(mods);
+ var ranges=await _virtualDbContext.Set().Where(o=>o.Id=="1001").ToShardingListAsync();
+ Assert.Empty(ranges);
+ }
+ [Fact]
+ public async Task ToList_Name_Eq_Not_In_Db_Test()
+ {
+ var mods=await _virtualDbContext.Set().Where(o=>o.Name=="name_1001").ToShardingListAsync();
+ Assert.Empty(mods);
+ var ranges=await _virtualDbContext.Set().Where(o=>o.Name=="name_range_1001").ToShardingListAsync();
+ Assert.Empty(ranges);
+ }
+ [Fact]
+ public async Task FirstOrDefault_Order_By_Id_Test()
+ {
+ var sysUserMod=await _virtualDbContext.Set().OrderBy(o=>o.Id).ShardingFirstOrDefaultAsync();
+ Assert.True(sysUserMod!=null&&sysUserMod.Id=="1");
+ var sysUserRange=await _virtualDbContext.Set().OrderBy(o=>o.Id).ShardingFirstOrDefaultAsync();
+ Assert.True(sysUserRange!=null&&sysUserRange.Id=="1");
+ }
+ [Fact]
+ public async Task FirstOrDefault2()
+ {
+ var sysUserMod=await _virtualDbContext.Set().Where(o=>o.Id=="1").ShardingFirstOrDefaultAsync();
+ Assert.True(sysUserMod!=null&&sysUserMod.Id=="1");
+ var sysUserRange=await _virtualDbContext.Set().Where(o=>o.Id=="1").ShardingFirstOrDefaultAsync();
+ Assert.True(sysUserRange!=null&&sysUserRange.Id=="1");
+ }
+ [Fact]
+ public async Task FirstOrDefault3()
+ {
+ var sysUserMod=await _virtualDbContext.Set().Where(o=>o.Name=="name_2").ShardingFirstOrDefaultAsync();
+ Assert.NotNull(sysUserMod);
+ Assert.Equal("2",sysUserMod.Id);
+ var sysUserRange=await _virtualDbContext.Set().Where(o=>o.Name=="name_range_2").ShardingFirstOrDefaultAsync();
+ Assert.NotNull(sysUserRange);
+ Assert.Equal("2",sysUserRange.Id);
+ }
+ [Fact]
+ public async Task FirstOrDefault4()
+ {
+ var sysUserMod=await _virtualDbContext.Set().Where(o=>o.Id!="1").ShardingFirstOrDefaultAsync();
+ Assert.NotNull(sysUserMod);
+ Assert.True(sysUserMod.Id!="1");
+ var sysUserRange=await _virtualDbContext.Set().Where(o=>o.Id!="1").ShardingFirstOrDefaultAsync();
+ Assert.NotNull(sysUserRange);
+ Assert.True(sysUserRange.Id!="1");
+ }
+ [Fact]
+ public async Task FirstOrDefault5()
+ {
+ var sysUserMod=await _virtualDbContext.Set().Where(o=>o.Name=="name_1001").ShardingFirstOrDefaultAsync();
+ Assert.Null(sysUserMod);
+ var sysUserRange=await _virtualDbContext.Set().Where(o=>o.Name=="name_range_1001").ShardingFirstOrDefaultAsync();
+ Assert.Null(sysUserRange);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/ShardingCore.Test50.MySql/Shardings/SysUserModVirtualRoute.cs b/test/ShardingCore.Test50.MySql/Shardings/SysUserModVirtualRoute.cs
new file mode 100644
index 00000000..4672d6fe
--- /dev/null
+++ b/test/ShardingCore.Test50.MySql/Shardings/SysUserModVirtualRoute.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using ShardingCore.Core.VirtualRoutes;
+using ShardingCore.Test50.MySql.Domain.Entities;
+using ShardingCore.VirtualRoutes;
+
+namespace ShardingCore.Test50.MySql.Shardings
+{
+/*
+* @Author: xjm
+* @Description:
+* @Date: Thursday, 14 January 2021 15:39:27
+* @Email: 326308290@qq.com
+*/
+ public class SysUserModVirtualRoute : AbstractSimpleShardingModVirtualRoute
+ {
+ public SysUserModVirtualRoute() : base(3)
+ {
+ }
+
+ protected override string ConvertToShardingKey(object shardingKey)
+ {
+ return shardingKey.ToString();
+ }
+
+ public override List GetAllTails()
+ {
+ return new() { "0","1","2"};
+ }
+
+ protected override Expression> GetRouteToFilter(string shardingKey, ShardingOperatorEnum shardingOperator)
+ {
+ var t = ShardingKeyToTail(shardingKey);
+ switch (shardingOperator)
+ {
+ case ShardingOperatorEnum.Equal: return tail => tail == t;
+ default:
+ {
+ Console.WriteLine($"shardingOperator is not equal scan all table tail");
+ return tail => true;
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/test/ShardingCore.Test50.MySql/Shardings/SysUserRangeVirtualRoute.cs b/test/ShardingCore.Test50.MySql/Shardings/SysUserRangeVirtualRoute.cs
new file mode 100644
index 00000000..b101efaa
--- /dev/null
+++ b/test/ShardingCore.Test50.MySql/Shardings/SysUserRangeVirtualRoute.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using ShardingCore.Core.VirtualRoutes;
+using ShardingCore.Core.VirtualRoutes.Abstractions;
+using ShardingCore.Helpers;
+using ShardingCore.Test50.MySql.Domain.Entities;
+
+namespace ShardingCore.Test50.MySql.Shardings
+{
+/*
+* @Author: xjm
+* @Description:
+* @Date: Wednesday, 20 January 2021 10:46:37
+* @Email: 326308290@qq.com
+*/
+ public class SysUserRangeVirtualRoute: AbstractShardingOperatorVirtualRoute
+ {
+ private int _mod = 1000;
+ protected override string ConvertToShardingKey(object shardingKey)
+ {
+ return shardingKey.ToString();
+ }
+
+ public override string ShardingKeyToTail(object shardingKey)
+ {
+ var shardingKeyStr = ConvertToShardingKey(shardingKey);
+ var m = Math.Abs(ShardingCoreHelper.GetStringHashCode(shardingKeyStr) % _mod);
+ if (m > 800)//801-999
+ {
+ return "3";
+ } else if (m > 600)//601-800
+ {
+ return "2";
+ } else if (m > 300)//301-600
+ {
+ return "1";
+ } else //0-300
+ {
+ return "0";
+ }
+ }
+
+ public override List GetAllTails()
+ {
+ return new(){"0", "1","2","3"};
+ }
+
+ protected override Expression> GetRouteToFilter(string shardingKey, ShardingOperatorEnum shardingOperator)
+ {
+ var t = ShardingKeyToTail(shardingKey);
+ switch (shardingOperator)
+ {
+ case ShardingOperatorEnum.Equal: return tail => tail == t;
+ default:
+ {
+ Console.WriteLine($"shardingOperator is not equal scan all table tail");
+ return tail => true;
+ }
+ }
+ }
+
+ // public override List AfterPhysicTableFilter(List allPhysicTables, List filterPhysicTables)
+ // {
+ // if (filterPhysicTables.Count > 1)
+ // throw new Exception($"query {nameof(SysUserRange)} not support cross table");
+ // return base.AfterPhysicTableFilter(allPhysicTables, filterPhysicTables);
+ // }
+ }
+}
\ No newline at end of file
diff --git a/test/ShardingCore.Test50.MySql/Startup.cs b/test/ShardingCore.Test50.MySql/Startup.cs
new file mode 100644
index 00000000..3f9e23dd
--- /dev/null
+++ b/test/ShardingCore.Test50.MySql/Startup.cs
@@ -0,0 +1,109 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using ShardingCore.DbContexts.VirtualDbContexts;
+using ShardingCore.Extensions;
+using ShardingCore.Test50.MySql.Domain.Entities;
+
+using ShardingCore.MySql;
+using ShardingCore.Test50.MySql.Shardings;
+
+namespace ShardingCore.Test50.MySql
+{
+/*
+* @Author: xjm
+* @Description:
+* @Date: Friday, 15 January 2021 15:37:46
+* @Email: 326308290@qq.com
+*/
+ public class Startup
+ {
+ // // 自定义 host 构建
+ public void ConfigureHost(IHostBuilder hostBuilder)
+ {
+ hostBuilder
+ .ConfigureAppConfiguration(builder =>
+ {
+ builder.AddJsonFile("Configs/DbConfig.json");
+ });
+ }
+
+ // 支持的形式:
+ // ConfigureServices(IServiceCollection services)
+ // ConfigureServices(IServiceCollection services, HostBuilderContext hostBuilderContext)
+ // ConfigureServices(HostBuilderContext hostBuilderContext, IServiceCollection services)
+ public void ConfigureServices(IServiceCollection services, HostBuilderContext hostBuilderContext)
+ {
+ services.AddShardingMySql(o =>
+ {
+ o.ConnectionString = hostBuilderContext.Configuration.GetSection("MySql")["ConnectionString"];
+ o.ServerVersion = new MySqlServerVersion(new Version());
+ o.AddSharding();
+ o.AddSharding();
+ o.CreateIfNotExists((provider, config) =>
+ {
+ config.EnsureCreated = true;
+ });
+ });
+ }
+
+ // 可以添加要用到的方法参数,会自动从注册的服务中获取服务实例,类似于 asp.net core 里 Configure 方法
+ public void Configure(IServiceProvider serviceProvider)
+ {
+ var shardingBootstrapper = serviceProvider.GetService();
+ shardingBootstrapper.Start();
+ // 有一些测试数据要初始化可以放在这里
+ InitData(serviceProvider).GetAwaiter().GetResult();
+ }
+
+ ///
+ /// 添加种子数据
+ ///
+ ///
+ ///
+ private async Task InitData(IServiceProvider serviceProvider)
+ {
+ using (var scope = serviceProvider.CreateScope())
+ {
+ var virtualDbContext = scope.ServiceProvider.GetService();
+ if (!await virtualDbContext.Set().ShardingAnyAsync(o => true))
+ {
+ var ids = Enumerable.Range(1, 100);
+ var userMods = new List();
+ foreach (var id in ids)
+ {
+ userMods.Add(new SysUserMod()
+ {
+ Id = id.ToString(),
+ Age = id,
+ Name = $"name_{id}"
+ });
+ }
+
+ await virtualDbContext.InsertRangeAsync(userMods);
+
+
+ var idRanges = Enumerable.Range(1, 1000);
+ var userRanges = new List();
+ foreach (var id in idRanges)
+ {
+ userRanges.Add(new SysUserRange()
+ {
+ Id = id.ToString(),
+ Age = id,
+ Name = $"name_range_{id}"
+ });
+ }
+
+ await virtualDbContext.InsertRangeAsync(userRanges);
+ await virtualDbContext.SaveChangesAsync();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/ShardingCore.Test50/ShardingCore.Test50.csproj b/test/ShardingCore.Test50/ShardingCore.Test50.csproj
index de8c2967..1d54417d 100644
--- a/test/ShardingCore.Test50/ShardingCore.Test50.csproj
+++ b/test/ShardingCore.Test50/ShardingCore.Test50.csproj
@@ -3,7 +3,6 @@
net5.0
9.0
- TRACE;DEBUG;EFCORE5SQLSERVER;
diff --git a/test/ShardingCore.Test50/Startup.cs b/test/ShardingCore.Test50/Startup.cs
index e568fcff..e8289d1a 100644
--- a/test/ShardingCore.Test50/Startup.cs
+++ b/test/ShardingCore.Test50/Startup.cs
@@ -8,6 +8,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Extensions;
+using ShardingCore.SqlServer;
using ShardingCore.Test50.Domain.Entities;
using ShardingCore.Test50.Shardings;
@@ -43,8 +44,7 @@ namespace ShardingCore.Test50
// ConfigureServices(IServiceCollection services, HostBuilderContext hostBuilderContext)
// ConfigureServices(HostBuilderContext hostBuilderContext, IServiceCollection services)
public void ConfigureServices(IServiceCollection services, HostBuilderContext hostBuilderContext)
- {
-#if EFCORE5SQLSERVER
+ {
services.AddShardingSqlServer(o =>
{
o.ConnectionString = hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"];
@@ -55,20 +55,6 @@ namespace ShardingCore.Test50
config.EnsureCreated = true;
});
});
-#endif
-#if EFCORE5MYSQL
- services.AddShardingMySql(o =>
- {
- o.ConnectionString = hostBuilderContext.Configuration.GetSection("MySql")["ConnectionString"];
- o.ServerVersion = new MySqlServerVersion(new Version());
- o.AddSharding();
- o.AddSharding();
- o.CreateIfNotExists((provider, config) =>
- {
- config.EnsureCreated = true;
- });
- });
-#endif
}
// 可以添加要用到的方法参数,会自动从注册的服务中获取服务实例,类似于 asp.net core 里 Configure 方法