업데이트 : Henk의 도움을 받아 공개 Dispose()가 호출되고 있으며, Dispose()가 Private Dispose (true)를 호출합니다. 이것은 IDisposable 인터페이스의 첫 번째 구현이므로 올바른지 확실하지 않습니다. Dispose를 명시 적으로 어디에도 호출하지 않습니다. WCF 아키텍처는 각 OperationContract 멤버를 종료 할 때이를 호출하는 것 같습니다.정적 데이터가 포함 된 WCF 서비스에 문제가 있음
비 관리 클린업 코드를 지금 Dispose에서 제거하고 여러 호출이 정적 데이터에 액세스 할 수 있습니다. 정적 저장소에 개체에 대한 참조가있는 경우에도 Dispose()는 호출로부터 반환 될 때 로컬로 할당 된 모든 개체에 대해 호출됩니다. net에서 IDisposable 인터페이스가 올바르게 호출되도록이 문제를 해결하는 방법을 잘 모릅니다. 나는이 객체들이 어떤 시점에서 가비지 컬렉션을 얻을 것이라고 추측한다. 폐기가 호출 될 때 여기에
는 첫번째 호출에서 반환에 호출 스택입니다!BossISeriesCwbxService.dll BossISeriesCwbxServices.DataContracts.ISeriesSystem.Dispose (부울 bDisposing = TRUE) 라인 119 C#
BossISeriesCwbxService.dll! BossISeriesCwbxServices.DataContracts.ISeriesSystem.Dispose() 라인 (107) + 0xd는 C#
바이트하여 System.ServiceModel.dll! System.ServiceModel.Dispatcher.MessageRpc.DisposeParametersCore() + 0x56 바이트 SYSTE m.ServiceModel.dll! System.ServiceModel.Dispatcher.MessageRpc.DisposeParameters() + 0xF입니다 바이트하여 System.ServiceModel.dll! System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessageCleanup (REF System.ServiceModel.Dispatcher.MessageRpc RPC = System.ServiceModel.Dispatcher.MessageRpc {}) + 0x135 바이트하여 System.ServiceModel.dll! System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5 (REF System.ServiceModel.Dispatcher.MessageRpc RPC = { System.ServiceModel.Dispatcher. MessageRpc}) + 0x1bf bytes System.ServiceModel.dll! System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4 (ref System.ServiceModel.Dispatcher.MessageRpc RPC) + 0x80으로 바이트
하여 System.ServiceModel.dll! System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3 (REF System.ServiceModel.Dispatcher.MessageRpc RPC) + 0x36 바이트
하여 System.ServiceModel.dll!는 system.serviceModel .Dispatcher.ImmutableDispatchRuntime.ProcessMessage2 (REF System.ServiceModel.Dispatcher.MessageRpc RPC) + 0x43부터 바이트
하여 System.ServiceModel.dll! System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1 (REF System.ServiceModel.Dispatcher.MessageRpc rpc) + 0xd7 bytes
System.ServiceModel.dll! System.Serv iceModel.Dispatcher.MessageRpc.Process (BOOL isOperationContextSet = 거짓) + 0x9b 바이트
하여 System.ServiceModel.dll! System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.Dispatch (REF System.ServiceModel.Dispatcher.MessageRpc RPC, BOOL isOperationContextSet) +하여 System.ServiceModel.dll! System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump (System.ServiceModel.Channels.RequestContext 요청 = {System.ServiceModel.Security.SecuritySessionServerSettings 바이트 0x2d.SecuritySessionRequestContext}, 부울 cleanThread, System.ServiceModel.OperationContext currentOperationContext) + 0x20c 바이트
하여 System.ServiceModel.dll! System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest (System.ServiceModel.Channels.RequestContext 요청, 시스템 .ServiceModel.OperationContext currentOperationContext) + 0xDF를 바이트하여 System.ServiceModel.dll! System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump (System.IAsyncResult 결과) + 0x43부터 바이트
하여 System.ServiceModel.dll! System.Ser viceModel.Dispatcher.ChannelHandler.OnContinueAsyncReceive (객체 상태) + 0x45 바이트
하여 System.ServiceModel.dll! System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke2() +부터 0x46 바이트하여 System.ServiceModel.dll! 시스템. ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.OnSecurityContextCallback (객체 O) +하는 0x28 바이트
가 mscorlib.dll! System.Security.SecurityContext.Run (System.Security.SecurityContext SecurityContext에, System.Threading.ContextCallback 콜백 개체 상태) + 0x55 바이트System.ServiceModel.dll! System.ServiceModel.Cha nnels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke() +
바이트에는 0x4d하여 System.ServiceModel.dll! System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ProcessCallbacks() + 0x180 바이트하여 System.ServiceModel.dll! 시스템. ServiceModel.Channels.IOThreadScheduler.CriticalHelper.CompletionCallback (객체 상태) +
하여 System.ServiceModel.dll! System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ScheduledOverlapped.IOCallback (단위 의 errorCode, UINT하는 numBytes 바이트 0x7a, 하여 System.Threading .NativeOverlapped * nativeOverlapped) + 0xf 바이트
SMDiagnostics.dll! System.Serv iceModel.Diagnostics.Utility.IOCompletionThunk.UnhandledExceptionFrame (단위 오류, UINT의 bytesRead, System.Threading.NativeOverlapped * nativeOverlapped)
가 mscorlib.dll 바이트 0x3d +! System.Threading._IOCompletionCallback.PerformIOCompletionCallback (단위 의 errorCode, UINT하는 numBytes , System.Threading.NativeOverlapped * pOVERLAP) + 0x54 바이트
나는 WCF 서비스의 구현 클래스에서 정적 데이터를 캐시에 대한 몇 가지 게시물을 읽고, A의 개체에 대한 처리 호출 GC에 문제가 있었다 정적 사전. IBM iSeries Access에서 일부 activex 객체를 참조하므로 IDisposable 인터페이스를 구현하여 iSeries에 대한 연결을 정리했습니다. 내 문제는 GC가 서비스 클래스의 정적 멤버에 개체를 삭제하는 것입니다. 모든 코드가 필요하다는 것은 확실하지 않지만, 어쨌든 여기에 있습니다. 문제는 각 OperationContract 메서드에서 반환 할 때 GC가 관련된 Dictionary에 추가 된 ISeriesSystem 또는 Queue 개체에서 Dispose를 호출하지만 ISeriesSystem Dictionary는 정적이므로 개체에 대한 참조를 보유하고 있다고 생각합니다. GC는 사전에서 제거 될 때까지 수행되지 않습니다.
서비스 인터페이스 :
[ServiceContract(Namespace="BossISeriesCwbxServices")]
public interface IDataQueueService
{
[OperationContract]
ISeriesSystem SystemInitialize(string sISeriesName);
[OperationContract(Name="FinalizeSystemByName")]
void SystemFinalize(string sISeriesName);
[OperationContract]
void SystemFinalize(ISeriesSystem oISeriesSystem);
[OperationContract]
Queue QueueInitialize(string sQueueName, string sLibrary, string sISeriesName);
[OperationContract(Name="FinalizeQueueByName")]
void QueueFinalize(string sQueueName, string sLibrary, string sISeriesName);
[OperationContract]
void QueueFinalize(Queue oDataQueue);
[OperationContract (Name="QueueWriteByName")]
void QueueWrite(string sQueueName, string sLibrary, string sISeriesName, string sMessage);
[OperationContract]
void QueueWrite(Queue oDataQueue, string sMessage);
[OperationContract (Name="QueueReadByName")]
string QueueRead(string sQueueName, string sLibrary, string sISeriesName);
[OperationContract]
string QueueRead(Queue oDataQueue);
}
서비스 구현 :
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
public class DataQueueService : IDataQueueService
{
private static Dictionary<string, ISeriesSystem> mdictISeriesSystems = new Dictionary<string, ISeriesSystem>();
public static IDictionary<string, ISeriesSystem> ISeriesDict
{
get { return mdictISeriesSystems; }
}
public ISeriesSystem SystemInitialize(string sISeriesName)
{
ISeriesSystem oISeriesSystem = AddSystem(sISeriesName);
return oISeriesSystem;
}
public void SystemFinalize(string sISeriesName)
{
}
public void SystemFinalize(ISeriesSystem oISeriesSystem)
{
SystemFinalize(oISeriesSystem.Name);
}
public Queue QueueInitialize(string sQueueName, string sLibrary, string sISeriesName)
{
ISeriesSystem oISeriesSystem = null;
Queue oDataQueue = null;
try
{
oISeriesSystem = AddSystem(sISeriesName);
oDataQueue = oISeriesSystem.AddQueue(sQueueName, sLibrary);
}
catch (Exception ex)
{
// ToDo: Log ex to WCF service log and remove from Console.
Console.WriteLine(ex.ToString());
oDataQueue = null;
}
return oDataQueue;
}
public Queue QueueInitialize(string sQueueName, string sLibrary, ISeriesSystem oISeriesSystem)
{
return QueueInitialize(sQueueName, sLibrary, oISeriesSystem.Name);
}
public void QueueFinalize(string sQueueName, string sLibrary, string sISeriesName)
{
string sISeriesKey = sISeriesName.Trim();
string sDataQueueKey = sLibrary.Trim() + sQueueName.Trim();
ISeriesSystem oISeriesSystem = null;
Queue oDataQueue = null;
if (DataQueueService.ISeriesDict.TryGetValue(sISeriesKey, out oISeriesSystem))
{
if (oISeriesSystem.DataQueueDict.TryGetValue(sDataQueueKey, out oDataQueue))
{
oDataQueue.Dispose();
oDataQueue = null;
oISeriesSystem.DataQueueDict.Remove(sDataQueueKey);
}
if (oISeriesSystem.DataQueueDict.Count == 0)
{
oISeriesSystem.Dispose();
oISeriesSystem = null;
}
}
}
public void QueueFinalize(Queue oDataQueue)
{
QueueFinalize(oDataQueue.Name, oDataQueue.Library, oDataQueue.ISeriesName);
}
public void QueueWrite(string sQueueName, string sLibrary, string sISeriesName, string sMessage)
{
string sISeriesKey = sISeriesName.Trim();
string sDataQueueKey = sLibrary.Trim() + sQueueName.Trim();
ISeriesSystem oISeriesSystem = null;
Queue oDataQueue = null;
if (DataQueueService.ISeriesDict.TryGetValue(sISeriesKey, out oISeriesSystem))
{
if (oISeriesSystem.DataQueueDict.TryGetValue(sDataQueueKey, out oDataQueue))
{
oDataQueue.Write(sMessage);
}
}
}
public void QueueWrite(Queue oDataQueue, string sMessage)
{
QueueWrite(oDataQueue.Name, oDataQueue.Library, oDataQueue.ISeriesName, sMessage);
}
public string QueueRead(string sQueueName, string sLibrary, string sISeriesName)
{
string sISeriesKey = sISeriesName.Trim();
string sDataQueueKey = sLibrary.Trim() + sQueueName.Trim();
ISeriesSystem oISeriesSystem = null;
Queue oDataQueue = null;
if (DataQueueService.ISeriesDict.TryGetValue(sISeriesKey, out oISeriesSystem))
{
if (oISeriesSystem.DataQueueDict.TryGetValue(sDataQueueKey, out oDataQueue))
{
return oDataQueue.Read();
}
}
return "";
}
public string QueueRead(Queue oDataQueue)
{
return QueueRead(oDataQueue.Name, oDataQueue.Library, oDataQueue.ISeriesName);
}
ISeriesSystem AddSystem(string sISeriesName)
{
ISeriesSystem oISeriesSystem = null;
string sISeriesKey = sISeriesName.Trim();
if (!DataQueueService.ISeriesDict.TryGetValue(sISeriesKey, out oISeriesSystem))
{
oISeriesSystem = new ISeriesSystem(sISeriesName);
DataQueueService.ISeriesDict[sISeriesKey] = oISeriesSystem;
}
return oISeriesSystem;
}
ISeriesSystem DataContract :
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
using cwbx;
namespace BossISeriesCwbxServices.DataContracts
{
public class ISeriesSystem : IDisposable
{
private string msName;
[DataMember]
public string Name
{
get { return msName; }
set { msName = value; }
}
private Dictionary<string, Queue> mdictDataQueues = new Dictionary<string, Queue>();
public IDictionary<string, Queue> DataQueueDict
{
get { return mdictDataQueues; }
}
private cwbx.AS400System mcwbxISeriesSystem = new AS400System();
private cwbx.AS400System CwbxISeriesSystem
{
get { return mcwbxISeriesSystem; }
set { mcwbxISeriesSystem = value; }
}
private bool bDisposed = false;
public ISeriesSystem()
{
}
public ISeriesSystem(string sISeriesName)
{
try
{
// Set DataContract properties.
this.Name = sISeriesName;
// Connect to iSeries, Logon and connect to iSeries services that may be used.
this.CwbxISeriesSystem.Define(sISeriesName);
this.CwbxISeriesSystem.UserID = "APP1DAK";
this.CwbxISeriesSystem.Password = "DONNA99";
this.CwbxISeriesSystem.Signon();
this.CwbxISeriesSystem.Connect(cwbcoServiceEnum.cwbcoServiceDataQueues);
this.CwbxISeriesSystem.Connect(cwbcoServiceEnum.cwbcoServiceSecurity);
this.CwbxISeriesSystem.Connect(cwbcoServiceEnum.cwbcoServiceRemoteCmd);
}
catch (Exception ex)
{
// ToDo: Log ex to WCF service log and remove from Console.
Console.WriteLine(ex.ToString());
foreach (cwbx.Error cwbxError in this.CwbxISeriesSystem.Errors)
{
Console.WriteLine(cwbxError.Text);
Console.WriteLine(cwbxError.ToString());
}
}
}
~ISeriesSystem()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool bDisposing)
{
// Only Dispose of the object 1 time.
if (!this.bDisposed)
{
// If disposing equals true, Dispose() was called by GC, so dispose all managed resources.
if (bDisposing)
{
// Dispose managed resources, calling object Dispose method for objects
// that implement IDisposable interface.
}
try
{
if (this.CwbxISeriesSystem.IsConnected(cwbcoServiceEnum.cwbcoServiceAny) == 1)
{
this.CwbxISeriesSystem.Disconnect(cwbcoServiceEnum.cwbcoServiceAll);
}
}
catch (Exception ex)
{
// ToDo: Log ex to WCF service log and remove from Console.
Console.WriteLine(ex.ToString());
foreach (cwbx.Error cwbxError in this.CwbxISeriesSystem.Errors)
{
Console.WriteLine(cwbxError.Text);
Console.WriteLine(cwbxError.ToString());
}
}
// Mark disposing as being done.
bDisposed = true;
}
}
public Queue AddQueue(string sQueueName, string sLibrary)
{
Queue oDataQueue = null;
string sDataQueueKey = sLibrary.Trim() + sQueueName.Trim();
if (!this.DataQueueDict.TryGetValue(sDataQueueKey, out oDataQueue))
{
oDataQueue = new Queue(sQueueName, sLibrary, this.CwbxISeriesSystem);
this.DataQueueDict[sDataQueueKey] = oDataQueue;
}
return oDataQueue;
}
}
}
큐 DataContract :
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
using cwbx;
namespace BossISeriesCwbxServices.DataContracts
{
[DataContract]
public class Queue : IDisposable
{
private string msName;
[DataMember]
public string Name
{
get { return msName; }
set { msName = value; }
}
private string msLibrary;
[DataMember]
public string Library
{
get { return msLibrary; }
set { msLibrary = value; }
}
private string msISeriesName;
[DataMember]
public string ISeriesName
{
get { return msISeriesName; }
set { msISeriesName = value; }
}
private short miWaitTime = 10;
[DataMember]
public short WaitTime
{
get { return miWaitTime; }
set { miWaitTime = value; }
}
private short miNumberOfAttempts = 1;
[DataMember]
public short NumberOfAttempts
{
get { return miNumberOfAttempts; }
set { miNumberOfAttempts = value; }
}
private short miMaxQueueIndex = 1;
public short MaxQueueIndex
{
get { return miMaxQueueIndex; }
set { miMaxQueueIndex = value; }
}
private short miCurrentQueueIndex = 1;
public short CurrentQueueIndex
{
get { return miCurrentQueueIndex; }
set { miCurrentQueueIndex = value; }
}
private cwbx.DataQueue mcwbxDataQueue = new cwbx.DataQueue();
private cwbx.DataQueue CwbxDataQueue
{
get { return mcwbxDataQueue; }
set { mcwbxDataQueue = value; }
}
private bool bDisposed = false;
public Queue()
{
}
public Queue(string sQueueName, string sLibrary, cwbx.AS400System cwbxISeriesSystem)
{
this.Name = sQueueName;
this.Library = sLibrary;
this.ISeriesName = cwbxISeriesSystem.SystemName;
this.CwbxDataQueue.QueueName = sQueueName;
this.CwbxDataQueue.LibraryName = sLibrary;
this.CwbxDataQueue.system = cwbxISeriesSystem;
}
~Queue()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool bDisposing)
{
// Only Dispose of the object 1 time.
if (!this.bDisposed)
{
// If disposing equals true, Dispose() was called by GC, so dispose all managed resources.
if (bDisposing)
{
// Dispose managed resources, calling object Dispose method for objects
// that implement IDisposable interface.
}
// Call the appropriate methods to clean up unmanaged resources here.
try
{
this.CwbxDataQueue = null;
}
catch (Exception ex)
{
// ToDo: Log ex to WCF service log and remove from Console.
Console.WriteLine(ex.ToString());
foreach (cwbx.Error cwbxError in this.CwbxDataQueue.Errors)
{
Console.WriteLine(cwbxError.Text);
Console.WriteLine(cwbxError.ToString());
}
}
// Mark disposing as being done.
bDisposed = true;
}
}
public void Write(string sMessage)
{
try
{
cwbx.StringConverter cwbxStringConverter = new cwbx.StringConverter();
Object oBytes = cwbxStringConverter.ToBytes(sMessage);
this.CwbxDataQueue.Write(oBytes, false);
}
catch (Exception ex)
{
// ToDo: Log ex to WCF service log and remove from Console.
Console.WriteLine(ex.ToString());
foreach (cwbx.Error cwbxError in this.CwbxDataQueue.Errors)
{
Console.WriteLine(cwbxError.Text);
Console.WriteLine(cwbxError.ToString());
}
}
}
public string Read()
{
try
{
Object oObject = null;
return (new cwbx.StringConverter()).FromBytes(this.CwbxDataQueue.Read(this.WaitTime * this.NumberOfAttempts, out oObject));
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
foreach (cwbx.Error cwbxError in this.CwbxDataQueue.Errors)
{
Console.WriteLine(cwbxError.Text);
Console.WriteLine(cwbxError.ToString());
}
return "";
}
}
}
}
클라이언트 코드 :
이ISeriesSystem oISeriesSystem = null;
Queue oDataQueue = null;
oISeriesSystem = DQService.SystemInitialize("A2029D2.AS400.US.UPS.COM");
oDataQueue = DQService.QueueInitialize("SMTLST020", "IB5EXE", oISeriesSystem.Name);
oISeriesSystem.DataQueueDict.Add(oDataQueue.Library + oDataQueue.Name, oDataQueue);
ISeriesSystemDict.Add(oISeriesSystem.Name, oISeriesSystem);
DQService.QueueWrite(oDataQueue, "Testing cwbx.DataQueue WCF service");
string sMessage = DQService.QueueRead(oDataQueue);
의 exe 호스팅 서비스 :
Uri baseAddress = new Uri("http://localhost:8080/BossISeriesCwbxServices");
//Instantiate new ServiceHost
moServiceHost = new ServiceHost(typeof(BossISeriesCwbxServices.DataQueueService), baseAddress);
// Add Endpoint
moServiceHost.AddServiceEndpoint(typeof(BossISeriesCwbxServices.IDataQueueService), new WSHttpBinding(), "IDataQueueService");
// Enable metadata exchange.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
moServiceHost.Description.Behaviors.Add(smb);
//Open moServiceHost
moServiceHost.Open();
Console.WriteLine("The IDataQueueService is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
SessionMode와 동일한 동작입니다.필수 사항. 나는 Http 바인딩에 묶여 있지 않다. 이것이 생산에 들어간다면 실제로 NetTcp를 사용할 것입니다. –