简体   繁体   English

在 ASP.NET MVC 应用程序中记录用户活动

[英]Log user activity in ASP.NET MVC application

I am planning to create filter based on ActionFilterAttribute to log user activity:我打算创建基于ActionFilterAttribute过滤器来记录用户活动:

public class LogAttribute : ActionFilterAttribute
{
    public ActionType Type { get; set; }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
      // logic for log
    }
}

I would like to use this attribute on Actions in my controllers.我想在我的控制器中的 Actions 上使用这个属性。 I'd like to log some values X,Y,Z which user is set in my views and also some action related info.我想记录用户在我的视图中设置的一些值X,Y,Z以及一些与操作相关的信息。 In that case I have to probably send these X,Y,Z to my actions as parameters and then in Attribute code get these values from ResultExecutedContext.在这种情况下,我可能必须将这些 X、Y、Z 作为参数发送到我的操作,然后在属性代码中从 ResultExecutedContext 获取这些值。 But this approach confused a little bit me because I will have redundant parameters on each of my actions.但是这种方法让我有点困惑,因为我的每个动作都会有多余的参数。

Is there any good approach to share values from View to C# code?有什么好的方法可以将值从 View 共享到 C# 代码吗?

I am able to achieve this by following the below way我可以通过以下方式实现这一目标

Create a table(name - Portal_Logger and D_MASTER )创建一个表(名称 - Portal_LoggerD_MASTER

Next, Created a filter which will track the activity for user/s like below接下来,创建一个过滤器,它将跟踪用户的活动,如下所示

LoggerActionFilter.cs LoggerActionFilter.cs

using System;
using System.Web.Mvc;
using System.Net;
using System.Linq;
using System.Net.Sockets;
using MyMvcApplication.Models.Entity;
using MyMvcApplication.Utilities;

namespace MyMvcApplication.Filters
{
    /// <summary>
    /// 
    /// </summary>
    public class LoggerActionFilter : ActionFilterAttribute
    {
        private static TimeZoneInfo INDIAN_ZONE = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time");
        IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // Stores the Request in an Accessible object
            var request = filterContext.HttpContext.Request;
            var visitCount = Convert.ToInt64(filterContext.HttpContext.Session["LoggerActivityTracking"].ToString());
            // Generate an audit
            Portal_Logger aLogger = new Portal_Logger()
            {
                // Your Logger Identifier     
                LoggerId = Guid.NewGuid(),
                //Logged On User Id
                LogedUserId = Convert.ToInt32(filterContext.HttpContext.Session["LogedUserID"]),
                // The IP Address of the Request
                IPAddress = Convert.ToString(ipHostInfo.AddressList.FirstOrDefault(address => address.AddressFamily == AddressFamily.InterNetwork)),
                //Get the Web Page name(from the URL that was accessed)
                AreaAccessed = UserActivityUtility.GetWebPageName(request.RawUrl == "/"? "/Home/UserLandingPage" : request.RawUrl),
                // Creates our Timestamp
                Timestamp = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, INDIAN_ZONE),
                VisitorSessionId = visitCount
            };
            
            // Stores the Logger in the Database
            using (dbEntities context = new dbEntities())
            {
                if (aLogger.LogedUserId != null)
                {
                    aLogger.LogedUserEmpId = context.D_MASTER
                        .Where(x => x.User_Id == aLogger.LogedUserId)
                        .Select(x => x.Emp_Id).FirstOrDefault();
                    aLogger.LogedUserEmpName = context.D_MASTER
                        .Where(x => x.User_Id == aLogger.LogedUserId)
                        .Select(x => x.Emp_Name).FirstOrDefault();
                    aLogger.AccessedType = aLogger.AreaAccessed.Contains("Report") ? "Report" : "Page";
                }
                context.Portal_Logger.Add(aLogger);
                context.SaveChanges();
            }
            // Finishes executing the Logger as normal 
            base.OnActionExecuting(filterContext);
        }

    }
}

Note : Session["LoggerActivityTracking"] and Session["LogedUserID"] data i am initializing in a Separate Controller( AuthController ) Action( ValidateUser ) which executes when user logging into the application.注意: Session["LoggerActivityTracking"]Session["LogedUserID"]数据我在单独的控制器( AuthController ) Action( ValidateUser ) 中初始化,当用户登录应用程序时执行。

Below i am using a Utility class which will get the exact name for the web page from the RawUrl(eg : /Home/MyController or /Home/MyController1?id=1&name=chandan )下面我正在使用一个实用程序类,它将从 RawUrl 获取网页的确切名称(例如: /Home/MyController/Home/MyController1?id=1&name=chandan

Below is my Utility Class下面是我的实用程序类

UserActivityUtility.cs UserActivityUtility.cs

using System;       
namespace MyMvcApplication.Utilities
{
    public static class UserActivityUtility
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pageName"></param>
        /// <returns></returns>
        public static string GetWebPageName(string pageName)
        {
            string formattedPageName = string.Empty;
            //For All user web pages
            if (pageName.Contains("UserLandingPage"))
            {
                formattedPageName = "Home - App Management";
            }            
            //For Report Web Pages 
            else if (pageName.Contains("AppUtilization"))
            {
                formattedPageName = "Application Utilization Report";
            }           
            else if (pageName.Contains("AlertReport"))
            {
                formattedPageName = "Alert Report";
            }                       
            else
            {
                formattedPageName = pageName;
            }
            return formattedPageName;
        }
    }
}

And finally apply that attribute to the Controller Action/s(which actions you want to track) like below最后将该属性应用到 Controller Action/s(您要跟踪哪些操作),如下所示

public class HomeController : Controller
{
    [LoggerActionFilter(Order = 1)]
    public ActionResult UserLandingPage()
    {
        return View();
    }
}


public class AdminController : Controller
{
    [LoggerActionFilter(Order = 1)]
    public ActionResult CreateUser()
    {
        return View();
    }
}


public class ReportController : Controller
{
    [LoggerActionFilter(Order = 1)]
    public ActionResult AppUtilization()
    {
        return View();
    }
}

And below are the "MS SQL StoredProcedure" to get the user login details and page wise access summary details以下是“MS SQL StoredProcedure”,用于获取用户登录详细信息和页面访问摘要详细信息

User Login Details用户登录详情

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE Procedure [dbo].[sp_Portal_GetUserLoginDetails_Logger]
(
@FromDate DATE,
@ToDate DATE
)
AS
BEGIN
        --EXEC sp_Portal_GetUserLoginDetails_Logger '2017-06-16','2017-06-16'
        SET NOCOUNT ON

        SELECT  u.LogedUserID,u.UserName,u.IPAddress,u.AreaAccessed,u.[Timestamp],u.LastLoggedInDay
        FROM 
        (
                SELECT  DISTINCT l.LogedUserID,e.Emp_Name as 'UserName',l.IPAddress,l.AreaAccessed,l.[Timestamp],l.LastLoggedInDay
                FROM 
                (
                        SELECT * 
                        FROM 
                        (
                            SELECT  Row_Number() Over ( PARTITION BY LogedUserID ORDER BY [Timestamp] DESC) As RowNum, LogedUserID,

                                    IPAddress,AreaAccessed,TIMESTAMP, DATEDIFF(D,TIMESTAMP,CURRENT_TIMESTAMP) AS 'LastLoggedInDay'
                            FROM    Portal_Logger 
                            WHERE   CAST([Timestamp] AS DATE) BETWEEN @FromDate AND @ToDate
                        ) t2
                    WHERE RowNum = 1
                ) l
                JOIN D_MASTER e on l.LogedUserID = e.User_Id                
        ) u     
        ORDER BY u.[Timestamp] DESC     
END

Page Wise Access Summary Details Page Wise 访问摘要详细信息

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[sp_Portal_GetUserAccessedSummary_Logger]
(
@FromDate DATE,
@ToDate DATE
)
AS
BEGIN       
        --EXEC sp_Portal_GetUserAccessedSummary_Logger '2017-06-16','2017-06-16'

        SET NOCOUNT ON      
            SELECT  A.AreaAccessed,
                    COUNT(A.Timestamp) AS NoofTimeAccessed,
                    CONVERT(TIME(0), DATEADD(SECOND,SUM(SessionSeconds), 0)) AS TotalTimeSpent,
                    CONVERT(TIME(0), DATEADD(SECOND,AVG(SessionSeconds), 0)) AS AvgTimeSpent,
                    COUNT(DISTINCT LogedUserID) AS NoofUserAccessed
  
            FROM
            (
                SELECT  
                        A.AreaAccessed,A.Timestamp,
                        ISNULL(DATEDIFF(S,A.Timestamp,ISNULL(LEAD(A.Timestamp,1)OVER(PARTITION BY A.VisitorSessionId ORDER BY A.Timestamp),A.Timestamp)),0) AS SessionSeconds,
                        A.LogedUserID
        
                FROM    Portal_Logger A(NOLOCK)
                JOIN    D_MASTER B(NOLOCK) ON A.LogedUserID=B.User_Id
                WHERE   A.VisitorSessionId IS NOT NULL
                AND     CAST(A.Timestamp AS DATE) BETWEEN @FromDate AND @ToDate

            )A
            GROUP BY A.AreaAccessed
            ORDER BY NoofTimeAccessed DESC      
        SET NOCOUNT OFF
END

The values would have to be set at some point, either by the user or by code.这些值必须在某个时候由用户或代码设置。 You can however, use the Session array to contain these values.但是,您可以使用Session数组来包含这些值。 They will be preserved for the duration of the login session.它们将在登录会话期间保留。

To store to session存储到会话

Session["key"] = "data";

and later in code后来在代码中

var val = Session["key"]; // val now has a value of "data";

what I use is a helper method that use reflection and dumps the model into a dictionary, that way you don't have the issue to copy the values elsewhere, everything ships from a single place "your model"我使用的是一种辅助方法,它使用反射并将模型转储到字典中,这样您就没有问题将值复制到其他地方,所有内容都从一个地方“您的模型”发货

private static Dictionary<string, string> DumpModel(object obt)
        {
            Type type = obt.GetType();
            if (TypeDefinitionIsList(type))
                return null;

            PropertyInfo[] properties = obt.GetType().GetProperties();
            Func<PropertyInfo, string> func = info =>
                                                  {
                                                      if (info.PropertyType.GetInterface(typeof (ICatalogue<>).FullName) != null)
                                                      {
                                                          dynamic propertyValue = info.GetValue(obt, null);
                                                          if (propertyValue != null)
                                                              return string.Format("{{ Id: {0}, Description: {1} }}",
                                                                                   propertyValue.Id,
                                                                                   propertyValue.Description);
                                                          return "null";
                                                      }
                                                      object normalValue = info.GetValue(obt, null);
                                                      if (normalValue == null) return "null";
                                                      return TypeDefinitionIsList(normalValue.GetType()) ? HelpersMessages.NotSupportedList : normalValue.ToString();
                                                  };

            return properties.ToDictionary(x => "model-"+x.Name, func);
        }

you can use it in your filter attribute您可以在过滤器属性中使用它

var request = filterContext.HttpContext.Request;
object model = filterContext.Controller.ViewData.Model;

and you can use something like你可以使用类似的东西

 DumpModel(model);    

use the values to log wharever you need, I hope this helps使用这些值来记录你需要的任何人,我希望这会有所帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM