I wanted to send one custom object in system.servicemodel.Channels.Message. Like
public class person
{
string Id;
string Name;
}
MessageVersion mv = MessageVersion.Create(Soap12);
String action = "Msg";
Message msg = Message.Create(mv, action, new person());
serviceref.ProcessMsg(msg) // this is my service reference in client
//when i tried to access this in Service like
person p = msg.GetBody<person>()
//I am getting an serialization exception
//I have the Person class on both client and service side
Can some one please help me in figure out my error?
Looks like you're looking for a DataContract:
using System.Runtime.Serialization;
[DataContract]
public class person
{
[DataMember]
string Id;
[DataMember]
string Name;
}
Check out Using Data Contracts for more information on DataContracts and WCF.
EDIT
Not sure if this will do the trick or not, but as I noted in my response to your comment, there's an overload of the CreateMessage method that takes an XmlObjectSerializer. MSDN docs on it are rather thin, but I think something like this might do it:
Message msg = Message.Create(mv, action, new person(), new DataContractSerializer(typeof(person)));
I haven't tested this, but at the least it may get you pointed in the right direction.
The DataContractSerializer will need to be supplied a DataContract (person in the first part of my answer).
Related
I am trying to send one parameter of Complex type to a WCF operation, but when I try to consume it, the signature of the operation become different and be converted to multiple parameters of simple types.
How can I keep the signature at client side as declared in server ?
For Example, My WCF looks like:
[MessageContract]
public class Foo
{
[MessageBodyMember]
public int ID {get; set;}
[MessageBodyMember]
public DateTiem Birthdate {get; set;}
[MessageBodyMember]
public string Name {get; set;}
}
[ServiceContract]
public interface IMyService
{
[OperationContract]
string Get(Foo request);
}
public class MyService
{
public string Get(Foo request)
{
// My Code
}
}
and the Clint side looks like:
MySvc.MyServiceClient c = new MySvc.MyServiceClient();
// The following code does not work
MySvc.Foo req = new MySvc.Foo();
req.Id = 5;
req.Birthdate = DateTiem.Now;
req.Name = "John";
c.Get(req);
//I should pass the parameters like the following since the signature here be different
c.Get(5, DateTime.Now, "John");
There are multiple solutions.
The best would be to compile your contract (data and service) objects into a common client assembly and use that same assembly on both the client and server side (so there's no need to create a service reference at all).
It would also be good to not use message contracts at all, only simple data contracts. Those usually look just like the server side when adding a service reference on the client side.
Finally, if you insist on message contracts (you shouldn't, IMHO), you can ask Visual Studio to generate message contracts on the client side when adding a service reference (there should be a checkbox for that).
So I am new to working with MVC4 and the serialization of objects on the back end seems pretty "magical" to me so if I am doing this the wrong way please let me know.
My goal however is to build a simple rest API and return JSON out. I figured that I would use System.Json and just return JsonObject. I have simplified this down for the sake of this question but the objects are much more complicated in my real issue.
Here is my controller....
....
public class ActionsController : ApiController
{
// GET api/actions
public JsonObject Get()
{
JsonObject testObjet = new JsonObject();
testObjet.Add("Name", "Test name");
testObjet.Add("Description", "Test Description");
return testObjet;
}
....
I would expect to see:
{"Name":"Test name","Description":"Test Description"}
Instead I see:
{"Name":[],"Description":[]}
I actually seem to get better results when I return a string of the JsonObject or heck even just return the object itself with the exception it has enums and I want to return the names not the number values, which is what led me to JsonObject for customization.
Does anyone know why it is dropping off the values?
EDIT:
So because of Dan's comments below I tried just for giggles to see what the XML serializer spit out with the JSON object and I get the below exception...
"Type 'System.Json.JsonPrimitive' with data contract name 'JsonPrimitive:http://schemas.datacontract.org/2004/07/System.Json' is not expected."
So it appears that you can not serialize the System.Json.JsonObject object, because it uses a type that it does not expect.
That is shocking. Does anyone have a workaround? If not I am off to find out how to show enum names when serializing instead of values.
So the answer is apparently... You Can't!
It appears that the type JsonPrimitive is not supported to serialize objects. The answers provided below by Obi and Dan helped me to poke around a bit more and find out that the XML serializer actually throws an exception while the JSON serializer simply eats it and puts out an empty array which is what you see above.
There are any number of correct answers here.
Make your own custom serializer
Output JSON as a string
Return custom objects and then work around things like the Enum
values
I am sure there are others.
But whatever you do don't try to use System.Json as a return in the ApiController because you will get the results above.
You should not force your WebApi call to use a particular format like JSON. One of the features of WebApi is that you can specify the format as part of the request. Return an object from your Get call, and let the WebApi engine do the serialization and deserialization:
public class DataObject
{
public string Name { get; set; }
public string Description { get; set; }
}
public class ActionsController : ApiController
{
// GET api/actions
public DataObject Get()
{
var testObject = new DataObject
{
Name = "Test name",
Description = "Test Description"
};
return testObject;
}
}
You can specify the format by setting the Accept header to application/xml, application/json, etc.
The default JSON serializer has no problem serializing simple string properties like Name and Description.
I would suggest you did this instead
// GET api/actions
public object Get()
{
//New up a strongly typed object if you want to return a specific type
//and change Action return type accordingly
var testObjet = new (){
Name= "Test name",
Description= "Test Description"
};
return testObjet;
}
Dan has posted a similar answer below so let me try to address your other problem. To serialize the enum, I would suggest you hide it in a public string property which would return the string value of the enum,
public class DataObject{
public MyEnum SomeEnumValue;
public string EnumValue{
get {
//..return SomeEnumValue string value
}
}
}
You can then read the value from EnumValue which should be properly serialized as you want.
I'm having difficulty fully grasping a particular function of Windows Communication Foundation. I've read tutorial after tutorial, book after book. So the entire conceptual nature I feel confident on.
Except for one part; this is the part that is almost like magic. Which actually made the learning slightly difficult.
I'll use the most common example on the web.
I'll start with the DataContract:
[DataContract]
public class Customer
{
// Declerations:
private Guid id;
private string firstName;
private string lastName;
private string emailAddress;
[DataMembers]
public Guid Id
{
get { return id; }
set { id = value; }
}
[DataMember]
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
[DataMember]
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
[DataMember]
public string EmailAddress
{
get { return emailAddress; }
set { emailAddress = value; }
}
}
Now I've created an object; that I'd like to be exposed to my Client.
So I then create my ServiceContract.
[ServiceContract]
public interface ICustomer
{
[OperationContract]
Customer AddCustomer(Customer info);
}
So this where I keep confusing myself; lets say you have a Client-Side Application. You've consumed the service. You have three textboxes in a separate Assembly / Namespace. The Client puts in the criteria:
First Name
Last Name
Email Address
If you set those text boxes to the date; they will transfer over in Metadata. But on the server; how can I pull that information variable out? Do I just reference the private Guid and private string variables?
I saw a tutorial on how to add it to a database; but I don't fully comprehend what WCF is actually doing. Which is similar to what I'd like. I'd like to get the Client interface input and write it to a database and a separate log file.
I could just follow the tutorial; but I want to know how the Customer object data and it's variables are being assembled for use on the server.
Any assistance would be amazing, some clarification.
Sorry if my question is stupid; I'm not trying to start a debate. Just want to understand how to pull those variables and use them on the server.
Thanks in advance. If I didn't format the question correctly please let me know. I'd really like to understand what it is conceptually doing.
Update:
My true intention is to understand how the Client interface references that object; so when the call is made the server has a valid object that isn't null.
Client types in text box ---> Proxy Sends ---> De-serialized ---> Service ---> Serializes ---> Makes Property available for usage.
The actual types, such as your Customer class are not really transmitted across the wire. However, the public information within those types is sent across through a process called serialization. Serialization allows a type to be represented in a way that allows it to be transmitted over a network. This is often expressed using a format such as SOAP, JSON or XML. WCF even allows you to control exactly how objects are serialized, allowing you to write your own formatter if you want. Basically, when AddCustomer is called, WCF is constructing a Customer object on the server, serializing it, and sending those bits across the wire.
Now, on the client you would have a matching Customer object called a proxy. It might look something like:
public class Customer
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
}
Basically, a scaled down version with just the data members of the server version, with no code or logic. On the client, the serialized representation of Customer is deserialized back into an instance of this local proxy class, where it can be used for various client purposes, including being bound to local UI elements.
Web services can expose this type information using WSDL (which is an XML format for describing a web service contract). Visual Studio (using the wsdl.exe tool) can automatically write these proxy classes for you, which makes everything just work magically.
I am not sure but may be this is what you are looking for
Data Transfer and Serialization
In particular you can check DataContractSerializer
You can check this article too : Serialization in Windows Communication Foundation
It looks like serverside cannot receive the passed values, requestVersion.Ping is empty.
namespace Communication
{
public class DataForRequestVersion
{
public string Ping = "";
}
public class DataForResponseVersion
{
public string Pong = "";
public string Version = "";
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
Communication.DataForResponseVersion Version(Communication.DataForRequestVersion requestVersion);
}
//Server
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class ServiceImplementation : WCFSimple.Contract.IService
{
public Communication.DataForResponseVersion Version(Communication.DataForRequestVersion requestVersion)
{
//Here requestVersion.Ping is EMPTY
Communication.DataForResponseVersion responseVersion = new Communication.DataForResponseVersion();
responseVersion.Pong = requestVersion.Ping;
responseVersion.Version = "MyApp v" + Settings.version;
return responseVersion;
}
}
//Client makes a request here
Communication.DataForRequestVersion requestVersion = new Communication.DataForRequestVersion();
requestVersion.Ping = DateTime.Now.ToString(Settings.DayTimePreciseFormat);
//Here requestVersion.Ping has a value
Communication.DataForResponseVersion responseVersion =
Service.Version(requestVersion);
What am I missing?
UPDATE
My application works very well, both sides communicate by passing custom data classes without any problem. However I tried to modify test client which one only sends-receives current time as string and made its parameter a bit complex; from string to custom data class. Main solution's application can send Version request and receive the answer. So I think my little test client got a problem.
Here is the pastebin code:
2nd UPDATE:
Some moderator doesn't allow me to answer my own question, I don't know why, I found a very similar question and the guy answered his own too. To help others next time I'm explaining the reason; I used namespace instead of creating class...And I fixed:
//namespace Communication
public class Communication
You need to label your request (and response) classes with the [DataContract] attribute, and their properties with the [DataMember] attribute:
[DataContract]
public class DataForRequestVersion
{
[DataMember]
public string Ping = "";
}
try using [DataContract] on your Data...classes... and [DataMember] on their fields...
Change the fields in DataForRequestVersion DataForResponseVersion classes to properties. By Default DatacontractSerializer will serialize public properties.
I'm quite stuck on one part of using WCF for a client/server messaging system, and would very much appreciate some help.
On the server, I've got a Message DataContract object where one of the properties points to a typed collection of MessageBody DataContracts. A stripped down version of the class looks like this:
[DataContract]
class Message {
[DataMember]
string From;
[DataMember]
string To;
[DataMember]
string Subject{get;set;}
[DataMember]
MessageBodies {get;}
}
[DataContract]
class MessageBodies : CollectionBase<MessageBody>{}
[DataContract]
class MessageBody {
[DataMember]
BodyType Type get {get;set;}
[DataMember]
string Body {get;set;}
}
From the App.Client.dll, I create a WCF Proxy of the a ServiceContract and DataContracts (btw: no referencing to a common 'App.Contracts.dll' where I could have put the above defined DataContracts), For transporting data from client to server, I'm now all set...
But from user functionality side on the client side, there's still a ways to go.
I want to ensure that users can work with the above properties, but with some type checking happening as they instantiate the client objects.
For example, I wish the actual class that users work with to look more like:
class MessageBody {
//ReadOnly only:
public BodyType Type get {get {return _Type;}}
private BodyType _Type;
//Validated property:
public string Body {
get{ return _Body;}
set{
if (value == null){throw new ArgumentNullException();}
_Body = value;
}
}
private string _Body;
//Set via Constructor only:
public MessageBody (BodyType type, string body){
//validate type and body first...
_Type = type;
_Body = body;
}
}
One direction I tried to use to solve this was as follows:
If I renamed the DataContract from Message to CommMessage, I could then wrap the POCO/WCF object with a smarter object... But although this would work for most of the properties, except for the collection properties:
public Message {
CommMessage _InnerMessage;
public string Subject {get {_InnerMessage.Subject;}}
//Option 1: give direct access to inner object...but they are just poco's...
public CommMessageBodies MessageBodies { get {_InnerMessage.Addresses;}}
//Option 2...don't have one yet...what I would like is something like
//this (returning MessageBody rather than CommMessageBody):
//public MessageBodies MessageBodies {get {_InnerMessage.Bodies;}}
}
Thanks very much for any and all suggestions!
I think it is very important to note that messages/datacontracts have a very specific purpose in a service-oriented environment. A message is a packet of information that needs to be transferred between a client and a server (or vice versa.) If your client needs specific behavior, then you should have client-specific types that provide for the specific needs of the client. Those types should be populated by some kind of adapter or facade that wraps your service references, abstracting your client application from the service as much as possible, and providing the necessary behavior, rules, and restrictions as appropriate.
using WCF.ServiceClientReference; // Contains WCF service reference and related data contracts
class ServiceFacade
{
private ServiceClient m_client;
void SendMessage(ClientMessage message)
{
Message serviceMessage = new Message
{
Subject = message.Subject,
MessageBodies = new CommMessageBodies(message.MessageBodies.Select(b => new CommMessageBody(b))
}
m_client.SendMessage(serviceMessage);
}
}
class ClientMessage
{
public ClientMessage()
{
MessageBodies = new List<ClientMessageBody>();
}
public string Subject {get; }
public IList<ClientMessageBody> MessageBodies { get; private set; }
}
// etc.
You're looking for something that's not meant to be there. The types on the client will not, in general, be the same as the types on the server, and, in general, they should not be. In the general case, the client won't even be running .NET.
Remember that these Data Contracts are meant to become the XML Schema definitions of some XML messags that will flow from the client to the service. XML Schema does not describe programming-language concepts such as Read-only.
If you feel you need the clients to have an API like that, then you do need them to use an assembly that you will have to provide. This assembly could contain the exact same data contract types that the server is using, but could potentially contain a set of types intended solely for the use of the clients. Of course, you'll have to keep the two sets of types compatible (same name, order, type and namsspace for each data member).
Lost my editing points/anon profile...but just wanted to say thanks to both of you for the clear answers. Got me moving on to the following solution:
ClientMessage on Server, creating a proxy of that on Client, with no direct dependency.
create Message on client that has properties that mirror names of poco/wcf ClientMessage, but with added arg checking, etc.
created Extension method to VisualStudio generated ClientMessage, with static Extension method MapFrom(this ClientMessage thisClientMessage, Message message){...} to map from Client facing message, to transport message object.
off it goes.
ClientMessage on server could have logic so that webpages would use that as the backing object. Costs a bit more to map those back and forth, even though on same server, but I gain from being able to cut/paste/use the same client logic for both scenarios (web and distance client). (Unless anybody sees an error with this logic as well :-) ...)
Again, thank you.