If I wish to submit a http get request using System.Net.HttpClient there seems to be no api to add parameters, is this correct?
Is there any simple api available to build the query string that doesn't involve building a name value collection and url encoding those and then finally concatenating them?
I was hoping to use something like RestSharp's api (i.e AddParameter(..))
If I wish to submit a http get request using System.Net.HttpClient
there seems to be no api to add parameters, is this correct?
Yes.
Is there any simple api available to build the query string that
doesn't involve building a name value collection and url encoding
those and then finally concatenating them?
Sure:
var query = HttpUtility.ParseQueryString(string.Empty);
query["foo"] = "bar<>&-baz";
query["bar"] = "bazinga";
string queryString = query.ToString();
will give you the expected result:
foo=bar%3c%3e%26-baz&bar=bazinga
You might also find the UriBuilder class useful:
var builder = new UriBuilder("http://example.com");
builder.Port = -1;
var query = HttpUtility.ParseQueryString(builder.Query);
query["foo"] = "bar<>&-baz";
query["bar"] = "bazinga";
builder.Query = query.ToString();
string url = builder.ToString();
will give you the expected result:
http://example.com/?foo=bar%3c%3e%26-baz&bar=bazinga
that you could more than safely feed to your HttpClient.GetAsync method.
For those who do not want to include System.Web in projects that don't already use it, you can use FormUrlEncodedContent from System.Net.Http and do something like the following:
keyvaluepair version
string query;
using(var content = new FormUrlEncodedContent(new KeyValuePair<string, string>[]{
new KeyValuePair<string, string>("ham", "Glazed?"),
new KeyValuePair<string, string>("x-men", "Wolverine + Logan"),
new KeyValuePair<string, string>("Time", DateTime.UtcNow.ToString()),
})) {
query = content.ReadAsStringAsync().Result;
}
dictionary version
string query;
using(var content = new FormUrlEncodedContent(new Dictionary<string, string>()
{
{ "ham", "Glaced?"},
{ "x-men", "Wolverine + Logan"},
{ "Time", DateTime.UtcNow.ToString() },
})) {
query = content.ReadAsStringAsync().Result;
}
In a ASP.NET Core project you can use the QueryHelpers class, available in the Microsoft.AspNetCore.WebUtilities namespace for ASP.NET Core, or the .NET Standard 2.0 NuGet package for other consumers:
// using Microsoft.AspNetCore.WebUtilities;
var query = new Dictionary<string, string>
{
["foo"] = "bar",
["foo2"] = "bar2",
// ...
};
var response = await client.GetAsync(QueryHelpers.AddQueryString("/api/", query));
TL;DR: do not use accepted version as It's completely broken in relation to handling unicode characters, and never use internal API
I've actually found weird double encoding issue with the accepted solution:
So, If you're dealing with characters which need to be encoded, accepted solution leads to double encoding:
query parameters are auto encoded by using NameValueCollection indexer (and this uses UrlEncodeUnicode, not regular expected UrlEncode(!))
Then, when you call uriBuilder.Uri it creates new Uri using constructor which does encoding one more time (normal url encoding)
That cannot be avoided by doing uriBuilder.ToString() (even though this returns correct Uri which IMO is at least inconsistency, maybe a bug, but that's another question) and then using HttpClient method accepting string - client still creates Uri out of your passed string like this: new Uri(uri, UriKind.RelativeOrAbsolute)
Small, but full repro:
var builder = new UriBuilder
{
Scheme = Uri.UriSchemeHttps,
Port = -1,
Host = "127.0.0.1",
Path = "app"
};
NameValueCollection query = HttpUtility.ParseQueryString(builder.Query);
query["cyrillic"] = "кирилиця";
builder.Query = query.ToString();
Console.WriteLine(builder.Query); //query with cyrillic stuff UrlEncodedUnicode, and that's not what you want
var uri = builder.Uri; // creates new Uri using constructor which does encode and messes cyrillic parameter even more
Console.WriteLine(uri);
// this is still wrong:
var stringUri = builder.ToString(); // returns more 'correct' (still `UrlEncodedUnicode`, but at least once, not twice)
new HttpClient().GetStringAsync(stringUri); // this creates Uri object out of 'stringUri' so we still end up sending double encoded cyrillic text to server. Ouch!
Output:
?cyrillic=%u043a%u0438%u0440%u0438%u043b%u0438%u0446%u044f
https://127.0.0.1/app?cyrillic=%25u043a%25u0438%25u0440%25u0438%25u043b%25u0438%25u0446%25u044f
As you may see, no matter if you do uribuilder.ToString() + httpClient.GetStringAsync(string) or uriBuilder.Uri + httpClient.GetStringAsync(Uri) you end up sending double encoded parameter
Fixed example could be:
var uri = new Uri(builder.ToString(), dontEscape: true);
new HttpClient().GetStringAsync(uri);
But this uses obsolete Uri constructor
P.S on my latest .NET on Windows Server, Uri constructor with bool doc comment says "obsolete, dontEscape is always false", but actually works as expected (skips escaping)
So It looks like another bug...
And even this is plain wrong - it send UrlEncodedUnicode to server, not just UrlEncoded what server expects
Update: one more thing is, NameValueCollection actually does UrlEncodeUnicode, which is not supposed to be used anymore and is incompatible with regular url.encode/decode (see NameValueCollection to URL Query?).
So the bottom line is: never use this hack with NameValueCollection query = HttpUtility.ParseQueryString(builder.Query); as it will mess your unicode query parameters. Just build query manually and assign it to UriBuilder.Query which will do necessary encoding and then get Uri using UriBuilder.Uri.
Prime example of hurting yourself by using code which is not supposed to be used like this
You might want to check out Flurl [disclosure: I'm the author], a fluent URL builder with optional companion lib that extends it into a full-blown REST client.
var result = await "https://api.com"
// basic URL building:
.AppendPathSegment("endpoint")
.SetQueryParams(new {
api_key = ConfigurationManager.AppSettings["SomeApiKey"],
max_results = 20,
q = "Don't worry, I'll get encoded!"
})
.SetQueryParams(myDictionary)
.SetQueryParam("q", "overwrite q!")
// extensions provided by Flurl.Http:
.WithOAuthBearerToken("token")
.GetJsonAsync<TResult>();
Check out the docs for more details. The full package is available on NuGet:
PM> Install-Package Flurl.Http
or just the stand-alone URL builder:
PM> Install-Package Flurl
Along the same lines as Rostov's post, if you do not want to include a reference to System.Web in your project, you can use FormDataCollection from System.Net.Http.Formatting and do something like the following:
Using System.Net.Http.Formatting.FormDataCollection
var parameters = new Dictionary<string, string>()
{
{ "ham", "Glaced?" },
{ "x-men", "Wolverine + Logan" },
{ "Time", DateTime.UtcNow.ToString() },
};
var query = new FormDataCollection(parameters).ReadAsNameValueCollection().ToString();
Since I have to reuse this few time, I came up with this class that simply help to abstract how the query string is composed.
public class UriBuilderExt
{
private NameValueCollection collection;
private UriBuilder builder;
public UriBuilderExt(string uri)
{
builder = new UriBuilder(uri);
collection = System.Web.HttpUtility.ParseQueryString(string.Empty);
}
public void AddParameter(string key, string value) {
collection.Add(key, value);
}
public Uri Uri{
get
{
builder.Query = collection.ToString();
return builder.Uri;
}
}
}
The use will be simplify to something like this:
var builder = new UriBuilderExt("http://example.com/");
builder.AddParameter("foo", "bar<>&-baz");
builder.AddParameter("bar", "second");
var uri = builder.Uri;
that will return the uri:
http://example.com/?foo=bar%3c%3e%26-baz&bar=second
Good part of accepted answer, modified to use UriBuilder.Uri.ParseQueryString() instead of HttpUtility.ParseQueryString():
var builder = new UriBuilder("http://example.com");
var query = builder.Uri.ParseQueryString();
query["foo"] = "bar<>&-baz";
query["bar"] = "bazinga";
builder.Query = query.ToString();
string url = builder.ToString();
Darin offered an interesting and clever solution, and here is something that may be another option:
public class ParameterCollection
{
private Dictionary<string, string> _parms = new Dictionary<string, string>();
public void Add(string key, string val)
{
if (_parms.ContainsKey(key))
{
throw new InvalidOperationException(string.Format("The key {0} already exists.", key));
}
_parms.Add(key, val);
}
public override string ToString()
{
var server = HttpContext.Current.Server;
var sb = new StringBuilder();
foreach (var kvp in _parms)
{
if (sb.Length > 0) { sb.Append("&"); }
sb.AppendFormat("{0}={1}",
server.UrlEncode(kvp.Key),
server.UrlEncode(kvp.Value));
}
return sb.ToString();
}
}
and so when using it, you might do this:
var parms = new ParameterCollection();
parms.Add("key", "value");
var url = ...
url += "?" + parms;
The RFC 6570 URI Template library I'm developing is capable of performing this operation. All encoding is handled for you in accordance with that RFC. At the time of this writing, a beta release is available and the only reason it's not considered a stable 1.0 release is the documentation doesn't fully meet my expectations (see issues #17, #18, #32, #43).
You could either build a query string alone:
UriTemplate template = new UriTemplate("{?params*}");
var parameters = new Dictionary<string, string>
{
{ "param1", "value1" },
{ "param2", "value2" },
};
Uri relativeUri = template.BindByName(parameters);
Or you could build a complete URI:
UriTemplate template = new UriTemplate("path/to/item{?params*}");
var parameters = new Dictionary<string, string>
{
{ "param1", "value1" },
{ "param2", "value2" },
};
Uri baseAddress = new Uri("http://www.example.com");
Uri relativeUri = template.BindByName(baseAddress, parameters);
Or simply using my Uri extension
Code
public static Uri AttachParameters(this Uri uri, NameValueCollection parameters)
{
var stringBuilder = new StringBuilder();
string str = "?";
for (int index = 0; index < parameters.Count; ++index)
{
stringBuilder.Append(str + parameters.AllKeys[index] + "=" + parameters[index]);
str = "&";
}
return new Uri(uri + stringBuilder.ToString());
}
Usage
Uri uri = new Uri("http://www.example.com/index.php").AttachParameters(new NameValueCollection
{
{"Bill", "Gates"},
{"Steve", "Jobs"}
});
Result
http://www.example.com/index.php?Bill=Gates&Steve=Jobs
To avoid double encoding issue described in taras.roshko's answer and to keep possibility to easily work with query parameters, you can use uriBuilder.Uri.ParseQueryString() instead of HttpUtility.ParseQueryString().
Thanks to "Darin Dimitrov", This is the extension methods.
public static partial class Ext
{
public static Uri GetUriWithparameters(this Uri uri,Dictionary<string,string> queryParams = null,int port = -1)
{
var builder = new UriBuilder(uri);
builder.Port = port;
if(null != queryParams && 0 < queryParams.Count)
{
var query = HttpUtility.ParseQueryString(builder.Query);
foreach(var item in queryParams)
{
query[item.Key] = item.Value;
}
builder.Query = query.ToString();
}
return builder.Uri;
}
public static string GetUriWithparameters(string uri,Dictionary<string,string> queryParams = null,int port = -1)
{
var builder = new UriBuilder(uri);
builder.Port = port;
if(null != queryParams && 0 < queryParams.Count)
{
var query = HttpUtility.ParseQueryString(builder.Query);
foreach(var item in queryParams)
{
query[item.Key] = item.Value;
}
builder.Query = query.ToString();
}
return builder.Uri.ToString();
}
}
HttpClient client = new HttpClient();
var uri = Environment.GetEnvironmentVariable("URL of Api");
var requesturi = QueryHelpers.AddQueryString(uri, "parameter_name",parameter_value);
client.BaseAddress = new Uri(requesturi);
And then you can add request headers also eg:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("x-api-key", secretValue);
response syntax eg:
HttpResponseMessage response = client.GetAsync(requesturi).Result;
Hope it will work for you.
My answer doesn't globally differ from the accepted/other answers. I just tried to create an extension method for the Uri type, which takes variable number of parameters.
public static class UriExtensions
{
public static Uri AddParameter(this Uri url, params (string Name, string Value)[] #params)
{
if (!#params.Any())
{
return url;
}
UriBuilder uriBuilder = new(url);
NameValueCollection query = HttpUtility.ParseQueryString(uriBuilder.Query);
foreach (var param in #params)
{
query[param.Name] = param.Value.Trim();
}
uriBuilder.Query = query.ToString();
return uriBuilder.Uri;
}
}
Usage example:
var uri = new Uri("http://someuri.com")
.AddParameter(
("p1.name", "p1.value"),
("p2.name", "p2.value"),
("p3.name", "p3.value"));
I couldn't find a better solution than creating a extension method to convert a Dictionary to QueryStringFormat. The solution proposed by Waleed A.K. is good as well.
Follow my solution:
Create the extension method:
public static class DictionaryExt
{
public static string ToQueryString<TKey, TValue>(this Dictionary<TKey, TValue> dictionary)
{
return ToQueryString<TKey, TValue>(dictionary, "?");
}
public static string ToQueryString<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, string startupDelimiter)
{
string result = string.Empty;
foreach (var item in dictionary)
{
if (string.IsNullOrEmpty(result))
result += startupDelimiter; // "?";
else
result += "&";
result += string.Format("{0}={1}", item.Key, item.Value);
}
return result;
}
}
And them:
var param = new Dictionary<string, string>
{
{ "param1", "value1" },
{ "param2", "value2" },
};
param.ToQueryString(); //By default will add (?) question mark at begining
//"?param1=value1¶m2=value2"
param.ToQueryString("&"); //Will add (&)
//"¶m1=value1¶m2=value2"
param.ToQueryString(""); //Won't add anything
//"param1=value1¶m2=value2"
I need to get the results of google searches in order to loop through and parse them. With that aim in view, I followed (as best I could) the tutorial on how to do that here
This is my code, based on the sample/example code in the article referenced above:
private void btnRentFlick_Click(object sender, EventArgs e)
{
OpenBestPageForSearchString("rent amazon movie Will Penny");
}
private void OpenBestPageForSearchString(string searchStr)
{
try
{
const string apiKey = "blaBlaBla"; // "blaBlaBla" stands for my API key
const string searchEngineId = "bla"; // "bla" stands for various things I tried: my client_id
(also called UniqueId), private_key_id (also called KeyId), and project_id. Not having
the correct value may be the problem. If so, how do I get it?
const string query = "rent amazon movie Will Penny";
var customSearchService = new CustomsearchService(new BaseClientService.Initializer { ApiKey
= apiKey });
//CseResource.ListRequest listRequest = customSearchService.Cse.List(query); // This is the
code in the article, but it won't compile - "no overload for "List" takes one argument"
// So how is the value in "query" assigned, then?
CseResource.ListRequest listRequest = customSearchService.Cse.List();
listRequest.Cx = searchEngineId;
List<string> linksReturned = new List<string>();
IList<Result> paging = new List<Result>();
var count = 0; // I don't know what the purpose of the counting is, but I'll leave as-is
until I get it working at least
while (paging != null)
{
listRequest.Start = count * 10 + 1;
paging = listRequest.Execute().Items; // this takes several seconds, then it throws an
exception
if (paging != null)
{
foreach (var item in paging)
{
linksReturned.Add("Title : " + item.Title + Environment.NewLine + "Link : " +
item.Link +
Environment.NewLine + Environment.NewLine);
}
}
count++;
}
MessageBox.Show("Done with google amazon query");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
As the comment at the end of that line says, this line of code:
paging = listRequest.Execute().Items;
...works for several seconds, then throws an exception, namely this:
So what is causing this exception? Is it because the searchEngineId value I assigned is bad? Or is it because the search string (assigned to the query variable) has not been provided to the call?
The info about my Ids is contained in a .json file provided by google, and there is no "searchEngineId" value in it. This is what it does contain:
"type": "service_account", "project_id": "flix4famsasinlocator",
"private_key_id": "[my private key id]", "private_key": "-----BEGIN
PRIVATE KEY-----. . . PRIVATE KEY-----\n", "client_email":
"[bla].gserviceaccount.com", "client_id": "[my client Id]",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url":
"https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url":
"https://www.googleapis.com/robot/v1/metadata/x509/[bla]gserviceaccount.com"
So though the article previously mentioned purported to be, and at first appeared to be, just what the doctor ordered, I have ran into a wall of considerable dimensions. Does anybody know how to scale this wall - perhaps primarily by providing the search string to the CseResource.ListRequest object?
UPDATE
Trying DalmTo's code first, I used this (not showing his GetService() method, which I copied verbatim):
var query = "rent amazon movie Will Penny";
var service = GetService("theRainInSpainFallsMainlyOnTheDirt");
var request = service.Cse.List();
// add option values to the request here.
request.ExactTerms = query;
request.Q = query;
var response = request.ExecuteAsync();
// my contribution:
List<string> linksReturned = new List<string>();
foreach (var item in response.Result.Items)
{
//Console.WriteLine(item.Title);
// next two lines also mine
MessageBox.Show(string.Format("Title: {0}; Link: {1}; ETag: {2}", item.Title, item.Link, item.ETag));
linksReturned.Add(item.Link);
}
...but this exception was thrown while in the foreach loop:
UPDATE 2
Yes, this works (adapted from Trekco's answer):
const string apiKey = "gr8GooglyMoogly";
const string searchEngineId = "theRainInSpainFallsMainOnTheDirt";
const string query = "rent amazon movie Will Penny";
var customSearchService = new CustomsearchService(new BaseClientService.Initializer { ApiKey = apiKey });
CseResource.ListRequest listRequest = customSearchService.Cse.List();
listRequest.Cx = searchEngineId;
listRequest.Q = query;
List<string> linksReturned = new List<string>();
IList<Result> paging = new List<Result>();
var count = 0;
while (paging != null)
{
listRequest.Start = count * 10 + 1;
paging = listRequest.Execute().Items;
if (paging != null)
{
foreach (var item in paging)
{
linksReturned.Add(item.Link);
}
}
count++;
}
The query is not being send to google. To fix your code you need to tell the api what query to use. After listRequest.Cx = searchEngineId; add listRequest.Q = query;
var count = 0;
string apiKey = "THE API KEY";
string searchEngineId = "THE SEARCH ENGIN ID";
string query = "rent amazon movie Will Penny";
var customSearchService = new CustomsearchService(new BaseClientService.Initializer
{
ApiKey = apiKey
});
CseResource.ListRequest listRequest = customSearchService.Cse.List();
listRequest.Cx = searchEngineId;
listRequest.Q = query; // <---- Add this line
List<string> linksReturned = new List<string>();
while (count < 10) // Google limit you to 100 records
{
listRequest.Start = count * 10;
var paging = listRequest.Execute().Items;
foreach (var item in paging)
{
linksReturned.Add("Title : " + item.Title + Environment.NewLine + "Link : " +
item.Link +
Environment.NewLine + Environment.NewLine);
}
count++;
}
In your code you have a comment that you don't know what var count = 0; is for. It is to keep track on how many items you have requested.
If you look at google's documentation you will see that they will only return 100 results max. After that they will give you a error. That error will also be the same generic message: "INVALID_ARGUMENT"
You can review the custom search api requirements here: https://developers.google.com/custom-search/v1/reference/rest/v1/cse/list
The searchEngineId variable is the search Engine id that you generate on the site https://www.google.com/cse/all. The documentation you followed is a bit out of date. you will find the id here:
If you check the doucmntation cse.list I think you will find that the list method has no required fields which means that you need to add the option values in the following manner.
I think ExactTerms may be the one you are looking for. But it could also be Q i think you should read though the option values and decide which one is best for your purpose.
var query = "rent amazon movie Will Penny";
var service = GetService("MYKEY");
var request = service.Cse.List();
// add option values to the request here.
request.ExactTerms = query;
request.Q = query;
var response = request.ExecuteAsync();
foreach (var item in response.Result.Items)
{
Console.WriteLine(item.Title);
}
My get service method
public static CustomsearchService GetService(string apiKey)
{
try
{
if (string.IsNullOrEmpty(apiKey))
throw new ArgumentNullException("api Key");
return new CustomsearchService(new BaseClientService.Initializer()
{
ApiKey = apiKey,
ApplicationName = string.Format("{0} API key example", System.Diagnostics.Process.GetCurrentProcess().ProcessName),
});
}
catch (Exception ex)
{
throw new Exception("Failed to create new Customsearch Service", ex);
}
}
My variable langURL currently returns a non-friendly url like so: http://localhost:57299/link/457fee1669e348febf67ecb57b281945.aspx?epslanguage=de-AT
Is it possible to get a friendly url?
public static IHtmlString HrefLangLinks(this PageData currentPage)
{
var availablePageLanguages = currentPage.ExistingLanguages.Select(culture => culture.Name).ToArray();
var Output = "";
var langURL = "";
foreach (string listitem in availablePageLanguages)
{
langURL = EPiServer.Web.UriUtil.AddLanguageSelection(currentPage.LinkURL, listitem);
Output += "<link href=\"" + langURL + "\" hreflang=\"" + listitem + "\" rel=\"alternate\" >";
}
// Dictionary<String, String>
return new HtmlString(Output.ToString());
}
For each page I would like to get the friendly urls with the language flag as well, for example:
/
/de-DE
/en-DE
Luckily we don't need to deal with the LinkURL property anymore. Instead, I would use the UrlResolver for this.
Your code could be quickly rewritten to something like this:
public static IHtmlString HrefLangLinks(this PageData currentPage)
{
// StringBuilder usually performs better than concatenating a variable number of strings.
var sb = new StringBuilder;
foreach (string language in currentPage.ExistingLanguages.Select(culture => culture.Name))
{
// Get the URL to the page in the individual languages, respecting the
// website language settings (sometimes a language is bound to another hostname)
string url = UrlResolver.Current.GetUrl(currentPage.ContentLink, language);
sb.AppendLine($"<link href=\"{url}\" hreflang=\"{language}\" rel=\"alternate\"/>");
}
return new MvcHtmlString(sb.ToString());
}
But I usually implement something like this as a Razor helper.
Yes this is possible.
Try this:
public string GetExternalUrl(string linkUrl)
{
var result = string.Empty;
try
{
var url = new UrlBuilder(linkUrl);
Global.UrlRewriteProvider.ConvertToExternal(url, linkUrl, Encoding.UTF8);
result = url.ToString();
}
catch (Exception)
{
}
return result;
}
I am trying to pass List as a parameter to web Api , Using below code;
Client Side
public async Task<ActionResult>BatchUpdatePartial(MVCxGridViewBatchUpdateValues<NewWorkItem, int> batchValues)
{
var updatedItems = new List<NewWorkItem>();
string url = "http://localhost:9198/api/values";
foreach (var item in batchValues.Update)
{
if (batchValues.IsValid((item)))
{
var updatedVals = new NewWorkItem();
updatedVals.CPK_ID = item.CPK_ID;
updatedVals.BYR_ID = item.BYR_ID;
updatedVals.P_ID = item.P_ID;
updatedVals.CPK_PRI_FLG = item.CPK_PRI_FLG;
updatedItems.Add(updatedVals);
}
else
batchValues.SetErrorText(item, "Correct Vallidation Errors");
}
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/json";
client.Encoding = System.Text.Encoding.UTF8;
string serialisedData = JsonConvert.SerializeObject(updatedItems);
string response = client.UploadString(url, serialisedData);
Object result = JsonConvert.DeserializeObject(response);
}
return PartialView("_GridViewPartial", NewWorkItem.GridData);
}
Server Side
public string Post([FromBody]string[] values)
{
string seperator = ",";
string data = string.Join(seperator, values.ToList<string>());
string result = string.Format("Succesfully uploaded: {0}", data);
return result;
}
But I am always getting NULL inside the values at server side ?
Can you please suggest me solution ?
Thanks
Unfortunately, you are not actually sending a string[] the way your POST method expects. You are sending serializedData, which is, by your own definition, a serialization of updatedItems. updatedItems is a list of a reference type - you do not provide the definition of it here, but I guarantee you it is not going to serialize the same way a string does.
You will need to change updatedItems to be List<string> or something similar.
I am trying validate Google Account using WebClient.
class PostDataBuilder
{
private static Dictionary<string, string>
ToPropertyDictionary(object data)
{
var values = data
.GetType()
.GetProperties()
.Select(x => new {
Key = x.Name,
Value = x.GetValue(data, null)
});
var result = new Dictionary<string, string>();
foreach (var item in values)
result.Add(item.Key, item.Value.ToString());
return result;
}
public static string Build(object data)
{
string result = "";
var dict = ToPropertyDictionary(data);
foreach (var name in dict.Keys)
result += name + "=" + HttpUtility.UrlEncode(dict[name]) + "&";
return result.Substring(0, result.Length - 1);
}
}
class Program
{
static void Main(string[] args)
{
string postText = PostDataBuilder.Build(
new
{
dsh = "-1903339439726094408",
GALX = "-Ggrv6gqusk",
timeStmp = "",
secTok = "",
Email = "WrongEmail#gmail.com",
Passwd = "WrongPassword",
signIn = "?????",
rmShown = "1"
});
byte[] data = Encoding.UTF8.GetBytes(postText);
WebClient wc = new WebClient();
byte[] result = wc.UploadData(
new Uri("https://accounts.google.com/ServiceLoginAuth"),
"POST", data);
string resultText = Encoding.UTF8.GetString(result);
}
}
ResultText variable has setted , even if data is correct. What's wrong?
You shouldn't ever screw around with login services such as the Google one or try to fake a browser. In the end it could be considered attempt hacking or whatever and it's very likely to break the next time they update their page (or even just because your IP changes).
Instead use OpenID or OAuth as described here.