我目前正在寻求将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属性。