Sure, just override the default model binder.
public class LoggingDataBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var request = context.HttpContext.Request;
//if you only want to deal with json requests
if (request.ContentType == "application/json")
{
//can now access QueryString, URL, or InputStream
using (var sr = new StreamReader(request.InputStream))
{
var jsonData = sr.ReadToEnd();
LogMethod(jsonData);
}
}
return base.BindModel(controllerContext, bindingContext);
}
}
Then in Global.asax.cs.Application_Start()
:
protected void Application_Start(Object sender, EventArgs e)
{
ModelBinders.Binders.DefaultBinder = new LoggingModelBinder();
}
You can customize this in various ways (having this custom binder for only specific types, for specific requests, grab details from the request to log), but this would satisfy your question of how to log when model binding occurs.
EDIT
To handle logging responses, I'd suggest overriding OnResultExecuted
in your controller (or base controller) and doing like so:
protected override void OnResultExecuting(ResultExecutingContext filterContext)
{
//assuming this will be the type of all of your JSON data actions
var json = filterContext.Result as JsonResult;
if (json != null)
{
//assuming you haven't overriden the default serializer here,
//otherwise may be inconsistent with what the client sees
LogMethod(new JavaScriptSerializer().Serialize(json.Data));
}
}
Instead of doing it at this level, you could create your own ActionFilterAttribute
and decorate your controllers/action methods appropriately (e.g. only decorate action methods that return JsonResult
). Here's an old article from MSDN that would still put you on the right path to getting that done.
EDIT 2
I'm inexperienced with Web API, but I believe your best bet would be to implement a message handler:
public class JsonMessageLoggerHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
bool isJson = false;
//not tested, you may have to play with this
if (request.Content != null && request.Content.Headers.ContentType.MediaType == "application/json")
{
isJson = true;
var requestText = await request.Content.ReadAsStringAsync();
LogMethod(requestText);
}
// Call the inner handler.
var response = await base.SendAsync(request, cancellationToken);
//log the response
if (isJson)
{
var responseText = await response.Content.ReadAsStringAsync();
LogMethod(responseText);
}
return response;
}
}
Then wire up your message handler with the WebApiConfig
class:
config.MessageHandlers.Add(new APITraceLogger());
Again, I'm not experienced with Web API so you may need to play around with this (and this frankly might not be the best way to go about this). Here are some links for more details: SO Question and ASP.NET