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.
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 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.
I'm trying to transfer some user information in the header of the message through message inspectors.
I have created a behavior which adds the inspector to the service (both client and server).
But when I try to communicate with the service I get the following error:
XmlException:
Name cannot begin with the '<' character, hexadecimal value 0x3C.
I have also get exception telling me that DataContracts where unexpected.
Type
'System.DelegateSerializationHolder+DelegateEntry'
with data contract name
'DelegateSerializationHolder.DelegateEntry:http://schemas.datacontract.org/2004/07/System'
is not expected. Consider using a
DataContractResolver or add any types
not known statically to the list of
known types - for example, by using
the KnownTypeAttribute attribute or by
adding them to the list of known types
passed to DataContractSerializer.
The thing is that my object contains other objects which are marked as DataContract and I'm not interested adding the KnownType attribute for those types.
Another problem might be that my object to serialize is very restricted in form of internal class and internal properties etc.
Can anyone guide me in the right direction. What I'm I doing wrong?
Some code:
public virtual object BeforeSendRequest(ref Message request, IClientChannel channel)
{
var header = MessageHeader.CreateHeader("<name>", "<namespace>", object);
request.Headers.Add(header);
return Guid.NewGuid();
}
Don't put the angle brackets into the actual strings. Remember, the serialization format may not even be text based, all you're doing is specifying the name of the element and the namespace. So your code should look more like this:
var header = MessageHeader.CreateHeader("name", "urn:myNamespace", object);
request.Headers.Add(header);
To close this question, I never solved the exception. Instead I implementated ISerializable which worked great for me.
Hey, I can't seem to access the returned value from a method I called on my Host.
//Service---------------------------------------------------------
[DataMember]
private List<CalculationRecord> History = new List<CalculationRecord>();
public IEnumerable<CalculationRecord> CalculationHistory()
{
return (IEnumerable<CalculationRecord>)History;
}
public CalculationResult Calculate(CalculationNode problem)
{
CalculationResult calcResult = new CalculationResult();
//Calculates results of expression
CalculationEvaluation Evaluator = new CalculationEvaluation();
Evaluator.Calculate(problem, calcResult);
return calcResult;
}
//interface---------------------------------------------------------
[ServiceContract]
public interface ICalculate
{
[OperationContract]
CalculationResult Calculate(CalculationNode problem);
[OperationContract]
IEnumerable<CalculationRecord> CalculationHistory();
}
//Client------------------------------------------------------------
CalculatorClient client = new CalculatorClient();
ICalculate calcProxy = client.ChannelFactory.CreateChannel();
CalculationNode calcRootNode = parser.Parse(expression);
CalculationResult result = calcProxy.Calculate(calcRootNode);//result is null
You're under a wrong impression - the DataContract that the server exposes can (and should) only contain data - never any behavior. As such, you can never share an object between client and host - all you can share are service methods to call, and concrete types to use on those methods. That's it.
The process is this: when the client connects up to the server, it will download the metadata for the service - it can find out what service methods are available, what data those take - but it cannot infer any additional methods on the data contract. It just can't. The client then builds up an exact copy of the data contract type - but it's a totally separate class, and it only matches the server-side data contract class as far as its serialized representation in XML is concerned. It is not the same class - it just look the same.
Because in the end, all that happens between the server and the client is an exchange of a serialized message - basically a XML text document. You are not sending across a .NET object! All you're exchanging is a data representation of your data contract, nothing more.
So in your case, the client side proxy will have a new class that looks like the one the server uses - at least on the serialized level on the wire - but it will not contain the Calculate method. The Calculate method you're calling is on the service contract - it's not the one on the data member you have.
In your concrete example, too - you seem to be intermixing [DataMember] and service interface definition. Avoid this at all costs. Also, all the types involved in the calculation - most definitely CalculationNode and CalculationResult - must be exposed as [DataContract] elements containing a number of [DataMember] fields or properties. This is not clear from the snippet of code you posted.