ASP.NET Web API - глобальный фильтр трассировки - PullRequest
0 голосов
/ 15 января 2019

Я хотел бы добавить некоторые общие регистрации в мой веб-API (используемый приложением Angular 7).

Моя идея состоит в том, чтобы создать глобальный фильтр действий для ведения журнала - это то, что я имею до сих пор:

public class GlobalTraceFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        TraceData data = new TraceData
        {
            ControllerName = actionContext.ControllerContext.ControllerDescriptor.ControllerName,
            ActionName = actionContext.ActionDescriptor.ActionName,
            RequestType = "Enter"
        };

        WriteToLog(data);
    }

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        TraceData data = new TraceData
        {
            ControllerName = actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerName,
            ActionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName,
            RequestType = "Exit"
        };

        WriteToLog(data);
    }

    private void WriteToLog(TraceData data)
    {
        if (data == null)
        {
            return;
        }

        try
        {
            // save metadata
            using (SqlCommand cmdInsertTraceData = new SqlCommand("dbo.WebApiRequest_Insert", DB.Connection))
            {
                cmdInsertTraceData.CommandType = CommandType.StoredProcedure;

                cmdInsertTraceData.Parameters.Add("@RequestType", SqlDbType.VarChar, 50).Value = GetValueOrDbNull(data.RequestType);
                cmdInsertTraceData.Parameters.Add("@ControllerName", SqlDbType.VarChar, 500).Value = GetValueOrDbNull(data.ControllerName);
                cmdInsertTraceData.Parameters.Add("@ActionName", SqlDbType.VarChar, 500).Value = GetValueOrDbNull(data.ActionName);
                cmdInsertTraceData.Parameters.Add("@Parameters", SqlDbType.VarChar, 8000).Value = ConvertToXml(data.Parameters);

                cmdInsertTraceData.ExecuteNonQuery();
            }
        }
        catch (Exception exc)
        {
            ErrorSignal.FromCurrentContext().Raise(exc);
        }
    }

    private string ConvertToXml(List<KeyValuePair<string, string>> traceParameters)
    {
        List<string> parameters = new List<string>();

        foreach (var kvp in traceParameters)
        {
            string paramEntry = $"<parameter name=\"{kvp.Key}\">{kvp.Value}</parameter>";
            parameters.Add(paramEntry);
        }

        return "<parameters>" + string.Join("", parameters) + "</parameters>";
    }

    private object GetValueOrDbNull(object value)
    {
        if (value == null)
        {
            return DBNull.Value;
        }

        return value;
    }
}

Прямо сейчас я получаю две записи - одну для того, когда действие выполнено (OnActionExecuting - RequestType=Enter), и другую для того, когда оно завершено (OnActionExecuted - RequestType=Exit).

Я хотел бы объединить эти два в одну запись, которая будет записывать действие и имя контроллера, дату / метку времени запроса и ответа, параметр вызова, содержимое ответа (если есть), когда действие сделано и т. д.

Моя проблема в : как и где я могу хранить информацию из OnActionExecuting (когда вызывается метод действия), чтобы ее можно было дополнить информацией ответа, когда она будет завершена?

Я надеялся, что у меня будет доступ к коллекции HttpContext.Items или к чему-то похожему (что-то (а) «локальное» для текущего запроса / вызывающего абонента и (б) достаточно «постоянное», чтобы оставаться там до тех пор, пока ответ находится и был обработан) - но этого, кажется, не существует.

Как и где я могу сохранить информацию из OnActionExecuting и записать ее в журнал только после ответа обработано (в методе OnActionExecuted)

...