Press "Enter" to skip to content

How to log your user’s controller actions for an ASP.Net MVC 4 website

Last updated on December 12, 2014

One of my projects is an ASP.Net MVC 4 website. While building it, I realized it would be useful to see what users do on the site.

Why you want logging of the user actions

  • You can discover functions that your users never use – which may mean you need to make them more visible, or maybe remove them.
  • You can find which actions are the most commonly used ones – which tells you what actions your users find most useful.
  • You can see if your users always call one action immediately after another – which may mean you can combine those actions on one page (making it look like less steps to your users).
  • It can show you which page is the most frequent one that users visit last – which may tell you that you need to simplify it, if users (or potential users) are abandoning your site immediately after seeing that page.

That information is extremely useful for determining what areas to work on to get new users, and keep existing users.

How I built my logging for ASP.Net MVC 4

I looked at some of the common logging libraries, and they seemed like more work to setup than to write on my own. So I decided to write my own.

Here’s the code I’m using to create a log of user activity.

First, you need to add a value to the user’s session variable. Apparently, if you don’t add at least one value, IIS may change your user’s Session.SessionID while they’re still in the same session.

Since I need the key value in a couple places, I added it to a static Constants class in my project.  That makes it easy to ensure I don’t mistype the key somewhere in the code.


using System.Collections.Generic;
namespace MyApp
    public static class Constants
        public const string SESSION_ACTIVITY_LOG_ID = "__SessionActivityLog";

Next, add a value to the user’s session variable in the Global.asax.cs file.  Place this code in the Session_Start method (or create the method, if it doesn’t already exist).


void Session_Start(object sender, EventArgs e)
    HttpContext.Current.Session.Add(Constants.SESSION_ACTIVITY_LOG_ID, Guid.NewGuid().ToString());

Now we need to create something to record the user’s action to the log. The simplest way to do this is to create a custom attribute.

Here’s the attribute I wrote – LogSessionActivityAttribute.cs.

This attribute checks if the session has a value set for the activity log ID.  That value should always exist, but I’d rather be safe and not worry about having a null exception thrown from my logging code.

If the ID exists, the attribute calls RecordPageAccess() – my logging code. RecordPageAccess writes the value of the session ID, user name, controller, and action (along with the current date/time) to a database table.

EDIT (24 April 2014): For me, SessionActionLogAccessor is a static class I created, and RecordPageAccess() does an insert of the logging values into a database table. You’ll need to create your own version of this class and method to save the logging information where you want it. Some options besides the database are a text file, an XML file, or a web service. Just remember that wherever you do the logging, make the method asynchronous, or the logging can slow down your website’s response time.

The logging is asynchronous.  There’s no need to make the user wait for a database insert that isn’t returning any values.  I also have the logging wrapped in a try…catch block that ignores any exceptions.  If the logging has an error, the users shouldn’t see any alerts about it.


using System.Web.Mvc;
using MyApp.DataAccessors;
namespace MyApp.CustomAttributes
    public class LogSessionActivityAttribute : ActionFilterAttribute
        public override void OnActionExecuting(ActionExecutingContext filterContext)
            if(filterContext.HttpContext.Session[Constants.SESSION_ACTIVITY_LOG_ID] != null)
                    // Don't raise any exceptions if the logging fails.

Now that the attribute exists, we need to have it called before every action.

The easiest way to do this in MVC is to add it to the App_Start\FilterConfig.cs class. The RegisterGlobalFilters lets you add any attributes you want executed for every action.  This saves you from needing to manually add it as an attribute before each action.

Here’s my RegisterGlobalFilters method, after adding the filter for this new logging attribute.


using System.Web.Mvc;
using MyApp.CustomAttributes;
namespace MyApp
    public class FilterConfig
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            filters.Add(new AuthorizeAttribute());
            filters.Add(new LogSessionActivityAttribute());

That’s it.

Now you’ll have a table showing you a log of the actions your users run when they use your ASP.Net MVC 4 website. This information will let you see what areas of the website need improvements, and if the improvements actually improve the user experience or retention.


  1. Anders
    Anders February 25, 2014


    I am trying to implement this in my system however in my filterconfig file It can’t seem to find LogSessionActivityAttribute, I am using mvc 5, any suggestions?


    • Scott Lilly
      Scott Lilly March 2, 2014

      Hello Anders,

      You need to add the new class named LogSessionActivityAttribute.cs. The source code for that new class is listed in the blog post above.

  2. Victor
    Victor April 22, 2014

    How about SessionActionLogAccessor ??

    • Scott Lilly
      Scott Lilly April 24, 2014

      SessionActionLogAccessor is something you’ll have to write on your own, depending on how and where you want to record the users’ action.

      For me, it’s a static class. The RecordPageAccess method inserts a new row with the parameter values into the database. You could also write them to a text file, send to a web service you write, or maybe you have some other need.

      One thing you want to remember when you write your RecordPageAccess method is to make the method asynchronous. That way, your application won’t be waiting for a response, making things slower for your users.

  3. Lorie
    Lorie April 24, 2014

    It works and easy to implement. Big thank you!

    • Scott Lilly
      Scott Lilly April 24, 2014

      You’re welcome

  4. ANIS
    ANIS September 22, 2014

    Huge thanks! 🙂 This is a very clever idea for log reporting… There is one question though! this method cannot differentiate between types of user events (resulted by actions) (login related attempts, url requesting events, etc)

    • Scott Lilly
      Scott Lilly September 23, 2014

      You’re welcome. To do deeper reporting, you’d need to create a table that lists each controller/action combination and defines what “type” it is – so, HomeController/Login would be a “Login” event.

      On my [too long] “To Do” list, I want to expand this idea into a library that would let you get deeper analytics from your MVC web app. It would give you more insight into what your users are really doing with your site, and where it may have problems.

      • ANIS
        ANIS September 24, 2014

        Great, I’m looking forward to your future tutorials

  5. Namaste00
    Namaste00 December 10, 2014

    Thanks Really Good Idea.
    I have some questions. HandleErrorAndLogAttribute() is have error for me . İt is not in default context . (in filterConfig.cs) and I have authorization problem when implemented this code. IIS cant authorizate session.
    Thanks again…

    • Scott Lilly
      Scott Lilly December 12, 2014

      The HandleErrorAndLogAttribute is another custom attribute I created in that solution to log error messages to the database. You can remove that line from your FilterConfig.cs file. If you aren’t using authorization, you can probably also remove the line with “filters.Add(new AuthorizeAttribute());”

      Let me know if that doesn’t solve the problem.

  6. lamis
    lamis September 17, 2015

    hi can u please provide the SessionActionLogAccessor class codes and big thanks

    • Scott Lilly
      Scott Lilly September 18, 2015

      You’ll need to create your own SessionActionLogAccessor. I don’t know where you want to do your logging (file, database, web service, Windows events, etc.), or what else you’re doing in your application (using Entity Framework, using a different ORM, using a logging library, etc.).

      When I wrote this for my application, SessionActionLogAccessor was a static class. The RecordPageAccess method did an asynchronous insert into the database.

  7. Sam
    Sam March 22, 2016

    Is there a way to get the entity name (code first approach) in action filter which is affected by an action.

    • Scott Lilly
      Scott Lilly March 23, 2016

      Hello Sam,

      I’m not sure how to do that. It’s been a long time since I worked on an ASP.NET/MVC application. I think you might be able to do this if you created a custom attribute, which would get the current entity, and pass it as a parameter to the attribute. But that would probably require you to manually add the attribute before each action.

      If someone else sees this message, and has a suggestion, please leave a comment.

      • Sam
        Sam March 23, 2016

        Thanks Scott.

  8. Julius
    Julius May 5, 2016

    I have some question.

    I have table ASPNET User Identity , patient, and appointment.

    Patient need some username to store table User and I can log in to the website.

    but the problem is, if I want to create appointment with username log in and I can’t store username on table user to table appointment in patient_id column.

    how to figure that ?

    Help me Scott. Thanks

    • Scott Lilly
      Scott Lilly May 5, 2016

      Hello Julius,

      I am having difficulty understanding the problem. Can you show the database table structure, and some example data? That might help me understand better.

  9. Paul Jones
    Paul Jones September 15, 2016

    Thank you for your very helpful guide.  Successfully implemented a modified version in MVC5 based on your code, logging data by overriding OnActionExecuted, so that values of session variables changed by the action could also be logged.

    • Scott Lilly
      Scott Lilly September 15, 2016

      Cool! It’s good to hear the concept still works in MVC5.

  10. Anh Tu
    Anh Tu April 26, 2018

    Hi, Its really great helpful guide. But I have a question that how to filter the actions to be logged and not?

    • Scott Lilly
      Scott Lilly April 27, 2018

      Thank you. To filter actions, you can modify the OnActionExecuting() function in LogSessionActivityAttribute.cs. Include additional “if” statements to filter the actions based on the value of “filterContext.Controller” or “filterContext.ActionDescriptor.ActionName”.

      Or you could create a new custom attribute to put before the controller actions you want to record (or exclude). Then, in OnActionExecuting(), see if the action has the tag or not, using the methods in this StackOverflow question.

      Let me know if that wasn’t clear, or if you have more questions.

  11. Imran Jalali
    Imran Jalali September 24, 2018

    That is I was looking for, moreover can you please let me know if I can log the Querying Strings Dictionaries (HTTPGet) and Forms (HttpPost) Dictionaries ??

    This will help me to understand what data was submitted by the user.

    • Scott Lilly
      Scott Lilly September 25, 2018

      Hello Imran,

      I have not worked in ASP.NET for several years, so I may not be correct. But, I think you can get those values from “filterContext.HttpContext.Request.Query”. Please let me know if you try that, and cannot find the values.

  12. pregunton
    pregunton April 11, 2019

    why not?
    filters.Add(new LogSessionActivityAttribute());
    filters.Add(new AuthorizeAttribute());

    filters.Add(new AuthorizeAttribute());
    filters.Add(new LogSessionActivityAttribute());

    • Scott Lilly
      Scott Lilly April 14, 2019

      I haven’t worked with MVC in several years, but either order will probably work.

  13. Jc Arenas
    Jc Arenas May 13, 2020

    thanks, your code help me to create a port in core!!

Leave a Reply

Your email address will not be published. Required fields are marked *