建立Log

Log的用途:

  • Debug,trace,analytics
  • 記錄exception
  • 集中管理訊息

此節將會透過「NLog」及「Exception Filters」記錄每一個Request的錯誤

實作

先切換到主專案

nuget

  • 加入 NLog
web.config
  • 加入Nlog區段
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    ...省略
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
  </configSections>
  ...省略
  <nlog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <targets>
      <target name="logfile" xsi:type="File" fileName="${basedir}/APILog/${date:format=yyyy-MM-dd}-api.log" />
      <target name="eventlog" xsi:type="EventLog" layout="${message}" log="Application" source="Api Services" />
    </targets>
    <rules>
      <logger name="*" minlevel="Trace" writeTo="logfile" />
      <logger name="*" minlevel="Trace" writeTo="eventlog" />
    </rules>
  </nlog>
</configuration>

建立Nlog的Helper

自行建立Helpers資料夾來放置Nlog的Helper

  • 繼承ITraceWriter取得web api的所有資訊
    • 主要的進入點在ITraceWriter方法
  • 記錄error /info 的訊息
JSONHelper.cs

透過JavaScriptSerializer反序列化成JSON格式

using System;
using System.Web.Script.Serialization;

namespace WebApi.Helpers
{
    public static class JSONHelper
    {
        #region Public extension methods.
        /// <summary>
        /// Extened method of object class, Converts an object to a json string.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ToJSON(this object obj)
        {
            var serializer = new JavaScriptSerializer();
            try
            {
                return serializer.Serialize(obj);
            }
            catch (Exception ex)
            {
                return "";
            }
        }
        #endregion
    }
}
NLogger.cs
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Web.Http.Tracing;

namespace WebApi.Helpers
{
    /// <summary>
    /// Public class to log Error/info messages to the access log file
    /// </summary>
    public sealed class NLogger : ITraceWriter
    {
        #region Private member variables.
        private static readonly Logger ClassLogger = LogManager.GetCurrentClassLogger();

        private static readonly Lazy<Dictionary<TraceLevel, Action<string>>> LoggingMap = new Lazy<Dictionary<TraceLevel, Action<string>>>(() => new Dictionary<TraceLevel, Action<string>> {
            { TraceLevel.Info, ClassLogger.Info },
            { TraceLevel.Debug, ClassLogger.Debug },
            { TraceLevel.Error, ClassLogger.Error },
            { TraceLevel.Fatal, ClassLogger.Fatal },
            { TraceLevel.Warn, ClassLogger.Warn } });
        #endregion

        #region Private properties.
        /// <summary>
        /// Get property for Logger
        /// </summary>
        private Dictionary<TraceLevel, Action<string>> Logger
        {
            get { return LoggingMap.Value; }
        }
        #endregion

        #region Public member methods.
        /// <summary>
        /// Implementation of TraceWriter to trace the logs.
        /// </summary>
        /// <param name="request"></param>
        /// <param name="category"></param>
        /// <param name="level"></param>
        /// <param name="traceAction"></param>
        public void Trace(HttpRequestMessage request, string category, TraceLevel level, Action<TraceRecord> traceAction)
        {
            if (level != TraceLevel.Off)
            {
                if (traceAction != null && traceAction.Target != null)
                {
                    category = category + Environment.NewLine + "Action Parameters : " + traceAction.Target.ToJSON();
                }
                var record = new TraceRecord(request, category, level);
                if (traceAction != null) traceAction(record);
                Log(record);
            }
        }
        #endregion

        #region Private member methods.
        /// <summary>
        /// Logs info/Error to Log file
        /// </summary>
        /// <param name="record"></param>
        private void Log(TraceRecord record)
        {
            var message = new StringBuilder();

            if (!string.IsNullOrWhiteSpace(record.Message))
                message.Append("").Append(record.Message + Environment.NewLine);

            if (record.Request != null)
            {
                if (record.Request.Method != null)
                    message.Append("Method: " + record.Request.Method + Environment.NewLine);

                if (record.Request.RequestUri != null)
                    message.Append("").Append("URL: " + record.Request.RequestUri + Environment.NewLine);

                if (record.Request.Headers != null && record.Request.Headers.Contains("Token") && record.Request.Headers.GetValues("Token") != null && record.Request.Headers.GetValues("Token").FirstOrDefault() != null)
                    message.Append("").Append("Token: " + record.Request.Headers.GetValues("Token").FirstOrDefault() + Environment.NewLine);
            }

            if (!string.IsNullOrWhiteSpace(record.Category))
                message.Append("").Append(record.Category);

            if (!string.IsNullOrWhiteSpace(record.Operator))
                message.Append(" ").Append(record.Operator).Append(" ").Append(record.Operation);


            Logger[record.Level](Convert.ToString(message) + Environment.NewLine);
        }
        #endregion
    }
}

建立ActionFilter

我們將會透過OnActionExecuting方法來記錄Reuest的資料至NLog

請先移至ActionFilters資料夾

LoggingFilterAttribute.cs
using System;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Web.Http.Tracing;
using WebApi.Helpers;

namespace WebApi.ActionFilters
{
    public class LoggingFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext filterContext)
        {
            //將ITraceWriter替換成NLogger類別(己實作ITraceWriter)
            GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new NLogger());
            //此時呼叫ITraceWriter實際上是透過NLogger裡的實作內容
            var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter();
            //記錄資訊
            trace.Info(filterContext.Request, "Controller : " + filterContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine + "Action : " + filterContext.ActionDescriptor.ActionName, "JSON", filterContext.ActionArguments);
        }
    }
}

註冊LoggingFilterAttribute

WebApiConfig.cs

打開主專案下的App_Start資料夾,並將之前要將每一次的Request資訊記錄到Log的ActionFilter註冊進全域設定

using System.Web.Http;
using WebApi.ActionFilters;

namespace WebApi
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 設定和服務
            //Log
            config.Filters.Add(new LoggingFilterAttribute());

            ..以下省略
        }
    }
}

記錄的Log格式

一般文字檔
2016-07-14 22:48:33.5750|INFO|WebApi.Helpers.NLogger|JSON
Method: POST
URL: http://localhost:8126/login
Controller : WebApi.Controllers.AuthenticateController
Action : Authenticate
Action Parameters : {"messageFormat":"JSON","messageArguments":[{}]}

2016-07-14 22:48:47.1250|INFO|WebApi.Helpers.NLogger|JSON
Method: GET
URL: http://localhost:8126/api/product
Token: 3e944339-bf5f-42f4-a0ea-c450e00dcdb3
Controller : WebApi.Controllers.ProductController
Action : Get
Action Parameters : {"messageFormat":"JSON","messageArguments":[{}]}

Log-發生例外的原因

之前是記錄每一筆Reqeust資訊,而現在是要改成發生例外才記錄。

移至ActionFilter資料夾

GlobalExceptionAttribute.cs
  • 繼承ExceptionFilterAttribute
  • 覆寫OnException方法
    • 將ITraceWriter替換成Nloger的服務
    • 呼叫GetTraceWriter並記錄例外訊息
using System;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Filters;
using System.Web.Http.Tracing;
using WebApi.Helpers;

namespace WebApi.ActionFilters
{
    /// <summary>
    /// Action filter to handle for Global application errors.
    /// </summary>
    public class GlobalExceptionAttribute : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext context)
        {
            GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new NLogger());
            var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter();
            trace.Error(context.Request, "Controller : " + context.ActionContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine + "Action : " + context.ActionContext.ActionDescriptor.ActionName, context.Exception);

            var exceptionType = context.Exception.GetType();

            if (exceptionType == typeof(ValidationException))
            {
                var resp = new HttpResponseMessage(HttpStatusCode.BadRequest) {
                    Content = new StringContent(context.Exception.Message), ReasonPhrase = "ValidationException",
                };
                throw new HttpResponseException(resp);

            }
            else if (exceptionType == typeof(UnauthorizedAccessException))
            {
                throw new HttpResponseException(context.Request.CreateResponse(HttpStatusCode.Unauthorized));
            }
            else
            {
                throw new HttpResponseException(context.Request.CreateResponse(HttpStatusCode.InternalServerError));
            }
        }
    }
}
NLogger.cs

針對Log方法加入Exception的判斷

using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Web.Http.Tracing;

namespace WebApi.Helpers
{
    /// <summary>
    /// Public class to log Error/info messages to the access log file
    /// </summary>
    public sealed class NLogger : ITraceWriter
    {
        ...省略

        #region Private member methods.
        /// <summary>
        /// Logs info/Error to Log file
        /// </summary>
        /// <param name="record"></param>
        /// <summary>
        /// Logs info/Error to Log file
        /// </summary>
        /// <param name="record"></param>
        private void Log(TraceRecord record)
        {
            /******  保持原本的方法-開始 *********/
            var message = new StringBuilder();

            if (!string.IsNullOrWhiteSpace(record.Message))
                message.Append("").Append(record.Message + Environment.NewLine);

            if (record.Request != null)
            {
                if (record.Request.Method != null)
                    message.Append("Method: " + record.Request.Method + Environment.NewLine);

                if (record.Request.RequestUri != null)
                    message.Append("").Append("URL: " + record.Request.RequestUri + Environment.NewLine);

                if (record.Request.Headers != null && record.Request.Headers.Contains("Token") && record.Request.Headers.GetValues("Token") != null && record.Request.Headers.GetValues("Token").FirstOrDefault() != null)
                    message.Append("").Append("Token: " + record.Request.Headers.GetValues("Token").FirstOrDefault() + Environment.NewLine);
            }

            if (!string.IsNullOrWhiteSpace(record.Category))
                message.Append("").Append(record.Category);

            if (!string.IsNullOrWhiteSpace(record.Operator))
                message.Append(" ").Append(record.Operator).Append(" ").Append(record.Operation);
             /********* 維持原本的方法-結束 *************/

            //加入Exception的判斷
            if (record.Exception != null && !string.IsNullOrWhiteSpace(record.Exception.GetBaseException().Message))
            {
                var exceptionType = record.Exception.GetType();
                message.Append(Environment.NewLine);
                message.Append("").Append("Error: " + record.Exception.GetBaseException().Message + Environment.NewLine);
            }

            //維持原本的方法
            Logger[record.Level](Convert.ToString(message) + Environment.NewLine);
        }
        #endregion


    }
}

註冊GlobalExceptionAttribute

WebApiConfig.cs

打開主專案下的App_Start資料夾,並將之前要將每一次的Request資訊記錄到Log的ActionFilter註冊進全域設定

using System.Web.Http;
using WebApi.ActionFilters;

namespace WebApi
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 設定和服務
            //exception
            config.Filters.Add(new GlobalExceptionAttribute());
            ..以下省略
        }
    }
}

測試方式

新增資料時不傳送任何資料,會記錄的Log格式如下:

HttpPost -> http://localhost/api/product/

若有啟用RoutePrefix,記得在Action上加入[Route("")]才能正常運作

一般文字檔
2016-07-14 23:36:49.1554|ERROR|WebApi.Helpers.NLogger|Method: POST
URL: http://localhost:8126/api/product/
Token: 3e944339-bf5f-42f4-a0ea-c450e00dcdb3
Controller : WebApi.Controllers.ProductController
Action : Post
Action Parameters : 
Error: 並未將物件參考設定為物件的執行個體。

自訂例外訊息

移至Helpers資料夾,並建立以下檔案

ServiceStatus.cs
using System;
using System.Runtime.Serialization;
using Newtonsoft.Json;

namespace WebApi.Helpers
{
    #region Status Object Class
    /// <summary>
    /// Public class to return input status
    /// </summary>
    [Serializable]
    [DataContract]
    public class ServiceStatus
    {
        #region Public properties.
        /// <summary>
        /// Get/Set property for accessing Status Code
        /// </summary>
        [JsonProperty("StatusCode")]
        [DataMember]
        public int StatusCode { get; set; }
        /// <summary>
        /// Get/Set property for accessing Status Message
        /// </summary>
        [JsonProperty("StatusMessage")]
        [DataMember]
        public string StatusMessage { get; set; }
        /// <summary>
        /// Get/Set property for accessing Status Message
        /// </summary>
        [JsonProperty("ReasonPhrase")]
        [DataMember]
        public string ReasonPhrase { get; set; }

        #endregion
    }

    #endregion
}

建立ErrorHelper資料夾,並建立以下檔案

IApiExceptions.cs
  • 錯誤訊息
  • 錯誤代碼
  • HttpStatusCode
using System.Net;

namespace WebApi.ErrorHelper
{
    /// <summary>
    /// IApiExceptions Interface
    /// </summary>
    public interface IApiExceptions
    {
        /// <summary>
        /// ErrorCode
        /// </summary>
        int ErrorCode { get; set; }
        /// <summary>
        /// ErrorDescription
        /// </summary>
        string ErrorDescription { get; set; }
        /// <summary>
        /// HttpStatus
        /// </summary>
        HttpStatusCode HttpStatus { get; set; }
        /// <summary>
        /// ReasonPhrase
        /// </summary>
        string ReasonPhrase { get; set; }
    }
}
ApiDataException.cs

記錄資料層級的Exception

using System;
using System.Net;
using System.Runtime.Serialization;

namespace WebApi.ErrorHelper
{
    /// <summary>
    /// Api Data Exception
    /// </summary>
    [Serializable]
    [DataContract]
    public class ApiDataException : Exception, IApiExceptions
    {
        #region Public Serializable properties.
        [DataMember]
        public int ErrorCode { get; set; }
        [DataMember]
        public string ErrorDescription { get; set; }
        [DataMember]
        public HttpStatusCode HttpStatus { get; set; }

        string reasonPhrase = "ApiDataException";

        [DataMember]
        public string ReasonPhrase
        {
            get { return this.reasonPhrase; }

            set { this.reasonPhrase = value; }
        }

        #endregion

        #region Public Constructor.
        /// <summary>
        /// Public constructor for Api Data Exception
        /// </summary>
        /// <param name="errorCode"></param>
        /// <param name="errorDescription"></param>
        /// <param name="httpStatus"></param>
        public ApiDataException(int errorCode, string errorDescription, HttpStatusCode httpStatus)
        {
            ErrorCode = errorCode;
            ErrorDescription = errorDescription;
            HttpStatus = httpStatus;
        }
        #endregion
    }
}
ApiBusinessException.cs

記錄商業邏輯層的Exception

using System;
using System.Net;
using System.Runtime.Serialization;

namespace WebApi.ErrorHelper
{
    /// <summary>
    /// Api Business Exception
    /// </summary>
    [Serializable]
    [DataContract]
    public class ApiBusinessException : Exception, IApiExceptions
    {
        #region Public Serializable properties.
        [DataMember]
        public int ErrorCode { get; set; }
        [DataMember]
        public string ErrorDescription { get; set; }
        [DataMember]
        public HttpStatusCode HttpStatus { get; set; }

        string reasonPhrase = "ApiBusinessException";

        [DataMember]
        public string ReasonPhrase
        {
            get { return this.reasonPhrase; }

            set { this.reasonPhrase = value; }
        }
        #endregion

        #region Public Constructor.
        /// <summary>
        /// Public constructor for Api Business Exception
        /// </summary>
        /// <param name="errorCode"></param>
        /// <param name="errorDescription"></param>
        /// <param name="httpStatus"></param>
        public ApiBusinessException(int errorCode, string errorDescription, HttpStatusCode httpStatus)
        {
            ErrorCode = errorCode;
            ErrorDescription = errorDescription;
            HttpStatus = httpStatus;
        }
        #endregion

    }
}
ApiException.cs

記錄API的Exception

using System;
using System.Net;
using System.Runtime.Serialization;

namespace WebApi.ErrorHelper
{
    /// <summary>
    /// Api Exception
    /// </summary>
    [Serializable]
    [DataContract]
    public class ApiException : Exception, IApiExceptions
    {
        #region Public Serializable properties.
        [DataMember]
        public int ErrorCode { get; set; }
        [DataMember]
        public string ErrorDescription { get; set; }
        [DataMember]
        public HttpStatusCode HttpStatus { get; set; }

        string reasonPhrase = "ApiException";

        [DataMember]
        public string ReasonPhrase
        {
            get { return this.reasonPhrase; }

            set { this.reasonPhrase = value; }
        }
        #endregion
    }
}
NLogger.cs

針對Log方法加入自訂Exception的判斷

using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Web.Http.Tracing;

namespace WebApi.Helpers
{
    /// <summary>
    /// Public class to log Error/info messages to the access log file
    /// </summary>
    public sealed class NLogger : ITraceWriter
    {
        ...省略

        #region Private member methods.
        /// <summary>
        /// Logs info/Error to Log file
        /// </summary>
        /// <param name="record"></param>
        /// <summary>
        /// Logs info/Error to Log file
        /// </summary>
        /// <param name="record"></param>
        private void Log(TraceRecord record)
        {
            /******  保持原本的方法-開始 *********/
            var message = new StringBuilder();

            if (!string.IsNullOrWhiteSpace(record.Message))
                message.Append("").Append(record.Message + Environment.NewLine);

            if (record.Request != null)
            {
                if (record.Request.Method != null)
                    message.Append("Method: " + record.Request.Method + Environment.NewLine);

                if (record.Request.RequestUri != null)
                    message.Append("").Append("URL: " + record.Request.RequestUri + Environment.NewLine);

                if (record.Request.Headers != null && record.Request.Headers.Contains("Token") && record.Request.Headers.GetValues("Token") != null && record.Request.Headers.GetValues("Token").FirstOrDefault() != null)
                    message.Append("").Append("Token: " + record.Request.Headers.GetValues("Token").FirstOrDefault() + Environment.NewLine);
            }

            if (!string.IsNullOrWhiteSpace(record.Category))
                message.Append("").Append(record.Category);

            if (!string.IsNullOrWhiteSpace(record.Operator))
                message.Append(" ").Append(record.Operator).Append(" ").Append(record.Operation);
             /********* 維持原本的方法-結束 *************/


            if (record.Exception != null && !string.IsNullOrWhiteSpace(record.Exception.GetBaseException().Message))
            {
                //加入自訂Exception的判斷邏輯
                var exceptionType = record.Exception.GetType();
                message.Append(Environment.NewLine);
                if (exceptionType == typeof(ApiException))
                {
                    var exception = record.Exception as ApiException;
                    if (exception != null)
                    {
                        message.Append("").Append("Error: " + exception.ErrorDescription + Environment.NewLine);
                        message.Append("").Append("Error Code: " + exception.ErrorCode + Environment.NewLine);
                    }
                }
                else if (exceptionType == typeof(ApiBusinessException))
                {
                    var exception = record.Exception as ApiBusinessException;
                    if (exception != null)
                    {
                        message.Append("").Append("Error: " + exception.ErrorDescription + Environment.NewLine);
                        message.Append("").Append("Error Code: " + exception.ErrorCode + Environment.NewLine);
                    }
                }
                else if (exceptionType == typeof(ApiDataException))
                {
                    var exception = record.Exception as ApiDataException;
                    if (exception != null)
                    {
                        message.Append("").Append("Error: " + exception.ErrorDescription + Environment.NewLine);
                        message.Append("").Append("Error Code: " + exception.ErrorCode + Environment.NewLine);
                    }
                }
                else
                    message.Append("").Append("Error: " + record.Exception.GetBaseException().Message + Environment.NewLine);
            }

            //維持原本的方法
            Logger[record.Level](Convert.ToString(message) + Environment.NewLine);
        }
        #endregion


    }
}
GlobalExceptionAttribute.cs

加入自訂Exception的判斷

using System;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Filters;
using System.Web.Http.Tracing;
using WebApi.ErrorHelper;
using WebApi.Helpers;

namespace WebApi.ActionFilters
{
    /// <summary>
    /// Action filter to handle for Global application errors.
    /// </summary>
    public class GlobalExceptionAttribute : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext context)
        {
            GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new NLogger());
            var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter();
            trace.Error(context.Request, "Controller : " + context.ActionContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine + "Action : " + context.ActionContext.ActionDescriptor.ActionName, context.Exception);

            var exceptionType = context.Exception.GetType();

            if (exceptionType == typeof(ValidationException))
            {
                var resp = new HttpResponseMessage(HttpStatusCode.BadRequest) {
                    Content = new StringContent(context.Exception.Message),
                    ReasonPhrase = "ValidationException", };
                throw new HttpResponseException(resp);

            }
            else if (exceptionType == typeof(UnauthorizedAccessException))
            {
                throw new HttpResponseException(context.Request.CreateResponse(HttpStatusCode.Unauthorized, new ServiceStatus() { StatusCode = (int)HttpStatusCode.Unauthorized, StatusMessage = "UnAuthorized", ReasonPhrase = "UnAuthorized Access" }));
            }
            else if (exceptionType == typeof(ApiException))
            {
                var webapiException = context.Exception as ApiException;
                if (webapiException != null)
                    throw new HttpResponseException(context.Request.CreateResponse(webapiException.HttpStatus, new ServiceStatus() { StatusCode = webapiException.ErrorCode, StatusMessage = webapiException.ErrorDescription, ReasonPhrase = webapiException.ReasonPhrase }));
            }
            //加入自訂的Exception
            else if (exceptionType == typeof(ApiBusinessException))
            {
                var businessException = context.Exception as ApiBusinessException;
                if (businessException != null)
                    throw new HttpResponseException(context.Request.CreateResponse(businessException.HttpStatus, new ServiceStatus() { StatusCode = businessException.ErrorCode, StatusMessage = businessException.ErrorDescription, ReasonPhrase = businessException.ReasonPhrase }));
            }
            else if (exceptionType == typeof(ApiDataException))
            {
                var dataException = context.Exception as ApiDataException;
                if (dataException != null)
                    throw new HttpResponseException(context.Request.CreateResponse(dataException.HttpStatus, new ServiceStatus() { StatusCode = dataException.ErrorCode, StatusMessage = dataException.ErrorDescription, ReasonPhrase = dataException.ReasonPhrase }));
            }
            else
            {
                throw new HttpResponseException(context.Request.CreateResponse(HttpStatusCode.InternalServerError));
            }
        }
    }
}
ProductController.cs

修改Controller拋出例外的方式

[Route("v2/productid/{id:int}")]
[Route("v2/particularproduct/{id:int}")]
[Route("v2/myproduct/{id:range(1, 3)}")]
[Route("{id}")]
// GET api/product/5
public HttpResponseMessage Get(int id)
{

    if (id > 0)
    {
        var product = _productServices.GetProductById(id);
        if (product != null){
            return Request.CreateResponse(HttpStatusCode.OK, product);
       }

       //原本回傳錯誤訊息的方式
      //return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No product found for this id");

      //改為拋出例外
      throw new ApiDataException(1001, "No product found for this id.", HttpStatusCode.NotFound);
    }

    throw new ApiException() { ErrorCode = (int)HttpStatusCode.BadRequest, ErrorDescription = "Bad Request..." };
}


// DELETE api/product/5
public bool Delete(int id)
{
    if (id > 0)
    {
        var isSuccess = _productServices.DeleteProduct(id);
        if (isSuccess)
        {
            return true;
        }
        throw new ApiDataException(1002, "Product is already deleted or not exist in system.", HttpStatusCode.NoContent);
    }
    throw new ApiException() { ErrorCode = (int)HttpStatusCode.BadRequest, ErrorDescription = "Bad Request..." };
}

測試方式

HttpGet -> http://localhost:8126/api/product/1231

記錄的錯誤訊息

記錄的檔案格式如下

一般文字檔

若是透過自訂的拋出例外方式,會額外記錄以下欄位:

  • Error(錯誤訊息)
  • Error Code(錯誤代碼)
//回傳的方法:
//return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No product found for this id");
2016-07-15 17:51:02.5458|INFO|WebApi.Helpers.NLogger|JSON
Method: GET
URL: http://localhost:8126/api/product/1231
Token: 0e9808df-28e8-44d9-b32e-27c036147500
Controller : WebApi.Controllers.ProductController
Action : Get
Action Parameters : {"messageFormat":"JSON","messageArguments":[{"id":1231}]}

//回傳的方法:
//throw new ApiDataException(1001, "No product found for this id.", HttpStatusCode.NotFound);
2016-07-15 17:51:04.6592|ERROR|WebApi.Helpers.NLogger|Method: GET
URL: http://localhost:8126/api/product/1231
Token: 0e9808df-28e8-44d9-b32e-27c036147500
Controller : WebApi.Controllers.ProductController
Action : Get
Action Parameters : 
Error: No product found for this id.
Error Code: 1001

results matching ""

    No results matching ""