Object hierarchy returned by WCF service is different than expected
My understanding may be wrong, but I thought that after you applied the correct attributes, the DataContractSerializer will return completed copies of the instances back to the caller.
The code runs and objects are returned. But oddly enough, as soon as I look at the returned objects, I noticed that the namespace disappeared and the object hierarchy viewed through the service reference (web applications) seems to have become "flat" (somehow). Now I expect this from a web service ... but not through WCF. Of course, my understanding of what WCF can do might be wrong.
... Please keep in mind that I am still experimenting with all of this.
So my questions ...
Q: Can I do something within the WCF service to force the namespace to render through the service reference proxy?
Q: Or maybe I (just) misused the service?
Q: Is this possible?
The service code looks like ...
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class DataService : IFishData
{
public C1FE GetC1FE(Int32 key)
{
//… more stuff here …
}
public Project GetProject(Int32 key)
{
//… more stuff here …
}
}
[ServiceContract]
[ServiceKnownType(typeof(wcfFISH.StateManagement.C1FE.New))]
[ServiceKnownType(typeof(wcfFISH.StateManagement.Project.New))]
public interface IFishData
{
[OperationContract]
C1FE GetC1FE(Int32 key);
[OperationContract]
Project GetProject(Int32 key);
}
[DataContract]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class Project
{
[DataMember]
public wcfFISH.StateManagement.ObjectState ObjectState { get; set; }
//… more stuff here …
}
[DataContract]
KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class C1FE
{
[DataMember]
public wcfFISH.StateManagement.ObjectState ObjectState { get; set; }
//… more stuff here …
}
[DataContract(Namespace = "wcfFISH.StateManagement")]
[KnownType(typeof(wcfFISH.StateManagement.C1FE.New))]
[KnownType(typeof(wcfFISH.StateManagement.Project.New))]
public abstract class ObjectState
{
//… more stuff here …
}
[DataContract(Namespace = "wcfFISH.StateManagement.C1FE", Name="New")]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class New : ObjectState
{
//… more stuff here …
}
[DataContract(Namespace = "wcfFISH.StateManagement.Project", Name = "New")]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class New : ObjectState
{
//… more stuff here …
}
The web application code looks like ...
public partial class Fish_Invite : BaseForm
{
protected void btnTest_Click(object sender, EventArgs e)
{
Project project = new Project();
project.Get(base.ProjectKey, base.AsOf);
mappers.Project mapProject = new mappers.Project();
srFish.Project fishProject = new srFish.Project();
srFish.FishDataClient fishService = new srFish.FishDataClient();
mapProject.MapTo(project, fishProject);
fishProject = fishService.AddProject(fishProject, IUser.UserName);
project = null;
}
}
In case Im not clear ...
The problem is that the namespace that I expect to see (returned) is different from what is actually returned.
fishProject.ObjectState SHOULD look like ...
srFish.StateManagement.Project.New
fishC1FE.ObjectState SHOULD look like ...
srFish.StateManagement.C1FE.New
fishProject.ObjectState ACTUALLY looks like ...
srFish.New1
fishC1FE.ObjectState ACTUALLY looks like ...
srFish.New
source to share
OK - The default behavior for a WCF service is:
- you define your service contracts, operations, and data contract on the server (for example, in the "Server.MyService" namespace).
- After starting and starting the service on your client, you will create a link to the service
- with that, what does Visual Studio do, or is
svcutil.exe
it requests this service for its metadata (description of methods and service data) - based on this metadata, a client-side proxy is created (namespace "Client.MyService") and contains replicas of the service contract (methods) and the data contract
Important: it contains replicas of these things! They look the same and they serialize to the same XML format on the wire - but they are different - in different namespaces, especially.
This is the very nature of WCF - everything you do is exchange serialized messages between client and server - everything that goes back and forth is text messages. Nothing else — no object references, no remote object — nothing like that. Get it out of your head! :-)
If you control both ends of the wire, it can be painful - if you need to change anything, you need to change it on the server side, update references to the client, etc.
So, if you control both ends of the wire - both the server and the client - and both are .NET based, you can do the following:
- put your service contracts and your data contracts (contracts only - no implementations!) in a separate assembly
- from your service implementation, link to build contracts
- copy the assembly of contracts to your client and also include it in your client project
Now if you add a service reference, by default the function Add Service Reference
in Visual Studio will reuse existing types in referenced assemblies, so if you reference your shared assembly "Contracts" these types (in their full glory, including their namespace) will be reused - no additional copies will be created.
This way you can create a single collaborative assembly of contracts used by both the server-side code and your client, and you don't have to mess with any duplicate data structures. But then again: this only works if you control both ends of the wire and both are .NET.
source to share