IIS에서 호스팅되는 Microsoft Asp.net WebApi2를 사용하고 있습니다. 요청 본문 (XML 또는 JSON)과 각 게시물에 대한 응답 본문을 기록하고 싶습니다.
이 프로젝트 또는 게시물을 처리하는 컨트롤러에는 특별한 것이 없습니다. 필요한 경우가 아니면 nLog, elmah, log4net 또는 웹 API의 기본 제공 추적 기능과 같은 로깅 프레임 워크를 사용하는 데 관심이 없습니다.
로깅 코드를 어디에 넣을지, 수신 및 발신 요청 및 응답에서 실제 JSON 또는 XML을 얻는 방법을 알고 싶습니다.
내 컨트롤러 게시 방법 :
public HttpResponseMessage Post([FromBody])Employee employee)
{
if (ModelState.IsValid)
{
// insert employee into to the database
}
}
답변
나는 DelegatingHandler
. 그러면 컨트롤러의 로깅 코드에 대해 걱정할 필요가 없습니다.
public class LogRequestAndResponseHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Content != null)
{
// log request body
string requestBody = await request.Content.ReadAsStringAsync();
Trace.WriteLine(requestBody);
}
// let other handlers process the request
var result = await base.SendAsync(request, cancellationToken);
if (result.Content != null)
{
// once response body is ready, log it
var responseBody = await result.Content.ReadAsStringAsync();
Trace.WriteLine(responseBody);
}
return result;
}
}
Trace.WriteLine
로깅 코드로 바꾸고 다음 과 WebApiConfig
같이 핸들러를 등록하십시오 .
config.MessageHandlers.Add(new LogRequestAndResponseHandler());
다음은 메시지 처리기에 대한 전체 Microsoft 설명서입니다 .
답변
모든 WebAPI 메서드 호출에 대한 요청 / 응답 로깅을 일반적으로 처리하는 방법에는 여러 가지가 있습니다.
-
ActionFilterAttribute
: 사용자 정의를 작성ActionFilterAttribute
하고 로깅을 활성화하기 위해 컨트롤러 / 액션 메서드를 장식 할 수 있습니다.단점 : 모든 컨트롤러 / 방법을 장식해야합니다 (여전히 기본 컨트롤러에서 할 수 있지만 교차 절단 문제는 해결되지 않습니다.
-
BaseController
거기에서 로깅을 무시 하고 처리합니다.단점 : 컨트롤러가 사용자 지정 기본 컨트롤러에서 상속 할 것으로 예상 / 강제합니다.
-
사용
DelegatingHandler
.장점 : 여기서는이 접근 방식으로 컨트롤러 / 방법을 건드리지 않습니다. 위임 처리기는 격리되어 있으며 요청 / 응답 로깅을 정상적으로 처리합니다.
더 자세한 기사는이 http://weblogs.asp.net/fredriknormen/log-message-request-and-response-in-asp-net-webapi를 참조 하십시오 .
답변
옵션 중 하나는 액션 필터를 만들고 WebApiController / ApiMethod를 장식하는 것입니다.
필터 속성
public class MyFilterAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.Request.Method == HttpMethod.Post)
{
var postData = actionContext.ActionArguments;
//do logging here
}
}
}
WebApi 컨트롤러
[MyFilterAttribute]
public class ValuesController : ApiController{..}
또는
[MyFilterAttribute]
public void Post([FromBody]string value){..}
도움이 되었기를 바랍니다.
답변
요청 메시지에 액세스하는 것은 쉽습니다. 귀하의 기본 클래스는ApiController
포함 .Request
속성을 이름에서 알 수 있듯이, 구문 분석 된 형태로 요청을 포함. 로깅하려는 것이 무엇이든간에 검사하고 로깅 시설로 전달하기 만하면됩니다. 이 코드는 한 번 또는 몇 번만 수행해야하는 경우 작업 시작 부분에 넣을 수 있습니다.
모든 작업에 대해 수행해야하는 경우 (모두 관리 할 수있는 소수 이상의 의미), .ExecuteAsync
컨트롤러에 대한 모든 작업 호출을 캡처하는 메서드를 재정의 하는 것입니다.
public override Task<HttpResponseMessage> ExecuteAsync(
HttpControllerContext controllerContext,
CancellationToken cancellationToken
)
{
// Do logging here using controllerContext.Request
return base.ExecuteAsync(controllerContext, cancellationToken);
}
답변
이것은 꽤 오래된 스레드처럼 보이지만 다른 솔루션을 공유하고 있습니다.
HTTP 요청이 종료 될 때마다 트리거되는 global.asax 파일에이 메서드를 추가 할 수 있습니다.
void Application_EndRequest(Object Sender, EventArgs e)
{
var request = (Sender as HttpApplication).Request;
var response = (Sender as HttpApplication).Response;
if (request.HttpMethod == "POST" || request.HttpMethod == "PUT")
{
byte[] bytes = request.BinaryRead(request.TotalBytes);
string body = Encoding.UTF7.GetString(bytes);
if (!String.IsNullOrEmpty(body))
{
// Do your logic here (Save in DB, Log in IIS etc.)
}
}
}
답변
이것은 정말 오래된 주제이지만 이러한 작업을 수행하는 데 많은 시간 (인터넷 검색)을 보냈으므로 여기에 솔루션을 게시하겠습니다.
개념
- 인바운드 요청을 추적하기 위해 APicontroller 메서드의 ExecuteAsync를 재정의합니다. 솔루션에서 Base_ApiController를 프로젝트 API 컨트롤러의 부모로 만듭니다.
- System.Web.Http.Filters.ActionFilterAttribute를 사용하여 API 컨트롤러의 아웃 바운드 응답 추적
- *** (추가) *** System.Web.Http.Filters.ExceptionFilterAttribute를 사용하여 예외 발생시 기록합니다.
1. MyController.cs
[APIExceptionFilter] // use 3.
[APIActionFilter] // use 2.
public class Base_APIController : ApiController
{
public bool IsLogInbound
{
get
{ return ConfigurationManager.AppSettings["LogInboundRequest"] =="Y"? true:false ; }
}
/// <summary>
/// for logging exception
/// </summary>
/// <param name="controllerContext"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public override Task<HttpResponseMessage> ExecuteAsync(
HttpControllerContext controllerContext,
CancellationToken cancellationToken
)
{
// Do logging here using controllerContext.Request
// I don't know why calling the code below make content not null Kanit P.
var content = controllerContext.Request.Content.ReadAsStringAsync().Result.ToString(); // keep request json content
// Do your own logging!
if (IsLogInbound)
{
try
{
ErrLog.Insert(ErrLog.type.InboundRequest, controllerContext.Request,
controllerContext.Request.RequestUri.AbsoluteUri
, content);
}
catch (Exception e) { }
}
// will not log err when go to wrong controller's action (error here but not go to APIExceptionFilter)
var t = base.ExecuteAsync(controllerContext, cancellationToken);
if (!t.Result.IsSuccessStatusCode)
{
}
return t;
}
2. APIActionFilter.cs
public class APIActionFilter : System.Web.Http.Filters.ActionFilterAttribute
{
public bool LogOutboundRequest
{
get
{ return ConfigurationManager.AppSettings["LogInboundRequest"] == "Y" ? true : false; }
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
try {
var returndata = actionExecutedContext.Response.Content.ReadAsStringAsync().Result.ToString();
//keep Json response content
// Do your own logging!
if (LogOutboundRequest)
{
ErrLog.Insert(ErrLog.type.OutboundResponse, actionExecutedContext.Response.Headers,
actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerName
+ "/"
+ actionExecutedContext.ActionContext.ActionDescriptor.ActionName
, returndata );
}
} catch (Exception e) {
}
}
}
}
3. APIExceptionFilter.cs
public class APIExceptionFilter : ExceptionFilterAttribute
{
public bool IsLogErr
{
get
{ return ConfigurationManager.AppSettings["LogExceptionRequest"] == "Y" ? true : false; }
}
public override void OnException(HttpActionExecutedContext context)
{
try
{
//Do your own logging!
if (IsLogErr)
{
ErrLog.Insert(ErrLog.type.APIFilterException, context.Request,
context.ActionContext.ControllerContext.ControllerDescriptor.ControllerName
+ "/"
+ context.ActionContext.ActionDescriptor.ActionName
, context.Exception.ToString() + context.Exception.StackTrace);
}
}catch(Exception e){
}
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
}
else {
context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
}
}