Я ищу лучшее решение для регистрации событий использования в базе данных, которые затем будут использоваться для создания отчетов и некоторых необычных диаграмм.
Способ, которым мы в настоящее время делаем это, заключается в следующем:
у нас есть фильтры действий MVC / API, которые прослушивают каждый запрос и вызывают службу, которая извлекает все метаданные и сохраняет их в базе данных.Текущая реализация ошибочна, не поддерживается и не расширяема, как вы можете видеть в приведенном ниже коде.(Я удалил неважный код для краткости)
public class LogActivityAttribute : ActionFilterAttribute{
// more code here...
public override void OnActionExecuted(ActionExecutedContext filterContext){
_eventLogService.LogMvcEventLog(filterContext);
}
}
public class EventLogService : IEventLogService
{
// more code here...
public EventLogSummaryModel LogMvcEventLog(ActionExecutedContext filterContext){
try
{
if (filterContext.Controller is ViewerController)
{
switch (filterContext.ActionDescriptor.ActionName)
{
case ReviewApproveDocumentActionName:
return LogEventLogForWorkflow(filterContext);
case ExternalDocumentActionName:
case DocumentActionName:
return HandlePossibleEventsForDocument(filterContext);
}
}
else if (filterContext.Controller is AppController
&& filterContext.ActionDescriptor.ActionName.Equals(AppExternalDocumentActionName))
return HandlePossibleEventsForDocument(filterContext);
else if (filterContext.Controller is Areas.Viewer.Controllers.HomeController
&& filterContext.ActionDescriptor.ActionName.Equals(HomeActionName))
return LogEventLogForWelcomePage(filterContext);
else if (filterContext.Controller is Areas.Viewer.Controllers.HomeController
&& filterContext.ActionDescriptor.ActionName.Equals(LegacySearchActionName))
return LogEventLogForLegacySearch(filterContext);
else if (filterContext.Controller is ApiSearchController
&& filterContext.ActionDescriptor.ActionName.Equals(LegacyApiSearchActionName))
return LogEventLogForLegacyApiSearch(filterContext);
else if (filterContext.Controller is Areas.Viewer.Controllers.FeedbackController)
{
if (filterContext.ActionDescriptor.ActionName.Equals(FeedbackCreateActionViewer))
LogEventsForAddFeedback(filterContext);
}
}
catch (Exception e)
{
ViewerLogger.Instance.Log.Error($"LogMvcEventLog:{e.Message}");
}
return new EventLogSummaryModel();
}
// more code here...
}
Я точно знаю, что, если я попытаюсь исправить любую из существующих проблем, я могу в конечном итоге ввести больше ошибок.Так что я думал о том, чтобы переделать все это лучше.
Мне удалось придумать 2 решения.
- Записать соответствующие события внутри каждого метода действия непосредственно перед возвратом
- Используя тот же поток фильтра действий, создать новыйКлассы следующим образом и извлекать данные и регистрировать их.
(обратите внимание, что оно неполное)
// event context metadata from mvc/api actions
public class EventContext
{
public ModeTypes ModeType { get; set; }
public string Instance { get; set; }
public string HttpVerb { get; set; }
public int HttpResponseCode { get; set; }
public int UserId { get; set; }
public ICollection<int> UserRoles { get; set; }
public DateTime Timestamp => DateTime.UtcNow;
}
internal class ApiEventContextDataExtractor
: IApiEventContextDataExtractor
{
private readonly IHttpContextService _httpContextService;
public ApiEventContextDataExtractor(IHttpContextService httpContextService)
{
_httpContextService = httpContextService;
}
public EventContext GetContext(HttpActionExecutedContext filterContext)
{
var userRole = _httpContextService.GetCurrentUserRoles();
var host = _httpContextService.GetHost();
var area = filterContext.ActionContext.RequestContext.RouteData.Values[Constants.EventLogService.AreaName]?.ToString() ?? "";
var mode = area.Equals(AnalyticConstants.EventLogService.AuthorArea, StringComparison.InvariantCultureIgnoreCase)
? ModeTypes.Editor
: ModeTypes.Display;
return new EventContext
{
HttpVerb = filterContext.Request.Method.Method,
HttpResponseCode = (int)filterContext.Response.StatusCode,
Instance = host,
UserId = userRole.Id,
ModeType = mode
};
}
}
internal class MvcEventContextDataExtractor : IMvcEventContextDataExtractor{
// implementation
}
internal class MvcEventReferrerDataExtractor
{
// implementation
}
internal class MvcEventModelDataExtractor
{
// implementation
}
, и тогда у меня будет общий сервис, который будет получать EventContext
вместе с данными реферера и данными модели и регистрировать ихв базе данных.
Так что я думаю, что мой вопрос будет, какой путь мне выбрать?Если бы я сделал это по-своему (2-й), я на правильном пути или есть лучший способ сделать это?