Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 一个请求记录器,异步记录每个对站点的请求_C#_Asp.net Mvc_Entity Framework_Asp.net Mvc 5_Async Await - Fatal编程技术网

C# 一个请求记录器,异步记录每个对站点的请求

C# 一个请求记录器,异步记录每个对站点的请求,c#,asp.net-mvc,entity-framework,asp.net-mvc-5,async-await,C#,Asp.net Mvc,Entity Framework,Asp.net Mvc 5,Async Await,我正在尝试将每个请求记录到我的网站(Asp.net mvc)。为此,我创建了一个全局过滤器属性,用于从当前请求中收集日志信息。异步执行此操作的主要思想是不要阻塞我的主应用程序。只需静默地记录数据。当我的操作记录器无法记录请求时,我设置了一个错误记录器来记录错误,一切都正常 下面的代码是我的过滤器 public class RequestLoggingAttribute : ActionFilterAttribute { private readonly IActionLogService

我正在尝试将每个请求记录到我的网站(Asp.net mvc)。为此,我创建了一个全局过滤器属性,用于从当前请求中收集日志信息。异步执行此操作的主要思想是不要阻塞我的主应用程序。只需静默地记录数据。当我的操作记录器无法记录请求时,我设置了一个错误记录器来记录错误,一切都正常

下面的代码是我的过滤器

public class RequestLoggingAttribute : ActionFilterAttribute
{
    private readonly IActionLogService _actionLogService;
    public RequestLoggingAttribute(IActionLogService actionLogService)
    {
        _actionLogService = actionLogService;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {           
        //Run an async method here to log any data you need.
        Task.Run(() => GatherActionLog(filterContext)).ConfigureAwait(false); 

        base.OnActionExecuting(filterContext);           
    }

    private async Task GatherActionLog(ActionExecutingContext filterContext)
    {
        try
        {                                
            var httpContext = filterContext.RequestContext.HttpContext;
            var request = httpContext.Request;
            if (!request.Url.AbsoluteUri.Contains("elmah"))
            {
                var roles = ((ClaimsIdentity) httpContext.User.Identity).Claims
                    .Where(c => c.Type == ClaimTypes.Role)
                    .Select(c => c.Value).ToArray();

                var parameters = filterContext.ActionParameters.Select(x => new {x.Key, x.Value});
                var jsonParameters = Json.Encode(parameters);

                var actionLog = new ActionLog()
                {
                    Action = filterContext.ActionDescriptor.ActionName,
                    Controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,
                    DateTimeUTC = DateTime.UtcNow,
                    IpAddress = request.UserHostAddress,
                    UserName = httpContext.User.Identity.Name,
                    Request = request.Url.AbsoluteUri,
                    ComputerName = request.UserHostName,
                    UserRole = String.Join(",", roles),
                    UserAgent = request.UserAgent,
                    ClientLoggedInUser = request.LogonUserIdentity.Name,
                    HttpMethod = httpContext.Request.HttpMethod,
                    Parameters = jsonParameters,
                    BrowserName = request.Browser.Id,
                    BrowserVersion = request.Browser.Version
                };

                await _actionLogService.InsertAsync(actionLog);
            }
        }
        catch (Exception ex)
        {               
            Elmah.ErrorLog.GetDefault(filterContext.HttpContext.ApplicationInstance.Context).Log(new Elmah.Error(ex));

        }                       
    }
}
在my Elmah的错误列表中,此方法有两个错误。详情如下:

public class ActionLog
{
    public Guid ActionLogId { get; set; }
    public string UserRole { get; set; }
    public string UserName { get; set; }
    public string ClientLoggedInUser { get; set; }
    public string UserFullName { get; set; }
    public DateTime DateTimeUTC { get; set; }
    public string Action { get; set; }
    public string Controller { get; set; }
    public string Request { get; set; }
    public string ComputerName { get; set; }
    public string IpAddress { get; set; }
    public string HttpMethod { get; set; }
    public string Parameters { get; set; }
    public string UserAgent { get; set; }   
    public string BrowserName { get; set; }
    public string BrowserVersion { get; set; }               
}
public class GenericRepository<T> : BaseRepository<T, ApplicationDbContext> where T : class
{
    public GenericRepository(ApplicationDbContext db)
        :base(db)
    {
    }

}

public class LoggerRepository<T> : BaseRepository<T, LoggerDbContext> where T : class
{
    public LoggerRepository(LoggerDbContext db)
        :base(db)
    {

    }
}
第一:

在上一个异步操作完成之前,在此上下文上启动了第二个操作。使用“await”确保在此上下文上调用另一个方法之前已完成任何异步操作。任何实例成员都不能保证线程安全

第二:

保存或接受更改失败,因为“Domain.LogEntities.ActionLog”类型的多个实体具有相同的主键值。确保显式设置的主键值是唯一的。确保在数据库和实体框架模型中正确配置了数据库生成的主键。使用实体设计器进行数据库优先/模型优先配置。使用“HasDatabaseGeneratedOption”fluent API或“DatabaseGeneratedAttribute”进行代码优先配置

ActionLog的域类如下所示:

public class ActionLog
{
    public Guid ActionLogId { get; set; }
    public string UserRole { get; set; }
    public string UserName { get; set; }
    public string ClientLoggedInUser { get; set; }
    public string UserFullName { get; set; }
    public DateTime DateTimeUTC { get; set; }
    public string Action { get; set; }
    public string Controller { get; set; }
    public string Request { get; set; }
    public string ComputerName { get; set; }
    public string IpAddress { get; set; }
    public string HttpMethod { get; set; }
    public string Parameters { get; set; }
    public string UserAgent { get; set; }   
    public string BrowserName { get; set; }
    public string BrowserVersion { get; set; }               
}
public class GenericRepository<T> : BaseRepository<T, ApplicationDbContext> where T : class
{
    public GenericRepository(ApplicationDbContext db)
        :base(db)
    {
    }

}

public class LoggerRepository<T> : BaseRepository<T, LoggerDbContext> where T : class
{
    public LoggerRepository(LoggerDbContext db)
        :base(db)
    {

    }
}
如果重要的话,我使用了两个数据库,一个用于我的主应用程序,另一个用于日志记录(错误和请求日志记录)。因此,我在DAL层中有两个实体框架DbContext。一个DbContext用于应用程序,另一个用于记录器。但我使用了一个接受DbContext的BaseRepository来处理。我对BaseRepository的调用如下:

public class ActionLog
{
    public Guid ActionLogId { get; set; }
    public string UserRole { get; set; }
    public string UserName { get; set; }
    public string ClientLoggedInUser { get; set; }
    public string UserFullName { get; set; }
    public DateTime DateTimeUTC { get; set; }
    public string Action { get; set; }
    public string Controller { get; set; }
    public string Request { get; set; }
    public string ComputerName { get; set; }
    public string IpAddress { get; set; }
    public string HttpMethod { get; set; }
    public string Parameters { get; set; }
    public string UserAgent { get; set; }   
    public string BrowserName { get; set; }
    public string BrowserVersion { get; set; }               
}
public class GenericRepository<T> : BaseRepository<T, ApplicationDbContext> where T : class
{
    public GenericRepository(ApplicationDbContext db)
        :base(db)
    {
    }

}

public class LoggerRepository<T> : BaseRepository<T, LoggerDbContext> where T : class
{
    public LoggerRepository(LoggerDbContext db)
        :base(db)
    {

    }
}
公共类GenericRepository:BaseRepository,其中T:class
{
公共通用存储库(ApplicationDbContext数据库)
:基准(db)
{
}
}
公共类LoggerRepository:BaseRepository,其中T:class
{
公共LoggerRepository(LoggerDbContext数据库)
:基准(db)
{
}
}
1) 有更好的方法吗!?(我不想改变我的整个代码,只是适合这种方法的更好的方法)

2) 如何防止上述错误

谢谢

希望我有足够的“声誉”将此添加到评论中。无论如何,ActionFilters应该在HTTP管道将请求移动到控制器之前完成其工作。请查看


您可以将日志详细信息发送到MQ(例如,在单独的进程中运行的MSMQ),并让MQ与DB对话,这样您的主应用程序就不会被阻止。

您可以使用nuget软件包。它可以帮助您记录每个HTTP请求,包括对存储的响应(例如DB或文件).

您是否缺少
任务.Run()
上的
wait
?我不想等待此任务,因此我为任务设置了configurewait(false)。我不想请求记录器阻止主应用程序。“使用“wait”确保在此上下文上调用另一个方法之前已完成任何异步操作。”“-只是说‘我不知道你在哪里设置ActionLogId?它们是否都是使用默认的(Guid)@Fran创建的,它使用Identity生成,我在fluent Api中设置了这一行:this.Property(p=>p.ActionLogId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);