. NET и Castle DynamicProxy - Как проверить, находится ли один перехват «внутри» другого перехвата - PullRequest
1 голос
/ 14 марта 2020

У меня есть библиотека аудита AOP, которая перехватывает методы с использованием Castle DynamicProxy с Autofa c и проверяет, есть ли у них этот атрибут c:

[Audit(AuditOperation.Create), MethodImpl(MethodImplOptions.NoInlining)]
public virtual TEntity Add(TEntity entity, [MethodIsAuditableParam]bool methodIsAuditable = true)
{
   entity = entity.DeleteNestedProperties();

   using (var entityContext = ContextCreator())
   {
      TEntity addedEntity = entityContext.Set<TEntity>().Add(entity);
      entityContext.SaveChanges();

      return addedEntity;
   }
}

Это универсальный c метод репозитория это добавляет сущность c в базу данных. Но у меня также есть определенные c методы в моем доменном слое, которые делают дополнительные вещи, а затем вызывают следующие обобщенные c методы репозитория:

[Audit(AuditOperation.Create), MethodImpl(MethodImplOptions.NoInlining)]
public virtual User AddUser(int currentUserId, User newUser, [MethodIsAuditableParam]bool methodIsAuditable = true)
{
   try
   {
      UserDBValidations(currentUserId, newUser);

      if (newUser.UserProfileId == (int)UserProfileType.Admin ||
         newUser.UserProfileId == (int)UserProfileType.ProcessSpecialist)
         newUser.UGBs = _ugbRepository.FindAll().ToList();

      _userRepository.Add(newUser);

      return newUser;
   }
   catch (Exception ex)
   {
      throw new Exception("Erro no cadastro de usuário: " + ex.Message);
   }       
}

Я предполагаю, что, если метод домена Auditable (который может вызвать существует много обобщенных c методов хранилища), мой перехватчик аудита будет проверять только этот метод домена и будет игнорировать прослушивание обобщенного c хранилища. Но если я вызову методы репозитория generi c напрямую, они будут проходить обычную проверку.

Я попытался добиться такого поведения, используя трассировку стека в моем перехватчике. Этот следующий метод проверяет, содержит ли массив кадров стека метод IInterceptor.Intercept . :

private bool CheckIfMethodCallersAreBeingIntercepted()
{
   StackTrace stackTrace = new StackTrace();
   StackFrame[] stackFrames = stackTrace.GetFrames();
   //the int number should match the exact number of method calls in this interception until this current method
   StackFrame[] realStackFrames = stackFrames.SubArray(5, stackFrames.Count() - 5);

   foreach (StackFrame realStackFrame in realStackFrames)
   {
      MethodBase method = realStackFrame.GetMethod();
      if (method == null)
         continue;

      Type declaringType = method.DeclaringType;
      if (declaringType == null)
         continue;

      string declaringTypeFullName = declaringType.FullName;
      if (declaringTypeFullName == null)
         continue;

      if(declaringTypeFullName
         .Contains("AwesomeAuditing.AwesomeAuditingInterceptor"))
         return true;
   }

   return false;
}

Но это не работает, потому что я могу перехватить метод и не проверять его:

public void Intercept(IInvocation invocation)
{
   if (!CheckIfMethodShouldBeIntercepted(invocation.Method, invocation.Arguments))
   {
      invocation.Proceed();
      return;
   }

   if (!CheckIfMethodReturnTypeInheritAuditEntity(invocation.Method))
      throw new AwesomeAuditingException(@"The audited method's return type most inherit the IAuditableEntity interface.");

   invocation.Proceed();

   if (CheckIfMethodIsAsync(invocation.Method))
      invocation.ReturnValue = AsyncProceedExecution((dynamic)invocation.ReturnValue, invocation);
   else
      AfterProceedExecution(invocation.ReturnValue, invocation);
}

Я не хочу управлять статусом c коллекция со всеми текущими перехваченными методами, потому что я хочу, чтобы эта библиотека AOP работала во многих типах проектов (Web API, Windows Services, Console Applications, WPF и т. д. c.), и у каждого типа есть свой собственный способ управления stati c экземпляра. Например, в контексте Web API я не хочу, чтобы два HTTP-запроса совместно использовали эту коллекцию stati c. В сервисе Windows я не хочу делиться этой коллекцией stati c между двумя потоками выполнения.

Ребята, вы знаете лучший способ управления этим многоуровневым перехватом? Знаете ли вы хорошую практику, которая будет хорошо работать во многих типах проектов?

...