C# 从数据层访问HttpContext和用户标识

C# 从数据层访问HttpContext和用户标识,c#,asp.net-mvc,asp.net-identity,httpcontext,C#,Asp.net Mvc,Asp.net Identity,Httpcontext,我需要在我的基础实体上实现AddedBy/ChangedBy类型字段,所有其他实体都从中继承(Fluent Nhibernate) 从我的存储库/数据层中访问HttpContext.User.Identity可能不是一个好主意。。还是这样? 获取我的用户(当前身份)信息以记录谁添加或更改了记录的最佳方式是什么? 重新分解整个应用程序以在存储库调用中包含用户信息将是愚蠢的。我相信有一种更好、更通用的方法。AddedBy/ChangedBy字段在任何数据后端都可能很重要。您甚至可能想让Accesse

我需要在我的基础实体上实现AddedBy/ChangedBy类型字段,所有其他实体都从中继承(Fluent Nhibernate)

从我的存储库/数据层中访问
HttpContext.User.Identity
可能不是一个好主意。。还是这样? 获取我的用户(当前身份)信息以记录谁添加或更改了记录的最佳方式是什么?
重新分解整个应用程序以在存储库调用中包含用户信息将是愚蠢的。我相信有一种更好、更通用的方法。

AddedBy/ChangedBy字段在任何数据后端都可能很重要。您甚至可能想让AccessedBy用于日志记录。因此,您可能会认为用户信息是数据的核心部分。出于安全原因,您可能还需要记录其他详细信息,例如客户端的IP地址。将整个上下文向下扩展到数据层可能是一个好主意,这样您就可以灵活地捕获和保存客户机信息

你说得对。从存储库中引用
HttpContext.User.Identity
类不是一个好主意。
HttpContext
是一个UI关注点,因此不应超出UI层

您应该做的是利用IoC容器(如StructureMap)将依赖项(
HttpContext.User.Identity
)详细信息通过依赖项注入注入存储库或任何其他层(如服务层)


有关如何设置它的示例(在本例中,它是会话对象),请参阅的后半部分。

HttpContext.Current是一个静态成员,您可以在应用程序中的任何位置访问它。 显然存在一些问题,例如在调用代码时没有HttpContext

所以HttpContext.Current.User应该适合您。我不建议这样做,因为您的底层数据访问代码现在取决于应该保存在显示器或控制器逻辑中的内容等。此外,这假设您的数据访问在web应用程序本身中,而不是外部库的一部分


就我个人而言,我只是在添加和修改数据库调用中传递一些重要的细节,比如用户ID和访问时间。制作一个“AuditTrail”类或其他东西。这将使您可以在另一个项目中重用该数据访问代码(始终是一件好事),而不必取出所有的HttpContext内容。

从数据层访问HttpContext会使工作更加困难,特别是在使用单元测试的情况下。解决方案是创建一个服务来提供应用程序范围的用户信息,例如:

public interface ICurrentUserService {
   string UserName {get;}
   string UserId {get;}
   string HostIP {get;}
   // etc.
}
然后可以实现具体的服务,并使用 首选IoC容器

public class CurrentWebUserService : ICurrentUserService {
    // implement interface members 
    public CurrentWebUserService(HttpContext context) { ... }

    public string UserName { get { ... } } 
    // etc.
}

// maybe you want a stub service to inject while unit testing.
public class CurrentUserServiceStub : ICurrentUserService {

}

// data layer
public class MyDaoService {
    public DaoService(ICurrentUserService currentUser) { ... }
}

我使用了一个工厂来获得正确的回购协议,无论是否有“当前用户”,因为有时你需要知道用户是谁,有时你不知道

//I have a current user that I got from the Identity
var repo = RepoFactory.GetRepo<Users>(currentUserId);

//I don't have a current user
var repo = RepoFactory.GetRepo<Users>()
//我有一个从标识中获取的当前用户
var repo=RepoFactory.GetRepo(currentUserId);
//我没有当前用户
var repo=RepoFactory.GetRepo()
通过这种方式,您可以从HttpContext中提取标识,并只将所需的详细信息传递给repo

  • HttpContext.User.Identity
    属于
    System.Security.Principal.IIdentity
    类型。不要把它和Microsoft.AspNet.Identity库(NuGet软件包)搞混了,它实际上是由您问题中的asp.net-Identity标签指向的

  • 标识库由公共部分及其ORM实现组成。通常用于实体框架。但是,如果您打算以NHibernate描述的方式使用
    Microsoft.AspNet.Identity
    包,那么您很可能需要


  • 我没有使用它,但我使用了EF实现。请参见如何继承预定义的
    IdentityDbContext
    ,其中T是您的用户类。我想,NH也有类似的fluent配置。然后,您可以将
    DbContext
    中的任何实体链接到
    AppUser

    谢谢您的评论,但您没有回答如何以及最好的方式是什么的问题。谢谢如果您尝试从数据层访问UserManager,听起来您将遇到循环依赖。长途跋涉,在每次创建/更新时填写By属性将是最好的选择。我是否正确理解这建议即使在依赖项注入时也使用会话?是的,没错。您的目标应该始终是编程到接口,而不是实现。因此,与其直接针对
    HttpContext.Current.Session
    对象(或者在您的示例中是
    HttpContext.User.Identity
    )编程,不如针对应用程序的应用程序中构建的抽象对象编程。当ASP.NET MVC 5之类的更改出现时,如果它们更改了
    HttpContext
    对象,则必须在单个位置而不是在整个应用程序中进行更改。我一直在尝试,但在将这一切放在一起时遇到了问题:1)在我的Web项目中创建一个具有所需用户属性的接口/类。2) 从数据层访问这些属性类在什么时候被注入数据?有趣的解决方案,但它会在我这方面导致大量代码重构。在所有存储库中传递用户凭据意味着进行大量代码重构。我正在研究其他人建议的IoC容器解决方案,我还不太了解。是的,它确实涉及很多重构,尽管在开发过程中规范发生变化时会发生重构。我对国际奥委会了解不多。希望你不用重写所有的东西。