xingtan
xingtan

Reputation: 53

ASP.NET Core Logging With ActionFilter

I am trying to add a logging function to save to my SQL server database. I tried to create ActionFilter class and apply on one of my controller but not working. i want to capture userid, IP address, controller and action visit and timestamp. What am i missing?

AuditAttribute Action Filter class

public class AuditAttribute : ActionFilterAttribute
{
    private readonly ApplicationDbContext _db;

    //Inject ApplicationDBContext
    public AuditAttribute(ApplicationDbContext db)
    {
        _db = db;
    }

    IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {

         //Stores the Request in an Accessible object
         var request = filterContext.HttpContext.Request;

        //Generate an audit
        Portal_Logger audit = new Portal_Logger()
        {
            teacherNRIC = filterContext.HttpContext.User.Identity.Name,
            IPAddress = Convert.ToString(ipHostInfo.AddressList.FirstOrDefault(address => address.AddressFamily == AddressFamily.InterNetwork)),
            ControllerAccess = (string)filterContext.RouteData.Values["controller"],
            Timestamp = DateTime.Now,
        };

         public DbSet<Portal_Logger> Portal_LoggerDBSet { get; set; }
        //Store objects to database
        _db.Portal_LoggerDBSet.Add(audit);
        _db.SaveChanges();

        base.OnActionExecuting(filterContext);
    }

}
}     


Home controller class
[AuditAttribute]
public class HomeController : Controller
{ ..content of controller
}


Portal_logger model class
public class Portal_Logger
{
    [Key]
    public int LoggerId { get; set; }

    [StringLength(10)]
    public string userid{ get; set; }

    [StringLength(50)]
    public string IPAddress { get; set; }

    [StringLength(50)]
    public string ControllerAccess { get; set; }

    public DateTime? Timestamp { get; set; }

}

Please see the error message as attached image Screenshot of error message

I tried and have a new issue. enter image description here

I tried this method also not working. [AuditActionFilter] -> Error message (AuditActionFilter is not an attribute class)

public class HomeController : Controller
{
}

I tried this method but not working still.

[AuditActionFilter] - error message -> "AuditActionFilter" is not an 
public class HomeController : Controller
{
}

I have added services.AddMVC to startup.cs
services.AddMvc(options => options.Filters.Add(typeof(AuditActionFilter)));

This is the AuditActionFilter.cs

public class AuditActionFilter : IActionFilter
{
    private readonly ApplicationDbContext _db;

    public AuditActionFilter(ApplicationDbContext db)
    {
        _db = db;
    }

    IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {

        var request = filterContext.HttpContext.Request;

        Portal_Logger audit = new Portal_Logger()
        {
            teacherNRIC = filterContext.HttpContext.User.Identity.Name,
            IPAddress = Convert.ToString(ipHostInfo.AddressList.FirstOrDefault(address => address.AddressFamily == AddressFamily.InterNetwork)),
            ControllerAccess = (string)filterContext.RouteData.Values["controller"],
            Timestamp = DateTime.Now,
        };

        //Store objects to database
        _db.Portal_LoggerDBSet.Add(audit);
        _db.SaveChanges();
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // do something after the action executes or leave it empty
    }

}

Upvotes: 3

Views: 16012

Answers (4)

tomasat
tomasat

Reputation: 598

To use the attribute without having to resort to [TypeFilter(typeof(AuditAttribute))] or [ServiceFilter(typeof(AuditAttribute))] it should be possible to get the ApplicationDbContext by using filterContext.HttpContext.RequestServices.GetService instead of through the constructor.

public class AuditActionFilter : IActionFilter
{

public AuditActionFilter(){}

IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());

public void OnActionExecuting(ActionExecutingContext filterContext)
{
    ApplicationDbContext _db = filterContext.HttpContext.RequestServices.GetService<ApplicationDbContext>();

    var request = filterContext.HttpContext.Request;

    Portal_Logger audit = new Portal_Logger()
    {
        teacherNRIC = filterContext.HttpContext.User.Identity.Name,
        IPAddress = Convert.ToString(ipHostInfo.AddressList.FirstOrDefault(address => address.AddressFamily == AddressFamily.InterNetwork)),
        ControllerAccess = (string)filterContext.RouteData.Values["controller"],
        Timestamp = DateTime.Now,
    };

    //Store objects to database
    _db.Portal_LoggerDBSet.Add(audit);
    _db.SaveChanges();
}

Upvotes: 0

Patrick Koorevaar
Patrick Koorevaar

Reputation: 1343

How to use DI in Action filters is described here: https://www.c-sharpcorner.com/blogs/custom-filter-in-mvc-or-logging-using-mvc-filter

The article in short:

Enable for all controllers:

starup.cs:

services.AddMvc(options =>  
{  
   options.Filters.Add(typeof(AuditAttribute));  
});

Enable for only one controller:

starup.cs:

services.AddScoped<AuditAttribute>();

Next you place on the controller or action method:

[ServiceFilter(typeof(AuditAttribute))] 

Upvotes: 0

Robert Perry
Robert Perry

Reputation: 1954

The error is occurring because you have a parameter of "DbContext" on your attribute, but you are not supplying it when applying it to the controller?

public AuditAttribute(ApplicationDbContext db)
{
    _db = db;
}

Upvotes: 0

Edward
Edward

Reputation: 30056

For using AuditAttribute on the specific method or controller, you could try ServiceFilterAttribute or TypeFilterAttribute.

Here are the available two options:

Option1

Use TypeFilterAttribute.

[TypeFilter(typeof(AuditAttribute))]
public class HomeController : Controller

Option2

Use ServiceFilterAttribute

  1. Register AuditAttribute in Startup.cs

     services.AddScoped<AuditAttribute>();
    
  2. Use AuditAttribute

     [ServiceFilter(typeof(AuditAttribute))]
     public class HomeController : Controller
    

Upvotes: 2

Related Questions