26

I have an ASP.NET MVC application for which I want to log events. I have already a Log class with all the tools I need, but I have to instantiate and to close it explicitly (because it opens files, so I can't depend on the GC). My actions would look like this:

public ActionResult MainMenu()
{
    CreateLog();

    // Do controller stuff
    Log(message);
    // Do more controller stuff

    CloseLog();
    return View(mModel);
}

Or I could use a using block, but it would be just a little less intrusive AND it would create troubles with exception handling. I've read about ActionFilters, which I could use to create and close my Log, but then I would have no way to access the Log object inside the method.

Do you have any suggestion? How could I avoid having to repeat the code?

Simone
  • 1,260
  • 1
  • 16
  • 27
  • Possible duplicate of [Run a method in each request in MVC, C#?](https://stackoverflow.com/questions/9511462/run-a-method-in-each-request-in-mvc-c) – Liam Jan 24 '18 at 13:15

3 Answers3

50

If the other suggestions don't work or if you need to do things other than just logging also be aware that you can override the OnActionExecuting method (often in a base class for reuse).

// Custom controller.
public class CustomController : Controller
{
    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // Do whatever here...
    }
}

// Home controller.
public class HomeController : CustomController
{
    // Action methods here...
}
David Godwin
  • 721
  • 5
  • 5
0

I would recommend you to push in a Logger (probably ILogger) object as a dependency to your controller. You can control the lifetime of this logger object by a DI container (Unity, for example) - and if neccessary you can define its lifetime as request scoped. The other benefit of this soution that your code will remain testable.

aberkes
  • 134
  • 1
  • 5
  • Quite good, but how would I go about logging in methods that are not members of the controller? – Simone Oct 10 '14 at 12:38
  • You can simply pass your logger object to any other methods so they can also use it. Alternatively if it suit better for your needs you can implement your logger (or simply wrap your already existing logger implementation) as [Ambient Context](http://blogs.msdn.com/b/ploeh/archive/2007/07/23/ambientcontext.aspx). – aberkes Oct 10 '14 at 12:41
  • I like the Ambient Context solution (while I would rather not pass the Log around, as I'd prefer my method not to know so much about a cross-cutting concern). However, what about thread safety? I need to close open log files, so every time (at the end of the request), I have to close the Log. I can't have a singleton (or quasi-singleton), otherwise it'd exist across requests. Multiple Logs would try to open the same file, failing (and losing events); a single Log may close the file while another requested action still has stuff to log. – Simone Oct 10 '14 at 13:47
  • If I understand correctly you have a class (let's call it "A") that is used by your controller. The use case is you want to use your logger implementation both in class "A" and in your controller. Then you can inject your Logger both into class "A" and into your controller also. – aberkes Oct 10 '14 at 14:02
  • In other words: your application components (controllers, services or any other classes that contains business logic) should not know anything about the logging mechanism. They only should have to know that there's a logger object which will log my events. No matter how. What if you want to store your logs in database in the future? Then you have to change every piece of code where your open-log-close logic is present. So I would put the file handling INSIDE the logger implementation. – aberkes Oct 10 '14 at 15:22
  • It IS inside the logger application, and I already have set up the logger so that it handles multiple outputs. The thing is, no matter how you look at it, the file is opened when the log is created, and is locked until the log is destroyed. – Simone Oct 13 '14 at 08:10
  • If you propagate an OpenLog and CloseLog method on your logger interface then the caller side will be responsible for when the log resource (maybe a file) should be opened or closed. In my opinion this responsibility should be somewhere else and the only thing the caller should access is a simple Log method. – aberkes Oct 13 '14 at 08:19
  • I agree, @aberkes. But I can't rely on the GC to decide when the logger should be destroyed (and the file released), because in the meantime another request may have started and another logger may be created. As of now, this is my biggest problem. – Simone Oct 13 '14 at 08:28
0

you can use modules because they both sit in a pipeline and can provide pre and post processing for the core execution of a request. BeginRequest / ActionExecuting and EndRequest / ResultExecuted. They both also provide authorization hooks.

http://msdn.microsoft.com/en-us/library/aa719858(v=vs.71).aspx

Fabio
  • 1,890
  • 1
  • 15
  • 19