How to use collections when define DataContract? - wcf

I want to 'send' collection that contain numbers ( double ).
I try to add array to my DataContract but its fail ( thru exception .. when i remark the array type its work fine ).
How can i do it ?
Thanks for any help.

Collection Serialization happens automatically only when the collection in the contract is a concrete collection (that is, not an interface) and is serializable (annotated with the Serializable attribute). If that is the case, WCF can automatically serialize the collection as an array of the collection’s type as long as the collection contains an Add operation. This holds true for both the built-in .NET collections and for any of your own custom collections that implement the IEnumerable or IEnumerable interface; as long as they are serializable and have an Add operation, they can be serialized to arrays automatically.
If your collection does not meet these constraints specify the CollectionDataContractAttribute.
[CollectionDataContract(Name = "MyCollectionOf{0}")]

Related

How can I see the NewEnum method that for each calls?

In the microsoft docs for 'collection', it says that
Collections must implement a method called NewEnum that accepts no
arguments, returns an appropriate IUnknown object, and has its
VB_UserMemId attribute set to -4.
If I look at 'Collection' in the excel VBA object browser, I can only see Add, Count, Item and Remove.
How do I see that Collection has a NewEnum method? Where do I see documentation for its NewEnum method? Is there any way to see the source code?
Many thanks!
Collections are Standard Objects defined in the COM Automation standard. This was written at the same time as VBA and for VBA. A programmer has to implement the collection.
A collection is created by a program according to some rules. There is no source code as it a standard that programmers must follow to create a collection. It purpose is to enable the For - Each construct.
VBA has an implementation of a generic collection for programmers to quickly use but advise not to use it in code that other code calls. You are supposed wrap VBA's generic collection in a class. You can stick anything in VBA's generic collection and you write a class to restrict what can be added.
When you get a collection from Excel Excel works out what to give you by what object you asked for in your For Each loop. EG Rows inherit from range so you treat it as a range object as it has same properties and methods. Under COM rules it could have more methods but not fewer than the range object. If you ask a rows object, via IUnknown:QueryInterface, are you a range it will answer yes.
From https://learn.microsoft.com/en-us/windows/win32/api/oaidl/nn-oaidl-ienumvariant
Collection Object Properties
A collection provides a set of objects over which iteration can be
performed. All collection objects must provide the following
properties:
Property name Return type Description
Count VT_I4 Returns the number of items in the collection; read only. Required.
_NewEnum VT_DISPATCH A special property that returns an enumerator object that
implements IEnumVARIANT. Required.
IEnumVARIANT Interface
The IEnumVARIANT interface provides a method for enumerating a
collection of variants, including heterogeneous collections of objects
and intrinsic types. Callers of this interface do not need to know the
specific type (or types) of the elements in the collection.
Implemented by Used by Header file name
Applications that expose collections of objects Applications that
access collections of objects Oleauto.h (32-bit systems)
Dispatch.h (16-bit systems)
The following is the definition that results from expanding the
parameterized type IEnumVARIANT:
interface IEnumVARIANT : IUnknown {
virtual HRESULT Next(unsigned long celt,
VARIANT FAR* rgvar,
unsigned long FAR* pceltFetched) = 0;
virtual HRESULT Skip(unsigned long celt) = 0;
virtual HRESULT Reset() = 0;
virtual HRESULT Clone(IEnumVARIANT FAR* FAR* ppenum) = 0;
};
To see how to implement a collection of objects using IEnumVARIANT,
refer to the file Enumvar.cpp in the Lines sample code.
IEnumVARIANT Methods Description
Clone Creates a copy of the current state of enumeration.
Next Gets the next items in the enumeration sequence
Reset Resets the enumeration sequence to the beginning.
Skip Attempts to skip over the next celt elements in the enumeration sequence.

Combine JsonDeserialize#contentAs with JsonDeserialize#contentConverter or JsonDeserialize#contentUsing for custom deserialization

In JsonDeserialize annotation documentation the contentAs field is supposed to define the "Concrete type to deserialize content".
I tried to use this in combination, with either a Converter (via contentConverter field of the same annotation) or a JsonDeserializer (via contentUsing field of the same annotation), by extending either StdConverter or StdDeserializer, respectively, in an attempt to create an agnostic custom deserializer.
I cannot find a way to access the JsonDeserialize#contentAs information inside any of these two classes.
I am aware that the classes I extend from have a type parameter, I just put an Object class there. Documentation states
contentAs Concrete type to deserialize content (elements of a Collection/array, values of Maps) values as, instead of type otherwise declared. Must be a subtype of declared type; otherwise an exception may be thrown by deserializer.
Apparently I am applying the #JsonDeserializer annotation on a Collection of some persistable Class. I want to deserialize each such object, solely by knowing its id. Well, if I could only get that very type I defined in the #JsonDeserializer#contentAs field...
Can anyone tell me if this is possible anyhow?
I managed to implement the agnostic deserializer withou the use of #JsonDeserializer#contentAs after all.
After reading the javadocs of com.fasterxml.jackson.databind.JsonDeserializer I concluded that my custom deserializer should implement the com.fasterxml.jackson.databind.deser.ContextualDeserializer interface.
Inside the implementation of ContextualDeserializer#createContextual(DeserializationContext ctxt, BeanProperty property)
I could finally get access to the class type of the content of the collection, which I applied the #JsonDeserialize annotation on,
by calling:
ctxt.getContextualType().getRawClass()
NOTE that the same call inside the implementation of com.fasterxml.jackson.databind.JsonDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext) returned null, hence the need of the aforementioned interface.
All I had to do then is store the returned class in a member field (of type Class< ? >) of the custom deserializer and use it in the execution of JsonDeserializer#deserialize()
The only thing that remains to check is whether an instance of this custom deserializer is shared between threads. I only did some minor checks; I used the same implementation for two different collections of different types. I observed that ContextualDeserializer#createContextual(DeserializationContext ctxt, BeanProperty property) was called once (among multiple deserialization invokations), for each distinct type that was going to be deserialized. After checking during debugging, it seems that the same deserializer object is used for the same type. In my case, since what I store in the member field is this type itself, I don't mind if the same deserializer is used for the same java type to be deserialized because they should contain the same value. So we 're clear on this aspect as well.
EDIT: It appears all I have to do is update the com.fasterxml.jackson.databind.deser.std.StdDeserializer#_valueClass value to the now known class. Since it is final and since the ContextualDeserializer#createContextual(DeserializationContext ctxt, BeanProperty property) returns a JsonSerializer object, which is actually used,
instead of returning "this" serializer I can create a new one, passing the discovered class in the constructor, which actually sets the StdDeserializer#_valueClass to the class I actually want, and I'm all set!
Finally, NOTE that I didn't have to use the #JsonDeserializer#contentAs annotationfield as I get the value from the ctxt.getContextualType().getRawClass() statement inside ContextualDeserializer#createContextual(DeserializationContext ctxt, BeanProperty property) implementation

Guava - Can a Multimap be serialized?

I am looking at this API ArrayListMultiMap which implements the Serializable interface. Does that mean I can serialize this object ? Are all Multimap objects serialized ?
The meaning of Serializable is always the same: If an object isn't serializable, it can't be serialized. If it is, it may work or not... Especially in case of collections (including maps and multimaps), it depends on their content.
As an example, you can surely serialize ArrayList<String> as ArrayList.class is serializable and so is each member of the list. OTOH trying to serialize ArrayList<Object> may or may not work: If all contained objects are e.g. strings, it will work. If any member is not serializable, you'll get an exception.
Does it mean I can serialize this object?
If all keys and values are serializable, you can.
Are all multiMap object serializable?
No, the interface Multimap doesn't extend Serializable, so there may be non-serializable implementation. Indeed, you can get such an instance via e.g. Multimaps.filterEntries.
ArrayListMultimap and HashMultimap are Serializable BUT the Collection views (in asMap() for example) are not.
This problem is answered here:
To use the map returned by asMap(), you can re-create a new map and wrap the Multimap Collection views into other collections (for example a Set), that will make the new map Serializable:
Multimap<MyClass, MyOtherClass> myMultiMap = HashMultimap.create();
// ... build your multimap
Map<MyClass, Set<MyOtherClass>> map = myMultiMap.asMap().entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
(entry) -> ImmutableSet.copyOf(entry.getValue())
));
Or java 7 compliant code:
Multimap<MyClass, MyOtherClass> myMultiMap = HashMultimap.create();
// ... build your multimap
Map<MyClass, Set<MyOtherClass>> map = Maps.newHashMap();
for (Map.Entry<MyClass, Collection<MyOtherClass>> entry :
myMultiMap.asMap().entrySet()) {
map.put(entry.getKey(), ImmutableSet.copyOf(entry.getValue()));
}

Naming 'ArrayOf' when serialising using DataContractSerializer

I have created a WCF service that has multiple operation contracts defined. One of my contracts returns a collection of known types. The type is defined separately as a data contract.
When the collection is serialised by the DataContractSerializer the xml representation defines the name of the collection as
<ArrayOfMyType*></ArrayOfMyType>
I want to alter this to return it as
<MyTypes></MyTypes>
but can seem to find the required attribute within the documentation. I have used XmlRootAttribute in another part of the system but that is designed for the XMLSerialiser
Try to define custom collection type:
[CollectionDataContract(Name = "MyTypes", ItemName = "MyType")]
public class MyTypeList : List<MyType>
{ }
And use this type as return value from your operation.

Derived class members not available when added to custom collectionbase

I have a Base Class, called primitive Graphics. derived from this class are several different types of graphics, squares, rectangles, lines, etc.
I am storing those graphics in an object that inherits collectionbase. This causes a problem because I cannot access any of the members in the derived class when they are added to the collection.
Here is the default property for my primitivecollection class
Public Class PrimitiveCollection
Inherits CollectionBase
''' <summary>
''' Get or set a primitive object by index
''' </summary>
Default Public Property Item(ByVal index As Integer) As Primitive
Get
Return DirectCast(List(index), Primitive)
End Get
Set(ByVal value As Primitive)
List(index) = value
End Set
End Property
My current workaround is to just put all of the public members in the base class, however this is starting to look ugly as I add more derived classes that need members available to the derived class only
Your question is about inheritance and interfaces. The following is my opinion
Each Primitive should implement an interface, IPrimitive. Every Primitive in the Collection implements IPrimitive and the only things in IPrimitive are the things that apply to all types of IPrimitives. For example: Draw()
So when working with your collection, you have a collection of drawable objects. If you intend to work with a collection as a collection of just Rectangles, you should use a List<Rectangle> rather than a collection of Primitives.
Putting more properties onto the base class (or IPrimitive) is a bad idea, because they won't make sense for all objects. Width could work for a Rectangle, but gets shady when you're working with a Trapezoid or Triangle. Instead the Commonality should be as little as is necessary to work with the objects as a collection. And when you need to work with the objects as their derived classes, you should be referencing them without using the collection.
If you're storing multiple types of object within a single collection, then you'll need to cast between them to access type-specific members, yes.
If you're actually storing multiple objects of a single derived type in a collection, you should look at using generics instead, so that the collection remains strongly typed (i.e. the compiler knows that the collection only contains instances of the derived type).
You will need to cast the instances in the collection to the derived type in order to access their specific members.
I will add an example:
PrimitiveCollection primitives = GetPrimitives() ' this gets a mixture of types
If GetType(PrimitiveRectangle) = primitives[0].GetType() Then
' this is a PrimitiveRectangle object
PrimitiveRectangle rect = CType(primitives[0], PrimitiveRectangle)
' now you can access specialized members through rect
End If
I didn't use VB.NET in a couple of years, so there may be issues with the syntax...