문제

I'm having a problem getting the helper method specified in my ServiceKnownType attribute to run. For simplicity's sake, I have two assemblies: one with my service interface and interfaces for my data contracts, and another with my service implementation and concrete data contracts.

Here's a simplified/stripped down version of my service and its implementation.

MyService.Interface.dll

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

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

MyService.dll (with a reference to 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; }
}

The root of the problem is that to serialize the result of GetData(), the service must be informed about the concrete MyData class and the concrete List<IMyData> generic class because the service definition uses interface types not the concrete types.

The simple answer is to decorate IMyService with:

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

However, MyData is defined in an assembly that is not referenced within MyService.Interface.dll (and cannot be due to a circular reference.)

My next thought was to use the "helper method" form of ServiceKnownType on MyService itself:

[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.
    }
    //...
}

As far as I can see that ought to work except that GetDataContracts is never called. I tried moving it into a separate static class (parallel to MyService and nested within it) but in no case can I get a breakpoint to stop there.

EDIT: I meant to also say that adding the known types through web.config doesn't work either because I have generic types can't be added that way. You can only add simple, concrete types via web.config:

<knownType type="TypeName, Assembly" />

My concrete List<IMyData> doesn't have a fully-qualified type name in an assembly.

올바른 솔루션이 없습니다

다른 팁

Fixed. The answer was to add the ServiceKnownType, using the helper method form, to the service interface, not the service implementation, and to add a helper class that reflects the types I need instead of adding them by referring to the concrete types in code. (Recall, I couldn't do that because I can't add a reference to that assembly.)

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

And I added a new MyServiceHelper class to Nightingale.Interface, but it's not public so I'm not concerned about unnecessarily exposing a class from an assembly that I want to be "pure" interface only.

// 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;
    }
}

This particular solution works for me because all of my DataContract classes extend a common base class. It could be reworked to load all Types from the assembly that have the DataContract attribute which would result in the same set, in my case.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top