You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WCF单实例服务访问异常:多次调用返回不同Guid问题排查

问题根源:WCF默认实例模式导致多实例创建

你遇到的问题核心在于WCF的InstanceContextMode(实例上下文模式)默认设置是PerCall——这个模式下,每一次客户端的方法调用都会触发WCF创建一个全新的服务实例。所以你每次调用GetServiceId时,都会执行一次emmbeeService的构造函数,生成新的Guid;而每个实例里的List(Of T)都是独立的,自然无法在不同客户端/节点间共享。

解决方案:设置单实例模式(Single)

要实现全局唯一的服务实例,你需要把服务实现类的InstanceContextMode改成Single,同时还要处理多用户并发访问的问题。

步骤1:修改服务实现类的特性

在你的emmbeeService类上方添加ServiceBehavior特性,指定实例模式为Single,并配置并发模式:

Imports System.ServiceModel

<ServiceBehavior(
    InstanceContextMode:=InstanceContextMode.Single,
    ConcurrencyMode:=ConcurrencyMode.Multiple ' 允许多线程并发访问,适合多用户场景
)>
Public Class emmbeeService
    Implements IemmbeeService

    ' 唯一的服务ID,构造函数只执行一次
    Private ReadOnly _serviceId As Guid
    ' 共享的List,Single模式下所有客户端共用这个实例
    Private _sharedList As List(Of YourDataType)

    Public Sub New()
        ' 构造函数仅在服务启动时执行一次
        _serviceId = Guid.NewGuid()
        _sharedList = New List(Of YourDataType)()
    End Sub

    Public Function GetServiceId() As Guid Implements IemmbeeService.GetServiceId
        Return _serviceId
    End Function

    ' 示例:添加元素到共享列表
    Public Sub AddItemToSharedList(item As YourDataType) Implements IemmbeeService.AddItemToSharedList
        ' 多线程访问List必须加锁保证线程安全
        SyncLock _sharedList
            _sharedList.Add(item)
        End SyncLock
    End Sub

    ' 示例:获取共享列表
    Public Function GetSharedList() As List(Of YourDataType) Implements IemmbeeService.GetSharedList
        SyncLock _sharedList
            ' 返回副本避免外部直接修改原列表引发线程问题
            Return New List(Of YourDataType)(_sharedList)
        End SyncLock
    End Function
End Class

步骤2:关键配置说明

  • InstanceContextMode.Single:告诉WCF整个服务生命周期只创建一个实例,所有客户端的调用都共享这个实例,构造函数仅在服务首次启动时执行一次。
  • ConcurrencyMode.Multiple:允许多个客户端同时调用服务方法(多线程访问),这是多用户场景的必要配置。但要注意:
    • 对共享资源(比如你的List(Of T))进行读写操作时,必须用SyncLock保证线程安全,否则会出现数据错乱。
    • 如果你不需要并发,也可以用ConcurrencyMode.Single,但这样会导致客户端调用排队,性能下降。

额外注意事项(IIS托管场景)

因为你的服务托管在外部IIS上,还要注意避免IIS回收服务实例:

  • 打开IIS管理器,找到你的服务所在的应用程序池,修改回收设置:
    • 禁用“固定时间间隔回收”(设为0)
    • 禁用“虚拟内存/物理内存限制回收”(如果不需要的话)
  • 否则IIS会定期回收应用程序池,导致服务实例被销毁重建,Guid会重新生成,共享数据也会丢失。
验证效果

修改完成后,重启IIS上的服务,然后用多个客户端/节点调用GetServiceId,应该会返回同一个Guid;调用添加列表的方法后,其他客户端调用获取列表的方法应该能看到新增的元素。

内容的提问来源于stack exchange,提问作者Michael Bayer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:35:07