【问题标题】:Log user activity in ASP.NET MVC application在 ASP.NET MVC 应用程序中记录用户活动
【发布时间】:2013-09-23 01:21:21
【问题描述】:

我打算根据ActionFilterAttribute 创建过滤器来记录用户活动:

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

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

我想在我的控制器中的 Actions 上使用这个属性。我想记录一些值X,Y,Z 在我的视图中设置了哪些用户以及一些与操作相关的信息。在这种情况下,我可能必须将这些 X、Y、Z 作为参数发送到我的操作,然后在属性代码中从 ResultExecutedContext 获取这些值。但是这种方法让我有点困惑,因为我的每个动作都会有冗余参数。

有没有什么好的方法可以将 View 的值共享到 C# 代码?

【问题讨论】:

    标签: c# asp.net-mvc-4 architecture


    【解决方案1】:

    这些值必须在某个时候由用户或代码设置。但是,您可以使用Session 数组来包含这些值。它们将在登录会话期间保留。

    存储到会话

    Session["key"] = "data";
    

    及以后的代码

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

    【讨论】:

    • 我认为在 mvc 中使用会话是个坏主意
    • @Polaris 这对我来说是个新闻 - stackoverflow.com/questions/6744493/… - 你认为它们是一个糟糕的选择的任何具体原因?
    • @Polaris 为什么是坏主意?
    【解决方案2】:

    我使用的是一种辅助方法,它使用反射并将模型转储到字典中,这样您就不必将值复制到其他地方,所有内容都来自“您的模型”的一个地方

    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);
            }
    

    你可以在你的过滤器属性中使用它

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

    你可以使用类似的东西

     DumpModel(model);    
    

    使用这些值来记录您需要的数据, 我希望这会有所帮助

    【讨论】:

      【解决方案3】:

      我可以通过以下方式实现这一点

      创建一个表(名称 - Portal_LoggerD_MASTER

      接下来,创建一个过滤器来跟踪用户的活动,如下所示

      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);
              }
      
          }
      }
      

      注意:Session["LoggerActivityTracking"]Session["LogedUserID"] 数据我在用户登录应用程序时执行的单独控制器(AuthController) 操作(ValidateUser) 中进行初始化。

      下面我使用了一个 Utility 类,它将从 RawUrl 获取网页的确切名称(例如:/Home/MyController/Home/MyController1?id=1&amp;name=chandan

      下面是我的实用类

      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;
              }
          }
      }
      

      最后将该属性应用于控制器 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();
          }
      }
      

      下面是“MS SQL StoredProcedure”,用于获取用户登录详细信息和页面访问摘要详细信息

      用户登录详情

      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 摘要详情

      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
      

      【讨论】:

      • 我希望我可以使用您的代码,但它不起作用。 [AuthenticationFilter(Order = 1)] 投了一个扩展,请更新你的答案。
      • 好的,但是为什么来自 LoggerActionFilter 的var visitCount = Convert.ToInt64(filterContext.HttpContext.Session["LoggerActivityTracking"].ToString()); 返回 Null 并因此中断该过程,我认为缺少一些东西。您在某处没有完整实现的代码作为参考吗?拜托,我喜欢你的代码,我想在我的练习中使用。
      • AuthenticationFilter 是什么?自定义身份验证过滤器?代码?
      • @Kiquenet 那是我拥有的另一个身份验证过滤器。我从我的代码中删除了它,因为此解决方案不需要它
      猜你喜欢
      • 2010-12-21
      • 2010-11-01
      • 2011-09-01
      • 2014-02-28
      • 2013-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多