servicestack,nhibernate-envers,C#,servicestack,Nhibernate Envers" /> servicestack,nhibernate-envers,C#,servicestack,Nhibernate Envers" />

C# 以线程安全的方式获取服务外部的当前用户会话

C# 以线程安全的方式获取服务外部的当前用户会话,c#,servicestack,nhibernate-envers,C#,servicestack,Nhibernate Envers,基于My ServiceStack的应用程序使用内置身份验证功能,并在自托管模式下运行(AppHostHttpListenerLongRunningBase) 我正在使用NHibernate和Envers进行审计跟踪。Envers可以提供可选的单例实例,用于填充其他修订信息。我想在修订信息中存储当前用户的身份验证名 我需要访问当前请求(即,当前用户会话)在我的singleton实例中服务代码的外部。如何使用ServiceStack实现这一点?如何使其线程安全?我自己不使用NHibernate或E

基于My ServiceStack的应用程序使用内置身份验证功能,并在自托管模式下运行(
AppHostHttpListenerLongRunningBase

我正在使用NHibernate和Envers进行审计跟踪。Envers可以提供可选的单例实例,用于填充其他修订信息。我想在修订信息中存储当前用户的身份验证名


我需要访问当前请求(即,当前用户会话在我的singleton实例中服务代码的外部。如何使用ServiceStack实现这一点?如何使其线程安全?

我自己不使用NHibernate或Envers,所以可能只是在这里吐痰。我不认为当前用户会话真的存在于服务范围之外。但是您应该能够传入Envers范围。我认为您需要做的是使用

AppHost
中设置singleton实例,然后将其注册到容器中,以便将其注入到每个服务请求中

通过这样做:

container.Register(c => singletonInstance).ReusedWithin(ReuseScope.None);
您需要扩展
服务
以使用自定义基:

public class MyServiceBaseWithEnversSupport : Service
{
    public EnversSingletonInstanceType Envers { get; set; } // IoC will inject here
}
然后您的处理程序将需要使用这个扩展的自定义
服务
基,因此类似这样的内容:
CustomerHandler
只是一个示例,您的服务处理程序会有所不同

您可以自动填充这些值,以避免通过设置自定义值在每个操作处理程序中设置值

创建自定义的
ServiceRunner

公共类ServiceRunner:ServiceStack.ServiceHost.ServiceRunner
{
PublicServiceRunner(IAppHost、appHost、ActionContext、ActionContext):基本(appHost、ActionContext)
{
}
公共重写对象执行(IRequestContext请求上下文、对象实例、T请求)
{
//检查实例是否为MyServiceBaseWithEnversSupport类型
var ms=实例作为MyServiceBaseWithEnversSupport;
//如果请求未使用MyServiceBaseWithEnversSupport,则允许其正常运行。
如果(ms==null)
return base.Execute(requestContext、instance、request);
//访问使用会话信息设置的Envers对象
ms.Envers.Username=ms.Session.Username;
return base.Execute(requestContext、ms、request);
}
}
通过将其添加到您的
AppHost
,配置您的应用程序以使用它:

公共覆盖IServiceRunner CreateServiceRunner(ActionContext ActionContext)
{
返回新的ServiceRunner(此,actionContext);
}
抱歉,在Enver的单例对象类型和调用对象以设置数据的正确属性或方法方面,部分内容有点模糊,但我假设您可以替换为适当的值

正如我所说,我对NHibernate或Envers都不熟悉,因此这可能会关闭,但至少在ServiceStack方面可能会有所帮助


更新的尝试: 我认为,对于您的服务的每个请求,都会发生以下情况:

  • 应用程序主机为请求创建服务上下文线程
  • 在线程中存在用户会话
  • 每个请求将执行一些NHibernate数据库操作
  • 数据库操作可能会触发envers侦听器中的事件处理程序。您需要填充当前请求的用户名,即在当前线程的范围内
您是否考虑过在侦听器中创建一个对ServiceStack和您的Envers事件处理程序都是全局的
静态
变量

public static class Global
{
    [ThreadStatic]
    public static string Username;
}
然后在ServiceStack中,在身份验证点设置
Username
的值,该值将出现在侦听器的处理程序之前。然后在侦听器处理程序中,从
Global.Username
读取值。该值是线程安全的,仅存在于请求的范围内


注意:我假设NHibernate/Envers在请求线程上运行,并且它不会为每个请求生成其他工作线程。

您好,谢谢您的想法。我正在考虑以某种方式访问实例和“手动”设置当前用户的听众(我认为您的代码“手动”的方式,无论它是多么自动化;)。但是我非常担心它的线程安全性。同时处理两个请求时会发生什么情况?恐怕这需要我为整个请求处理锁定“enverslistener”单例实例。这听起来不是个好主意…@migajek我明白你的担忧,你能发布你的单身汉代码吗,以及你将如何设置它?所以我知道你是在告诉单身汉用户是谁,它如何知道他们在请求期间更改了哪些记录?如果我能理解的话,我认为解决方案应该是构建一个队列,使用已完成的请求运行更新单例,并且因为它是后台工作程序,所以不会阻止正常操作。Envers是审计跟踪库,因此它负责跟踪实体中的更改。我的singleton是envers listener,负责为revision分配额外的数据——在我的例子中,我希望分配当前用户名。因此,每次Envers调用singleton的方法时,我都需要知道当前用户的名称。如果任何实体发生了更改,Envers将在我手动创建的同一事务中创建修订并询问其详细信息,因此-它将在请求处理结束之前被调用。它不会以任何方式排队,因此至少执行顺序是certain@migajek我已经更新了我的答案。我曾经认为,也许使用
[ThreadStatic]
使请求线程可以访问
用户名
。请让我知道你进展如何。你得到
ThreadStatic
批准了吗
public static class Global
{
    [ThreadStatic]
    public static string Username;
}