Webclient doesnt like UrlEncoded slash. How to make it work? - c#

I'm trying to pass an URL to an API using a .net 2.0 webclient (unable to upgrade). The webclient call only works if there are no slashes in the encoded value. Any idea why it is failing and how to make it work?
using System.Net;
using System.Text;
using System.Web;
namespace ConsoleAppWebClient
{
class Program
{
static void Main(string[] args)
{
using (var client = new WebClient())
{
client.Encoding = Encoding.UTF8;
client.Headers[HttpRequestHeader.Accept] = "application/xml";
var requestUrl = HttpUtility.UrlEncode("https://www.somewebsite.com");
var stringResult = client.DownloadString("https://localhost:12345/api/getstuff/" + requestUrl);
}
}
}
}
The above doesnt work but the below works just fine
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Xml.Serialization;
using System.Web;
namespace ConsoleAppWebClient
{
class Program
{
static void Main(string[] args)
{
using (var client = new WebClient())
{
client.Encoding = Encoding.UTF8;
client.Headers[HttpRequestHeader.Accept] = "application/xml";
var requestUrl = HttpUtility.UrlEncode("https:www.somewebsite.com");
var stringResult = client.DownloadString("https://localhost:12345/api/getstuff/" + requestUrl);
}
}
}
}

It looks like requestUrl is meant to be a query parameter, but you're adding it to the URL's path.
The result is
https://localhost:12345/api/getstuff/https%3A%2F%2Fwww.somewebsite.com
"%" is an unsafe character which can lead to unpredictable results.
Instead, try making it a querystring parameter:
var requestUrl = HttpUtility.UrlEncode("https:www.somewebsite.com");
var stringResult = client.DownloadString(
"https://localhost:12345/api/getstuff/?requestUrl=" + requestUrl);
Now that the URL-encoded parameter is in the querystring instead of the path it should be okay.

Related

C# REST API for Sharepoint search document authentication issue

I am trying to search sharepoint doc using below code :
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace AppConsole
{
public class Program
{
public static async Task Main(string[] args)
{
System.Net.Http.HttpClient client = new HttpClient();
string WebUri= "https://company.sharepoint.com/_api/search/query?querytext='documentname'";
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "username", "password"))));
using (client)
{
HttpResponseMessage httpResponseMessage = await client.GetAsync(webUri);
HttpResponseMessage responsemMsgx = httpResponseMessage;
if (responsemMsgx.IsSuccessStatusCode)
{
Console.Writeline("responsemMsgx");
}
}
}
}
}
I am getting 403 forbidden message when i run the program and debug , i think there is a issue in Authentication. Please suggest an authentication method which works.
I have also tried below code ,but it doesn't work:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Configuration;
namespace AppConsoleSharePoint
{
public class Program
{
private static string listTitle;
public static object JToken { get; private set; }
public static async Task Main(string[] args)
{
var webUri = new Uri("https://XXXXXX.sharepoint.com");
const string userName = "XXXXXXXX";
const string password = "XXXXXX";
var securePassword = new SecureString();
foreach (var c in password)
{
securePassword.AppendChar(c);
}
var credentials = new SharePointOnlineCredentials(userName, securePassword);
object list = GetList(webUri, credentials, "Contacts");
//print List title
// Console.WriteLine(list["Title"]);
}
private static object GetList(Uri webUri, SharePointOnlineCredentials credentials, string v)
{
throw new NotImplementedException();
}
public static JToken GetList(Uri webUri, ICredentials credentials, string listTitle)
{
using (var client = new WebClient())
{
client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
client.Credentials = credentials;
client.Headers.Add(HttpRequestHeader.ContentType, "application/json;odata=verbose");
client.Headers.Add(HttpRequestHeader.Accept, "application/json;odata=verbose");
var endpointUri = new Uri(baseUri: webUri, string.Format("/_api/web/lists/getbytitle('{0}')", listTitle));
var result = client.DownloadString(endpointUri);
return JToken.Parse(result)["d"];
}
}
}
}
But,i get error in return JToken.Parse(result)["d"];
Exception: Severity Code Description Project File Line Suppression State
Error CS1061 'object' does not contain a definition for 'Parse' and no accessible extension method 'Parse' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) Active
Please help.
The following code for your reference.
string siteUrl = "https://tenant.sharepoint.com/sites/team";
string userName = "test#tenant.onmicrosoft.com";
string password = "xxx";
string searchQuery = "/_api/search/query?querytext='documentname IsDocument:True'";
var securePassword = new SecureString();
foreach (char c in password.ToCharArray()) securePassword.AppendChar(c);
var credential = new SharePointOnlineCredentials(userName, securePassword);
HttpClientHandler handler = new HttpClientHandler() { Credentials = credential };
Uri uri = new Uri(siteUrl);
handler.CookieContainer.SetCookies(uri, credential.GetAuthenticationCookie(uri));
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");
client.DefaultRequestHeaders.Add("ContentType", "application/json;odata=verbose");
var result = client.GetAsync(siteUrl + searchQuery).Result;
var content = result.Content.ReadAsStringAsync().Result;
JObject jobj = JObject.Parse(content);
JArray jarr = (JArray)jobj["d"]["query"]["PrimaryQueryResult"]["RelevantResults"]["Table"]["Rows"]["results"];
foreach (JObject j in jarr)
{
JArray results = (JArray)j["Cells"]["results"];
var title = "";
var path = "";
foreach (JObject r in results)
{
if (r["Key"] != null)
{
if (r["Key"].ToString() == "Title")
{
title = r["Value"].ToString();
}
if (r["Key"].ToString() == "Path")
{
path = r["Value"].ToString();
}
}
}
Console.WriteLine(title + "|" + path);
}
Console.ReadKey();

Rest URL consumption guidance required

I have a rest url provided by client , It looks something like www.baseurl/api// I couldn't get result if I try to consume it from console application getting error 503.
However I m able to browse it from my browser and it returns the proper json of Entity Details. Please help me with this.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp15
{
public class Class1
{
private const string URL = "www.baseurl/api/<EntityName>/<EntityID>";
static void Main(string[] args)
{
Class1.CreateObject();
}
private static void CreateObject()
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "GET";
request.ContentType = "application/json";
try
{
WebResponse webResponse = request.GetResponse();
using (Stream webStream = webResponse.GetResponseStream() ?? Stream.Null)
using (StreamReader responseReader = new StreamReader(webStream))
{
string response = responseReader.ReadToEnd();
Console.Out.WriteLine(response);
}
}
catch (Exception e)
{
Console.Out.WriteLine("-----------------");
Console.Out.WriteLine(e.Message);
}
}
}
}

Authorisation Header and Content Type in C#

I am writing a code in C# to build the console to implement get request.
We were using POSTMAN to achieve the task but we decided to build our own.
I need to pass the user name and pw in headers of the request.
Since i am new to programming,can you guide me.
I have written below code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
namespace ConsoleApp2
{
class Program
{
private static object response;
static void Main(string[] args)
{
GetRequest("https://www.google.com");
Console.ReadKey();
}
async static void GetRequest(string url)
{
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage response = await client.GetAsync(url))
{
using (HttpContent content = response.Content)
{
string mycontent = await content.ReadAsStringAsync();
Console.WriteLine(mycontent);
}
}
}
}
}
}
You can try following code snippet
HttpClient client = new HttpClient()
var byteArray = Encoding.ASCII.GetBytes("username:password1234");
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
DefaultRequestHeaders is not working, I have used below snippet for authentication
string _ContentType = "application/json";
httpWebRequest.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(_ContentType));
var _CredentialBase64 = "xxxxxxxxx=";
httpWebRequest.DefaultRequestHeaders.Add("Authorization", String.Format("Basic {0}", _CredentialBase64));

adding an Interface

My main Program.cs is as follows:
using System;
using System.Collections.Generic;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.IO;
using System.Threading.Tasks;
namespace HTTPrequestApp
{
class Program
{
static void Main(string[] args)
{
var lstWebSites = new List<string>
{
"www.amazon.com",
"www.ebay.com",
"www.att.com",
"www.verizon.com",
"www.sprint.com",
"www.centurylink.com",
"www.yahoo.com"
};
string filename = #"RequestLog.txt";
{
using (var writer = new StreamWriter(filename, true))
{
foreach (string website in lstWebSites)
{
for (var i = 0; i < 4; i++)
{
MyWebRequest request = new MyWebRequest();
request.Request();
}
}
}
}
}
}
}
Then I have a class, and this is where the errors are.
The GetList() error - 'HTTPrequestApp.Program' does not contain a definition for 'GetList'
The client2 error - The name 'client2' does not exist in the current content
MyWebRequest.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace HTTPrequestApp
{
public class MyWebRequest : HTTPrequestApp.IWebRequest
{
public void Request()
{
List<string> lstWebSites = Program.GetList();
using (var client = new TcpClient(lstWebSites[1], 80))
{
using (NetworkStream stream = client2.GetStream())
using (StreamWriter writer = new StreamWriter(stream))
using (StreamReader reader2 = new StreamReader(stream))
{
writer.AutoFlush = true;
writer.WriteLine("GET / HTTP/1.1");
writer.WriteLine("HOST: {0}:80", lstWebSites[1]);
writer.WriteLine("Connection: Close");
writer.WriteLine();
writer.WriteLine();
string theresponse = reader2.ReadToEnd();
Console.WriteLine(theresponse);
}
}
}
}
}
Finally, I have an Interface. Is this done correctly?
If I am doing something incorrectly please help me, how should I fix it?
IWebRequest.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HTTPrequestApp
{
interface IWebRequest
{
void Request();
}
}
What I have to do is: send HTTP request to get the initial page and get back the HTTP response. Save it into the .cvs file. Check that it is a 200 response code and time how long it took to retrieve the response. I have to get the response 4 times from each of those websites in my list.
Please help me.
First about your errors :
The provided code does not contain GetList method in Program class as the code shared contains the only main method which defines your websites.
The line using (var client = new TcpClient(lstWebSites[1], 80)) creates client object instead of client2.
Another point, instead of writing to open TCPClient connection to read the response of website you can use HttpClient or WebRequest in-built classes to achieve your functionality.
Here's a full example of what I mean. Keep adding all the websites you want to lstWebSites, and instead of dumping the HTML results to the console, you can write them to a file.
var lstWebSites = new List<string>
{
"https://www.stackoverflow.com",
"https://www.google.com"
};
foreach (string website in lstWebSites)
{
var request = WebRequest.Create(website);
request.Credentials = CredentialCache.DefaultCredentials;
((HttpWebRequest)request).UserAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"; // Lie
var response = request.GetResponse();
if (((HttpWebResponse)response).StatusCode == HttpStatusCode.OK)
{
var stream = response.GetResponseStream();
var reader = new StreamReader(stream);
Console.WriteLine(string.Format("***** {0} *****", website));
Console.WriteLine(reader.ReadToEnd()); // Dump HTML response
}
}

c# changing this line so it outputs the string as a variable

UPDATE TO POST ORIGIANAL POST AFTER THIS CODE --- this code is an update to what david has been helping me do its throwing one error need help
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using System.Net;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string URL = "http://localhost/test2.php";
WebClient webClient = new WebClient();
NameValueCollection formData = new NameValueCollection();
formData["var1"] = formData["var1"] = string.Format("MachineName: {0}", System.Environment.MachineName);
formData["var2"] = ip();
byte[] responseBytes = webClient.UploadValues(URL, "POST", formData);
string responsefromserver = Encoding.UTF8.GetString(responseBytes);
Console.WriteLine(responsefromserver);
webClient.Dispose();
System.Threading.Thread.Sleep(5000);
}
public void ip()
{
String publicIP = "";
System.Net.WebRequest request = System.Net.WebRequest.Create("http://checkip.dyndns.org/");
using (System.Net.WebResponse response = request.GetResponse())
{
using (System.IO.StreamReader stream = new System.IO.StreamReader(response.GetResponseStream()))
{
publicIP = stream.ReadToEnd();
}
}
//Search for the ip in the html
int first = publicIP.IndexOf("Address: ") + 9;
int last = publicIP.LastIndexOf("</body>");
publicIP = publicIP.Substring(first, last - first);
Console.WriteLine(publicIP);
System.Threading.Thread.Sleep(5000);
}
}
}
this is the error I am getting
Error 2 - An object reference is required for the non-static field, method, or property 'ConsoleApplication1.Program.ip()'
I am trying to create a function that will send the out put as var2
I have this c# script
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("MachineName: {0}", System.Environment.MachineName);
System.Threading.Thread.Sleep(5000);
}
}
}
how can I change this so it outputs the string to a variable say "VAR2" and use it in this script
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using System.Net;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string URL = "http://localhost/test2.php";
WebClient webClient = new WebClient();
NameValueCollection formData = new NameValueCollection();
formData["var1"] = "THIS IS WHERE VAR2 NEEDS TO BE ";
byte[] responseBytes = webClient.UploadValues(URL, "POST", formData);
string responsefromserver = Encoding.UTF8.GetString(responseBytes);
Console.WriteLine(responsefromserver);
webClient.Dispose();
System.Threading.Thread.Sleep(5000);
}
}
}
SO HOW CAN I ADD THE MACHINE NAME SCRIPT TO THIS FUNCTION AND THEN USE IT AS VAR2
any help would be brilliant
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication5
{
class Program
{
public static int Main(string[] args)
{
String publicIP = "";
System.Net.WebRequest request = System.Net.WebRequest.Create("http://checkip.dyndns.org/");
using (System.Net.WebResponse response = request.GetResponse())
{
using (System.IO.StreamReader stream = new System.IO.StreamReader(response.GetResponseStream()))
{
publicIP = stream.ReadToEnd();
}
}
//Search for the ip in the html
int first = publicIP.IndexOf("Address: ") + 9;
int last = publicIP.LastIndexOf("</body>");
publicIP = publicIP.Substring(first, last - first);
Console.WriteLine(publicIP);
System.Threading.Thread.Sleep(5000);
return 0;
}
}
}
her is the update david I would like to incude this script in my other script so it looks like this
formData["var1"] = formData["var1"] = string.Format("MachineName: {0}", System.Environment.MachineName);
formData["var2"] = "this is where this script needs to be ";
Why does it need to be in a separate application? If one application's output is going to be the command-line argument for another application's input, then they're both running on the same machine. Which means, in this case, they'd both get the same value from System.Environment.MachineName.
You can just get the value in the application where it's needed:
formData["var1"] = string.Format("MachineName: {0}", System.Environment.MachineName);

Categories

Resources