多租户解决方案中的 PostSharp
PostSharp in a multitenant solution
我目前正在寻求将 PostSharp 日志记录(以及可能的其他自定义方面)添加到 ASP.NET Core API 项目中。我 运行 遇到的问题是我们有一个多租户设计,其中租户信息存储在用户声明中,并且似乎没有从 PostSharp 方面获取当前会话的好方法, 因此似乎没有访问正确租户数据库的好方法。
我是不是找错人了?是否有其他我应该关注的 AOP 框架?
为了完整起见,这是我想出的解决方案,它同时使用了 PostSharp 和 AutoFac。
PostSharp 方面可以在编译时应用的 类 上创建属性。使用 AutoFac 的 InjectUnsetProperties
函数,我们可以将适当范围的成员注入这些 类 即使我们在编译时不知道它们 .
因此,我们设置了 PostSharp 方面:
[PSerializable]
public class LoggingAspect : OnMethodBoundaryAspect, IInstanceScopedAspect
{
[IntroduceMember(Visibility = Visibility.Public, OverrideAction = MemberOverrideAction.Ignore)]
[CopyCustomAttributes(typeof(ImportMemberAttribute))]
public IInjectedObject InjectedObject { get; set; }
[ImportMember("InjectedObject", IsRequired = true)]
public Property<IInjectedObject> InjectedObjectProperty;
public override void OnEntry(MethodExecutionArgs args)
{
var data = InjectedObjectProperty.Get().MyData;
Debug.Print($"OnEntry: {args.Method.Name}, Data: {data}\n");
}
public object CreateInstance(AdviceArgs adviceArgs)
{
return MemberwiseClone();
}
public void RuntimeInitializeInstance()
{
}
}
然后在我们的 Startup
方法中注册我们要使用方面的服务:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
var builder = new ContainerBuilder();
builder.Populate(services);
builder.RegisterType<TestService>().As<ITestService>()
.InstancePerLifetimeScope()
.OnActivated(e => e.Context.InjectUnsetProperties(e.Instance))
;
builder.RegisterType<InjectedObject>().As<IInjectedObject>()
.InstancePerLifetimeScope()
;
var container = builder.Build();
return new AutofacServiceProvider(container);
}
并将方面添加到我们要记录的方法中:
public class TestService : ITestService
{
public TestService()
{
Debug.Print("TestService ctor\n");
}
private int _myData = 100;
[LoggingAspect]
public int GetData()
{
return _myData++;
}
}
在请求期间创建服务时,会创建一个范围为该请求的新服务,并且它会插入一个新的 IInjectedObject
,该服务的范围也为请求,即使 IInjectedObject 属性 没有出现在我们的源代码中。
我目前正在寻求将 PostSharp 日志记录(以及可能的其他自定义方面)添加到 ASP.NET Core API 项目中。我 运行 遇到的问题是我们有一个多租户设计,其中租户信息存储在用户声明中,并且似乎没有从 PostSharp 方面获取当前会话的好方法, 因此似乎没有访问正确租户数据库的好方法。
我是不是找错人了?是否有其他我应该关注的 AOP 框架?
为了完整起见,这是我想出的解决方案,它同时使用了 PostSharp 和 AutoFac。
PostSharp 方面可以在编译时应用的 类 上创建属性。使用 AutoFac 的 InjectUnsetProperties
函数,我们可以将适当范围的成员注入这些 类 即使我们在编译时不知道它们 .
因此,我们设置了 PostSharp 方面:
[PSerializable]
public class LoggingAspect : OnMethodBoundaryAspect, IInstanceScopedAspect
{
[IntroduceMember(Visibility = Visibility.Public, OverrideAction = MemberOverrideAction.Ignore)]
[CopyCustomAttributes(typeof(ImportMemberAttribute))]
public IInjectedObject InjectedObject { get; set; }
[ImportMember("InjectedObject", IsRequired = true)]
public Property<IInjectedObject> InjectedObjectProperty;
public override void OnEntry(MethodExecutionArgs args)
{
var data = InjectedObjectProperty.Get().MyData;
Debug.Print($"OnEntry: {args.Method.Name}, Data: {data}\n");
}
public object CreateInstance(AdviceArgs adviceArgs)
{
return MemberwiseClone();
}
public void RuntimeInitializeInstance()
{
}
}
然后在我们的 Startup
方法中注册我们要使用方面的服务:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
var builder = new ContainerBuilder();
builder.Populate(services);
builder.RegisterType<TestService>().As<ITestService>()
.InstancePerLifetimeScope()
.OnActivated(e => e.Context.InjectUnsetProperties(e.Instance))
;
builder.RegisterType<InjectedObject>().As<IInjectedObject>()
.InstancePerLifetimeScope()
;
var container = builder.Build();
return new AutofacServiceProvider(container);
}
并将方面添加到我们要记录的方法中:
public class TestService : ITestService
{
public TestService()
{
Debug.Print("TestService ctor\n");
}
private int _myData = 100;
[LoggingAspect]
public int GetData()
{
return _myData++;
}
}
在请求期间创建服务时,会创建一个范围为该请求的新服务,并且它会插入一个新的 IInjectedObject
,该服务的范围也为请求,即使 IInjectedObject 属性 没有出现在我们的源代码中。