根据用户使用httpcontext登录的时间获取asp.net mvc

问题描述:

在我们的应用程序中,我们有一个选项供每个用户选择他们自己的timezone,当显示特定用户的数据时,我们提取timezone选择他并相应地显示。现在,作为每答案mentioned here,这实在是一个真棒一个,我继续在model一级执行上面提到的选项,即日期的转换,我已经按以下步骤进行的:根据用户使用httpcontext登录的时间获取asp.net mvc

NotificationViewModel.cs

public class NotificationViewModel 
{ 

    public string Text{ get; set; } 
    public DateTime Moment 
    { 
     get 
     { 
      return _Created; 
     } 
     set 
     { 
      _Created = Repository.GetUserTimeZoneDateTime(value); 
     } 
    } 
    private DateTime _Created { get; set; } 
    public string Icon { get; set; } 
} 

Repository.cs

GetUserTimeZoneDateTime具有2个重载

public static DateTime GetUserTimeZoneDateTime(DateTime dTime) 
{ 
    using (var context = new EntityContext()) 
    { 
     var tZone = context.tbl_usrs.AsNoTracking().FirstOrDefault(x => x.uname == HttpContext.Current.User.Identity.Name).preferred_timezone; 
     var tZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tZone); 
     return TimeZoneInfo.ConvertTimeFromUtc(dTime, tZoneInfo); 
    } 
} 

public static DateTime GetUserTimeZoneDateTime(EntityContext context, DateTime dTime) 
{ 
    var tZone = context.tbl_usrs.AsNoTracking().FirstOrDefault(x => x.uname == HttpContext.Current.User.Identity.Name).preferred_timezone; 
    var tZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tZone); 
    return TimeZoneInfo.ConvertTimeFromUtc(dTime, tZoneInfo); 
} 

在上述情况下,首先会调用过载,但是当从model级别调用HttpContext.Current时将会调用null,因此它会失败。


在第二个方法,我试过了,timezone将从控制器级别牵强。

NotificationViewModel.cs

public class NotificationViewModel 
{ 
    public string Text { get; set; } 
    public DateTime Moment { get; set; } 
    public string Icon { get; set; } 
} 

TestController.cs

using (var context = new EntityContext()) 
{ 
    var localTime = Repository.GetUserTimeZoneDateTime(context, DateTime.UtcNow); 
    List<NotificationViewModel> model = new List<NotificationViewModel>(); 
    int days = DateTime.UtcNow.DayOfWeek - DayOfWeek.Sunday; 
    DateTime weekStart = localTime.AddDays(-days); 
    DateTime weekEnd = weekStart.AddDays(6); 
    var p = context.tbl_prchs 
        .Where(x => x.c_date <= weekEnd && x.c_date >= weekStart) 
        .Select(x => new NotificationViewModel() 
        { 
          Icon = "fa fa-gbp", 
          Moment = Repository.GetUserTimeZoneDateTime(context,x.c_date), 
          Text = "Test notes", 
        }).ToList(); 
    model.AddRange(p); 
} 

var localTime = Repository.GetUserTimeZoneDateTime(context, DateTime.UtcNow);取适当datetime根据优选用户timezone。但随后Moment= Repository.GetUserTimeZoneDateTime(context,x.c_date),内部linq expression抛出错误如下

LINQ实体无法识别方法“的System.DateTime GetUserTimeZoneDateTime(Direct_Commercial_Van.Models.EntityDataModel.dcvEntities, 的System.DateTime)”方法,和这种方法不能被翻译成 商店表达式。

这是预期的。还有什么其他选择我可以尝试在此实现?或者如何以其他方式处理时区问题?

+1

对于第二一个,物化查询你打电话之前'。选择()'即 - '变种P = context.tbl_prchs.Where(.. ..)。ToList()。Select({...})。ToList();' –

+0

那么,这将是一个不错的选择,但不会是性能开销? –

+0

另外,有没有什么办法可以处理'ToListAsync()'而不是'ToList()'? –

在第一种情况下,您需要将HttpContext(或User.Identity.Name)注入模型(查看构造函数),然后从该方法中通过方法中的其他参数注入方法(所有内容非常混乱且不推荐) 。

在第二种情况下,你需要之前,首先物化查询您的.Select()

var p = context.tbl_prchs 
    .Where(...) 
    .ToList() // materialize query in in-memory set 
    .Select(x => new NotificationViewModel() 
    { 
    }).ToList(); 

但是你的代码是非常低效的,因为你(通过GetUserTimeZoneDateTime()方法)调用数据库中的每一行的查询返回。在调用您的查询之前,您应该更改您的代码以获取TimeZoneInfo

// Get the time zone info 
var tZone = context.tbl_usrs.AsNoTracking().......' 
var tZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tZone); 
// Generate the view model 
var p = context.tbl_prchs 
    .Where(...) 
    .ToList() // materialize query in in-memory set 
    .Select(x => new NotificationViewModel() 
    { 
     .... 
     Moment = TimeZoneInfo.ConvertTimeFromUtc(x.c_date, tZoneInfo); 
    }).ToList(); 

另外,如果你不想先物化查询,你可以注入TimeZoneInfo到您的视图模型和修改Moment来计算特性。

public class NotificationViewModel 
{ 
    public string Text { get; set; } 
    public DateTime CDate { get; set; } 
    public string Icon { get; set; } 
    public TimeZoneInfo TimeZoneInfo { get; set; } 
    public DateTime Moment 
    { 
     get { return TimeZoneInfo.ConvertTimeFromUtc(CDate, TimeZoneInfo); } 
    } 
} 

,然后查询将

.... 
var tZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tZone); 
var p = context.tbl_prchs 
    .Where(...) 
    .Select(x => new NotificationViewModel() 
    { 
     .... 
     CDate = x.c_date, 
     TimeZoneInfo = tZoneInfo 
    }).ToList(); 
+0

获取'只有无参数的构造函数和初始化器在LINQ to Entities.'异常兄弟中受支持.. :(另外,我正在使用'ToListAsync()':(忘记提及.. –

+1

在这种情况下,您需要实现查询第一(但除非你查询返回成千上万的行,它没有什么可担心的)但我会尽快编辑答案,以显示一个替代方案,我认为应该工作 –

+0

肯定好友.. :) –