2013-05-01 45 views
2

我有一个wcf服务(托管在IIS中),是setup to use sessions。它似乎工作。当调用Application_PostAcquireRequestState时,我有一个会话ID。WCF是否在多个线程上运行会话?

我最终使用它像这样(在我的Global.asax):

if (Context.Handler is IRequiresSessionState) 
{ 
    log4net.ThreadContext.Properties["sessionId"] = Session.SessionID; 
} 

这似乎很好地工作。该值存储在我的log4net属性中。

但是当我的服务操作开始时(我的实际WCF服务代码),log4net属性再次为空。

由于该属性是按线程(ThreadContext)存储的,我只能假设这意味着会话在一个线程上设置,然后在另一个线程上执行。我对吗?

有没有办法让我的log4net属性设置在正确的线程上(而不必记住在每个服务操作开始时进行上述调用)?

+0

我总是期望涉及多个线程。我不确定我是在哪里选择的。您是否在自己的服务中寻找(定制)行为来实现您想要的? – rene 2013-05-01 14:28:20

回答

1

有多种场景中WCF可能会改变你的线程:

  1. 不保证该Global.asx线程用于服务电话(其实它不太可能)。
  2. 如果在同一会话期间有多个呼叫,线程也可能在对相同服务实例的呼叫之间改变。

理论上这样的状态信息应该存储在Operation Context对象中。但是,因为log4net使用线程本地存储,它成为一个尴尬的解决方案。

反正是有让我的log4net的属性设定(无需记住上作出上述呼吁在开始每一个业务操作的 )上正确 线程?

是的。创建一个自定义IOperationInvoker。我所知道的最好的例子是Carlos Figueira's blog如果将此作为服务行为应用,则应始终为服务代码定义log4net属性。

一个警告:当添加到线程本地存储时,一定要清理。这就是为什么log4net.ThreadContext.Stacks []。Push()返回一个IDisposable。换句话说,你的Invoke方法应该看起来像(不完整的,未经测试):

public object Invoke(object instance, object[] inputs, out object[] outputs) 
{ 
    using (log4net.ThreadContext.Stacks[key].Push(value)) 
    { 
     return this.originalInvoker.Invoke(instance, inputs, out outputs); 
    } 
} 

见卡洛斯的博客理解为什么您呼叫的‘originalInvoker’。请注意,如果您想支持需要实现其他方法的异步操作。

2

是的,IIS可能使用多个线程为多个WCF请求提供服务。有关更多详细信息,请参见http://msdn.microsoft.com/en-us/library/cc512374.aspx

您可能会考虑为每个WCF请求使用不同的记录器实例。

+0

你说“多线程来服务多个WCF请求”。我正在谈论单个WCF调用...(不是多个) – Vaccano 2013-05-01 14:36:30

1

自定义属性不需要是字符串。所以,你可以在下面的类的实例存储在全球范围内:

public class SessionIdProperty 
{ 
    public override string ToString() 
    { 
     // error handling omitted 
     return Session.SessionID; 
    } 
} 

这样log4net的可以直接访问Session对象时,它会记录一条消息。 Log4net在非字符串属性上调用ToString()方法。

相关问题