using custom types in a WCF service - wcf

I'm new in WCF and now stuck in something about using custom types in WCF service.
I have two classes Class1 and Class2 in TestClass project
public Class1: ArrayList{
public string street;
}
public Class2{
public string name;
public string address;
}
My WCF service TestService include function DoSomething using two above classes
public string DoSomething(Class1 c1){
return c1.street;
}
And when try to call this function
Class1 c1 = new Class1();
Class2 c2 = new Class2();
c1.Add(c2);
ServiceClient1.Dosomething(c1);
I get the Exception
There was an error while trying to serialize parameter http://tempuri.org/:c1. The
InnerException message was 'Type 'WebApplication1.Class2' with data contract name
'Class2:http://schemas.datacontract.org/2004/07/WebApplication1' is not expected. 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.'. Please see InnerException for more details.
Can anyone tell me how to add DataContract for a class defined outside the WCF service, and how to solve this problem.
Thanks a lot!

Add the lines below to your service interface declaration (add them just below the ServiceContract attribute):
[ServiceKnownType(typeof(Class1))]
[ServiceKnownType(typeof(Class2))]
alternatively, and this is the recommended approach, define your set of DTO objects exported by the service and decorate them with [DataContract] and [DataMember] attributes.

Related

DataContractException in hosted WCF service

I am trying a host a service where there is a method that returns the following type:
[DataContract]
[Obfuscation(ApplyToMembers = true, Exclude = true)]
[Serializable]
public class Output
{
[DataMember]
public DataSet dsOutput{get;set;}
}
The method signature is as follows:
[OperationContract]
[WebGet]
function Output matchData(DataSet pDSSide1,DataSet pDSSide2)
{
return new Output();
}
On browsing the service I encounter the following exception:
System.InvalidOperationException: An exception was thrown in a call to a WSDL export extension:System.ServiceModel.Description.DataContractSerializerOperationBehavior
contract: http://tempuri.org/:TesterTool ---->
System.Runtime.Serialization.InvalidDataContractException: Type 'System.Data.DataRow' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
`
Any suggestions.
It's not a good practice to send a DataTable over a service.
As stated by govindaraj here:
The best way is to use custom collection of custom object.
If you're using 2.0, then you can use generic collection instead of
custom collection to reduce code.
How?
Create a custom data object (containing only private fields and public properties for each field) that is similar to each row in the
datatable.
Create a layer that will do all database (in this case, dataset) access and translation to the custom object.
All client code will access that layer.

Problem with sending object via wcf service with private fields

I have a class Car
public class Car
{
private Member _owner;
public string OwnerName
{
get { return _owner.Name; }
}
public Car(Member owner)
{
_owner = owner;
}
}
I'm using it both at Silverlight application and wcf service
So, at application I call WCF service to give me instance of car class, but when I get it at application, I see that _owner is empy.
I know that it is empty because of private, but how can I deal with it?
I'm using this class in my app as model (MVVM) if it could helps :/
For a start none of your properties are marked as DataMembers. The class isn't marked as a DataContract. If this is getting returned from a WCF service I would expect to see:
[Serializable]
[DataContract]
public class Car
{
private Member _owner;
[DataMember]
public string OwnerName
{
//getter
//setter
}
etc..
}
Does Member have to be private? Could it be converted into a property?
Keep in mind that a [DataMember] property needs both a set and a get (so that WCF can read into and from the object).
http://msdn.microsoft.com/en-us/library/ms733127.aspx
From a WCF serialization point of view, your Car class actually looks something like this to the WCF service:
public class Car
{
public string OwnerName { get; set; }
//other public properties here....
}
The WCF serializer uses the .NET class definition as a template for serializing its contents as a simple data transfer object. When the WCF service sends back a Car instance, only the public properties will contain values. The serializer ignores all methods in the class. Also, later versions of WCF don't require the DataContract/DataMember attribute markup.
The _owner variable is never initialized because it is not part of the public properties of the Car class. You'll need to modify the structure of the Car class (maybe add a public Owner property of type Member) to get all the data sent from the WCF service to your client.
When you are using the default Data Contract Serializer with WCF services it serializes and deserializes only the public properties of the class. Also another thing to note is that while deserializing the object graph the constructor is not called. You can have a public property with getter and setter.
Here is a very nice article by Jeremy Likeness explaining the problem similar to yours. From Architecture as well as best practices point of view you can use a POCO class generally called as DTO (Data Transfer Object) when transferring objects between the service layer and the clients.

Do WCF and DataContractSerializer serialize CollectionDataContract-decorated collection types differently?

I have a really simple customized collection type that inherits from List<> and uses a CollectionDataContract.
When I use DataContractSerializer.WriteObject to serialize it, it respects the CollectionDataContract attribute the way I'd expect; however, when I use it as a return type for a WCF method, I get the default ArrayOfFoo.
I'm wondering if there is some decoration I'm missing in the service contract.
Details:
[DataContract(Namespace = "")]
public class Foo
{
[DataMember]
public string BarString { get; set; }
}
[CollectionDataContract(Namespace = "")]
[Serializable]
public class FooList : List<Foo> {}
If I just instantiate a Foo and then use DataContractSerializer.WriteObject to serialize it, I get what you'd expect:
<FooList>
<Foo>
<BarString>myString1</BarString>
</Foo>
</FooList>
However, if I have a service with a method like this...
[ServiceContract Name = "MyService"]
public interface IMyService
{
[OperationContract, WebGet(UriTemplate = "foos/")]
FooList GetAllFoos();
}
and then do a GET for http://www.someEndpoint.com/foos/, I get this:
<ArrayOfFoo>
<Foo>
<BarString>myString1</BarString>
</Foo>
</ArrayOfFoo>
I've also tried specifying Name="MyFooListName" in the CollectionDataContract attribute. Same results: DataContractSerializer gets the memo; WCF doesn't.
Saeed sent me in the right direction: I inadvertently ended up with XmlSerializer, when I had been hoping for DataContractSerializer.
I had ended up with XmlSerializer... well... by asking for it.
In particular, I had decorated methods in my service with the XmlSerializerFormat like this:
[ServiceContract Name = "MyService"]
public interface IMyService
{
// ... other stuff ...
[OperationContract, WebInvoke(UriTemplate = "foos/", Method = "POST")]
[XmlSerializerFormat]
Foo PostAFoo(Foo yourNewFoo);
}
I had done this in the hopes of forgiving member order in hand-rolled Foo XML blobs. Of course, when one does this one ends up with XmlSerializer, not DataContractSerializer.
When I take away the XmlSerializerFormat attribute, problem solved: WCF is now serializing my FooList collection the way I want.
See MSDN for detail:
The DataContractSerializer does not
support the programming model used by
the XmlSerializer and ASP.NET Web
services. In particular, it does not
support attributes like
XmlElementAttribute and
XmlAttributeAttribute. To enable
support for this programming model,
WCF must be switched to use the
XmlSerializer instead of the
DataContractSerializer.
So the serialization going to be done by XMLSerializer, and you can't change it.
Have you selected Generic types while configuring your WCF service? if not then,
right click and go to configuration, then select Generic Type, by default it is arraylist type.

WCF with shared objects and derived classes on client

I have a WCF service and I'm sharing types with a client in a shared assembly.
If the client create a derived class will it be possible to pass back the derived type to the service so that I can read the added properties through reflection ?
I tried but having issues with KnownTypes since the service don't know how to deserialize the derived type.
[Serializable]
public abstract class Car : ICar
{........
//on the client :
[Serializable]
public class MyCar : Car
{......
when passing myCar to Service I get the exception complaining about knownType but I cant add this on the server since I wont know what the client will be sending through and I want to handle extra properties through reflection.
Possible to register client types as knowntypes at runtime ?
Is this maybe the solution ?
http://blogs.msdn.com/b/sowmy/archive/2006/03/26/561188.aspx
This is not possible. Both service and client has to know what types will be sent in messages. If you want to use known type you have to define that relation to parent type on the service.
Why do you need to know added properties on the server?
I think there is a way.
I vaguely remember that when I studied WCF, I met ExtensionData which should be a mechanism to get everything that does not match the serialization of the class. for example, if you enable ExtensionData and you are in this situation
//Server
public class GenericRQ
{
public string GenericProperty {get;set;}
}
public Service GenericService
{
Public void GenericMethod(GenericRQ RQ)
{
}
}
// client
Public class MoreSpecificRQ : GenericRQ
{
public string SpecificProperty {get;set;}
}
At
Public void GenericMethod(GenericRQ RQ)
{
// the serializer adds automatically in RQ.ExtensionData everything that has come and that does not match the class GenericRQ.
}
On how to enable ExtensionData you to easily search on the web

Is it possible to serialize objects without a parameterless constructor in WCF?

I know that a private parameterless constructor works but what about an object with no parameterless constructors?
I would like to expose types from a third party library so I have no control over the type definitions.
If there is a way what is the easiest? E.g. I don't what to have to create a sub type.
Edit:
What I'm looking for is something like the level of customization shown here: http://msdn.microsoft.com/en-us/magazine/cc163902.aspx
although I don't want to have to resort to streams to serialize/deserialize.
You can't really make arbitrary types serializable; in some cases (XmlSerializer, for example) the runtime exposes options to spoof the attributes. But DataContractSerializer doesn't allow this. Feasible options:
hide the classes behind your own types that are serializable (lots of work)
provide binary formatter surrogates (yeuch)
write your own serialization core (a lot of work to get right)
Essentially, if something isn't designed for serialization, very little of the framework will let you serialize it.
I just ran a little test, using a WCF Service that returns an basic object that does not have a default constructor.
//[DataContract]
//[Serializable]
public class MyObject
{
public MyObject(string _name)
{
Name = _name;
}
//[DataMember]
public string Name { get; set; }
//[DataMember]
public string Address { get; set; }
}
Here is what the service looks like:
public class MyService : IMyService
{
#region IMyService Members
public MyObject GetByName(string _name)
{
return new MyObject(_name) { Address = "Test Address" };
}
#endregion
}
This actually works, as long as MyObject is either a [DataContract] or [Serializable]. Interestingly, it doesn't seem to need the default constructor on the client side. There is a related post here:
How does WCF deserialization instantiate objects without calling a constructor?
I am not a WCF expert but it is unlikely that they support serialization on a constructor with arbitrary types. Namely because what would they pass in for values? You could pass null for reference types and empty values for structs. But what good would a type be that could be constructed with completely empty data?
I think you are stuck with 1 of 2 options
Sub class the type in question and pass appropriate default values to the non-parameterless constructor
Create a type that exists soley for serialization. Once completed it can create an instance of the original type that you are interested in. It is a bridge of sorts.
Personally I would go for #2. Make the class a data only structure and optimize it for serialization and factory purposes.