2012-07-23 43 views
3

我有一個WCF服務,託管在IIS中。該服務由通用接口定義,其接口類型爲參數或返回類型,因此我們使用ServiceKnownType屬性在運行時定義所述接口的可用實現。運行一段時間(或IIS應用程序池回收?)後,與ServiceKnownType相關的WCF CommunicationException?

這一切似乎工作正常,但有時,我們看到所有這些服務的請求失敗與CommunicationException;而試圖序列參數http://tempuri.org/時出錯:ARG設置InnerException消息是‘類型’MyNamespace.SomeInterfaceImplementation‘數據合同名稱’SomeInterfaceImplementation:HTTP://schemas.datacontract.org/2004/07/MyNamespace',不需要將任何靜態未知類型添加到已知類型列表中 - 例如,使用KnownTypeAttribute屬性或將它們添加到傳遞給DataContractSerializer的已知類型列表中。 。

我無法可靠地重現此錯誤,但它經常在服務運行一段時間(例如;週末)後出現。我最初推測這是由於IIS應用程序池回收而發生的,但是手動回收或小間隔(例如2分鐘)的計劃回收無法重現此問題。

我能夠從「ServiceKnownTypes」的供應商排除「MyNamespace.MyType」可靠地再現異常,但並沒有真正告訴我這是爲什麼擺在首位間歇性的。

以下代碼片段顯示服務聲明。它是針對不同實施類型的通用服務,其中。請注意,它是產生CommunicationException的操作參數'arg'。

[ServiceKnownType("GetKnownTypes", typeof(KnownTypesCache))] 
[ServiceContract] 
public interface IMyService<T> 
    where T : class, IMyServiceTypeInterface 
{ 
    [OperationContract] 
    [TransactionFlow(TransactionFlowOption.Allowed)] 
    MyReturnType HandleRequest(T element, ISomeInterfaceArgumentType arg); 
} 

現在,KnownTypesCache,它提供了已知類型的用於ISomeInterfaceArgumentType的實現是像這樣;

public static class KnownTypesCache 
{ 
    private static readonly List<Assembly> queriedAssemblies = new List<Assembly>(); 
    private static readonly List<Type> knownTypes = new List<Type>(); 


    static KnownTypesCache() 
    { 
     // get all available assemblies at this time 
     List<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList(); 

     // find all available known types publishers 
     IEnumerable<Type> knownTypesPublisherTypes = assemblies 
      .Where(a => !queriedAssemblies.Contains(a)) // exclude already queried assemblies to speed things up 
      .SelectMany(s => s.GetTypes()) 
      .Where(p => typeof(IKnownTypesPublisher).IsAssignableFrom(p) && p.HasAttribute(typeof(KnownTypesPublisherAttribute))); 

     // add all known types 
     foreach (Type type in knownTypesPublisherTypes) 
     { 
      IKnownTypesPublisher publisher = (IKnownTypesPublisher)Activator.CreateInstance(type); 

       AddRange(publisher.GetKnownTypes()); 
      } 
     } 


     // record the assemblies we've already loaded to avoid relookup 
     queriedAssemblies.AddRange(assemblies); 
    } 

    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider) 
    { 
     return knownTypes; 
    } 
} 

基本上,這個全局靜態緩存查詢中的AppDomain所有加載的組件關於「IKnownTypesPublisher」,這反過來提供可用的序列類型的每個組件的實現者。因此,每個程序集都有一個IKnownTypesPublisher,它只負責識別該程序集中的類型,而KnownTypesCache只是將所有這些信息聚合在一起,並在運行時返回到DataContractSerializer。

正如我所提到的,這種方法似乎在99%的時間內正常工作。然後我無法識別的原因,它停止工作,只能通過致電iisreset解決。

現在我非常難過,我嘗試了各種解決方案,但是因爲我只能等到第一件事星期一才能可靠地再現這個錯誤,這有點難!

我最後剩下的想法是靜態KnownTypesCache構造函數可能在所有程序集加載到AppDomain之前調用,因此緩存在實例的生命週期中將爲空...?

回答

2

我僅存的想法是,所有組件加載到 在AppDomain

通過此之前靜態KnownTypesCache 構造可能會被調用,你可能是很好的方式來回答你自己題。

AppDomain.GetAssemblies()僅返回已經被加載到應用程序域的執行上下文的那些組件。 IIS工作進程,這將創建一個新的AppDomain任何回收後,必須在第一次使用的KnownTypesCache類型之間潛在的競爭條件,幷包含您IKnownTypesPublisher類型之一的任何組件的裝載。間歇性的,難以重現bug,可以經常通過競爭條件引起的。

爲您設計能夠正常工作,你需要確保莫名其妙服務實現總是加載包含您的已知類型的所有組件,任何調用KnownTypesCache方法之前。

相關問題