Awesomium Wpf WebControl read json response from wcf service - c#

What I want to do is simply serve the Json response from a Wcf service to the Wpf WebControl. I have tested the Wcf service as working and I can see the Json response in the REST client.
I have basically tried two approaches (thanks to the generous developers who share their code here):-
Resource Interceptor
How to hide the cursor in Awesomium
Below is how my ResourceInterceptor constructing the ResourceResponse. From the docs ResourceResponse is simply a wrapper around a raw block of data and a specified mime-type. That should mean I should be able to pass in my response along with contentType and awesomium should recognize. But my ajax request all land up in "Error" with no content in the jqXHR :-
private ResourceResponse readWebResponse(HttpWebRequest webreq)
{
HttpWebRequest.DefaultMaximumErrorResponseLength = 1048576;
HttpWebResponse webresp = null;// = webreq.GetResponse() as HttpWebResponse;
var memStream = new MemoryStream();
Stream webStream;
try
{
webresp = (HttpWebResponse)webreq.GetResponse();
webStream = webresp.GetResponseStream();
byte[] readBuffer = new byte[4096];
int bytesRead;
while ((bytesRead = webStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
memStream.Write(readBuffer, 0, bytesRead);
}
catch (WebException e)
{
var r = e.Response as HttpWebResponse;
webStream = r.GetResponseStream();
memStream = Read(webStream);
var wrongLength = memStream.Length;
}
memStream.Position = 0;
StreamReader sr = new StreamReader(memStream);
string webStreamContent = sr.ReadToEnd();
byte[] responseBuffer = Encoding.UTF8.GetBytes(webStreamContent);
// Initialize unmanaged memory to hold the array.
int responseSize = Marshal.SizeOf(responseBuffer[0]) * responseBuffer.Length;
IntPtr pointer = Marshal.AllocHGlobal(responseSize);
try
{
// Copy the array to unmanaged memory.
Marshal.Copy(responseBuffer, 0, pointer, responseBuffer.Length);
return ResourceResponse.Create((uint)responseBuffer.Length, pointer,webresp.ContentType);
}
finally
{
// Data is not owned by the ResourceResponse. A copy is made
// of the supplied buffer. We can safely free the unmanaged memory.
Marshal.FreeHGlobal(pointer);
webStream.Close();
}
}
My Ajax request is simple as below:-
$.ajax({
url:urlBase+'/list'
,success: function(dt){deferred.resolve(dt);alert('hurray')},
error: function(jqXHR, textStatus, errorThrown ){
alert('oyei oyei something went wrong'+JSON.stringify(jqXHR));
var err = eval('(' + xhr.responseText + ')');
alert(err.Message);}
});
What I get is:-
{"readyState":0,"responseText":"",status:0,"statusText":"error"}
I've also tried using the Userscripts approach from here:-
http://answers.awesomium.com/questions/2289/can-i-use-userscripts-or-greasemonkey-scripts-in-a.html
In my Javascript request I simply called above utility like this:-
uScriptHelper.xmlHttpRequest({url:urlBase+'/list', onload=function(){return(this.responseText);}});
I can see the responseText is being set by the Userscripts. But my ajax response is still all the same - error result with all empty parameters. What am I doing wrong here?

Phew, I managed to finally get it work after putting in almost 4 days of trying various stuff. I will add the answer here hopefully it will help someone at some point of time.
First thing is :-
The Resource Interceptor approach doesn't work for Json response for Awesomium WebControl. No-matter what I tried applying all the mime types to ResourceResponse of Awesomium WebControl it didn't take me anywhere. The code above is there for anybody who would want to explore it further. I'm not very sure what header I am missing here. Moreover the good news is:-
The Awesomium JSObject approach as mentioned in above post works. So all we need to do here is create custom JSObject emulating the xmlHttpRequest object as in above post. As long as Javascript is talking to Javascript we are fine. (ResourceResponse seems to be hostile to ajax requests). So here is finally how I managed to get it work.
Here's my Factory - uses Jquery promise and calls the xmlHttpRequest emulation object as we created above:-
todoFactory.getTodos = function () {
var deferred = $.Deferred();
uScriptHelper.xmlHttpRequest({
url: urlBase + '/list', method: 'get',
onload: function (obj) {deferred.resolve(JSON.parse(obj.responseText)); }
});
return(deferred.promise());
};
And here's my Controller calling the above factory :-
var promise= todoFactory.getTodos();
promise.then(function (data) {
setInterval(function () {
$scope.todos = data;
$scope.$apply();
}, 10);
},function (error) {
$scope.status = 'Unable to load todo data: ' + error;
alert('unable to load data '+error);
}, function (update) {
alert('Got notification: ' + update);
});
Hope this helps someone at some point! Happy Coding!

Related

RestSharp "Error getting response stream (ReadAsync): ReceiveFailure Value cannot be null. Parameter name: src"

Hello all am trying to do a login to my xamarin api using RestSharp, the API ought to return status code 200 OK if the authentication works and status code 415 if the authentication fails(wrong password) and other codes depending on what the case scenario, but instead i get a status code 0 on all other case asides when the authentication pass(status code 200 ok), the source code below is how i implement
//payload am sending to the api
RequestPayload res = new RequestPayload();
res.appid = appid;
res.data = data;
res.method = "Login";
//convert to json object
var MySerializedObject = JsonConvert.SerializeObject(res);
string APIUrl = ""http://142.168.20.15:8021/RouteTask";
//create client
RestClient client = new RestClient(APIUrl);
//create request
RestRequest request = new RestRequest(Method.POST);
// set request headeer
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
//request.AddJsonBody(MySerializedObject); --i have also tried this
request.AddParameter("application/json", MySerializedObject, ParameterType.RequestBody);
request.JsonSerializer.ContentType = "application/json; charset=utf-8";
request.AddParameter("RequestSource", "Web", "application/json", ParameterType.QueryString);
client.Timeout = 2000000;
var response = client.Execute(request); // where the issue appears
//RestResponse response = client.Execute(request); // i have tried this
//IRestResponse response = client.Execute(request); // i have tried this
if (response.IsSuccessful)
{
//use response data
}
on all scenerio it comes back with a StatusCode: 0, Content-Type: , Content-Length: 0) and errorMessage
"Error getting response stream (ReadAsync): ReceiveFailure Value
cannot be null. Parameter name: src"
screenshot below indicate when the api call fails
Response receieved when the authentication is valid
I was finally able to find a workaround for this. Bear with the long-winded response.
The tags mention Xamarin, which is what I am working in as well - specifically with iOS. I think it may actually be a bug with Mono, but I didn't take it that far to confirm.
The problem lies with the default way of copying the response buffer. In the RestSharp code, this is done by an extension method in MiscExtensions.cs called ReadAsBytes. It appears that with certain response buffers, the call to the Stream.Read method is failing. When this happens, the exception causes RestSharp to "shortcut" the rest of the processing on the response, hence the status code never gets filled in since it happens after the call to ReadAsBytes.
The good news is RestSharp does give a way to replace this call to ReadAsBytes with one of your own. This is done via the ResponseWriter property on the IRestRequest object. If it has a function defined, it will bypass the ReadAsBytes call and call the function you gave it instead. The problem is, this is defined as an Action and you don't get a copy of the full response object, so it's somewhat useless. Instead you have to use the AdvancedResponseWriter property. This one includes both the response object and the response stream. But you still have to set the ResponseWriter property or it won't bypass the default handler and you'll still get the error.
Ok, so how do you make this work? I ended up implementing it as a wrapper to RestClient so I wouldn't have to implement the code all over the place. Here's the basic setup:
public class MyRestClient : RestClient
{
public MyRestClient(string baseUrl) : base(baseUrl)
{ }
public override IRestResponse Execute(IRestRequest request)
{
request.ResponseWriter = s => { };
request.AdvancedResponseWriter = (input, response) => response.RawBytes = ReadAsBytes(input);
return base.Execute(request);
}
private static byte[] ReadAsBytes(Stream input)
{
var buffer = new byte[16 * 1024];
using (var ms = new MemoryStream())
{
int read;
try
{
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{ ms.Write(buffer, 0, read); }
return ms.ToArray();
}
catch (WebException ex)
{ return Encoding.UTF8.GetBytes(ex.Message); }
};
}
}
The ReadAsBytes method is actually just a copy/paste of the RestSharp ReadAsBytes method with the addition of a try/catch. If it fails, it returns the exception reason in to the response buffer. This may or may not be what you want, so modify as needed. You may also need to override other methods for Execute, but in my case this is the only one we're using so it was enough.
So far this seems to be doing the trick for me. Perhaps if someone got ambitious they could trace it all the way in to Mono to try and see what it doesn't like about the stream, but I don't have the time for it at the moment.
Good luck!
OK so after toying around with RestSharp for a bit, i realize just as #steve_In_Co mentioned earlier there were compatibility issues with MONO (we presume this is a bug) so i did it in a basic way using the .Net HTTP library and it works for me, so in case someone is still looking for a way out, find the working .net http implementation code below.
//payload am sending to the api
RequestPayload res = new RequestPayload();
res.appid = appid;
res.data = data;
res.method = "Login";
//convert to json object
var MySerializedObject = JsonConvert.SerializeObject(res);
string APIUrl = ""http://142.168.20.15:8021/RouteTask";
//create basic .net http client
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(APIUrl);
// this was required in the header of my request,
// you may not need this, or you may need to adjust parameter
//("RequestSource","Web") or you own custom headers
client.DefaultRequestHeaders.Add("RequestSource", "Web");
// this class is custom, you can leave it out
connectionService = new ConnectionService();
//check for internet connection on users device before making the call
if (connectionService.IsConnected)
{
//make the call to the api
HttpResponseMessage response = await
client.PostAsJsonAsync(ApiConstants.APIDefault, res);
if (response.IsSuccessStatusCode)
{
string o = response.Content.ReadAsStringAsync().Result;
dynamic payload = JsonConvert.DeserializeObject(o);
string msg = payload["valMessage"];
resp.a = true;
resp.msg = payload["responseDescription"];
}
else
{
string o = response.Content.ReadAsStringAsync().Result;
dynamic payload = JsonConvert.DeserializeObject(o);
resp.a = false;
resp.msg = payload["response"];
}
}

Webrequest GET Body ViolationException

I'm using SolrExpress to search and index documents within c# (dotnet core). Inserting (indexing) documents works fine since this is a nice post request.
However when i'm trying to do a select query (to retrieve documents) i'm getting aggregation exceptions. By digging down the source in SolrExpress i came upon the following source:
private WebRequest Prepare(SecurityOptions options, string requestMethod, string handler, string data)
{
var baseUrl = $"{this.HostAddress}/{handler}";
var encoding = new UTF8Encoding();
var bytes = encoding.GetBytes(data);
var request = WebRequest.Create(baseUrl);
if (options.AuthenticationType == AuthenticationType.Basic)
{
var encoded = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(options.UserName + ":" + options.Password));
request.Headers[HttpRequestHeader.Authorization] = "Basic " + encoded;
}
request.Method = requestMethod;
request.ContentType = "application/json";
#if NET451
request.ContentLength = bytes.Length;
#endif
#if NETCORE
var taskStream = request.GetRequestStreamAsync();
taskStream.Wait();
var stream = taskStream.Result;
stream.Write(bytes, 0, bytes.Length);
#else
var stream = request.GetRequestStream();
stream.Write(bytes, 0, bytes.Length);
stream.Close();
#endif
return request;
}
The method calling this method is the following for GET:
public string Get(SecurityOptions options, string handler, string data)
{
var request = this.Prepare(options, "GET-X", handler, data);
#if NETCORE
var task = this.ExecuteAsync(request, data);
task.Wait();
return task.Result;
#else
return this.Execute(request, data);
#endif
}
This Get method caused an error by using a request method GET-X which Solr itself (6.4.1) did not understand. I've changed this to a normal request method: GET therefore solving the error on solr's side.
However currently i'm getting a System.Net.ProtocolViolationException with the message: Cannot send a content-body with this verb-type. This is happening when waiting for the taskStream to finish and write its result to the request-body.
My question:
How would one send a GET-request with a body (in json format (as string)) within dotnet core?
Since RFC2616 says it's not forbidden i'd like to use this 'feature' as answered in the following question
See RFC2616 - Hypertext Transfer Protocol -- HTTP/1.1, section 4.3 "Message Body":
A message-body MUST NOT be included in a request if the specification of the > > request method (section 5.1.1) does not allow sending an entity-body in requests.
In section 9.3 "GET" including an entity-body is not forbidden.
So, yes, you are allowed to send an entity-body with a HTTP GET request.

Using POST to communicate between controller methods on two separate servers

I'm using C# 6.0, ASP.NET 4.5 MVC 4.
I'm developing an API that is essentially a wrapper for another API that generates PDFs. A separate server will be implementing it directly, and all other applications will send their data to this server for conversion. The underlying PDF conversion software has specific system requirements so this will free us from the limitation of what machines our applications can run on. It's also somewhat brittle so isolating it is desireable.
To accomplish this I've set up two separate MVC applications, one with the conversion implementation, the other as a simple application that generates data to be converted, which implements the API I'm developing. They're set up to exchange data using POST.
The problem I've run into is that the PDF server isn't receiving the data to be converted. It runs, but its parameter only contains null. I set it up so that it will return a PDF containing the error if this happens. It comes through successfully, containing the resulting error message it generated so that part of it is functioning properly.
Here's the code running on the PDF server:
[HttpPost]
public FileResult MakePdf(string html)
{
byte[] pdf = null;
var converter = new HtmlToPdfConverter();
try
{
pdf = converter.GeneratePdf(html);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
var errorHtml = errorTop + new Regex("\\s").Replace(e.Message, " ") + errorBottom;
pdf = converter.GeneratePdf(errorHtml);
}
return File(pdf, "application/pdf");
}
Here's the code that's sending the HTML there to be converted:
public byte[] Fetch() {
var webRequest = (HttpWebRequest)WebRequest.Create("http://localhost:60272/PdfServer/MakePdf");
webRequest.Method = "POST";
var encoder = new UTF8Encoding();
byte[] data = encoder.GetBytes(Resource); // Resource contains valid HTML output by ASP.NET
webRequest.ContentLength = data.Length;
webRequest.ContentType = "text/html";
using (var stream = webRequest.GetRequestStream())
{
stream.Write(data, 0, data.Length);
stream.Flush();
}
using (var webResponse = webRequest.GetResponse())
{
using (Stream responseStream = webResponse.GetResponseStream())
{
using (var memoryStream = new MemoryStream())
{
int bufferLength = 1024;
data = new byte[bufferLength];
int responseLength = 0;
do
{
responseLength = responseStream.Read(data, 0, bufferLength);
memoryStream.Write(data, 0, responseLength);
} while (responseLength != 0);
data = memoryStream.ToArray();
}
}
}
return data;
}
I haven't tried sending data to an ASP.NET MVC controller method from a separate application before. The code I wrote here is based on examples I've found of how it's done.
Any ideas about what I'm doing wrong?
Try to form encode it: "application/x-www-form-urlencoded" and name the string-data html. So it would look something like:
var s = "html=" + Resource;
And then send s, instead of sending Resource. And of course set the content type to "application/x-www-form-urlencoded". This should help MVC map the data to the html parameter.
That's the only thing I can think of.
On a side note, I think you also should Close() your stream when you're done, rather than flushing it.
===
A final idea would be to try to change your encoding from text/html to text/plain. I know you're thinking it's HTML, but your method is taking in a string. So to MVC it's expecting a string, not HTML, the fact that it's actually HTML is incidental to the MVC deserializer.

Nancy (C#): How do I get my post data?

I'm using Corona SDK to post data to my C# server:
headers["Content-Type"] = "application/x-www-form-urlencoded"
headers["Accept-Language"] = "en-US"
local body = "color=red&size=small"
local params = {}
params.headers = headers
params.body = body
network.request( host .. "/UpdateHand", "POST", nwListener, params )
I receive a message on the server:
Post["/UpdateHand"] = x =>
{
Console.WriteLine("Received ...");
return "Ok";
};
But when I check the data (when I put a breakpoint on it) I don't see where my data is locaded (i.e. the params.body or params.headers). How can I extract this information?
I should POST it correctly according to the documentation on Corona: http://docs.coronalabs.com/daily/api/library/network/request.html
The post data is in
this.Request.Body
If you have suitable type you can deserialize your data to it using model binding:
var x = this.Bind<YourType>();
There is a Nancy extension for this. You will need to include the namespace for it.
using Nancy.Extensions;
var text = Context.Request.Body.AsString();
I like how concise this is, part of Nancy's super-duper easy path.
But a word of caution! This method leaves the stream at the end, so subsequent calls will return empty string. To fix this, always reset the stream immediately afterwards, like so:
Request.Body.Seek(0, SeekOrigin.Begin);
Nancy 2.0 is supposed to correct this so that the stream position is reset by default.
https://github.com/NancyFx/Nancy/pull/2158
This actually works great:
var body = this.Request.Body;
int length = (int) body.Length; // this is a dynamic variable
byte[] data = new byte[length];
body.Read(data, 0, length);
Console.WriteLine(System.Text.Encoding.Default.GetString(data));
For Nancy 2.0.0, Request.Body is a Stream rather than a RequestStream, so doesn't have an AsString method. However, this seems to work:
using (var reqStream = RequestStream.FromStream(Request.Body))
{
var body = reqStream.AsString();
// ... do stuff with body
}
Ideally getting your post data could be accomplished with a simple Bind() call. However, I've seen inconsistent results when using a Bind in a post call such that I've resorted to using the scheme outlined above.
I've seen various discussions about Nancy Bind() working and not working... I've seen both with Post but cannot explain the inconsistency. Where I saw it function properly was where I could guarantee the body of the request was managed as follows:
var data = Encoding.ASCII.GetBytes (postData);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream ()) {
stream.Write (data, 0, data.Length);
}
However, when sending data that should have been similarly handled (though I couldn't confirm) through WSO2 infrastructure (data serialized as a JSON event dictionary sent to a service proxy), Bind failed while the method above succeeded.

Http Post for Windows Phone 8

I am new to C# so I was wondering if someone can help me out on this. I am trying to send HttpPost from Windows Phone 8 to the server. I found two examples that I would like to combine.
The first one is an example of sending Http Post (http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetrequeststream.aspx). The problem with this one is that it is not support by Windows Phone 8.
The second example is using the BeginGetResponse (http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.net.httpwebrequest(v=vs.105).aspx). This supports windows phone 8.
I need to convert the second example into a BeginGetRequestStream() like the first example. I will try to figure out this myself, but I am posting online if someone already knows how to do this. I am sure this will be helpful for other WP8 developers.
Update
I am now trying to get response from the server. I have started a new question. Please follow this link (Http Post Get Response Error for Windows Phone 8)
I am also currently working on a Windows Phone 8 project and here is how I am posting to a server. Windows Phone 8 sort of has limited access to the full .NET capabilities and most guide I read say you need to be using the async versions of all the functions.
// server to POST to
string url = "myserver.com/path/to/my/post";
// HTTP web request
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "text/plain; charset=utf-8";
httpWebRequest.Method = "POST";
// Write the request Asynchronously
using (var stream = await Task.Factory.FromAsync<Stream>(httpWebRequest.BeginGetRequestStream,
httpWebRequest.EndGetRequestStream, null))
{
//create some json string
string json = "{ \"my\" : \"json\" }";
// convert json to byte array
byte[] jsonAsBytes = Encoding.UTF8.GetBytes(json);
// Write the bytes to the stream
await stream.WriteAsync(jsonAsBytes, 0, jsonAsBytes.Length);
}
I propose a more generic asynchronous approach supporting success and error callbacks here:
//Our generic success callback accepts a stream - to read whatever got sent back from server
public delegate void RESTSuccessCallback(Stream stream);
//the generic fail callback accepts a string - possible dynamic /hardcoded error/exception message from client side
public delegate void RESTErrorCallback(String reason);
public void post(Uri uri, Dictionary<String, String> post_params, Dictionary<String, String> extra_headers, RESTSuccessCallback success_callback, RESTErrorCallback error_callback)
{
HttpWebRequest request = WebRequest.CreateHttp(uri);
//we could move the content-type into a function argument too.
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
//this might be helpful for APIs that require setting custom headers...
if (extra_headers != null)
foreach (String header in extra_headers.Keys)
try
{
request.Headers[header] = extra_headers[header];
}
catch (Exception) { }
//we first obtain an input stream to which to write the body of the HTTP POST
request.BeginGetRequestStream((IAsyncResult result) =>
{
HttpWebRequest preq = result.AsyncState as HttpWebRequest;
if (preq != null)
{
Stream postStream = preq.EndGetRequestStream(result);
//allow for dynamic spec of post body
StringBuilder postParamBuilder = new StringBuilder();
if (post_params != null)
foreach (String key in post_params.Keys)
postParamBuilder.Append(String.Format("{0}={1}&", key, post_params[key]));
Byte[] byteArray = Encoding.UTF8.GetBytes(postParamBuilder.ToString());
//guess one could just accept a byte[] [via function argument] for arbitrary data types - images, audio,...
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
//we can then finalize the request...
preq.BeginGetResponse((IAsyncResult final_result) =>
{
HttpWebRequest req = final_result.AsyncState as HttpWebRequest;
if (req != null)
{
try
{
//we call the success callback as long as we get a response stream
WebResponse response = req.EndGetResponse(final_result);
success_callback(response.GetResponseStream());
}
catch (WebException e)
{
//otherwise call the error/failure callback
error_callback(e.Message);
return;
}
}
}, preq);
}
}, request);
}

Categories

Resources