C# 禁用WCF服务调用中输入参数的自动处理

C# 禁用WCF服务调用中输入参数的自动处理,c#,wcf,C#,Wcf,我有一个为单例实例配置的WCF服务器。我的客户端正在将参数作为参数传递给服务方法,该方法是一个实现IDisposable接口的对象,服务器正在尝试缓存此实例,但是,在执行服务方法后的某个时间点,WCF运行时会自动释放该参数,从而过早地销毁缓存的实例 通过查看堆栈跟踪,我发现参数的Dispose()调用正在MessageRpc.DisposeParametersCore()方法中调用 这是该方法的参考源,取自: 如您所见,输入参数的处理由bool参数excludeInput控制,它提示我此行为是可

我有一个为单例实例配置的WCF服务器。我的客户端正在将参数作为参数传递给服务方法,该方法是一个实现
IDisposable
接口的对象,服务器正在尝试缓存此实例,但是,在执行服务方法后的某个时间点,WCF运行时会自动释放该参数,从而过早地销毁缓存的实例

通过查看堆栈跟踪,我发现参数的
Dispose()
调用正在
MessageRpc.DisposeParametersCore()
方法中调用

这是该方法的参考源,取自:

如您所见,输入参数的处理由bool参数
excludeInput
控制,它提示我此行为是可选的

我知道,如果缓存参数的深度副本,它将避免此问题,但有没有办法关闭特定WCF方法的此自动行为

这里是我试图在服务器上缓存的对象类(用C++ CLI编写):


使用
OperationBehaviorAttribute.AutoDisposeParameters=false
装饰方法的实现(而不是契约)即可完成此任务

这是我的合同

[ServiceContract]
   public interface IStorageBackendSvc {
      ...
      [OperationContract]
      [FaultContract(typeof(DescriptiveFault))]
      Task AcceptWmaMediaType(int stationId, OpaqueMediaType mediaType);

   }
以下是实施方案:

  [OperationBehavior(AutoDisposeParameters = false)]
  Task IStorageBackendSvc.AcceptWmaMediaType(int stationId, OpaqueMediaType mediaType) {
     try {
        WmaWriter wmaWriter = GetWmaWriter(stationId);
        wmaWriter.MediaType = mediaType;
        return Task.CompletedTask;
     } catch( Exception exception ) {
        throw _faultFactory.Wrap(exception);
     }
  }
现在,
mediaType
参数是未处理的,因此缓存的引用保持有效,我可以绕过执行参数的深度复制

编辑:关于如何缓存对象的疑问,下面是代码:

  private Dictionary<int, WmaWriter> _wmaWriters;

  private WmaWriter GetWmaWriter(int stationId) {
         WmaWriter wmaWriter;
         lock( _wmaWriters ) {
            if( !_wmaWriters.TryGetValue(stationId, out wmaWriter) ) {
               wmaWriter = new WmaWriter(stationId, new DailyFileSplitter(), new WmaFileNameResolver(stationId));
               _wmaWriters[stationId] = wmaWriter;
            }
         }
         return wmaWriter;
      }
private Dictionary\u wmaWriters;
私有WmaWriter GetWmaWriter(int stationId){
WmaWriter WmaWriter;
锁(wmaWriters){
if(!\u wmaWriters.TryGetValue(stationId,out wmaWriter)){
wmaWriter=new wmaWriter(stationId,new dailyfilespliter(),new wmafilenamesolver(stationId));
_wmaWriters[stationId]=wmaWriter;
}
}
返回wmaWriter;
}

\u wmaWriters
是服务会员。它是一个字典,包含由电台Id键入的多个WMA编写器(我正在录制多个电视台和广播台)。
GetWmaWriter()
方法将返回与特定电台关联的现有WMA编写器,如果不存在,它将创建一个新的WMA编写器。缓存是有效的,因为对于同一站点Id的多个调用,我将获得相同的WmaWriter实例。

我想我找到了它:
OperationBehaviorAttribute.AutoDisposeParameters
“…服务器正在尝试缓存此实例…”-它是如何做到的?您需要显示该代码。考虑到您的服务器是单例的,这应该不难,只需将它放在服务类的一个字段中即可。不需要任何花哨的
DisposeParametersCore
。您也知道,WCF服务器的AppDomain中出现的任何对象都与客户端对该对象的表示无关。即使WCF客户机和服务器都在同一台计算机上,您也会有不同的对象。更改客户端不会影响服务器,反之亦然。WCF不是.NETRemoting@MickyD
DisposeParametersCore
是一个WCF内部方法,在服务接受我的请求后由WCF自动调用。我也知道WCF服务器反序列化了客户端传递的参数的副本,WCF基础设施正在自动处理该副本。我可以通过创建和缓存参数的深层副本来避免这个问题,但我想知道是否可以在契约中控制这种行为。显然是的。我正在阅读一些资料,在流媒体播放期间,AutoDisposeParameters选项可能很有用。你在某处使用它吗?@MickyD我添加了缓存
mediaType
参数的逻辑。如您所见,它是根目录的,因为我将它分配给对象的MediaType属性,该对象的生存期由服务本身控制。问题是,即使对象是根对象,WCF也坚持自动处理它,而不管对它的有效引用是否仍然保留。不,在这种情况下没有流。基本上,WCF客户端指定WMA记录的质量(比特率、样本大小、采样频率等)。客户端需要将此配置中继到远程WMA写入组件,该组件将从客户端接收压缩音频数据包。此信息存储在可序列化的
OpaqueMediaType
实例上,因此可通过WCF传输…哇,好的。很高兴你成功了+1@MickyD,谢谢你的意见。很抱歉,我输入了很多信息,这些信息对于正确的上下文是必要的。干杯=D
[ServiceContract]
   public interface IStorageBackendSvc {
      ...
      [OperationContract]
      [FaultContract(typeof(DescriptiveFault))]
      Task AcceptWmaMediaType(int stationId, OpaqueMediaType mediaType);

   }
  [OperationBehavior(AutoDisposeParameters = false)]
  Task IStorageBackendSvc.AcceptWmaMediaType(int stationId, OpaqueMediaType mediaType) {
     try {
        WmaWriter wmaWriter = GetWmaWriter(stationId);
        wmaWriter.MediaType = mediaType;
        return Task.CompletedTask;
     } catch( Exception exception ) {
        throw _faultFactory.Wrap(exception);
     }
  }
  private Dictionary<int, WmaWriter> _wmaWriters;

  private WmaWriter GetWmaWriter(int stationId) {
         WmaWriter wmaWriter;
         lock( _wmaWriters ) {
            if( !_wmaWriters.TryGetValue(stationId, out wmaWriter) ) {
               wmaWriter = new WmaWriter(stationId, new DailyFileSplitter(), new WmaFileNameResolver(stationId));
               _wmaWriters[stationId] = wmaWriter;
            }
         }
         return wmaWriter;
      }