我想记录某些实体的更改(用属性标记),所以我创建了AbstractSessionInterceptor
的后代来访问实体更改。另外我想知道谁做了这个改变,所以我需要访问当前用户,所以通过IWorkContextAccessor
我创建IWorkContextScope
、获取WorkContext
和尝试获取用户,当编辑现有实体时,我能够访问当前用户,当新实体是用 contentmanager 创建的,我遇到超时异常。然后我WorkContext
通过IWorkContextAccessor.GetContext()
我得到无限循环(拦截器被一次又一次地调用)。任何想法和建议将不胜感激。
谢谢。
资源:
public class AccountInterceptor : AbstractSessionInterceptor
{
private IProtocolLogger _logger;
private readonly Type _mainAttrType = typeof(ProtocolAttribute);
private readonly Type _fieldAttrType = typeof(ProtocolFieldAttribute);
private readonly IWorkContextAccessor _contextAccessor;
ISessionFactoryHolder _sessionFactoryHolder;
public AccountInterceptor(IWorkContextAccessor contextAccessor, ISessionFactoryHolder sessionFactoryHolder)
{
_contextAccessor = contextAccessor;
_sessionFactoryHolder = sessionFactoryHolder;
}
public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, NHibernate.Type.IType[] types)
{
var t = entity.GetType();
var attributes = t.GetCustomAttributes(_mainAttrType, true);
if (attributes.Length != 0)
{
IWorkContextScope scope = _contextAccessor.CreateWorkContextScope();
WorkContext context = scope.WorkContext;
if (context != null)
{
var attr = (ProtocolAttribute)attributes.FirstOrDefault();
var currentDic = currentState.Select((s, i) => new { S = s, Index = i }).ToDictionary(x => x.Index, x => x.S);
var prvDic = previousState.Select((s, i) => new { S = s, Index = i }).ToDictionary(x => x.Index, x => x.S);
var diff = compare(currentDic, prvDic);
if (!attr.LogAllData)
{
List<string> properties = new List<string>();
foreach (var propety in t.GetProperties())
{
var propertyAttributes = propety.GetCustomAttributes(_fieldAttrType, true);
if (propertyAttributes.Length != 0)
properties.Add(propety.Name);
}
if (properties.Count != 0)
{
var necesseryProps = propertyNames.Select((s, i) => new { S = s, Index = i }).Where(p => properties.Contains(p.S)).ToDictionary(x => x.Index, x => x.S);
TupleList<int, object, object> ToRemove = new TupleList<int, object, object>();
foreach (var tuple in diff)
{
if (!necesseryProps.Keys.Contains(tuple.Item1))
{
ToRemove.Add(tuple);
}
}
ToRemove.ForEach(d => diff.Remove(d));
}
}
if (diff.Count != 0)
{
_logger = ProtocolLogger.GetInstance();
var sessionFactory = _sessionFactoryHolder.GetSessionFactory();
var session = sessionFactory.OpenSession();
var user = GetCurrentUser(session, context.HttpContext);
string propertiesFormat = GetPropertiesStringFormat(diff, propertyNames);
object[] param = new object[] { DateTime.Now, entity, propertyNames };
string entityId = string.Empty;
try
{
if (entity is IAuditable)
{
entityId = ((IAuditable)entity).Id.ToString();
}
}
catch (Exception)
{
entityId = entity.ToString();
}
foreach (var pair in diff)
{
ProtocolPropertyInfo info = new ProtocolPropertyInfo(propertyNames[pair.Item1], Convert.ToString(pair.Item2), Convert.ToString(pair.Item3));
_logger.Log(user, entity, entityId, session, context, Operation.Write, info);
}
session.Flush();
session.Close();
}
}
}
return base.OnFlushDirty(entity, id, currentState, previousState, propertyNames, types);
}
private object GetCurrentUser(ISession session, HttpContextBase httpContext)
{
if (httpContext == null || !httpContext.Request.IsAuthenticated || !(httpContext.User.Identity is FormsIdentity))
{
return null;
}
var formsIdentity = (FormsIdentity)httpContext.User.Identity;
var userData = formsIdentity.Ticket.UserData ?? "";
// the cookie user data is {userId};{tenant}
var userDataSegments = userData.Split(';');
if (userDataSegments.Length != 2)
{
return null;
}
var userDataId = userDataSegments[0];
var userDataTenant = userDataSegments[1];
int userId;
if (!int.TryParse(userDataId, out userId))
{
return null;
}
Type regType = Assembly.Load("Orchard.Users").GetTypes().First(t => t.Name == "UserPartRecord");
var user = session.Get(regType, userId);
return user;
}
private string GetPropertiesStringFormat(TupleList<int, object, object> diffDic, string[] propertyNames)
{
StringBuilder result = new StringBuilder();
foreach (var pair in diffDic)
{
result.AppendFormat("Property name {0}, New value {1}, Old value {2}", propertyNames[pair.Item1], pair.Item2, pair.Item3);
}
return result.ToString();
}
private TupleList<int, object, object> compare(Dictionary<int, object> dic1, Dictionary<int, object> dic2)
{
var diff = new TupleList<int, object, object>();
foreach (KeyValuePair<int, object> pair in dic1)
{
if (!Equals(pair.Value, dic2[pair.Key]))
{
diff.Add(pair.Key, pair.Value, dic2[pair.Key]);
}
}
return diff;
}
}