WCF wsHttpBinding与IIS

时间:2011-10-26 16:11:41

标签: multithreading wcf iis

我使用带有IIS的wsHttpBinding设置了一组WCF服务,并实现了自定义安全性(使用邮件头)来确定发出请求的用户。基于几年的netTcpBinding经验(使用Windows服务来托管而不是IIS),我一直都理解,WCF端点收到的每个请求都会在新线程上结束。使用这个假设,我的自定义安全类(实现IDispatchMessageInspector)基于在消息头中找到“token”(Guid)来设置线程标识,如下所示:

public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
{
     string token = string.Empty;
     if (request.Headers.FindHeader("SecurityToken", Primitives.SerializationNamespace) > -1)
         token = request.Headers.GetHeader<string>("SecurityToken", Primitives.SerializationNamespace);

     if (!string.IsNullOrEmpty(token))
        Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(token, "AppName"), new string[] { "testrole" });
    else
        Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("guest", "AppName"), new string[] { });
     }

     return null;
 }

在测试中,尽管我的内部变量(包含用户对象)被标记为ThreadStatic,但新请求似乎保留了先前调用者的身份。

以下是一个例子:

[ThreadStatic]
private static User _CurrentUser = null;

internal static User CurrentUser
    {
        get
        {
            //this holds the value of the previous caller's identity still, even though the
            //thread's Identity.Name is now equal to the new caller's Guid
            if (_CurrentUser == null)
                    _CurrentUser = UserData.GetByToken(Thread.CurrentPrincipal.Identity.Name);


            return _CurrentUser;
        }
    }

我还尝试使用以下属性标记我的所有服务实现(直接在.svc文件后面),但这并没有改变任何内容:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]

关于如何保证每个请求的任何想法都在新线程上?或者是否有更好的方法来存储/确定发出请求的用户是否没有任何可能的重叠?

1 个答案:

答案 0 :(得分:2)

在您无法控制线程的环境中使用ThreadStatic变量是灾难的方法。 WCF(IIS和自托管)和ASP.NET内部都使用线程池=每个请求都由单独的线程提供服务,但这些线程被重用于后续请求,并且无法避免它。

使用自定义OperationContext extension来存储您的用户,而不是ThreadStatic变量。