为啥,当我在 WCF 服务中模拟时,当我尝试运行 LINQ to SQL 查询时,我的服务不能加载 System.Transactions?

Posted

技术标签:

【中文标题】为啥,当我在 WCF 服务中模拟时,当我尝试运行 LINQ to SQL 查询时,我的服务不能加载 System.Transactions?【英文标题】:Why, when I impersonate within a WCF service, can my service not load System.Transactions when I try to run a LINQ to SQL query?为什么,当我在 WCF 服务中模拟时,当我尝试运行 LINQ to SQL 查询时,我的服务不能加载 System.Transactions? 【发布时间】:2010-09-21 15:06:41 【问题描述】:

我有一个 WCF 服务,托管在 IIS 7.0 中,需要运行数据库查询。为了获得执行此操作的正确权限,我在服务中模拟如下:

代码

[OperationBehavior(Impersonation = ImpersonationOption.Allowed)]
public void MyOperation(int arg)

配置

<behavior name="ReceivingServiceBehavior">
    <!-- Other behaviors -->
    <serviceAuthorization impersonateCallerForAllOperations="true" />
</behavior>

当我尝试连接并运行我的查询时,我得到以下信息:

异常 - System.IO.FileLoadException:无法加载文件或 程序集'System.Transactions,版本=2.0.0.0,文化=中性, PublicKeyToken=b77a5c561934e089' 或其依赖项之一。要么 未提供所需的模拟级别,或提供的 模拟级别无效。 (来自 HRESULT 的异常:0x80070542) 文件名:'System.Transactions,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089' ---> System.Runtime.InteropServices.COMException (0x80070542):未提供所需的模拟级别,或提供的模拟级别无效。 (来自 HRESULT 的异常:0x80070542) 在 System.Data.Linq.SqlClient.SqlConnectionManager.UseConnection(IConnectionUser 用户) 在 System.Data.Linq.SqlClient.SqlProvider.get_IsSqlCe() 在 System.Data.Linq.SqlClient.SqlProvider.InitializeProviderMode() 在 System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(表达式查询) 在 System.Data.Linq.DataQuery`1.System.Collections.Generic.IEnumerable.GetEnumerator() 在 System.Linq.Buffer`1..ctor(IEnumerable`1 源) 在 System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 源) 在 Fourth.GHS.MessageRelay.RegistrationDBStorage.FindRegistration(SystemKey 键)

【问题讨论】:

【参考方案1】:

您的 WCF 客户端是否设置了所需的“允许的模拟级别”:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>

        <!-- .... -->

        <behaviors>
           <endpointBehaviors>
              <behavior name="ImpersonationBehavior">
                 <clientCredentials>
                      <windows allowedImpersonationLevel="Impersonation" />
                 </clientCredentials>
              </behavior>
           </endpointBehaviors>
        </behaviors>
    </system.serviceModel>
</configuration>

默认情况下,如果没有明确指定,则将其设置为 Identification。查看this blog post 了解更多信息。

【讨论】:

【参考方案2】:

如果您希望 SQL 查询作为模拟身份执行,您实际上可能需要启用对 SQL 服务器的委派。查看这篇文章了解更多信息:

http://msdn.microsoft.com/en-us/library/ms730088.aspx

【讨论】:

我已经让我们的管理员启用委派,这似乎对服务起到了作用。但是,该服务调用了另一个后端服务,并且委托现在落在了那里。 您是否遇到了 DTC 问题?如果您将事务通过服务跨到另一台机器,您可能需要考虑启用它。至于凭据,您是否在调用其他服务时使用 Windowsidentity.Impersonate 方法进行模拟?【参考方案3】:

谢谢你们, 我通过阅读以下声明下的 XML 解决了它:

[OperationBehavior(Impersonation:=ImpersonationOption.Required)]

只有当我直接从 WCFService 类读取 XML 时它才有效。

【讨论】:

【参考方案4】:

嗯……我不知道。但是,您可以强制 dll 尽早加载。由于您使用的是 IIS,这可能会在您的 global.asax 中 - 像创建和丢弃 TransactionScope 这样的事情应该可以完成这项工作......

【讨论】:

【参考方案5】:

在尝试了更多之后,IIS 托管服务最简单的解决方案是使用具有必要权限的域用户的身份运行您的应用程序池。这在安全性方面可能存在问题,但就我们的目的而言,它已经足够好了。我们可以限制授予该用户的权限,但一切正常,无需进入 Kerberos、模拟、委托和 AD 的奥秘。

【讨论】:

【参考方案6】:

谢谢你。在过去的一天半里,我一直在与这个战斗。这里有一些可以为我节省大量时间的东西。所以希望它会节省一些时间。 我遇到了 SQLConnection 问题,并且使用传输安全性拒绝模拟抛出注册表访问。我什至尝试使用transportwithmessagecredential。在 procmon 内部,我得到了“Bad Impersonation”。 我的配置是 IIS 7,虚拟目录仅启用了 Windows 身份验证,我禁用了内核模式身份验证。我将其设置为使用通过身份验证的基本设置。

服务配置-

  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="false" />
    <services>
      <service behaviorConfiguration="SymitarService.ScheduleServiceBehavior" name="SymitarService.ScheduleService">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsSecure" contract="SymitarService.IScheduleService">
          <identity>
            <dns value="localhost" />            
          </identity>
        </endpoint>
        <endpoint address="mex" binding="wsHttpBinding" bindingConfiguration="wsSecure" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="SymitarService.UserDirectoryBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceAuthorization impersonateCallerForAllOperations="true" />
        </behavior>
        <behavior name="SymitarService.ScheduleServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceAuthorization impersonateCallerForAllOperations="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netTcpBinding>
        <binding name="tcpSecure" portSharingEnabled="true" />
      </netTcpBinding>
      <wsHttpBinding>
        <binding name="wsSecure" allowCookies="true">
          <security mode="Transport">
            <transport clientCredentialType="Windows" proxyCredentialType="Windows" />
            <message clientCredentialType="Windows" negotiateServiceCredential="true" />
          </security>
        </binding>
      </wsHttpBinding>
      <mexTcpBinding>
        <binding name="mexSecure" />
      </mexTcpBinding>
    </bindings>
  </system.serviceModel>

和客户

<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="WSHttpBinding_IScheduleService" closeTimeout="01:00:00" openTimeout="01:00:00" receiveTimeout="01:00:00" sendTimeout="01:00:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" useDefaultWebProxy="true" allowCookies="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <reliableSession ordered="true" inactivityTimeout="00:20:00" enabled="false" />
          <security mode="Transport">
            <transport clientCredentialType="Windows" proxyCredentialType="Windows" realm="" />
            <message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="ImpersonationBehavior">
          <clientCredentials>
            <windows allowedImpersonationLevel="Impersonation" allowNtlm="true"/>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <client>
      <endpoint address="https://server:444/SymitarService/ScheduleService.svc" 
                binding="wsHttpBinding" 
                bindingConfiguration="WSHttpBinding_IScheduleService" 
                contract="Symitar.ScheduleService.IScheduleService" 
                name="WSHttpBinding_IScheduleService"
                behaviorConfiguration="ImpersonationBehavior"
                >
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>

【讨论】:

【参考方案7】:

这个解决了我的问题。

右键单击 Visual Studio(无论您使用哪个版本) 特性 选择兼容性选项卡 填写“以管理员身份运行此程序”复选框 从文件位置打开项目 运行应用程序

【讨论】:

以上是关于为啥,当我在 WCF 服务中模拟时,当我尝试运行 LINQ to SQL 查询时,我的服务不能加载 System.Transactions?的主要内容,如果未能解决你的问题,请参考以下文章

ssl、silverlight、wcf 和本地安装

WCF 模拟不是模拟管理员

在 WCF 服务中使用模拟时 SQL 登录失败

在IIS上运行C#WCF服务时获取重复记录

版本化服务合同后无法访问 WCF 服务

WCF 服务合同不匹配