Here is my WebClient class:
class MyWebClient : WebClient
{
private CookieContainer _cookieContainer = new CookieContainer();
public MyWebClient(string url, string login, string password)
{
var data = new NameValueCollection
{
{ "username", login},
{ "password", password}
};
UploadValues(new Uri(url), data);
}
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
if (request is HttpWebRequest)
{
(request as HttpWebRequest).CookieContainer = _cookieContainer;
}
return request;
}
}
And here is sample, how i want to use it:
private MyWebClient _client;
private void btnLogin_Click(object sender, RoutedEventArgs e)
{
_client = new MyWebClient("http://website/login.php", "account", "pw");
}
private async void btnContent_Click(object sender, RoutedEventArgs e)
{
_client = await _client.DownloadStringTaskAsync("http://website");
}
And my question is.. With this MyWebClient class, how can i login async?
I hope someone will be able to help me, thank you!
You can move the login logic outside the constructor and use the UploadValuesTaskAsync method like this:
class MyWebClient : WebClient
{
//...
private readonly string m_Uri;
private readonly string m_Login;
private readonly string m_Password;
public MyWebClient(string url, string login, string password)
{
m_Password = password;
m_Login = login;
m_Uri = url;
}
public async Task LogIn()
{
var data = new NameValueCollection
{
{"username", m_Login},
{"password", m_Password}
};
await UploadValuesTaskAsync(new Uri(m_Uri), data);
}
//...
}
And then use it like this:
private async void btnLogin_Click(object sender, RoutedEventArgs e)
{
_client = new MyWebClient("http://website/login.php", "account", "pw");
await _client.LogIn();
}
Related
I can't use the Twilio SDK in Microsoft Dynamics 365 (Twilio library is not installed in Dynamics and can't include the dll in my plugin registration) so I've had to do a http post using the HttpClient. The call to Twilio happens successfully because Twilio is able to send me an verification email but the breakpoint after PostAsync never gets hit, nor does an exception get caught. I need to capture the output from the PostAsync. What am I doing wrong?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public class TwilioMessageInput
{
public string To { get; set; }
public string Channel { get; set; }
}
public class TwilioMessageOutput
{
public string Message { get; set; }
}
private void button1_Click(object sender, EventArgs e)
{
// https://www.twilio.com/docs/verify
// https://www.twilio.com/docs/verify/email
string url = "https://verify.twilio.com/v2/Services/VA********************************/Verifications/";
string authToken = "AC********************************:********************************"; //-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
string email = "***************#************.com";
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("To", email),
new KeyValuePair<string, string>("Channel", "email")
});
using (var client = new Rest(url))
{
var response = client.PostAsync<TwilioMessageOutput>(url, formContent, authToken).Result;
}
}
}
public class Rest : IDisposable
{
private readonly TimeSpan _timeout;
private HttpClient _httpClient;
private HttpClientHandler _httpClientHandler;
private readonly string _baseUrl;
private const string ClientUserAgent = "twillio-client-v1";
private const string MediaTypeJson = "application/json";
public Rest(string baseUrl, TimeSpan? timeout = null)
{
_baseUrl = NormalizeBaseUrl(baseUrl);
_timeout = timeout ?? TimeSpan.FromSeconds(90);
//_timeout = TimeSpan.FromSeconds(1);
}
private async Task<string> PostAsyncInternal(string url, FormUrlEncodedContent input, string authToken)
{
try
{
EnsureHttpClientCreated();
var byteArray = Encoding.ASCII.GetBytes(authToken);
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
using (var response = await _httpClient.PostAsync(url, input))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
catch (Exception ex)
{
throw ex;
}
}
public async Task<TResult> PostAsync<TResult>(string url, FormUrlEncodedContent input, string authToken) where TResult : class, new()
{
var strResponse = await PostAsyncInternal(url, input, authToken);
return JsonConvert.DeserializeObject<TResult>(strResponse, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
public void Dispose()
{
_httpClientHandler?.Dispose();
_httpClient?.Dispose();
}
private void CreateHttpClient()
{
_httpClientHandler = new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
};
_httpClient = new HttpClient(_httpClientHandler, false)
{
Timeout = _timeout
};
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(ClientUserAgent);
if (!string.IsNullOrWhiteSpace(_baseUrl))
{
_httpClient.BaseAddress = new Uri(_baseUrl);
}
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeJson));
}
private void EnsureHttpClientCreated()
{
if (_httpClient == null)
{
CreateHttpClient();
}
}
private static string ConvertToJsonString(object obj)
{
if (obj == null)
{
return string.Empty;
}
return JsonConvert.SerializeObject(obj, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
private static string NormalizeBaseUrl(string url)
{
return url.EndsWith("/") ? url : url + "/";
}
}
Twilio developer evangelist here.
I'm not a C# or Dynamics developer, so sorry if this doesn't help. When you make the request:
var response = client.PostAsync<TwilioMessageOutput>(url, formContent, authToken).Result;
it is an asynchronous request, but you do not seem to be waiting for the asynchronous response at all. Should that be?
var response = await client.PostAsync<TwilioMessageOutput>(url, formContent, authToken).Result;
I'm new to working with API's so bare with me. I'm trying to load 3 images into picture boxes by using the Bing Image Search API but I'm having trouble with my async method. From my POV everything looks like it should be working just fine. (I used this documentation for my code https://learn.microsoft.com/en-us/bing/search-apis/bing-image-search/quickstarts/sdk/image-search-client-library-csharp). Any advice would be greatly appreciated.
private static string _subscriptionKey = "MY_API_KEY";
private static string _baseUri = "https://api.bing.microsoft.com/v7.0/images/search";
private static string searchString = "car";
private static string _clientIdHeader = null;
private const string QUERY_PARAMETER = "?q="; // Required
private const string MKT_PARAMETER = "&mkt="; // Strongly suggested
private void searchButton_Click(object sender, EventArgs e)
{
RunAsync().Wait();
static async Task RunAsync()
{
try
{
// Remember to encode the q query parameter.
var queryString = QUERY_PARAMETER + Uri.EscapeDataString(searchString);
queryString += MKT_PARAMETER + "en-us";
HttpResponseMessage response = await MakeRequestAsync(queryString);
_clientIdHeader = response.Headers.GetValues("X-MSEdge-ClientID").FirstOrDefault();
// This example uses dictionaries instead of objects to access the response data.
var contentString = await response.Content.ReadAsStringAsync();
Dictionary<string, object> searchResponse = JsonConvert.DeserializeObject<Dictionary<string, object>>(contentString);
if (response.IsSuccessStatusCode)
{
PrintImages(searchResponse);
}
}
catch (Exception)
{
}
async Task<HttpResponseMessage> MakeRequestAsync(string queryString)
{
string count = "3";
string offset = "0";
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", _subscriptionKey);
return await client.GetAsync(string.Format("{0}q={1}&count={1}", _baseUri + queryString, count, offset));
}
void PrintImages(Dictionary<string, object> response)
{
var images = response["value"] as Newtonsoft.Json.Linq.JToken;
foreach (Newtonsoft.Json.Linq.JToken image in images)
{
string imagePic = (image["contentUrl"]).ToString();
optionOnePicture.ImageLocation = imagePic;
optionTwoPicture.ImageLocation = imagePic;
optionThreePicture.ImageLocation = imagePic;
}
}
}
Don't block on async code. Instead, use await:
private async void searchButton_Click(object sender, EventArgs e)
{
await RunAsync();
...
}
Side note: this code is using async void because the method is an event handler. Normally, you would want to avoid async void.
On the local network i have a similar page to this : http://demo.phpmyadmin.net/master (here use: username = "root", pass = blank)
In a Winforms app i need to pass the login/password and get this HTML: http://demo.phpmyadmin.net/master/server_status.php?db=&token=fda5205792a3caf29517c97c59ab1599
I'm looking for 3 days for a solution, but i can not get pass the login part.
This it the best i've got.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var client = new CookieAwareWebClient();
client.BaseAddress = #"http://demo.phpmyadmin.net/master";
var loginData = new NameValueCollection();
loginData.Add("input_username", "root");
//loginData.Add("password", "YourPassword");
client.UploadValues(#"http://demo.phpmyadmin.net/master", "POST", loginData);
string htmlSource = client.DownloadString("http://demo.phpmyadmin.net/master/server_status.php?db=&token=fda5205792a3caf29517c97c59ab1599");
richTextBox1.Text = htmlSource;
}
}
public class CookieAwareWebClient : WebClient
{
private CookieContainer cookie = new CookieContainer();
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
if (request is HttpWebRequest)
{
(request as HttpWebRequest).CookieContainer = cookie;
}
return request;
}
}
I am using WebClient to try and access a web page. I have to login first and the site sets cookies.
I am using code from this question
The cookies are being set correctly, however when I try to access the second page I am just returned to the login page.
private WebClientEx client;
public string GetFile(string URL)
{
Login();
// Download desired page
return client.DownloadString(URL);
}
private void Login()
{
using (client)
{
var values = new NameValueCollection
{
{ "Login", "xxxx" },
{ "Password", "xxxx" },
};
// Authenticate
client.UploadValues("http://www.xxxxxx.com/backoffice/login.php");
}
return;
}
}
/// <summary>
/// A custom WebClient featuring a cookie container
/// </summary>
public class WebClientEx : WebClient
{
public CookieContainer CookieContainer { get; private set; }
public WebClientEx()
{
CookieContainer = new CookieContainer();
}
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
if (request.GetType() == typeof(HttpWebRequest))
((HttpWebRequest)request).CookieContainer = CookieContainer;
return request;
}
}
Is there any way that I can actually use the cookies from a cookie container (taken from a WebRequest previously) and use them in a WebBrowser control? If so, how would I do this? This is for a Winforms application in C#.
You need to make use of InternetSetCookie. Here is a sample...
public partial class WebBrowserControl : Form
{
private String url;
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool InternetSetCookie(string lpszUrlName, string lbszCookieName, string lpszCookieData);
public WebBrowserControl(String path)
{
this.url = path;
InitializeComponent();
// set cookie
InternetSetCookie(url, "JSESSIONID", Globals.ThisDocument.sessionID);
// navigate
webBrowser.Navigate(url);
}
}
Here's an example oh how this could be achieved:
private class CookieAwareWebClient : WebClient
{
public CookieAwareWebClient()
{
CookieContainer = new CookieContainer();
}
public CookieContainer CookieContainer { get; private set; }
protected override WebRequest GetWebRequest(Uri address)
{
var request = base.GetWebRequest(address);
var httpRequest = request as HttpWebRequest;
if (httpRequest != null)
{
httpRequest.CookieContainer = CookieContainer;
}
return request;
}
}
private void Form1_Load(object sender, EventArgs e)
{
using (var client = new CookieAwareWebClient())
{
client.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials;
client.DownloadData("http://www.google.com");
var cookies = client.CookieContainer.GetCookies(new Uri("http://www.google.com"));
var prefCookie = cookies["PREF"];
webBrowser1.Navigate("http://www.google.com", "", null, "Cookie: " + prefCookie.Value + Environment.NewLine);
}
}
Try to first use "client" CookedWebClient for the first navitation and get all the cookies from server. Then you can take the CookedContainer from CookedWebClient, or some other source like WebRequest, and use them in WebBrowser as shown below:
namespace ExampleWebBrowser
{
public partial class Form1 : Form
{
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool InternetSetCookie(string lpszUrlName, string lbszCookieName, string lpszCookieData);
CookedWebClient client = new CookedWebClient();
..
..
..
private void usingWebBrowserWithWebClientCookies(string url)
{
CookieCollection cookies = client.Cookies.GetCookies(url);
for (int i = 0; i < cookies.Count; i++)
{
Cookie c = cookies[i];
InternetSetCookie(url, c.Name, c.Value);
}
webBrowser1.Navigate(url);
}
}
public class CookedWebClient : WebClient
{
CookieContainer cookies = new CookieContainer();
public CookieContainer Cookies { get { return cookies; } }
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
if (request.GetType() == typeof(HttpWebRequest))
((HttpWebRequest)request).CookieContainer = cookies;
return request;
}
}
}