I am using an abstract class as a parameter in a web service call. Currently, I am including an XmlInclude of a derived class in the base class, like so:
[XmlInclude(typeof(DerivedClass))]
public abstract class BaseClass
{
}
However, I'd rather not include all of the derived types in the base class.
In http://www.pluralsight.com/community/blogs/craig/archive/2004/07/08/1580.aspx, the author mentions an alternative - writing the attribute above the web method instead, like so:
[WebMethod]
[System.Xml.Serialization.XmlInclude(typeof(DerivedClass))]
public BaseClass getClass() {
return new DerivedClass();
}
However, I'd also like to not put the derived types in the web service either. Is there a way of keeping the attribute in the derived type?
Lets take it as a given that the framework would somehow need to know what types are in the type hiearchy when deserialization occurs, and how those types are represented in xml. It really has no way to infer this information if it is stored in a derived type.
You then have a couple of options:
- use the XmlInclude attribute
- specify the set of allowed types in the XmlSerializer Constructor overload
Now, if you're expecting a subclass to be passed in to the webservice, the webserver controls serialization and deserialization. So the XmlSerializer contstructor is no longer an option.
As you say, you can put the attribute on the webservice method instead of directly on the class. There's a trade-off between keeping your class "pure" and remembering to put those attributes in every place they may be required.
Of course, the real problem appears to be that you are trying to use your business objects as the message format in your webservice layer.
If you really want to keep the "message format" and "business object" responsibilities separate, then have another class (with the full hierarchy) for which the only use is to be used as a webservice parameter. In that case, there's no problem with sticking all the XmlInclude attributes you need, on the base class. Then, when making calls to the webservice, adapt your business object to and from the message format object. This gives you the added benefit of not applying webservice type constraints to the types of your parameters (eg no interfaces as parameters).
Of course, this method isn't as convenient.
In the end, the webservice needs to know what types to expect, or it won't be able to serialize and deserialize them properly.
And yes, this is a long winded explanation of why the answer is no, you can't only keep the attribute in the derived type. I'd love to be wrong though :)
I don't see how in this case. If you are deserializing there is an overload for specify extra types array where you pass in the derived types.
Related
I am trying to make use of covariant types in order to make generics useful.
I have a generic interface foo that I want to be able to both get and set a property of type T. When declaring the object I don't know what implementing instance I'll be given and so covariance allows for the following declaration
Foo<ibasetype> genericFoo = new implementationOfFoo();
Where implementationOfFoo is
Class implementationOfFoo : Foo<baseTypeA>{}
This works for declaration but it doesn't allow the interface to require an instance of the type baseTypeA as a parameter because covariance only allows returning an instance of the type.
I'm unable to make the interface type invariant as is suggested in other posts because that requires I specifically declare the appropriate class type during object declaration which is not possible as I don't know what instance of implementing class I'll be given.
I am also unable to declare a second type and make that type contravariant as that also triggers a compiler error similar to the invariant case during declaration.
The code that uses this class will handle the appropriate object generation based on reflection prior to passing the object to the implementations various functions so there's no concern of any rule breaking and any exceptions that occur will simply be cleaned up as part of the process of building the code that makes use of the interface.
I assume there's some trick with covariance to get around this shortcoming but I haven't found any guides which discuss this concern. How do I get around this?
Per the responses to my initial question, I would like to be able to build an interface with types of various interfaces I define as the requirements of the main generic interface types. For example
Public interface Foo<typeA> where typeA:iModelA{
typeA prop1{get;set;}
Void doSomething (typeA sameAsProp1)
}
The implementation of the interface must be providing a type which implements iModelA so I simply need to use reflection to determine what the type is and then in my case I use the url provided to construct an instance of that type and pass it to the interface instances ModelA parameter. Then when I need the object I just call the ModelA getter and get from the implementation the iModelA it seems appropriate to provide in that instance.
In my code is declare
Foo fooInstance = getFooInstance(inputs)
For example the page I'm constructing has input fields which on a button click generates a new url which is redirected to. Those same url parameters are then reviewed on the subsequent page load to construct an instance of the base object (which is also based on parameters in the url). The setter logic then reloads the fields based on the passed instance of the iModelA objects parameters.
This logic will be the same regardless of the implementation of the interface so I know its a perfect candidate for an interface and the generic types allow me to impose structure across various objects within the implementation. This if two objects need to reference the exact same type, the generic requirements can manage those needs.
I know that I could get away with not doing a generic interface like so
Interface nonGenericFoo{
iModelA prop1{get;set;}
Void doSomething (iModelA sameAsProp1)
}
However, this means that across functions and properties within the main interface the implementation of the interfaces might be declared differently which will be problematic. In addition, the implementing class will need to make assumptions about the implemention instance which I want to avoid. I want all assumptions to be handled by the main code and let the interface implementations know exactly what they're working with.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C# WCF: When is it appropriate to use the KnownType attribute?
Not long ago, we needed in class to create, as part of a project, a C# web client. The teacher instructed us to put the attribute DataContract above each class that will be passed.
Then the teacher told us that if you have some thing like this:
A
/ \
/ \
B C
you need to write class A in the following way:
[DataContract]
[KnownType(typeof(B))]
[KnownType(typeof(C))]
public class A
{
}
Isn't this completly against the idea of polymorphism? why should a class know who inherits the class?
This doesn't really have anything to do with C# and polymorphism; rather with serialization. The WCF infrastructure needs to be able to take something like a byte array off the wire and create an object out of it. If class A is an abstract type, there is no way that object can be instantiated. The framework needs to know what types it might receive over the wire so it can inspect the metadata and instantiate the right type of object.
Put another way, the attributes don't tell the class anything about its inheritors (indeed, the list need not include all inheritors); this is strictly so the framework will know what types it can expect to be asked to construct.
I would add, though, that adding the DataContract and DataMember attributes is not always required. They are available for scenarios where you may want to have more fine grained control, such as excluding a public property from serialization. Usually if the type is serializable it can be passed without the attributes.
The WCF serializer separates out the concept of inheritance from the concept of polymorphism. CLR inheritance only means that the base class members are automatically added to the derived class as far as the serializer is concerned, it does not imply any kind of relationship between the two elements in the XML document. To get polymorphism, you have to explicitly tell the serializer that the XML representation of the derived class is substitutable for the XML representation of the base class.
Personally I find the distinction convenient. I sometimes use CLR inheritance without KnownType to add common properties onto classes without implying any kind of business relationship between them.
First of all, as Daniel Says, you are talking about Windows Comunication Fundation (WCF) , not web.
By decorating the class, you are telling to the client that there two classes that he must know to use the class "A", for example
[DataContract]
[KnownType(typeof(B))]
[KnownType(typeof(C))]
public class A
{
[DataMember]
private SuperClass myProp;
}
public Class B : SuperClass {}
public Class C : SuperClass {}
Please review this link for more information : MSDN DataContract
I have a very odd exception in my C# app: when trying to deserialize a class containing a generic List<IListMember> (where list entries are specified by an interface), an exception is thrown reporting that "the type ...IListMember is not marked with the serializable attribute" (phrasing may be slightly different, my VisualStudio is not in English).
Now, interfaces cannot be Serializable; the class actually contained in the list, implementing IListMember, is [Serializable]; and yes, I have checked that IListMember is in fact defined as an interface and not accidentally as a class!
I have tried reproducing the exception in a separate test project only containing the class containing the List and the members, but there it serializes and deserializes happily :/
Does anyone have any good ideas about what it could be?
Edit:
We are using a BinarySerializer; and I repeat, when extracted to a test project the class serializes happily. So I do not need a workaround to serialize a class containing a List<IThing>, as in general this works fine (as long as the actual classes implementing IThing are serializable); what I am looking for is reasons why it might not work this particular time...
I have now put in a workaround (serializing each list member individually, together with the number of entries, and recreating the List by hand), but would really like to find out what it could be for future reference.
It doesn't matter that the class backing the interface is serializable. Interfaces cannot be serialized, period.
In order to deserialize, the serializer needs to be able to instantiate a concrete type, and it determines this type by reflecting on the fields/properties of the class-to-be-deserialized.
If the type of one of those properties is an interface, then it will never be able to construct a concrete type to assign to that member. All it sees is the interface, it has no idea which class originally implemented it when the data was serialized.
If you want the class to be serializable, then every class in the object graph must be a concrete type. No interfaces allowed.
(Postscript: Actually, I sort of lied, the BinaryFormatter can serialize/deserialize directly to/from interface types, but I strongly suspect that's not what's being used here.)
The Easy Way (Although ugly) Wrap your list:
public ListMemberCollection : List<IListMember>, ISerializable
{
// Implement ISerializable Here
}
The Alternative Way (Although better) AbstractBaseClass:
[Serializable]
public ListMemberBase : IListMember
{
// Implement abstract versions of everything
}
A possibility?: (On your other class)
class TheClassYoureSerializing
{
[Serializable]
public List<IListMember> list { get; set; }
}
I can use TypeDescriptor.AddAttributes to add an attribute to a type in runtime. How do I do the same for a method and parameter? (maybe 2 separate questions...)
TypeDescriptor.AddAttributes only affects a very specific use-case; i.e. from within System.ComponentModel. For the rest of reflection, it knows nothing about the extra attribute. And indeed, System.ComponentModel doesn't really apply to methods or parameters.
So in short; you can't. You will need to store this information somewhere else (bespoke), or add it at compile-time.
As I see from analyzing the TypeDescriptor class in Reflector, the .AddAttributes method internally calls the .AddProvider method. The TypeDescriptionProvider instance passed to it is actually responsible for providing meta-data. You could try adding the [TypeDescriptionProviderAttribute] attribute to your class and implement your own provider by deriving from the TypeDescriptionProvider class. As the documentation says, by overriding TypeDescriptionProvider.CreateInstance, you could provide a substitute object whose type has all necessary attributes. I suspect that the attributes applied to methods inside the substitution type will also take effect. However, I haven't tried that myself, so feel free to experiment...
I'm using the DataContractSerializer to serialize an objects properties and fields marked with DataMember attributes to xml.
Now a have another use case for the same class, where I need to serialize other properties and other fields.
Are there a way to add "another DataMemberAttribute" that can be used for my other serialization scenario?
No, basically.
If you want to use the existing DataContractSerializer, you'll have to maintain a second version of the DTO class and convert the data between them.
Options if you are writing your own serialization code:
declare your own [DataMember]-style attribute(s) and interpret them at runtime in your own serialization code
use a "buddy class"
use external metadata (such as a file)
use code-based configuration (i.e. via a DSL)
In reality, I expect the first will be the simplest choice.
In a similar scenario in the past, we've taken an Object Oriented approach, and created a new class that extends from the main class.
To help you achieve inhertience with the DataContractSerializer, check out KnownTypeAttribute
In one of your comments to your question,
If the same class is implementing multiple interfaces, certain data elements may be relevant to only one of the interfaces.
If that is the case in your scenario, then perhaps your Data Service Contracts should be exposing just the Interfaces, and not the Class?
For example, if you have a class like:
[DataContract]
public class DataObject : IRed, IBlue
then rather than have your operation contract expose DataObject, you have two operation contracts one for IRed and one for IBlue.
This eliminates the need for custom serialization code.
There is a way to do it, but it's an ugly hack.
The DataContractSerializer can serialize objects that implement the IXmlSerializable interface. You could implement the interface and create your own ReadXml(XmlReader reader) and WriteXml(XmlWriter writer) methods that could serialize the object in different ways.
Note that you'd have to have a flag embedded within the class itself to determine which way to serialize the object. (There's no way to tell the DataContractSerializer which mode to use, so the flag has to be contained in the object itself.)
A second version of the DTO class, as #Marc suggests, would be much cleaner.