在 ASP.NET 兼容模式下运行的 WCF 服务中 HttpContext 为 null
我有一个托管 WCF 服务的 asp.net 网站。然后从桌面应用程序访问该服务。在我的服务中,在 UserNamePasswordValidator 类的实现中执行 Validate 方法期间,HttpContext 始终为 null。我使用用户名作为客户端凭据类型。我需要访问 http 上下文才能获取访问服务的 Url,以便正确验证用户名和密码,因为可以使用不同的 Url 访问该站点,并且每个 Url 都有不同的用户存储。
类上的以下属性包含将在验证器类(以及验证器类)之后调用的方法,
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
我有一个服务配置如下:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpSecurityOptions">
<security mode="Message">
<message clientCredentialType="UserName" establishSecurityContext="true" negotiateServiceCredential="true"/>
<transport clientCredentialType="Certificate" proxyCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SecurityServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WCFServer.MyAuthenticator" includeWindowsGroups="false"/>
<serviceCertificate findValue="myurl.com" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="SecurityServiceBehavior" name="Test.WCF.Actions">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpSecurityOptions" contract="WCFServer.IActions"/>
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
我已经看到了 HttpContext 未在首次调用错误时初始化 但每次对服务进行调用时都会发生这种情况,即使我在同一个连接上多次调用相同的方法
编辑:澄清问题以回答 marc_s 的评论和 Aliostad 的问题
编辑:添加了以下链接,建议 http 上下文不应为 null
- http://blogs.msdn.com /b/wenlong/archive/2006/01/23/516041.aspx
- http://msdn.microsoft.com/en-us/library/aa702682(v=VS.90).aspx
谁能借给我请问有这个吗?我不想将网站的 Url 放入所有网站的 appSettings 配置部分。
I have a asp.net website that is hosting a WCF service. This service is then accessed from a desktop app. In my service the HttpContext is always null during the execution of the Validate method in my implementation of the UserNamePasswordValidator class. I'm using Username as the client credential type. I need access to the http context in order to get the Url the service was accessed from in order to validate the username and password correctly as the site can be accessed using different Urls and each one has a different user store.
The following attribute on the class that contains the method that will be called after the validator class (and the validator class as well)
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
I have a service is configured as follows:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpSecurityOptions">
<security mode="Message">
<message clientCredentialType="UserName" establishSecurityContext="true" negotiateServiceCredential="true"/>
<transport clientCredentialType="Certificate" proxyCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SecurityServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WCFServer.MyAuthenticator" includeWindowsGroups="false"/>
<serviceCertificate findValue="myurl.com" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="SecurityServiceBehavior" name="Test.WCF.Actions">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpSecurityOptions" contract="WCFServer.IActions"/>
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
I've seen the HttpContext is not initialised on first call bug but this happens to me for every call I make to the service, even when I call the same method on the same connection more than once
Edit: clarified question to answer marc_s's comment and Aliostad's question
Edit: Added following links that suggest the http context should not be null
- http://blogs.msdn.com/b/wenlong/archive/2006/01/23/516041.aspx
- http://msdn.microsoft.com/en-us/library/aa702682(v=VS.90).aspx
Can anyone lend me a hand with this please? I'd rather not have to put the site's Url in the appSettings config section for all my sites.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
问题是您想从 Validate 方法访问 HttpContext。据我了解,内部 WCF 实现 Validate 方法在不同的线程中运行。根据设计,该线程无权访问可用于处理请求的主线程的任何上下文。在 Validate 方法中,您无法访问任何基于 WCF 的上下文(OperationContext、ServiceSecurityContext 等),因此我认为它与 HttpContext 相同。
The problem is that you want to access HttpContext from Validate method. As I understand internal WCF implementation Validate method runs in different thread. By design this thread doesn't have access to any context available to main thread processing the request. In Validate method you can't access any WCF based context (OperationContext, ServiceSecurityContext, etc.) so I think it will be the same with HttpContext.
UserNamePasswordValidator 的 validate 方法在 asp.net 管道初始化之前执行。所以 HttpContext 为空。尝试改用OperationContext。
UserNamePasswordValidator's validate method is executed before asp.net pipeline is initialized. So the HttpContext is null. Try using OperationContext instead.
我不清楚你想做什么。
据我所知,只有当您使用不需要绑定配置的新 WCF REST API 时,aspNetCompatibilityEnabled 才有意义。 WCF REST 中的绑定由 ASP.NET MVC 路由管理。
如果您使用配置 API 设置经典绑定,则您不会使用新功能,因此“没有启用 aspNetCompatibility你”!
I am not clear on what you are trying to do.
aspNetCompatibilityEnabled
only makes sense - as far as I know - when you are using new WCF REST API which does not require a binding configuration. Binding in WCF REST is managed by ASP.NET MVC routing.If you use configuration API to set up a classic binding, then you are not using the new feature hence "no aspNetCompatibilityEnabled for you"!
所以最后我想到了一个解决方法。我通过用户名参数将运行服务的 url 传递给 UserNamePasswordValidator.Validate。我使用 $username$|$siteurl$ 格式。然后在服务器上我将两者分开。需要注意的一件事是
property will then contain $username$|$siteurl$ for the rest of the request so you have to split it into its component everytime you want to access it.
只是为了澄清为什么我需要这样做。我们的系统可以在同一主目录上运行具有不同 url 的多个站点,每个站点都具有与 url 绑定的单独身份验证。因此,如果没有 url,我无法验证请求。我一直使用 appSetting 键来提供 url,但这意味着每个站点都必须有自己的主目录。
So finally I thought of a workaround. I pass the url that the service is running in to the UserNamePasswordValidator.Validate though the username parameter. I use the format $username$|$siteurl$. Then at the server I separate the two. One thing to note is the
property will then contain $username$|$siteurl$ for the rest of the request so you have to split it into its component everytime you want to access it.
Just to clarify why I need to do this. Our system can run multiple sites with different urls on the same home directory, each with separate authentication that is tied to the url. So without the url I can't authenticate the request. I had been using an appSetting key to provide the url but that meant each site had to have its own home directory.