KnownType for all derived types of an abstract class?
Asked Answered
D

4

12

We have an abstract class that is the base for a number of different requests we send over a WCF service. It's an ugly heinous hack that every time we add a new request we have to remember to add the [KnownType] attribute to this base class.

Is there a way to tell the DataContractSerializer to treat ALL derivations of this abstract type as a KnownType?

Dreary answered 7/6, 2011 at 14:3 Comment(0)
J
8

I had the same problem in a WCF service and did the following "less heinous" hack to work around the known type limitation. I'm outlining just for the sake of showing alternate options, it's up to you to decide if it's better or not.

  1. At service startup, load via reflection the types you want to expose. E.g. if all your WCF-exposed entities derive from a common abstract base (or more), load all types from the assembly they're supposed to be located into. Cache these types statically for performance reasons.

  2. Create a static method that returns the said cached types, with the following signature: public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)

  3. Mark the WCF interface with the following attribute [ServiceKnownType("GetKnownTypes", typeof(StaticClassThatCachesTypes))]

This should give you automatic exposing of all types that are or will be derived from the base class(es) of your choice, as long as the future developer(s) place them in the correct assembly.

Juanajuanita answered 7/6, 2011 at 14:53 Comment(3)
Thanks for this. It doesn't really scale out if there are multiple base types for different kinds of contracts (will have to have a static helper for each base) but it does take the human element out. :)Dreary
@Joe: not necessarily. If you have multiple base classes, there's nothing that prevents you from loading all their derived types in one go at step 1. GetKnownTypes must return a list of types. The actual limitations are that you have to know all your base classes (and adapt the type loader when you add a new one), and you have to know where they're located.Juanajuanita
Accepting this as a decent workaround. It'd still be nice to have something a little more intelligent at the language/compiler level...Dreary
B
2

Another option in addition to the one given by Dan C. is to switch to the NetDataContractSerializer - it does not require known type declarations, since it is tightly coupled to the exact contract implementation, so you'll need to share the assembly which contains the types between the client and the server - and you'll definitely lose interoperability in this scenario. There are a few posts about doing that (I've seen this one pop up in google/bing results often).

Blackberry answered 7/6, 2011 at 15:24 Comment(1)
Yeah, I was hoping to avoid that dependency. Thanks for the suggestion though.Dreary
C
-1

Here is an example of doing this with PostSharp. Look towards the bottom of the post.

Catlike answered 11/3, 2013 at 21:47 Comment(0)
V
-1

This is an example of achieving this with IL Weaving using Fody/Mono.Cecil.

Basically, this is a Fody extension that injects KnownTypeAttributes during build time using IL Weaving.

During the build pipeline, the extension locates all base classes marked with the KnowsDeriveTypes attribute (Part of the extension) and it will add the KnownTypeAttribute over all classes that derive (not necessarily directly) from one of the above base classes (with the KnowsDeriveTyepsAttribute).

This is another mirror for the post and here you can find the Github repo for the extension.

Voss answered 26/2, 2018 at 12:17 Comment(2)
Don't post link-only answers; if the link goes away then this is a useless post.Dreary
@Dreary I've added a brief explanation with more mirrors for the link. I'm not sure it will be a good idea to explain the whole blog post in one Stackoverflow answer.Voss

© 2022 - 2024 — McMap. All rights reserved.