У меня есть сервер WCF, настроенный для одноэлементного копирования.Мой клиент передает в качестве параметра методу службы, объект, который реализует интерфейс IDisposable
, и сервер пытается кэшировать этот экземпляр, однако параметр автоматически удаляется во время выполнения WCF в какой-то момент после метод службы выполняется, преждевременно уничтожая мой кэшированный экземпляр.
Просматривая трассировку стека, я обнаружил, что вызов Dispose()
параметра вызывается внутри метода MessageRpc.DisposeParametersCore()
.
Это эталонный источник для этого метода, взятый из здесь :
internal void DisposeParametersCore(bool excludeInput)
{
if (!this.ParametersDisposed)
{
if (!excludeInput)
{
this.DisposeParameterList(this.InputParameters);
}
this.DisposeParameterList(this.OutputParameters);
IDisposable disposableParameter = this.ReturnParameter as IDisposable;
if (disposableParameter != null)
{
try
{
disposableParameter.Dispose();
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
this.channelHandler.HandleError(e);
}
}
this.ParametersDisposed = true;
}
}
Как видите, удаление входных параметров контролируется параметром boolexcludeInput
, который намекает мне, что это поведение необязательно.
Я знаю, что если я кеширую глубокую копию параметра, это обойдет эту проблему, но есть ли способ отключить это автоматическое поведение для определенного метода WCF?
Вот класс объектов, который я пытаюсь кэшировать на сервере (написанный на C ++ CLI):
[Serializable()]
public ref class OpaqueMediaType : ISerializable, IConcreteMediaType {
private:
static const Byte _version = 1;
private:
clr_scoped_ptr<CComPtrIMFMediaType> _ppMediaType;
protected:
virtual DMO_MEDIA_TYPE* __clrcall GetConcreteDMOMediaType() sealed
= IConcreteMediaType::GetConcreteDMOMediaType;
virtual CComPtrIMFMediaType __clrcall GetConcreteMFMediaType() sealed
= IConcreteMediaType::GetConcreteMFMediaType;
virtual void __clrcall FreeConcreteDMOMediaType(DMO_MEDIA_TYPE* pDMOMediaType) sealed
= IConcreteMediaType::FreeConcreteDMOMediaType;
protected:
OpaqueMediaType(SerializationInfo^ info, StreamingContext context);
public:
OpaqueMediaType(DMO_MEDIA_TYPE& dmoMediaType);
OpaqueMediaType(IMFMediaType* pMFMediaType);
OpaqueMediaType(PCM_MediaType pcmMediaType);
virtual void __clrcall GetObjectData(SerializationInfo^ info, StreamingContext context);
PCM_MediaType AsPCM();
};
Член _ppMediaType
становится владельцем указателя производного класса CComPtr, поэтому, когдаэкземпляр удаляется, связанный объект COM освобождается.Поскольку этот член является одноразовым, интерфейс IDisposable
для класса OpaqueMediaType
автоматически определяется и реализуется C ++ / CLI.
Вот метод WCF, который кэширует объект:
Task IStorageBackendSvc.AcceptWmaMediaType(int stationId, OpaqueMediaType mediaType) {
try {
WmaWriter wmaWriter = GetWmaWriter(stationId);
wmaWriter.MediaType = mediaType; // parameter object is cached here (shallow copy)
return Task.CompletedTask;
} catch( Exception exception ) {
throw _faultFactory.Wrap(exception);
}
// the `mediaType` parameter is being disposed by WCF at some point AFTER calling this code, releasing the internal COM object held by the cached instance prematurely
}