WCF REST Format Output - wcf

I have a WCF service using REST protocol.
Code:
[ServiceContract]
public interface IHybridService
{
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "/hybridservice/compositedata/{value}", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare)]
CompositeType GetDataUsingDataContract(string value);
}
[DataContract]
public class CompositeType
{
List<Data> data = new List<Data>();
public CompositeType()
{
data.Add(new Data() { Id= 1, Value = "test1" });
}
[DataMember]
public List<Data> DataList
{
get { return data; }
set { data = value; }
}
}
public class Data
{
[DataMember(Name = "DataID")]
public int Id { get; set; }
public string Value { get; set; }
}
Currently it returns the following output:
{
"DataList": [
{
"Id": 1,
"Value": "test1"
}
]
}
How can I change the Id within DataList to DataID? I tried [DataMember(Name = "DataID")] but it doesn't work. I do not want to change the c# property to DataID to make it work.

Found the reason, I had to declare Data class as [DataContract].

Related

How to return a list of a defined type WCF service

I have defined the data contract as follows:
[DataContract]
public class TestResult
{
[DataMember]
public string[] NegResponses { get; set; }
[DataMember]
public bool Pass { get; set; }
[DataMember]
public string Request { get; set; }
[DataMember]
public string Response { get; set; }
}
Is it possible to return a list of the above type in the operation contract as follows:
[OperationContract]
[FaultContract(typeof(TestFault))]
List<TestResult> Tester(string nodeCaption);
And what else I have to look into to return a list of a type that has been defined ?
By the way I guess I am not using svcutil and instead using channel factory as follows:
private static readonly ITestService TestClient;
// initialize a channel factory
var channelFactory = new ChannelFactory<ITestService>(new NetTcpBinding(SecurityMode.None), endPoint);
// Create a channel
TestClient = channelFactory.CreateChannel();
The client-side and the server-side should share the same service contract and data contract. This is fundamental that we could consume the service on the client-side.
Here is an example, wish it is useful to you.
Server-side.
class Program
{
static void Main(string[] args)
{
Uri uri = new Uri("http://localhost:21011");
BasicHttpBinding binding = new BasicHttpBinding();
using (ServiceHost sh = new ServiceHost(typeof(MyService), uri))
{
sh.AddServiceEndpoint(typeof(IService), binding, "");
ServiceMetadataBehavior smb;
smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
{
smb = new ServiceMetadataBehavior()
{
HttpGetEnabled=true
};
sh.Description.Behaviors.Add(smb);
}
Binding mexbinding = MetadataExchangeBindings.CreateMexHttpBinding();
sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex");
sh.Opened += delegate
{
Console.WriteLine("Service is ready");
};
sh.Closed += delegate
{
Console.WriteLine("Service is clsoed");
};
sh.Open();
Console.ReadLine();
//pause
sh.Close();
Console.ReadLine();
}
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
List<Product> SayHello();
}
public class MyService : IService
{
public List<Product> SayHello()
{
return new List<Product>()
{
new Product()
{
ID=1,
Name="Apple"
},
new Product()
{
ID=2,
Name="Pear"
}
};
}
}
[DataContract(Namespace = "MyNamespace")]
public class Product
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Name { get; set; }
}
Client-side (Console application,we call the service with ChannelFactory).
class Program
{
static void Main(string[] args)
{
BasicHttpBinding binding = new BasicHttpBinding();
Uri uri = new Uri("http://10.157.13.69:21011");
ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, new EndpointAddress(uri));
IService service = factory.CreateChannel();
try
{
var result = service.SayHello();
foreach (var item in result)
{
Console.WriteLine($"ID:{item.ID}\n,Name:{item.Name}");
}
}
catch (Exception)
{
throw;
}
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
List<Product> SayHello();
}
[DataContract(Namespace = "MyNamespace")]
public class Product
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Name { get; set; }
}
Data Contract should be decorated with Namespace property, this will guarantee that the serialization and deserialization process properly). Actually, the service contract also needs a namespace to represent the practical method name, which will be used to addressing the method on the server-side. but there is a default value in the namespace.
http://tempuri.org
Feel free to let me know if there is anything I can help with.

How to set a method with class as a parameter in WCF service?

I am trying to create a method with class as a parameter. But it's throwing error. After some search I found the implementation of QueryStringConverter.
I am trying to do it but I didn't have much knowledge in it.
In my service class, the method is :
[WebInvoke(UriTemplate="LogInForMobileWithDeviceNo", Method="POST", RequestFormat=WebMessageFormat.Json, ResponseFormat=WebMessageFormat.Json, BodyStyle=WebMessageBodyStyle.Wrapped)]
string LogInForMobileWithDeviceNo(clsUserDeviceInfo userDeviceInfo);
In the clsUserDeviceInfo class, i declared the properties as:
[DataContract]
public class clsUserDeviceInfo
{
[DataMember]
public string UserID{get;set;}
[DataMember]
public string DeviceName{get;set;}
[DataMember]
public string CordovaVersion{get;set;}
[DataMember]
public string DevicePlatformJs{get;set;}
[DataMember]
public string DeviceUID{get;set;}
[DataMember]
public string DeviceModel { get; set; }
[DataMember]
public string DeviceVersion { get; set; }
}
but it's not working.
using Jquery i did Ajax posting:
var DeviceName = "samsung";
var CordovaVersion = "2.1.1.1";
var DevicePlatformJs = "windows 8";
var DeviceUID = "23dswd-234dff-23-2334nhj";
var DeviceModel = "grand duos";
var DeviceVersion = "3.2";
var DataArr = {DeviceName:DeviceName,CordovaVersion:CordovaVersion, DevicePlatformJs:DevicePlatformJs,DeviceUID:DeviceUID,DeviceModel:DeviceModel,DeviceVersion:DeviceVersion};
$.ajax({
type: "GET",
url: serverurl,
data: JSON.stringify(DataArr),
success: function (result) {
alert(result);
},
accept: 'application/json'
});
Am I doing anything wrong?
Do you have a OperationContract, this should work!
[OperationContract]
[WebGet(BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json, UriTemplate = "/LogInForMobileWithDeviceNo?userDeviceInfo={userDeviceInfo}")]
string LogInForMobileWithDeviceNo(clsUserDeviceInfo userDeviceInfo);

WCF RESTful Console-hosted, return 400 Bad Request

Studying WCF RESTful, host in a Console,
my steps:
create sample models
create contract of service
create service
host this service in a console.
run this host, looks ok.
create a winform, use service address via json post to service host.
i hope it would work, but return http 400.
I tried on WCF(not REST) Console-hosted, WebAPI, steps all ok.
finally, stackoverflow.com
please help
Models
[Serializable]
public abstract class Building
{
public Manufacturer Manufacturer { get; set; }
}
[Serializable]
public class Manufacturer
{
public string Name { get; set; }
public string Telephone { get; set; }
}
[Serializable]
public class Furniture : Building
{
public string Name { get; set; }
}
[Serializable]
public class Reception
{
public int Floor { get; set; }
public int Number { get; set; }
}
[Serializable]
public class Room : Building
{
public string Number { get; set; }
public List<Furniture> Furnitures { get; set; }
}
[Serializable]
public class Hotel : Building
{
public Guid Guid { get; set; }
public List<Reception> Receptions { get; set; }
public List<Room> Rooms { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
Contract
[ServiceContract]
public interface IHotel
{
// Create objct Hotel
[OperationContract]
[WebInvoke(UriTemplate = "", Method = "POST", RequestFormat= WebMessageFormat.Json, ResponseFormat=WebMessageFormat.Json)]
bool Create(Hotel hotel);
}
Service
public class HotelService : I Hotel
{
public bool Build(Models.Hotel hotel)
{
if (hotel == null)
return false;
// codes here is object hotel(EF) creation, test OK
return true;
}
}
Host(Console)
WebServiceHost serviceHost = new WebServiceHost(typeof(Demo.Services.HotelService), new Uri("http://192.168.1.101/HotelService"));
ServiceEndpoint endpoint = serviceHost.AddServiceEndpoint(typeof(Demo.Contracts.IHotel), new WebHttpBinding(), "");
ServiceDebugBehavior sdb = serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>();
sdb.HttpHelpPageEnabled = false;
Console.WriteLine("Starting Service...");
// start service
serviceHost.Open();
Console.WriteLine("Started, press RETURN to exit.");
Console.ReadLine();
serviceHost.Close();
Client(Winform)
Caller
public bool BuildHotel(string json)
{
WebRequest request = HttpWebRequest.Create("http://192.168.1.101/HotelService");
request.ContentType = "application/json";
byte[] data = Encoding.UTF8.GetBytes(json);
request.ContentLength = data.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(data, 0, data.Length);
requestStream.Close();
WebResponse response = request.GetResponse(); // 400 throwed here
Stream responseStream = response.GetResponseStream();
StreamReader responseStreamReader = new StreamReader(responseStream);
string result = responseStreamReader.ReadToEnd();
return true;
}
Json String for 'bool BuildHotel(string)' upon
{
"Guid":"ea59c011-d656-4870-b29b-30a44e668560",
"Receptions":[
{"Floor":1,"Number":1},
{"Floor":2,"Number":2}
],
"Rooms":[
{
"Number":"c",
"Furnitures":[
{"Name":"1","Manufacturer":{"Name":"1","Telephone":"1"}},
{"Name":"2","Manufacturer":{"Name":"2","Telephone":"2"}}
],
"Manufacturer":{"Name":"c","Telephone":"c"}
}
],
"Name":"x",
"Address":"x",
"Manufacturer":{"Name":"x","Telephone":"x"}
}
it expects such kind of JSON:
{"k_BackingField":{"k_BackingField":"4","k_BackingField":"4"},"k_BackingField":"x","k_BackingField":"ea59c011-d656-4870-b29b-30a44e668560","k_BackingField":"x","k_BackingField":[{"k_BackingField":1,"k_BackingField":1},{"k_BackingField":2,"k_BackingField":2}],"k_BackingField":[{"k_BackingField":{"k_BackingField":"3","k_BackingField":"3"},"k_BackingField":[{"k_BackingField":{"k_BackingField":"1","k_BackingField":"1"},"k_BackingField":"1"},{"k_BackingField":{"k_BackingField":"2","k_BackingField":"2"},"k_BackingField":"2"}],"k__BackingField":null}]}
To change it you can mark all your data contracts with DataContract and DataMember attribute:
[DataContract]
public abstract class Building
{
[DataMember]
public Manufacturer Manufacturer { get; set; }
}
In this case it will understand json as you have given us in the question and will process it successfully.

Post object to a WCF method

I am a newbie to both RestSharp and WCF and I am trying to write a working sample that has a post method which takes a string and an object as parameters. I have looked at another post here where someone asked the same question and I still couldn't get it to work. Can someone please point me in the right direction. I debugged the code and I am getting a null in the object. It seems like its pretty straight forward but I am not sure what I am missing. This is what I have so far.
Server side:
[OperationContract]
[Description("addUser")]
[WebInvoke(Method = "POST", UriTemplate = "/addUser?id={id}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
TSCRUResponse addUser(string id, User usr);
public TSCRUResponse addUser(string id, User usr)
{
TSCRUResponse r = new TSCRUResponse();
r.status = id + usr.name + usr.age + usr.gender;
return r;
}
The first parameter for the above method comes through OK but not the object.
These are the objects:
[DataContract]
public class TSCRUResponse
{
[DataMember(Name = "status")]
public string status { get; set; }
}
[DataContract]
public class User
{
[DataMember(Name = "name")]
public string name { get; set; }
[DataMember(Name = "age")]
public string age { get; set; }
[DataMember(Name = "gender")]
public string gender { get; set; }
}
Client side :
public void postmethod(string uri)
{
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateRemoteCertificate);
RestClient client = new RestClient();
client.BaseUrl = "http://localhost:1119/TestService.svc/";
client.Authenticator = new HttpBasicAuthenticator("username", "password");
RestRequest request = new RestRequest("addUser?id={id}", Method.POST);
request.AddHeader("Accept", "application/json");
request.JsonSerializer = new RestSharp.Serializers.JsonSerializer();
request.RequestFormat = DataFormat.Json;
request.AddParameter("id", "12839", ParameterType.UrlSegment);
User itm = new User { age = "40", name = "user1", gender = "M" };
request.AddBody(itm);
var response = client.Execute<TSCRUResponse>(request);
TSCRUResponse addres = response.Data;
Console.WriteLine(addres.status);
}

Serialization issue while returning object having collection of Navigation Objects

I am using WCF WebAPI for creating REST service and EF4. While returning an object(of POCO class) which is having NavigationProperty, I am getting following Serialization exception:
Cannot serialize member Models.Customer.Orders of type System.Collections.Generic.ICollection`1[[Models.Order, Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] because it is an interface.
Following is the POCO class
[Serializable]
[DataContract(IsReference = true)]
[KnownType(typeof(Order))]
public partial class Customer
{
#region Primitive Properties
[DataMember]
public virtual int CustomerID { get; set; }
[DataMember]
public virtual string CustomerCode { get; set; }
[DataMember]
public virtual string Description { get; set; }
[DataMember]
public virtual string Comments { get; set; }
[DataMember]
public virtual bool DeleteFlag { get; set; }
[DataMember]
public virtual byte[] RowVersion { get; set; }
#endregion
#region Navigation Properties
[DataMember]
public virtual ICollection<Order> Orders
{
get
{
if (_order == null)
{
var newCollection = new FixupCollection<Order>();
newCollection.CollectionChanged += FixupOrders;
_order = newCollection;
}
return _order;
}
set
{
if (!ReferenceEquals(_order, value))
{
var previousValue = _order as FixupCollection<Order>;
if (previousValue != null)
{
previousValue.CollectionChanged -= FixupOrders;
}
_order = value;
var newValue = value as FixupCollection<Order>;
if (newValue != null)
{
newValue.CollectionChanged += FixupOrders;
}
}
}
}
private ICollection<Order> _order;
#endregion
#region Association Fixup
private void FixupOrders(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (Order item in e.NewItems)
{
item.Customer = this;
}
}
if (e.OldItems != null)
{
foreach (Order item in e.OldItems)
{
if (ReferenceEquals(item.Customer, this))
{
item.Customer = null;
}
}
}
}
#endregion
}
The method in service is as follows:
[WebGet(UriTemplate = "Customer",
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml)]
public List<Customer> Get()
{
CustEntities context = new CustEntities();
return context.Customer.Include("Orders").ToList();
}
Any help in above regard is highly appreciable.
Thanks
I don't think you can serialize Properties as interfaces in this way, otherwise the deserializer wouldn't know which concrete type to create when the object is deserialized.
Can you change your ICollection property to a concrete type like List<T>?