I've created a WCF Web Service which returns data in JSON format. The code for the service is as follows:
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
List<MyCustomer> GetCustomerJSON();
And
public List<MyCustomer> GetCustomerJSON()
{
var nm = (from n in _ent.Customers
select new MyCustomer() { CustomerID = n.CustomerID, AccountNumber = n.AccountNumber }).Take(10);
return nm.ToList();
}
However, the output isn't well formed. It included square brackets at start and end.
Because of which I can't use Json Parser tool.
Please help.
If you return List<T> it will be encoded like array of T in the JSON and array will be encoded with respect of square brackets:
[{"strProprety":"bla","intProperty":123,"booleanProperty":true}]
In your case it will be probably
[{"CustomerID":1,"AccountNumber":123},{"CustomerID":2,"AccountNumber":456}]
It is valid JSON. You can use http://www.jsonlint.com/ to verify this. So WCF produce correct output and you have problem only with the "Json Parser tool".
Related
I'm having issues with strings containing ampersands in my client generated from dotnet-svcutil.
When I recieve a response through the client all ampersands are serialized as
<Users xsi:type=\"xsd:string\">John & Jane</Users>
When i extract the value from the request in my code it has been deserialized as an ampersand
UserResponse users = await GetUsersAsync()
users.Names = "John & Jane"
In a later stage i need to send the value of the users back like this
await SetUsersAsync(users.Names);
When i intercept the generated soap request I can see that the ampersand has not been escaped
public class MyMessageInspector : IClientMessageInspector
{
public void AfterReceiveReply(ref Message reply, object correlationState)
{
var xml = reply.ToString(); // This shows <Users xsi:type=\"xsd:string\">John & Jane</Users>
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
var xml = request.ToString(); // This shows <Users xsi:type=\"xsd:string\">John & Jane</Users>
return null;
}
}
This causes the whole request to fail in the connected service. From the information I've found online the ampersand should be converted to & by the serializer. I could convert the value myself, but since I'm only returning a value I got from the soap client, I would have to check and convert every single string that is returned back.
Do you have any suggestions on how I could configure the generated client to automatically escape ampersands?
For .net core 2.1+:
Use the HtmlEncode method of HttpUtility available in System.Web to encode the strings you send to the client.
using System.Web;
await SetUsersAsync(HttpUtility.HtmlEncode(users.Names));
For .net core 2.0 (or .net 1.* with a package install):
use HtmlEncoder.Default.Encode(users.Names)
which is available in System.Text.Encodings.Web
My wcf project returns the Countries List as json, in wcf project parse using Newtonsoft json. I get json in my client website built on mvc, i show the data using jtable plugin in jquery. The plugin failed to display because, the json contains /(back slashes).
Code to display jtable is
Name:{
title: 'Country Name',
width: '40%',
options: '/Country/Index'
}
Country/Index result is
{"Result":"OK","Options":"[{\"DisplayText\":\"India\",\"Value\":1},{\"DisplayText\":\"Singapore\",\"Value\":2}]"}
Country/Index gets the result from wcf service. Is there any way to strip the / in json.
Edit:
My wcf code is
List<JSONDisplayNameValue> lstLanguages = new List<JSONDisplayNameValue>();
//Get data from db.
//JSONDisplayNameValue has two variables DisplayName, Value
var json = JsonConvert.SerializeObject(lstLanguages);
return json;
Country/Index mvc code is
public JsonResult Index()
{
string Countries_list = processsvc.GetAllCountries();
return Json(new { Result = "OK", Options = Countries_list }, JsonRequestBehavior.AllowGet);
}
You are getting backslashes because you are double-serializing your data.
In your WCF code, you call JsonConvert.SerializeObject() to serialize your list of countries/languages to JSON before returning it.
In your MVC controller, you call your WCF service to get the list, which is already in JSON format. But then you add that JSON to another object and call Json() which causes the list to be serialized a second time. That is where the backslashes get added.
To fix this, you either need to
Deserialize the list you get back from your WCF service before adding it to the MVC result.
-- OR --
Make a way to retrieve your list of countries/languages without serializing it to JSON. Then add the unserialized list to your MVC result and serialize it as normal.
public string ReturnString()
{
string s = "";
s = HttpUtility.SomeValiable;
return s;
}
SomeValiable = <Dependent><DependentId>
But I am getting the string s value like <Dependent><DependentId>
NOTE: I have not applied ; after < as it converted it into <
Might be the string is not compatible with the HTML format. Please suggest me what datatype I have to use to return HTMLDecode format.
ANY QUICK HELP PLEASE
See this question.
The data type you are looking for is XElement or XmlElement as a return type.
Another easy way that can use string as a return type is to use System.Net.WebUtility to htmlencode before returning in the service and htmldecode in the client.
I put together a simple REST service in WCF as such:
....
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml, UriTemplate = "{uid}/{pwd}/{exrcsPrgmId}/{exchEnum}")]
string GetLiftDataExchange(string uid, string pwd, string exrcsPrgmId, string exchEnum);
....
When calling it however I do not get back XML exactly. I get HTXML (my own made up acronym)
Instead of what I expect:
<Exercise>
<AccountName>Joe Muscle</AccountName>
<UserID>8008008</UserID>
I get the XML with html encoding:
<Exercise>
<AccountName>John Bonner</AccountName>
<UserID>8008008</UserID>
In other words I have no need to see this data in the browser instead it will be accessed and parsed in an application so straight up XML will work just fine.
What am I doing wrong with the service decorations to return this encoded xml?
When you return a string, and the result type is XML, you'll get the string encoded to be able to represent all characters in the string - which causes the XML characters to be escaped.
You have two options for your scenario. If you want to return "pure" XML (i.e., XHTML, or HTML which happens to be well-formed XML), you can use the return type as either XmlElement or XElement. That is telling WCF that you do want to return arbitrary XML. If you do like the code below, you'll get the "pure" XML which you need.
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "...")]
public XElement GetLiftDataExchange(string uid, string pwd, string exrcsPrgmId, string exchEnum)
{
return XElement.Parse(#"<Exercise>
<AccountName>Joe Muscle</AccountName>
<UserID>8008008</UserID>
</Exercise>");
}
Another alternative is to return a Stream - which means that you control the output (see this blog post for more details), and your code would look something like the one below. The advantage of this method is that your HTML doesn't need to be well-formed XML (i.e., you can have things like <br> or <hr> which are valid HTML but not valid XML).
[OperationContract]
[WebGet(UriTemplate = "...")]
public Stream GetLiftDataExchange(string uid, string pwd, string exrcsPrgmId, string exchEnum)
{
var str = #"<html><head><title>This is my page</title></head>
<body><h1>Exercise</h1><ul>
<li><b>AccountName</b>: Joe Muscle</li>
<li><b>UserID</b>: 8008008</li></body></html>";
WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
return new MemoryStream(Encoding.UTF8.GetBytes(str));
}
On a related node, please don't use [WebInvoke(Method="GET")], use [WebGet] instead.
I'm fairly new to web services and especially WCF so bear with me.
I'm writing an API that takes a couple of parameters like username, apikey and some options, but I also need to send it a string which can be a few thousands words, which gets manipulated and passed back as a stream. It didn't make sense to just put it in the query string, so I thought I would just have the message body POSTed to the service.
There doesn't seem to be an easy way to do this...
My operation contract looks like this
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate="Method1?email={email}&apikey={apikey}"+
"&text={text}&quality={qual}", BodyStyle = WebMessageBodyStyle.Bare)]
Stream Method1(string email, string apikey, string text, string qual);
And this works. But it is the 'text' parameter I want to pull out and have in the post body. One thing I read said to have a stream as another parameter, like this:
Stream Method1(string email, string apikey, string qual, Stream text);
which I could then read in. But that throws an error saying that if I want to have a stream parameter, that it has to be the only parameter.
So how can I achieve what I am trying to do here, or is it no big deal to send up a few thousand words in the query string?
https://social.msdn.microsoft.com/Forums/vstudio/en-US/e2d074aa-c3a6-4e78-bd88-0b9d24b561d1/how-to-declare-post-parameters-in-wcf-rest-contract?forum=wcf
Best answer I could find that tackles this issue and worked for me so I could adhere to the RESTful standards correctly
A workaround is to not declare the query parameters within the method signature and just manually extract them from the raw uri.
Dictionary<string, string> queryParameters = WcfUtils.QueryParameters();
queryParameters.TryGetValue("email", out string email);
// (Inside WcfUtils):
public static Dictionary<string, string> QueryParameters()
{
// raw url including the query parameters
string uri = WebOperationContext.Current.IncomingRequest.UriTemplateMatch;
return uri.Split('?')
.Skip(1)
.SelectMany(s => s.Split('&'))
.Select(pv => pv.Split('='))
.Where(pv => pv.Length == 2)
.ToDictionary(pv => pv[0], pv => pv[1].TrimSingleQuotes());
}
// (Inside string extension methods)
public static string TrimSingleQuotes(this string s)
{
return (s != null && s.Length >= 2 && s[0] == '\'' && s[s.Length - 1] == '\'')
? s.Substring(1, s.Length - 2).Replace("''", "'")
: s;
}
Ended up solving simply by using WebServiceHostFactory