Working cefsharp POST example - c#

Having a difficult time getting an HTTP POST request/response using cefsharp / ChromiumWebBrowser. I'm unable to find a working example on Stackoverflow, nor in the documentation. Looking to see if anyone has a full example? I'm stuck on if it can be done with a Navigate function (as show in one example), or needs to be a done with a handler / schema.
I'm trying a basic POST to a PHP script. If the data1/data2 match the input, it's return json status:success, otherwise failure. I see in the devtools that the html body comes back with json success, but this code returns or nothing at all. I've tried too different ways to get the response data. I want to grab the JSON response for the C# code to review. Surely there should be an easy way to accomplish this? I want to send an HTTP request and then get the body (json) to parse. If this needs the schema/handler, I cannot find a full example of using this.
namespace BrowserTest
{
public partial class MainForm : Form
{
ChromiumWebBrowser browser = null;
public Loader()
{
browser = new ChromiumWebBrowser("http://localhost/test/"); // Initialize to this page
pBrowserLogin.Controls.Add(browser);
}
private void btnTest_Click(object sender, EventArgs e)
{
byte[] request = Encoding.ASCII.GetBytes("data1=" + txtData1.Text + "&data2=" + txtData2.Text);
PostTest.Navigate(browser, "http://localhost/test/posttest.php", request, "application/x-www-form-urlencoded");
}
}
public static class PostTest
{
public static void Navigate(this IWebBrowser browser, string url, byte[] postDataBytes, string contentType)
{
IFrame frame = browser.GetMainFrame();
IRequest request = frame.CreateRequest();
request.Url = url;
request.Method = "POST";
request.InitializePostData();
var element = request.PostData.CreatePostDataElement();
element.Bytes = postDataBytes;
request.PostData.AddElement(element);
NameValueCollection headers = new NameValueCollection();
headers.Add("Content-Type", contentType);
request.Headers = headers;
frame.LoadRequest(request);
frame.GetTextAsync().ContinueWith(taskHtml =>
{
var html = taskHtml.Result;
System.Windows.Forms.MessageBox.Show(html);
});
string script = string.Format("document.documentElement.outerHTML;");
frame.EvaluateScriptAsync(script).ContinueWith(x =>
{
var response = x.Result;
if (response.Success && response.Result != null)
{
var fullhtml = response.Result;
System.Windows.Forms.MessageBox.Show(fullhtml.ToString());
}
});
}
}
}

Related

How to pass parameters by POST to an Azure function?

I'm trying to do a simple Azure Function to learn about it. There will be 3 functions:
1 function to insert a row into a table of a database. This table will contain the current date and a string parameters typed by the user and passed by GET.
1 function similar to the previous one, but passing the parameter by POST.
1 function to read the table and show its content.
I've been able to do the first and the third ones. But I can't pass the parameter by POST. I've looked for examples but I couldn't run them with success. The client app is a Windows Forms one.
Could anyone show me an example anout how to pass parameters by POST to the function and how to read them?
Thank's in advance
EDIT:
Here's the code to pass the parameters by GET (this is working fine):
private void button2_Click(object sender, EventArgs e)
{
string cadena = lsql1.Text + "?notas=" + tNotas.Text;
try
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(cadena);
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
if (res.StatusCode == HttpStatusCode.OK)
{
MessageBox.Show("Grabado");
}
else
{
MessageBox.Show(res.StatusDescription);
}
}catch (WebException ex)
{
using (Stream s = ex.Response.GetResponseStream())
{
StreamReader sr = new StreamReader(s);
string text = sr.ReadToEnd();
text = text.Substring(1, text.Length - 2);
sr.Close();
text = text.Replace("\\", "");
text = "{" + text + "}";
Error mensajeError = JsonConvert.DeserializeObject<Error>(text);
MessageBox.Show(mensajeError.ExceptionMessage);
}
}
}
And here's the code to receive it and do the insert (this is working too):
[FunctionName("sql1")]
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
try
{
log.Info("C# HTTP trigger function processed a request.");
var cnnString = "Server=SERVIDOR;Database=base_prueba;User ID =azure;Password=0000;Trusted_Connection=False;Encrypt=False;";
using (SqlConnection connection = new SqlConnection(cnnString))
{
connection.Open();
SqlCommand cmd = connection.CreateCommand();
DateTime fecha = DateTime.Today;
string notas = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "notas", true) == 0)
.Value;
// insert a log to the database
cmd.CommandText = "INSERT INTO Prueba_Azure (fecha, notas) VALUES ('" + fecha.ToString() + "', '" + notas + "')";
cmd.ExecuteNonQuery();
}
// Get request body
dynamic data = await req.Content.ReadAsAsync<object>();
return name == req.CreateResponse(HttpStatusCode.OK, "Done");
}
catch (Exception ex)
{
HttpResponseMessage res = req.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
return res;
}
}
What I'm looking for is to to this by POST
To get the request content from the request body(post request), you could use req.Content.ReadAsAsync method. Here is the code sample.
Sample request body.
{
"name": "Azure"
}
Define a class to deserialize the post data.
public class PostData
{
public string name { get;set; }
}
Get the post data and display it.
PostData data = await req.Content.ReadAsAsync<PostData>();
log.Info("name:" + data.name);
Client side code to send the post request.
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("function-url");
req.Method = "POST";
req.ContentType = "application/json";
Stream stream = req.GetRequestStream();
string json = "{\"name\": \"Azure\" }";
byte[] buffer = Encoding.UTF8.GetBytes(json);
stream.Write(buffer,0, buffer.Length);
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
For passing parameters as POST request, you need to do following things:
Make Json model of the parameters that u need to pass,ex:
{"UserProfile":{ "UserId":"xyz1","FirstName":"Tom","LastName":"Hank" }}
Post your data model using client like POSTMAN
Now you will get the posted content in HttpRequestMessage body, sample code is as follows:
[FunctionName("TestPost")]
public static HttpResponseMessage POST([HttpTrigger(AuthorizationLevel.Function, "put", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
try
{
//create redis connection and database
var RedisConnection = RedisConnectionFactory.GetConnection();
var serializer = new NewtonsoftSerializer();
var cacheClient = new StackExchangeRedisCacheClient(RedisConnection, serializer);
//read json object from request body
var content = req.Content;
string JsonContent = content.ReadAsStringAsync().Result;
var expirytime = DateTime.Now.AddHours(Convert.ToInt16(ConfigurationSettings.AppSettings["ExpiresAt"]));
SessionModel ObjModel = JsonConvert.DeserializeObject<SessionModel>(JsonContent);
bool added = cacheClient.Add("RedisKey", ObjModel, expirytime); //store to cache
return req.CreateResponse(HttpStatusCode.OK, "RedisKey");
}
catch (Exception ex)
{
return req.CreateErrorResponse(HttpStatusCode.InternalServerError, "an error has occured");
}
}
The query string (name/value pairs) is by default sent in the HTTP message body of a POST request and not as query string. The GetQueryNameValuePairs method will parse the query string and will by default not work with POST request.
For the POST request you could use something similar to this:
var content = request.Content;
string contentInString = content.ReadAsStringAsync().Result;
You need to attach data to the body of the post request and process it properly:
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) {
// This reads your post request body into variable "data"
string data = await req.Content.ReadAsStringAsync();
// Here you can process json into an object
dynamic parsed = JsonConvert.DeserializeObject(data);
return exitstring == null
? req.CreateResponse(HttpStatusCode.BadRequest, "Something went wrong, sorry")
: req.CreateResponse(HttpStatusCode.OK);
}
You can find a slightly different example here and the exact example here.

Use C# HttpWebRequest to send json data to web service

I am trying to send http request of json data to a web service. It successfully get directed to the web service but the data is always null...
Here is my web service:
public bool CheckUserExist ([FromBody] string Email)
{
List<User> all_users = repo.getUsers();
var match = all_users.Find(i => i.Email == Email);
if (match == null)
{
return false;
}
else
{
return true;
}
}
and here is my Http Request:
var webAddr = "http://localhost:59305/api/User/CheckUserExist";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(webAddr);
httpWebRequest.ContentType = "application/json; charset=utf-8";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = "{\"Email\":\"Email\"}";
streamWriter.Write(json);
streamWriter.Flush();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
return RedirectToAction("Index");
}
as i mentioned...Iam using a debugger at the web service function...the request get directed to the service but variable "Email" is always null
The quick fix is to change what you are posting. If you want your API endpoint to work with [FromBody] string Email, then you should change your "json":
string json = "\"a#b.c\"";
streamWriter.Write(json);
streamWriter.Flush();
However, you may want to consider a few other changes for the long term on your approach:
Let your repo return IQueryable instead of List or some other IEnumerable. As written, you will always return every user from the database. With Linq, you can leverage the lazy initialization and let your query only get the matching user instead of get EVERY user and then find the match. This will not scale well.
Use new HttpClient and async functionality in your action instead of HttpWebRequest
Instead of manually building your JSON, let .NET do the work and create a class that gets serialized
With the above solutions in place (except for first since you didn't post your data context, didn't want to make too many assumptions), here are some examples to get you started:
Define a shared user search class (shared either in same project or shared DLL)
public class UserSearch
{
public string Email { get; set; }
}
Let Web API map post against the search class
public bool CheckUserExist([FromBody] UserSearch userSearch)
{
IQueryable<User> all_users = repo.getUsers();
var isMatch = all_users.Any(i => i.Email == userSearch.Email);
return isMatch;
}
Change to HttpClient and use async to send API request with new search class
public async Task<ActionResult> Check()
{
using (var client = new HttpClient())
{
var search = new UserSearch() { Email = "a#b.c" };
var response = await client.PostAsJsonAsync("http://localhost:59305/api/User/CheckUserExist", search);
if (response.IsSuccessStatusCode)
{
bool exists = await response.Content.ReadAsAsync<bool>();
// Handle what to do with exists
return RedirectToAction("Index");
}
else
{
// Handle unsuccessful call
throw new Exception("Application error");
}
}
}
You can't use string to accept the post data, please define a struct class or use dynamic to receive the Json string.

How to know if a url is valid for navigating in webbrowser winforms

I'm making a web browser in windows form application based on webbrowser control.
I'm trying to make the url address textbox for 2 purposes : for navigating and for searching , as in chrome for example .
I added this code :
try
{
Uri urlResult = new Uri(urlText.Text);
webbrowser1.Navigate(urlText.Text);
}
catch
{
webbrowser1.Navigate("http://google.com/search?q=" + urlText.Text);
}
the problem is that when I enter "youtube.com" for example , this can not be a Uri so I get this in google
How to perform this ?
any other suggestions are welcomed
thanx in advance
Problem : in your current code you are not checking wether the URL is valid or not.you need to first verify wether the given url is reachable or not.
Solution: create a seperate function to verify the reachbility of the url if it succeeds then Navigate to the url otherwise open it in google.
Try This:
using using System.Net;
private void button3_Click_1(object sender, EventArgs e)
{
string url = string.Empty;
string urlProtocol = "http://"; //or https
if (!urlText.Text.Trim().Contains(urlProtocol))
url = urlProtocol + urlText.Text;
else
url = urlText.Text;
if (CheckURL(url))
{
Uri urlResult = new Uri(url);
webbrowser1.Navigate(url);
}
else
{
webbrowser1.Navigate("http://google.com/search?q=" + urlText.Text);
}
}
bool CheckURL(string url)
{
var req = (HttpWebRequest)HttpWebRequest.Create(url);
bool isURLValid = false;
req.AllowAutoRedirect = false;
try
{
using (var resp = req.GetResponse())
{
var location = resp.Headers["Location"];
if (!String.IsNullOrEmpty(location))
{
isURLValid = true;
}
}
}
catch
{
isURLValid = false;
}
return isURLValid;
}

C# webclient: fail to read ajax html content

I want to create a HttpModule to generate html snapshot for google bot, my code is:
private void Application_BeginRequest(Object source, EventArgs e)
{
// Create HttpApplication and HttpContext objects to access
// request and response properties.
var application = (HttpApplication)source;
HttpContext context = application.Context;
string escapedFragment = HttpContext.Current.Request.Params["_escaped_fragment_"];
if (!string.IsNullOrWhiteSpace(escapedFragment))
{
string result = string.Empty;
using (var client = new WebClient())
{
Stream data = client.OpenRead("http://giadinhthinhvuong.com/#/" + escapedFragment);
if (data != null)
{
var reader = new StreamReader(data);
result = reader.ReadToEnd();
}
}
context.Response.Write(result);
}
}
However it seem not working with ajax content in webpage.
Here you can find my link test.
So my questions are:
Is there other way to generate html snapshot for C#?
Or is there other way to read ajax content in C#?

How to convert a fake ASP.NET WebMethod HTTP proxy into a real proxy?

I'm building a rich web client that uses AJAX to communicate with a RESTful API. To get around cross-domain browser restrictions, I wrote a super-simple (but fake) HTTP proxy in C# and ASP.NET so my client app on http://localhost can talk to http://restful.api.com.
Someone else will write a "proper" proxy in Java so I was tasked initially to "keep it simple". My current version is just a static ASP.NET [WebMethod] that blindly creates a URL and optional QueryString based on values in a string array.
For GET, POST, and PUT operations, I create an instance of the System.Net.WebClient() and either call client.downloadString(...) or client.UploadData(...). The method returns a string, so I lose all the headers and the response codes returned by the RESTful API.
This was fine to get started, but now I need to convert to a full-blown proxy, one that can handle headers, response codes, payloads, and whatever else you get with a real proxy.
Is it possible to retrofit the code snippets below, or do I need to rewrite something from scratch?
Here's the WebMethod:
[WebMethod]
public static string rest(string[] values, string[] queryStringParams, string verb, string jsonData)
{
string r = WebAppUtils.UnifiedMessagingApi(values, queryStringParams, verb, jsonData);
return r;
}
And here's the worker method (showing just GET and POST). Sorry for the length, I tried to trim out as much fluff as possible for this question.)
public static string UnifiedMessagingApi(string[] values, string[] queryStringParams, string verb, string jsonData)
{
var r = String.Empty;
var query = String.Format("{0}{1}", BaseUrl, String.Join("/", values));
if (queryStringParams.Length > 0)
{
var queryString = String.Join("&", queryStringParams);
query = query + "?" + queryString;
}
using (var client = new WebClient())
{
client.Encoding = Encoding.UTF8;
client.Headers.Add("Content-Type","application/json; charset=utf-8");
client.Proxy = null;
switch (verb)
{
case HttpVerb.GET:
try
{
r = client.DownloadString(query);
}
catch (WebException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Status);
}
break;
case HttpVerb.POST:
try
{
var encoding = new System.Text.UTF8Encoding();
Byte[] data = encoding.GetBytes(jsonData);
// Call the REST API
Byte[] retValBytes = client.UploadData(query, verb, data);
// Convert the byte array to a string
r = System.Text.UTF8Encoding.Default.GetString(retValBytes);
}
catch (WebException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Status);
}
break;
}
}
return r;
}
Thanks!

Resources