У меня есть библиотека аудита 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 между двумя потоками выполнения.
Ребята, вы знаете лучший способ управления этим многоуровневым перехватом? Знаете ли вы хорошую практику, которая будет хорошо работать во многих типах проектов?