我正在做一个REST服务(使用惊人的ServiceStack,虽然它与问题无关),我现在需要记录在PUT
请求时发生的更改。
目前我的更新方法如下:
public object Put(PostActivityInformation request)
{
var session = this.SessionAs<MyCustomApiAuthSession>();
var activity = _activitiesRepository.GetActivityById(_companyRepository, session.CurrentCompany.Guid, request.Id);
if (_activitiesRepository.IsActivityDuplicated(session.CurrentCompany.Id, request.SmsCode, request.Name, request.Id))
return HttpError.Conflict("Found a duplicated activity");
// update what is passed
activity.Category = request.Category ?? activity.Category;
activity.Description = request.Description ?? activity.Description;
activity.ExtraTextDescription = request.ExtraTextDescription ?? activity.ExtraTextDescription;
activity.Name = request.Name ?? activity.Name;
activity.Points = request.Points ?? activity.Points;
activity.SaveExtraText = request.SaveExtraText ?? activity.SaveExtraText;
activity.SmsCode = request.SmsCode ?? activity.SmsCode;
activity.IsActive = request.Active ?? activity.IsActive;
activity.IsArchived = request.Archived ?? activity.IsArchived;
// update stamp
activity.UpdatedTime = DateTime.UtcNow;
activity.UpdatedUser = session.CurrentUser.Id;
// save
_activitiesRepository.SaveOrUpdate(activity);
// log
session.AddLog("Activity updated: {0}".Fmt(activity.Name), LogArea.Activities, activity.Id);
return activity.ToActivityResponse();
}
但我希望更具描述性,并保存更改,例如替换
activity.Category = request.Category ?? activity.Category;
activity.Description = request.Description ?? activity.Description;
通过
var log = new StringBuilder();
if (request.Category != null)
{
log.AppendFormat("Category changed from '{0}' to '{1}'", activity.Category, request.Category);
activity.Category = request.Category;
}
if (request.Description != null)
{
log.AppendFormat("Description changed from '{0}' to '{1}'", activity.Description, request.Description);
activity.Description = request.Description;
}
然后将log
变量保存到我的审计表中......
什么是最好的方法,因为我在API中有几个更新,而不仅仅是“活动”?
我正在考虑使用 ExtensionMethod ,但这会使用 Refection 并且会稍微减慢一些......
你们有没有通过这个问题,你做了什么?
答案 0 :(得分:2)
使用一对辅助方法更改设置时格式化日志的一种方法:
private static void T? Update(T? newVal, T? oldVal, string name, StringBuilder log) where T : struct {
if (!Equals(newVal, oldVal)) {
log.AppendFormat("{0} changed from '{1}' to '{2}'", name, oldVal, newVal);
}
return newVal ?? oldVal;
}
private static void T Update(T newVal, T oldVal, string name, StringBuilder log) where T : class {
if (!Equals(newVal, oldVal)) {
log.AppendFormat("{0} changed from '{1}' to '{2}'", name, oldVal, newVal);
}
return newVal ?? oldVal;
}
现在您可以按如下方式统一代码:
activity.Category = Update(request.Category, activity.Category, nameof(activity.Category), log);
activity.Description = Update(request.Description, activity.Description, nameof(activity.Description), log);
activity.ExtraTextDescription = Update(request.ExtraTextDescription, activity.ExtraTextDescription, nameof(activity.ExtraTextDescription), log);
...
注意:我认为此时您在更改架构方面没有太大的灵活性,但是保持审计的一个很好的替代方法是让审计成为您的主要信息来源已经改变。当然,这会将审计日志从格式化字符串列表转换为完整的对象注册表。有关详细信息,请参阅Event Sourcing Pattern。
答案 1 :(得分:0)
我会在您的Activity类中实现类似于INotifyPropertyChanged的东西,在事件数据中您将拥有属性名称,旧值和新值。