Для полноты картины, вот решение, которое я придумал, которое использует и PostSharp, и AutoFac.
Аспекты PostSharp могут создавать свойства классов, к которым они применяются во время компиляции. Используя функцию InjectUnsetProperties
от AutoFac, мы можем внедрить в эти классы члены с правильной областью действия, даже если мы не знаем о них во время компиляции .
Итак, мы настроили наш аспект 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 не отображается в нашем исходном коде.