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.
Related
I have a ServiceContract which returns dynamic type and looks like following:
public dynamic LoginViaOpenId(string openIdUrl)
The dynamic return type could be a DataContract that I have defined, or a string. But since I have not used my DataContract on the service, client does not know anything about it and cannot access it.
My DataContract is something like below:
[DataContract]
public enum OpenIdStatus
{
[EnumMember]
Authenticated,
[EnumMember]
Authenticating,
[EnumMember]
Cancelled,
[EnumMember]
Failed,
[EnumMember]
RedirectToLogon
}
I know if I had hierarchical types I could have used KnownType to conquer this, but am out of idea for this scenario.
Any idea?
A dynamic DataContract is an oxymoron. A DataContract is a predetermined and mutually agreed-upon data structure, and dynamic is an object whose structure is not predetermined and thus cannot be agreed-upon, since it can be anything.
It doesn’t appear you actually need to return a dynamic data type, but rather a varying data type. The difference is that a varying data type is one of a set of fixed data types, whereas a dynamic data type is one which does not have a predetermined structure. Since your return value is one of several knows shapes, there is no need to use the "shapeless" (or "freeform") dynamic type, which isn't supported by WCF.
Instead, you could have the [OperationContract] method return a type with a [DataContract] that will act as a wrapper object that has a single data member of type object, and use [KnownType] on the wrapper object to specify the possible types that may be returned inside the wrapper. Since everything inherits from object, there is already a hierarchy in place.
[DataContract]
[KnownType(typeof(OpenIdStatus))]
[KnownType(typeof(string))]
public class ReturnValue
{
[DataMember]
public object Value { get; set; }
}
I think that WCF is going to have issues serializing / deserializing your dynamic type. I would recommend that you set up a contract for the method return based on a defined interface. Alternatively, you could take responsibility for the serialization yourself and make your service return a string. The client will have to have knowledge of what type to de-serialize the string to. There is a similar question on this here:-
How to return dynamic List from WCF HTTP Service
Here is the Method signature in the WCF service:
APIMessageList<APISimpleContact> GetMembers(string apiKey, APIContactSearchFilter filter);
APIMessageList inherits from IList. Once I have built a proxy against this WCF service the class name is APIMessageListOfAPISimpleContactjHldnYZV.
Why do I not get: APIMessageListOfAPISimpleContact?
It adds random text to the end of every APIMessageList object in the interface (there are several) They all end with the same few chars - jHldnYZV. I have looked online for possible causes, but I can't find any posts of people having this problem.
This is a purely cosmetic issue but this interface is exposed to our external customers so its appearance is important.
Anybody know why I am getting this problem?
Many thanks
Joe
Your solution will be at http://msdn.microsoft.com/en-us/library/ms731045.aspx. Basically, since you could have multiple "SimpleContract" classes (in different namespaces), WCF will add a disambiguation hash to the end of the contract name, which is what you have in the 8 chars at the end of the contract name. But you can control that, by using the CollectionDataContract and its Name property:
[CollectionDataContract(Name = "APIMessageListOfSimpleContract")]
public class APIMessageList : IList<SimpleContract> { ... }
We had a similar problem while using Generic types for return values. If we are not specifying a concrete type, the default data contract serializer or the WCF serializer is unable to infer the exact type of the returned entity. Hence it generates a random class name for the returned type.
In our project we overcame this problem by building a data contract which was of specific type and returned the same as a result of a WCF operation call.
My guess is that you are using a generic type and the serializer is unable to infer the type of the returned object.
I suggest you create a Data Transfer Object (DTO) and return the same from the WCF service. That should solve your problem.
I have a problem using an custom data type in a WCF service method, below is my sample code
[ServiceContract()]
public class SampleServise : ISampleServise
{
void object GetSomething(ICustomData objectData)
{
// Do Something
}
}
What shall I do with ICustomData class interface?
Thanks
Afshin
WCF is based on message passing, and that message passing is modelled using XML schema (XSD). As such, whatever can be expressed in XML schema can be used in WCF.
This also means: interfaces are not supported. You need to use actual, concrete types for the parameters in your WCF service methods.
In your case, create a concrete class that implements ICustomData and then use that class as the parameter type.
For a good reference, read MSDN Designing Service Contracts which states for parameters:
Parameters and Return Values
Each operation has a return value and a parameter, even if these are
void. However, unlike a local method, in which you can pass references
to objects from one object to another, service operations do not pass
references to objects. Instead, they pass copies of the objects.
This is significant because each type used in a parameter or return
value must be serializable; that is, it must be possible to convert an
object of that type into a stream of bytes and from a stream of bytes
into an object.
I'm using the svcutil tool to generate a set of proxies for a 3rd party wdsl. One of the types, defined in an associated XSD file uses the xs:any element:
<xs:any namespace="##any" processContents="lax"/>
The code produced uses a property of type XmlElement to represent this:
[System.Xml.Serialization.XmlAnyElementAttribute(Order=0)]
public System.Xml.XmlElement Any
{
get
{
return this.anyField;
}
set
{
this.anyField = value;
}
}
What actually needs to go in this field is one of the strongly-typed objects also generated by the tool.
My question is: is there an easy/recommended way to get from an instance of the object to an instance of XmlElement?
All I can think of is serializing the object graph into a XmlDocument and then using that. But that seems awkward.
The generated code is correct for the schema. xs:any mas to a xml blob. You will need to change the schema from xs:any to the specific type if you want the generated code to be more specific.
However, if the schema is not under your control, this is the only correct way to consume the schema. You cannot assume that a message contains any specific type.
With the XmlSerializer I can have my members in different namespaces to the parent type.
Can I do the same thing with DataContractSerializer?
I would like the following XML:
<h:Type xmlns:h="http://schemas.e.com/WebServices"
xmlns="http://schemas.e.com/WebServices">
<Member xmlns="http://schemas.e.com/CoreTypes">0</Member>
</h:Type>
Is this possible in with DataContractSerializer?
You can define subdatacontracts in different namespaces and use them as members of another datacontract, but you can't control the individual member names and/or shapes. The DataContractSerializer isn't intended to replace XmlSerializer for fine-grained control of the "shape" of your XML.
While it is true as stated in this answer by nitzmahone that a specific data contract type cannot have declared members in multiple namespaces, it is possible that, in a type hierarchy, derived types can belong to different data contract namespaces than the base types from which they inherit. When this happens, each member will be serialized into the namespace in which it is declared. By constructing an appropriate type hierarchy, XML entities with members in disparate namespaces can be (de)serialized by DataContractSerializer.
The specific rules are as follows:
If a data contract type is a part of an inheritance hierarchy, data members of its base types are always first in the order.1
Data members are serialized into the data contract namespace of the data member type in which they are declared.
The root namespace of a data contract type is the namespace of its most derived type.
XML elements are (de)serialized in the order specified by Data Member Order. DataContractSerializer does not allow for data members to be freely reordered during deserialization.2
Collections have their own rules as specified in Collection Types in Data Contracts; this answer does not apply to them.
Thus the XML in the question can be consumed by DerivedType in the following type hierarchy:
[DataContract(Name = "Base", Namespace = "http://schemas.e.com/CoreTypes")]
public class BaseType
{
[DataMember]
public int Member { get; set; }
}
[DataContract(Name = "Type", Namespace = "http://schemas.e.com/WebServices")]
public class DerivedType : BaseType
{
}
And, in general, any sequence of XML elements in any sequence of namespace(s) can be obtained by applying the rules above to construct an appropriate type hierarchy, offering a workaround that meets the requirement of deserializing elements in different namespaces.
Of course, such a hierarchy might be inconvenient for other reasons, in which case the preferred data model types can be replaced with DTOs by using the data contract surrogate mechanism.
1 Data Member Order.
2 Data Member Order and XML Deserialization