WCF REST Svc GET Returning HTML - wcf

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.

Related

How to change the ResponseFormat from XML to JSON depending on request headers

I have a REST Service written in vb.net and be default the Response comes back as XML unless I set the ResponseFormat:=WebMessageFormat.Json. So I was hoping that I could change the ResponseFormat depending on what headers the user passed in. So I'd code my <WebGet> like this:
<WebGet(UriTemplate:="UserNames/", BodyStyle:=WebMessageBodyStyle.WrappedResponse)>
Public Function UserNamesList() As List(Of UserNames)
'check the Headers for either XML or Json and then set the ResponseFormat
Return intUserNamesList()
End Function
So is there a way to set the ResponseFormat or equivalent outside of the <WebGet> declaration?
Think I've cracked this. I can use WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Xml or WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json inside my function

Ignore content type for specific WCF OperationContracts

I have a WCF REST Service that primarily sends and receives JSON.
In general, I'm okay with using the DataContractJsonSerializer, but for some objects that are passed in as parameters to the OperationContact methods, I need to use JSON.NET for the deserialization.
To do this, the standard approach is to have a Stream as an input parameter.
[OperationContract]
[WebInvoke(UriTemplate = "DoStuff", Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare)]
public void SetAppSettings(Stream input)
{
// parse input as JSON string, deserialize, process
}
However, when I try to POST content with Content-Type: application/json to this method, I get an exception saying that Raw content was expected.
From the point of view of the client, I am always sending application/json content. I don't want the client to have be aware that it should be setting Content-Type: text/plain instead of application/json (which is used in every other case).
Is there a way to get WCF to ignore the request content type for specific OperationContracts (rather than switching to a raw model for the entire service)?
Alternatively, is there some way I could omit the Stream parameter, and instead get the raw bytes of the request body from, say, HttpContext.Current while inside the method?
Have you tried explicitly setting the request format at the operation contract level?
[OperationContract]
[WebInvoke(UriTemplate = "DoStuff", Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare
**RequestFormat = WebMessageFormat.Json**)]
public void SetAppSettings(Stream input)
{
// parse input as JSON string, deserialize, process
}

WCF WebInvoke with query string parameters AND a post body

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

WCF Service JSON Data

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".

How can I return bare result back to WCF client [duplicate]

This question already has answers here:
WCF ResponseFormat For WebGet
(4 answers)
Closed 8 years ago.
I have code something like the following:
<OperationContract()>
<Description("")>
<WebGet(Bodystyle:=WebMessageBodyStyle.Bare, UriTemplate:="TestConnection")>
Function TestConnection() As String
Public Function TestConnection() As String Implements ITestSvc.TestConnection
WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain"
Return "Connection Success"
End Function
But it returns is <string xmlns='...'>Connection Success</string>
How can I have only "Connection Success" to be returned without XML wrapper. I know that we can do something with MessageEncoder. But, I want to have it available at operation level (certain operations need XML/JSON wrappers and certain operations don't).
Can anyone help me on this?
here is the simplest solution to return plain text. Set response format to xml and set outgoingresponse to text/html. Should do the trick.
[WebGet(ResponseFormat = WebMessageFormat.Xml)]
public string DoWork()
{
WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
return "THIS IS PLAIN TEXT";
}
There is one way how to achieve this if you're dealing with HTTP, it's not exactly nice, but I thought I could mention it.
You can set the return type of your method to void and just output your raw string directly into the response.
[OperationContract]
[WebGet(UriTemplate = "foo")]
void Foo()
{
HttpContext.Current.Response.Write("bar");
}
The answer is here WCF ResponseFormat For WebGet (and it worked for me)