当前位置:   article > 正文

ABP VNext学习日记27_abp 切换租户

abp 切换租户

1.常见应用交互方式
解析:
[1]浏览器与Web应用程序之间的通讯
[2]Web应用程序与Web API之间的通讯[Web应用程序自身或代表用户与Web API通信]
[3]基于浏览器的应用程序与Web API通讯
[4]本地应用程序与Web API通讯
[5]基于服务器的应用程序与Web API通讯
[6]Web API与Web API通讯[Web API自身或代表用户与另一个Web API通讯]

2.IDS4介绍
解析:IdentityServer是基于OpenID Connect协议标准的身份认证和授权程序,它实现了OpenID Connect和OAuth 2.0协议。

3.身份验证
解析:
[1]不进行身份验证
[2]个人用户账号
[3]工作或学校账户
[4]Windows身份验证

4.如何在项目当中使用租户
解析:用户必须是租户的前提下登录:
[1]先管理租户,增删改查
[2]然后切换租户,默认存储到Cookie
[3]然后从Cookie中取租户
[4]最后取出租户Id存储到表

5.ABP租户相关模块
解析:
[1]Volo.Abp.MultiTenancy
[2]Volo.Abp.AspNetCore.MultiTenancy
[3]Volo.Abp.TenantManagement

6.tenant为什么放在Cookie中
解析:不一定要放在Cookie中,可以放在:
[1]请求头header
[2]表单form中
[3]路由Route
[4]查询参数QueryString
[5]域名Domain

7.多租户取值原理
解析:
[1]MultiTenancyMiddleware
[2]TenantConfigurationProvider
[3]TenantResolver
[4]ItenantResolveContributor

8.Abp租户解析器
解析:
[1]查询字符串:QueryStringTenantResolveContributor()
[2]表单:FormTenantResolveContributor
[3]路由:RouteTenantResolveContributor
[4]请求头:HeaderTenantResolveContributor()
[5]Cookie:CookieTenantResolveContributor()

9.Autofac基本流程
解析:
[1]按照控制反转[IoC]的思想构建应用
[2]添加Autofac引用
[3]在应用的startup处
[4]创建ContainerBuilder
[5]注册组件
[6]创建容器,将其保存以备后续使用
[7]应用执行阶段
[8]从容器中创建一个生命周期
[9]在此生命周期作用域内解析组件实例

10.Autofac设置工厂来替换实例
解析:

public static IHostBuilder CreateHostBuilder(string[] args)
{
    //var assemblyName = typeof(Startup).GetTypeInfo().Assembly.FullName;
    return Host.CreateDefaultBuilder(args)
        // 设置工厂来替换实例
        .UseServiceProviderFactory(new AutofacServiceProviderFactory())  
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

11.Autofac的ConfigureContainer方法
解析:在Startup类增加ConfigureContainer方法,在方法中注入依赖:

public void ConfigureContainer(ContainerBuilder builder)
{
    // Register your own things directly with Autofac, like:
    builder.RegisterType<TransientService>().As<ITransientService>();
    builder.RegisterType<SingletonService>().As<ISingletonService>().SingleInstance();
    builder.RegisterType<ScopedService>().As<IScopedService>().InstancePerLifetimeScope();
    builder.RegisterType<TestService>().As<ITestService>().InstancePerLifetimeScope();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

12.Autofac使用ConfigureContainer配置
解析:
[1]在配置WebHostBuilder的Program.Main方法中,调用AddAutofac将Autofac挂钩到启动管道中。
[2]在Startup类的ConfigureServices方法中,使用其它库提供的扩展方法将内容注册到IServiceCollection中。
[3]在Startup类的ConfigureContainer方法中,将内容直接注册到Autofac ContainerBuilder中。

13.Autofac注册组件
解析:
[1]通过创建ContainerBuilder来注册组件,并且告诉容器哪些组件,暴露了哪些服务。
[2]使用Register()方法来注册实现:ContainerBuilder包含一组Register()注册方法,而组件暴露服务,可用使用ContainerBuilder上的As()方法。
[3]即在容器初始化时候,向容器组件添加对象的操作过程。
[4]通过梳理Autofac所有可用的注册组件方法,显示如下图展示的流程图。
在这里插入图片描述

14.Autofac反射注册
解析:直接注册的组件必须是具体的类型,并可用暴露抽象和接口作为服务,但不能注册一个抽象和接口组件。使用RegisterType<T>()或者RegisterType(typeof(T))方法:

builder.RegisterType<TestService>().As<ITestService>();
// 或者
builder.RegisterType(typeof(TestService)).As(typeof(ITestService))
  • 1
  • 2
  • 3

在多个构造函数时,如果需要,也可手动指定一个构造函数。使用UsingConstructor方法和构造方法中代表参数类型的类型。

builder.RegisterType<TestService>()
          .UsingConstructor(typeof(TransientService), typeof(SingletonService));
  • 1
  • 2

15.Autofac实例注册
解析:提前生成对象的实例并加入容器,以供注册组件时使用。使用RegisterInstance()方法。

// new出一个对象注册:
var output = new StringWriter();
builder.RegisterInstance(output).As<TestService>();
  • 1
  • 2
  • 3

如果单例中存在实例且需要在容器中被组件使用时:

builder.RegisterInstance(MySingleton.Instance).ExternallyOwned();
  • 1

16.Autofac的Lambda表达式注册
解析:当组件创建不再是简单调用构造方法时,可用利用lambda表达式来实现一些常规反射无法实现的操作。比如一些复杂参数注册,参数注入,以及选择参数值实现等。

builder.Register(x => new TransientService()).As<ITransientService>();
// 或者指定参数
builder.Register(x => new TestService(x.Resolve<ITransientService>(), x.Resolve<IScopedService>(), x.Resolve<ISingletonService>()))
.As<ITestService>().InstancePerLifetimeScope();
  • 1
  • 2
  • 3
  • 4

17.Autofac泛型注册
解析:支持泛型注册操作,使用RegisterGeneric()方法:

builder.RegisterGeneric(typeof(NHibernateRepository<>))
       .As(typeof(IRepository<>))
       .InstancePerLifetimeScope();
  • 1
  • 2
  • 3

18.Autofac条件注册
解析:在一些特殊场景,可能需要通过加上判断条件,来决定是否执行该条注册语句。
[1]OnlyIf()-提供一个表达式,表示只有满足条件,才会执行语句。

builder.RegisterType<Manager>()
       .As<IManager>()
       .OnlyIf(reg =>
         reg.IsRegistered(new TypedService(typeof(IService))) &&
         reg.IsRegistered(new TypedService(typeof(HandlerB))));
  • 1
  • 2
  • 3
  • 4
  • 5

[2]IfNotRegistered()-表示没有其它服务注册的情况下,就执行语句。方法在ContainerBuilder.Build()时执行并且以实际组件注册的顺序执行。

builder.RegisterType<ServiceA>()
       .As<IService>();
builder.RegisterType<ServiceB>()
       .As<IService>()
       .IfNotRegistered(typeof(IService));
  • 1
  • 2
  • 3
  • 4
  • 5

19.Autofac属性注入
解析:构造方法参数注入是一种传值给组件的首选的方法。在构造函数中是直接使用服务类型作为参数,然后AutoFac解析该类时,就会去容器内部已存在的组件中查找,然后将匹配的对象注入到构造函数中去。同样也可以使用属性方法注入来传值。是将容器内对应的组件直接注入到类内的属性中去,在注册该属性所属类的时候,需要使用PropertiesAutowired()方法额外标注。接下来说明控制器中属性如何实现注入:
[1]注册组件方法,并使用属性注入PropertiesAutowired()标注

builder.RegisterType<TransientService>().As<ITransientService>().PropertiesAutowired();
  • 1

[2]在控制器中使用属性来接收,其中注入属性必须标注为public

[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
    public ITransientService _transientService { get; set; }  
    [HttpGet]
    public JsonResult Get()
    {
        var data1 =   _transientService.GetGuid();
        return new JsonResult(new { data1 });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

[3]运行测试发现_transientService为null,所以根本没有注入成功。这是因为控制器本身的实例(以及它的处理)是由框架创建和拥有的,而不是由容器所有。因此我们需要改变控制器本身的创建及其拥有。
[4]在Startup.cs中修改ConfigureServices方法,替换从IServiceProvider中解析控制器实例的所有者。替换的方法一定要在AddControllers之前。

public void ConfigureServices(IServiceCollection services)
{
    //替换控制器的所有者
    services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
    services.AddControllers();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

[5]在ContainerBuilder中通过注册控制器,并使用属性注入功能实现,这样就可以在Controller中进行属性注入了。

public void ConfigureContainer(ContainerBuilder builder)
{ 
    // 找到所有的controller进行注册,并使用属性注入功能
    var controllerTypesInassembly = typeof(Startup).Assembly.GetExportedTypes()
    .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
    builder.RegisterTypes(controllerTypesInassembly).PropertiesAutowired();
    builder.RegisterType<TransientService>().As<ITransientService>().PropertiesAutowired();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

20.Autofac程序集注册
解析:当需要实现批量注册的时候,也可以使用程序集的方式来注册,这也是常用的方法。可通过指定过滤类型,服务,扫描模块等方式来找到需要注册的组件。

var assemblies = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(assemblies)//程序集内所有具象类 
.Where(c => c.Name.EndsWith("Service"))
.PublicOnly()//只要public访问权限的
.Where(cc => cc.IsClass)//只要class型(主要为了排除值和interface类型) 
.AsImplementedInterfaces();//自动以其实现的所有接口类型暴露(包括IDisposable接口)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

[1]RegisterAssemblyTypes():接收包含一个或多个程序集的数组作为参数
[2]RegisterAssemblyModules():接收模块作为参数,进行模块扫描注册
[3]PublicOnly():指定公有方法被注册
[4]Where():要过滤注册的类型
[5]Except():要排除的类型
[6]As():反射出其实现的接口
[7]AsImplementedInterfaces():自动以其实现的所有接口类型暴露[包括IDisposable接口]

21.Autofac暴露服务
解析:注册组件时,告诉Autofac组件暴露了哪些服务。在上面注册实现中,大部分使用到了As()方法。当然Autofac也提供了其它标注来暴露服务的方法。

22.Autofac默认暴露自身类型服务
解析:常用的几种方法如下:

builder.RegisterType<CallLogger>();//不标注,默认以自身类型暴露服务
builder.RegisterType<CallLogger>().AsSelf();
builder.RegisterType<CallLogger>().As<CallLogger>();
builder.RegisterType<CallLogger>().As(typeof(CallLogger));
  • 1
  • 2
  • 3
  • 4

23.Autofac多个暴露服务类型
解析:
[1]以其实现的接口[interface]暴露服务,暴露的类型可以是多个,比如CallLogger类实现了ILogger接口和ICallInterceptor接口。
[2]暴露服务后,可以解析基于该服务的组件了。一旦将组件暴露为一个特定的服务,默认的服务(组件类型)将被覆盖。
[3]为了防止被其它服务覆盖,可以使用AsSelf()方法。

Copybuilder.RegisterType<CallLogger>()
       .As<ILogger>()
       .As<ICallInterceptor>()
       .AsSelf();
  • 1
  • 2
  • 3
  • 4

这样既可以实现组件暴露一系列特定的服务, 又可以让它暴露默认的服务。

24.Autofac程序集注册指定暴露类型
解析:
[1]可通过指定接口类型暴露服务,使用As()方法

publi void ConfigureContainer(ContainerBuilder builder)
{
    builder.RegisterAssemblyTypes(assemblies)//程序集内所有具象类 
        .Where(cc =>cc.Name.EndsWith("Repository")|//筛选
               cc.Name.EndsWith("Service"))
        .As(x=>x.GetInterfaces()[0])//反射出其实现的接口,并指定以其实现的第一个接口类型暴露
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

[2]指定所有实现的接口类型进行暴露
使用AsImplementedInterfaces()函数实现,相当于一个类实现了几个接口[interface]就会暴露出几个服务,等价于上面连写多个As()的作用。

publi void ConfigureContainer(ContainerBuilder builder)
{
    builder.RegisterAssemblyTypes(asm)
        .Where(t => t.Name.EndsWith("Repository"))
        .AsImplementedInterfaces();//自动以其实现的所有接口类型暴露(包括IDisposable接口)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

25.Autofac解析服务
解析:在注册完组件并暴露相应的服务后,可以从创建的容器或其生命周期中解析服务。使用Resolve()方法来解析实现:通过梳理Autofac所有可用的解析服务方法,显示如下图展示的流程图。
在这里插入图片描述
在注册完组件并暴露相应的服务后,可以从创建的容器或其子生命周期中解析服务,让使用Resolve()方法来实现:

var builder = new ContainerBuilder();
builder.RegisterType<MyComponent>().As<IService>();
var container = builder.Build();
using(var scope = container.BeginLifetimeScope())
{
  var service = scope.Resolve<IService>();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

参考文献:
[1]Autofac思维导图:https://www.processon.com/view/link/6072ed8863768912ae50b483
[2]Autofac官方网站:https://autofaccn.readthedocs.io/en/latest/getting-started/index.html
[3]Autofac框架初识与应用:https://mp.weixin.qq.com/s/YsbjKJ7MG5DeGFIZzkD3cQ

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/141340?site
推荐阅读
相关标签
  

闽ICP备14008679号