2013-02-20 77 views
2

我遇到了一個問題,即要讓我的ServiceKnownType屬性中指定的幫助器方法運行。爲了簡單起見,我有兩個程序集:一個具有我的服務接口和用於數據協定的接口,另一個具有我的服務實現和具體的數據協定。無法讓我的服務調用ServiceKnownType幫助器方法

這是我的服務及其實施的簡化/精簡版本。

MyService.Interface.dll

// IMyService.cs 
[ServiceContract] 
IMyService 
{ 
    [OperationContract] 
    IList<IMyData> GetData(); 
} 

// IMyData.cs 
public interface IMyData 
{ 
    int Foo { get; set; } 
} 

MyService.dll(具有到MyService.Interface.dll的引用)

// MyService.svc.cs 
public class MyService: IMyService 
{ 
    public IList<IMyData> GetData() 
    { 
     // Instantiate List<IMyData>, add a new MyData to the list 
     // return the List<IMyData>. 
    } 
} 

// MyData.cs 
[DataContract] 
public class MyData : IMyData 
{ 
    [DataMember] 
    public int Foo { get; set; } 
} 

問題的根源在於,序列化GetData()的結果,服務必須被通知有關具體MyData類和具體List<IMyData>泛型類,因爲服務e定義使用接口類型而不是具體類型。

簡單的答案是裝飾IMyService與:(並且不能是由於循環引用)

[ServiceKnownType(typeof(MyData))] 
[ServiceKnownType(typeof(List<IMyData>))] 

然而,MyData在未內MyService.Interface.dll引用的組件被定義

我的下一個想法是對的MyService本身使用的ServiceKnownType的「helper方法」的形式:

[ServiceKnownType("GetDataContracts", MyService)] 
public class MyService: IMyService 
{ 
    public static IEnumerable<Type> GetDataContracts(ICustomeAttributeProvider provider) 
    { 
     // create a List<Type>, add MyData to it, and return it. 
    } 
    //... 
} 

至於我可以看到,除了GetDataContracts永遠不會被調用。我試着將它移動到一個單獨的靜態類(與MyService並行並嵌套在它內部),但絕不能在這裏獲得一個斷點。

編輯:我也想說,通過web.config添加已知類型不起作用,因爲我有泛型類型不能添加這種方式。你只能通過web.config中添加簡單的,具體類型:

<knownType type="TypeName, Assembly" /> 

我的具體List<IMyData>沒有在裝配中完全限定的類型名稱。

回答

1

固定。答案是使用helper方法形式將ServiceKnownType添加到服務接口,而不是服務實現,並添加一個幫助類,該類反映我需要的類型,而不是通過引用代碼中的具體類型來添加它們。 (回想一下,我不能這樣做,因爲我不能引用該程序集添加。)

[ServiceContract] 
[ServiceKnownType("GetDataContractTypes", typeof(MyServiceHelper))] 
public interface IMyService 
{ ... } 

而且我添加了一個新的MyServiceHelper類Nightingale.Interface,但它不是公共所以我不關心不必要地暴露一個我只想成爲「純粹」接口的程序集。

// Not public outside of this assembly. 
static class MyServiceHelper 
{ 
    public static IEnumerable<Type> GetDataContractTypes(ICustomAttributeProvider paramIgnored) 
    { 
     // Get the assembly with the concrete DataContracts. 
     Assembly ass = Assembly.Load("MyService"); // MyService.dll 
     // Get all of the types in the MyService assembly. 
     var assTypes = ass.GetTypes(); 
     // Create a blank list of Types. 
     IList<Type> types = new List<Type>(); 
     // Get the base class for all MyService data contracts 
     Type myDataContractBase = ass.GetType("MyDataContractBase", true, true); 
     // Add MyService's data contract Types. 
     types.Add(assTypes.Where(t => t.IsSubclassOf(myDataContractBase))); 
     // Add all the MyService data contracts to the service's known types so they can be serialized. 
     return types; 
    } 
} 

這個特殊的解決方案適用於我,因爲我所有的DataContract類擴展了一個公共基類。在我的情況下,可以重新加載所有具有DataContract屬性的程序集中的所有類型,這會導致相同的集合。