[.NET] 在WebAPI中使用AOP的方式,在控制器中加入Attribute集中進行Log的處理

在前一篇文章[.NET] 在WebAPI中使用AOP的方式,控制器中加入Attribute集中進行例外狀態的處理
說明了如何透過AOP的方式攔截Exception的方式,當然也可以透過AOP的處理,來寫入Log的內容
這篇文章中,會說明了如何在控制器中加入一個Attribute,就可以把在控制器中的輸入與輸出完全寫入至Log中

要在控制器中加入對應的Attribute,並直接將輸入與輸出的參數寫入至Log,這個功能製作起來非常的簡單

首先先在WebAPI的專案中加入一個類別庫LogHandle.cs

接著將下面的程式碼加入至該類別庫中

using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.IO;
using Newtonsoft.Json;

/// <summary>
/// 進行Log處理的類別物件
/// </summary>
public class LogHandle : ActionFilterAttribute
{
    /// <summary>
    /// 實際寫入Log的動作
    /// </summary>
    /// <param name="strAction">動作類別字串</param>
    /// <param name="strContent">寫入Log的內容</param>
    private void WriteLogContent(string strAction, string strContent)
    {
        string strLineContent = DateTime.Now.ToString("yyyyMMdd HH:mm:ss") + " Type:" + strAction + " Content:" + strContent;
        File.AppendAllLines(@"D:\Log\File.txt", new string[] { strLineContent });
    }
}

在這個LogHandle.cs的類別庫中,讓LogHandle繼承ActionFilterAttribute這個物件,並覆寫OnActionExecuting與OnActionExecuted這兩個事件

/// <summary>
/// 當WebAPI的控制器剛被啟動的時候,會進入至這個覆寫的事件中
/// </summary>
/// <param name="actionContext"></param>
public override void OnActionExecuting(HttpActionContext actionContext)
{
    // 因為傳入的參數為多數,所以ActionArguments必須用迴圈將之取出
    foreach (var item in actionContext.ActionArguments)
    {
        // 取出傳入的參數名稱
        string strParamName = item.Key;

        // 取出傳入的內容並作Json資料的處理
        string strContent = strParamName + ":" + JsonConvert.SerializeObject(item.Value);

        // 寫入Log
        this.WriteLogContent("Input", strContent);
    }
}

OnActionExecuting的事件,主要是發生在當WebAPI被呼叫,且一進入控制器中的Action時會引發的事件,所以在這個事件裡,透過迴圈的方式,將傳入的參數與資料取出後,並寫入Log之中

/// <summary>
/// 當WebAPI的控制器結束動作,會進入這個覆寫的事件中
/// </summary>
/// <param name="actionExecutedContext"></param>
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
    // 將actionExecutedContext.Response.Content轉換成Json的字串
    string strResponseContent = JsonConvert.SerializeObject(actionExecutedContext.Response.Content);

    // 將Json字串轉換成我們自訂的ResponseContentModel物件
    ResponseContentModel objResponseContent = JsonConvert.DeserializeObject<ResponseContentModel>(strResponseContent);

    // 取出從WebAPI回傳的物件,並轉會成Json字串
    string strContent = JsonConvert.SerializeObject(objResponseContent.Value);

    // 寫入Log
    this.WriteLogContent("Output", strContent);
}

OnActionExecuted的事件,則是發生在將值return出WebAPI的事件之後,也就是當這個Action結束時引發的,而在這個事件中,透過JsonConvert的方式,將Response.Content的內容轉換成字串,再轉出成為我們需要的物件,因為Response的內容很多,但是如果我們只想要將最後回傳的內容寫入到Log的話,就必須取出Response.Content.Value這個物件,所以不得不透過這樣的方式將值作取得。
當然,取得之後,就可以透過寫入Log的副程式寫入Log

接著,我們加入一個新的控制器,並命名為LogSample

接著我們在LogSample裡,加入一個簡單的Post事件

[HttpPost]
[ActionName("WriteLogSample")]
[LogHandle]
public WriteLogSampleResultModel Post(WriteLogSampleModel value)
{
    // 在這裡處理一些事,然後return物件
    WriteLogSampleResultModel objResult = new WriteLogSampleResultModel()
    {
        IsGet = true,
        Message = "我收到你的資料了",
    };

    return objResult;
}

public class WriteLogSampleModel
{
    public string Name { get; set; }
    public int Age { get; set; }
    public DateTime Birthday { get; set; }
}

/// <summary>
/// 輸出WebAPI的物件模型
/// </summary>
public class WriteLogSampleResultModel
{
    public bool IsGet { get; set; }
    public string Message { get; set; }
}

這個Action中,傳入了一個我們自訂的物件WriteLogSampleModel,並回傳了WriteLogSampleResultModel物件

這裡的重點是,必須在這個Action上,加入[LogHandle]的屬性,切記

接下來,就可以實際執行一下這個WebAPI的功能了,下圖是透過Postman呼叫WebAPI的動作,可以看到這個WebAPI是有正確回傳我們要的結果的

最後,我們打開在WriteLogContent這個副程式裡,寫入指定路徑的Log檔內容,可以看到傳入WebAPI的參數物件,以及要回傳出WebAPI的物件內容都有被正確的寫入到Log檔之中了

透過AOP的方式,採用ActionFilterAttribute的處理,可以在最小幅度改寫現有程式的情況下,取得在WebAPI中Request以及Response的內容,並寫入至所需的位置、儲存體或是資料庫,是個非常便利的處理方式。

程式碼下載
https://github.com/madukapai/maduka-WebAPI