PostSharp в мультитенантном решении - PullRequest
1 голос
/ 03 апреля 2019

В настоящее время я ищу, чтобы добавить запись PostSharp (и, возможно, другие пользовательские аспекты) в проект ASP.NET Core API. Проблема, с которой я сталкиваюсь, заключается в том, что у нас есть мультитенантный дизайн, в котором информация об арендаторах хранится в заявках пользователей, и, похоже, нет хорошего способа получить текущую сессию с точки зрения PostSharp, поэтому не кажется хорошим способом доступа к базе данных соответствующего арендатора.

Я просто лаю не на том дереве? Есть ли какая-то другая структура AOP, на которую я должен обратить внимание?

1 Ответ

1 голос
/ 05 апреля 2019

Для полноты картины, вот решение, которое я придумал, которое использует и 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 не отображается в нашем исходном коде.

...