How to avoid escaping character in RestSharp? - c#

I am writing a small application that sends data to a server through REST API as simple URL calls. I use the RestSharp library to do this. My problem is, that some data strings I am sending include the / character.
I can't leave the character as it is, since the called URL would then be invalid. But when I replace it with %2F (which is then translated back on the server side), the RestSharp replaces the % character again, giving %252F. The Rest call than fails since server is missing the backslash.
I have searched the web but found no working solution to this problem. Do you have any idea how to solve it, without using different library and rewriting it myself? Also, not using the backslash is NOT an option.
My code is here:
using RestSharp; //Version 104
private string RestRequest(string URL, RestSharp.Method Method)
{
var Client = new RestClient();
Client.Authenticator = new HttpBasicAuthenticator(ID, Password);
var Request = new RestRequest(URL, Method);
IRestResponse Response = Client.Execute(Request);
return Response.Content;
}
Sample URL that is passed to the function:
htp://localhost:8080/api/jsonws/knowledge-base-portlet.kbarticle/add-kb-article/portlet-id/1_WAR_knowledgebaseportlet/parent-resource-class-name-id/20704/parent-resource-prim-key/20200/title/SomeTitle/url-title/%2FTitle/content/SomeContent

After snooping around Resharper's Github issues, like this one, it seems you have to use RestRequest.AddURLSegment(). Tested with RestSharp v. 104.0.0
var url = "http://localhost:4422/api/jsonws/knowledge-base-portlet.kbarticle/add-kb-article/portlet-id/1_WAR_knowledgebaseportlet/parent-resource-class-name-id/20704/parent-resource-prim-key/20200/title/SomeTitle/url-title/{segment}/content/SomeContent";
var Client = new RestClient();
var Request = new RestRequest(url,Method.GET);
Request.AddUrlSegment("segment", "%2Ftitle");
I don't know if it's possible for you to pass multiple arguments. If you cannot, the simplest scenario would be splitting by %2F and concatenate multiple arguemnts. Something like this:
private string RestRequest(string URL, RestSharp.Method Method)
{
var Client = new RestClient();
string requestUrl;
bool hasBackslashArgument = ParseEncodedBackSlash(URL, out requestUrl);
RestRequest request;
if (hasBackslashArgument)
{
request = new RestRequest(requestUrl, Method);
request.AddUrlSegment("segment", "%2F");
}
else
{
request = new RestRequest(URL, Method);
}
IRestResponse response = Client.Execute(request);
return response.Content;
}
private bool ParseEncodedBackSlash(string url, out string preformattedString)
{
preformattedString = null;
var urlSegments = url.Split(new string[] { "%2F" }, StringSplitOptions.None);
if (urlSegments.Length == 0) return false;
preformattedString = string.Join("{segment}", urlSegments);
return true;
}

Related

C# Post Variables can't be read on Website - HttpClient PostAsync()

I have a web server on which I'm hosting my own api for one of my projects.
This is the php-code of the api-website:
$user = $_POST['username'];
$password = $_POST['password'];
if(strcmp($user, "username") == 0 && strcmp($password, "password") == 0) {
...
} else {
die("No Permissions");
}
I want to send the two variables username and password with a HttpClient and the postAsync-method to this website and if the right log in data is detected, it returns the data I want.
For this I have the following code in C#:
Task<HttpResponseMessage> response;
var url = "www.url.de"; //not the url I'm actually calling!
var vars = "[{\"username\":\"username\", \"password\":\"password\"}]";
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
response = client.PostAsync(url, new StringContent(vars, Encoding.UTF8));
Console.WriteLine(response.Result.Content.ReadAsStringAsync().Result);
if (response.IsCompleted)
{
Console.WriteLine(response.Result.Content.ReadAsStringAsync().Result);
}
}
But the problem is that no matter what I have tried the output from this code is, that i have no permissions. And I have changed the php-code, so that I can see which data is stored in $username and $password, but they are empty and I don't know why. I hope somebody can help me with this.
Your PHP code is expecting the data sent as application/x-www-form-urlencoded, but your C# code is sending it as JSON.
As mentioned in the comment by M. Eriksson, you either need to change your PHP to accept JSON, or change your C# to send as form data.
This answer shows how to use HTTPClient to send data like that.
Here's my modification of your code based on the above code (I did test it):
public static async Task DoSomething()
{
string url = "http://httpbin.org/post"; //not the url I'm actually calling!
Dictionary<string, string> postData = new();
postData["username"] = "username";
postData["password"] = "password";
using HttpClient client = new();
client.DefaultRequestHeaders.Accept.Add(new("application/json"));
HttpRequestMessage request = new(HttpMethod.Post, url);
request.Content = new FormUrlEncodedContent(postData);
HttpResponseMessage response = await client.SendAsync(request);
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
}

Send a string in body via SendRequestAsync

I need to send a Patch request to a backend API via SendRequestAsync func. This is regarding a UWP C# app.
Backend expected to like this:
On the app this is the code I wrote. But doesn't work
if (requestMehtod == ApplicationConstants.RequestType.PATCH)
{
Uri uri = new Uri(requestUrl);
HttpRequestMessage requestMessage = null;
if (postData != null)
{
var itemAsJson = JsonConvert.SerializeObject(postData);
requestMessage = new HttpRequestMessage(HttpMethod.Patch, uri)
{
Content = new HttpStringContent(itemAsJson, Windows.Storage.Streams.UnicodeEncoding.Utf8, "application/json-patch+json")
};
}
else
{
requestMessage = new HttpRequestMessage(HttpMethod.Patch, uri);
}
response = await httpClient.SendRequestAsync(requestMessage).AsTask(cancellationTokenSource.Token);
var rdModel = ProcessResponseData(response);
return await Handle401Error(rdModel, response, postData, url, requestMehtod, isDownloadSite, OnSendRequestProgress, requestData);
}
The above code fine to send JSON data to the same API and works fine. But I need to know how to send just a string in the body. Thank for the consideration
NOTE: App uses HttpClient from Windows.Web.Http and will not be able to use anything inside System.Net.Http namespace.
The answer is given by the #gusman and #Simon Wilson. Just to amend to their answer, in order to be able to send a string in the request body, the string needs to be within double-quotes.
var requestData = "\"hello world\"";
var request = new HttpRequestMessage(HttpMethod.Post, uri)
{
Content = new HttpStringContent(requestData, Windows.Storage.Streams.UnicodeEncoding.Utf8, "application/json")
};
response = await httpClient.SendRequestAsync(request);
This worked in my scenario.

Need help converting my RestSharp code to use HttpClient instead

Due to the fact that I need to convert this C# dll into a tlp file to be called from Visual Basic 6, I need avoid using external dependencies. I have used RestSharp to consume a WebAPI by doing the following (working):
using RestSharp;
using Newtonsoft.Json;
..
public string GetToken (string Key, string Password) {
var client = new RestClient (BaseUrl + "auth/GetToken");
var request = new RestRequest (Method.POST);
request.AddHeader ("cache-control", "no-cache");
request.AddHeader ("Content-Type", "application/json");
Dictionary<string, string> data = new Dictionary<string, string> {
{ "APIKey", Key },
{ "APIPassword", Password }
};
var dataJSON = JsonConvert.SerializeObject (data);
request.AddParameter ("undefined", dataJSON, ParameterType.RequestBody);
IRestResponse response = client.Execute (request);
GetTokenResults g = JsonConvert.DeserializeObject<GetTokenResults> (response.Content);
return g.Token;
}
where GetTokenResults was a struct that contained a declaration for the string Token. I want to achieve this same functionality without using RestSharp. Here is my unsuccessful attempt:
using System.Net.Http;
using System.Net.Http.Headers;
..
public async void GetToken (string Key, string Password) {
var client = new HttpClient ( );
client.DefaultRequestHeaders.Accept.Clear ( );
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue ("application/json"));
client.BaseAddress = new Uri (BaseUrl + "auth/GetToken");
Dictionary<string, string> data = new Dictionary<string, string> {
{ "APIKey", Key },
{ "APIPassword", Password }
};
var dataJSON = JsonConvert.SerializeObject (data);
var content = new StringContent (dataJSON, Encoding.UTF8, "application/json");
var response = await client.PostAsync ("", content);
}
I am unclear on how to achieve the same results (send API key and password, return token as string) using HttpClient as I did using RestSharp earlier. Anything that can point me in the right direction is greatly appreciated!
I think you got stung by this issue. In short, the URI in client.BaseAddress needs a slash at the end of it.
However, I wouldn't simply add it, I'd consider doing it a little different. Presumably your BaseUrl already has a trailing slash, given you're appending "auth/GetToken" to it. I'd do it this way:
client.BaseAddress = new Uri(BaseUrl);
...
var response = await client.PostAsync("auth/GetToken", content);
As you can see, HttpClient fits very cleanly with how your code is already set up, i.e. you have a "base" address with a trailing slash and you want to append to it for a specific call.
That should get you un-stuck to this point. The next thing you'll need to tackle is deserializing the JSON response so you can get the token out of it. It's similar to how you did it in RestSharp, except that response.Content is not a string in the HttpClient world, so you need one more step to get that:
var json = await response.Content.ReadAsStringAsync();
GetTokenResults g = JsonConvert.DeserializeObject<GetTokenResults>(json);
return g.Token;
Last thing you'll need to do to get this to compile is change the method signature to:
public async Task<string> GetTokenAsync
One final note: you are now in the async world, and that's a good thing, but you need to know how to use it correctly or you could end up with deadlocks and other mysterious bugs. In short, don't block on async code by calling .Result or .Wait() anywhere up the call stack. That's by far most common mistake people make. Use async/await all the way down.
I think you are missing first parameter in the method PostAsync i.e. requestUri=Client.BaseAddress (see my implementation below).
Try with this first, if did not work, read below. I have a little different implementation where I passed client.BaseAddress as first parameter and I am passing my content as ByteArrayContent. In my case I have to pass my content as "application/x-www-form-urlencoded" excerpt of my code:
var buffer = Encoding.UTF8.GetBytes(content);
var byteContent = new ByteArrayContent(buffer);
//as I can't send JSON, probably, you can skip as it's already JSON
byteContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
//requestUri=client.BaseAddress
await client.PostAsync(requestUri, byteContent).ConfigureAwait(false);
We have somewhat different need but I think you are pretty close. If it does not help, write me I will share my code. After reading the comment, I would like to share how I have made my HttpClient. The code is as it is:
using (var client = CreateMailClientForPOST($"{BaseUrl}/"))
{
//removed code, you can call above code as method like
var response= await client.DoThingAsAsync($"{client.BaseAddress}, content").ConfigureAwait(false);
}
protected HttpClient CreateMailClientForPOST(string resource)
{
var handler = new HttpClientHandler();
if (handler.SupportsAutomaticDecompression)
{
handler.AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate;
}
var client = new HttpClient(handler)
{
BaseAddress = new Uri($"https://api.address.com/rest/{resource}")
};
return client;
}

Get Request in C# Returning 401 Not Authorised

Currently trying to do a Get request as part of a c# program. The request works fine on Postman as it uses a header for authorization. However I cannot get the code working for the program to use this header correctly in its Get request. I've had a good look around and tried various bits of code I've found but haven't managed to resolve it so any help would be appreciated!
public string Connect()
{
using (WebClient wc = new WebClient())
{
string URI = "myURL.com";
wc.Headers.Add("Content-Type", "text");
wc.Headers[HttpRequestHeader.Authorization] = "Bearer OEMwNjI2ODQtMTc3OC00RkIxLTgyN0YtNzEzRkE5NzY3RTc3";//this is the entry code/key
string HtmlResult = wc.DownloadString(URI);
return HtmlResult;
}
}
Above is one method inside the class.
Below is another attempt which is an extension method that gets passed the URL:
public static string GetXml(this string destinationUrl)
{
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create(destinationUrl);
request.Method = "GET";
request.Headers[HttpRequestHeader.Authorization] = "Bearer
OEMwNjI2ODQtMTc3OC00RkIxLTgyN0YtNzEzRkE5NzY3RTc3";
HttpWebResponse response;
response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
Stream responseStream = response.GetResponseStream();
string responseStr = new
StreamReader(responseStream).ReadToEnd();
return responseStr;
}
else
{
Console.Write(String.Format("{0}({1})",
response.StatusDescription, response.StatusCode));
}
return null;
}
Might I recommend the very handy RestSharp package (find it on Nuget).
It turns your current code into something like
public string Connect()
{
var client = new RestClient();
var request = new RestRequest("myURL.com", Method.GET);
request.AddParameter("Authorization", "Bearer OEMwNjI2ODQtMTc3OC00RkIxLTgyN0YtNzEzRkE5NzY3RTc3");
var response = client.Execute(request);
return response.Content;
}
It's much more succinct and easier to use (in my opinion) and thus lessens the likelihood of passing in or using incorrect methods.
If you're still having issues getting data back/connecting. Then using PostMan click Code in the upper right of PostMan and select the C# (RestSharp) option. Whatever is generated there matches exactly what PostMan is sending. Copy that over and you should get data back that matches your PostMan request.

How to remove opening and closing double quotes and all backslashes in a JSON string - C#

For performing a rest API call with C# I have to serialize a dictionary with parameters. These parameters have to be placed inside the body of the request as JSON.
The API call is done with the help of RestSharp. And the send string is checked with fiddler.
request.AddBody(_jsonrequeststring);
The problem is that the API is very picky, it doesn't accept break points (backslash) and it doesn't accept double quotes on the beginning and on the end of the JSON string.
So here what it's expecting:
{
"ConsumerToken":"aconsumertoken",
"UserId":"email#web.com",
"PasswordSha256Base64":"apassword"
}
And this is what I'm sending:
"{ConsumerToken:\"aconsumertoken\",UserId:\"email#web.com\",PasswordSha256Base64:\"apassword\"}"
I'm able to remove the \" but when it sends that string it also returns an error.
"{ConsumerToken:aconsumertoken,UserId:email#web.com,PasswordSha256Base64:apassword}"
Is it even possible to just remove the \ and opening and closing double quotes? And if so how? I just can't seem to wrap my head around it.
The complete call:
userhandler.cs
public static object Login(string uname, string pass, string conTok)
{
Dictionary<string, string> loginDictionary =
new Dictionary<string, string>();
loginDictionary.Add("ConsumerToken", conTok);
loginDictionary.Add("UserId", uname);
loginDictionary.Add("PasswordSha256Base64", pass);
string jsonRequestString = JsonConvert.SerializeObject(loginDictionary);
Proxy proxy = new Proxy(jsonRequestString);
return proxy.Execute();
}
Proxy.cs
public class Proxy
{
const string BaseUrl = "API url";
const string ActionUrl = "API action url";
string _jsonrequeststring;
public Proxy(string json)
{
_jsonrequeststring = json;
}
public Object Execute()
{
var client = new RestClient(BaseUrl);
var request = new RestRequest(ActionUrl);
request.RequestFormat = DataFormat.Json;
request.AddBody(_jsonrequeststring);
request.Method = Method.POST;
var response = client.Execute(request);
var content = response.Content;
return content;
}
}
It looks like you're adding the body content as a string, which means that it'll be encoded as a string by RestSharp. If possible, try adding the object itself and let RestSharp handle the serialization etc:
var obj = new {
ConsumerToken = "aconsumertoken",
UserId = "email#web.com",
PasswordSha256Base64 = "apassword"
};
request.AddBody(obj);
If you must use a pre-serialized JSON string for some reason, you should be able to do it like this:
request.AddParameter("application/json", _jsonrequeststring, ParameterType.RequestBody);
[NB: I haven't actually tested either of these suggestions, but I think they should do the trick]

Categories