i'm trying to make a app thats lets me query the database from discogs.
According to the Api documentation i can do this with just a token.
so i registered and got a user token.
now when i use postman with https://api.discogs.com/database/search?release_title=nevermind&artist=nirvana&per_page=3&page=1&token=<my_user_token>
i receive the json like i would expect.
but when i make a httpclient in c# with the token
public string token = <my_user_token>;
public static HttpClient client { get; set; }
public static async Task InitilizeClient()
{
await GetAccesToken();
}
private static async Task GetAccesToken()
{
client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.BaseAddress = new Uri(#"https://api.discogs.com");
//client.DefaultRequestHeaders.Authorization=new AuthenticationHeaderValue("Discogs", "token="+token);
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization","Discogs token=" + token);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
and then use the client like this
public static async Task QueryDataBaseAsync(string query)
{
if (query == null)
{
throw new Exception("query is empty");
}
string url = "";
url = #"https://api.discogs.com/database/search?release_title="+query;
if (client == null)
{
await InitilizeClient();
}
using (HttpResponseMessage response = await client.GetAsync(url))
{
if (response.IsSuccessStatusCode)
{
}
else
{
throw new Exception(response.ReasonPhrase + " \n" + response.RequestMessage.ToString());
}
}
}
then i always get a ReasonPhrase "forbidden","statuscode: 403"
when i put a breakpoint on my HttpResponseMessage response i can see that under "headers"=>"responsemessage"=>"headers"=>"authorization" it has my token.
what am i doing wrong?
ps, sorry about the bad english, its not my motherlangue
ps2, i'm new at programming so i would appreciate it if you could eli5 what i did wrong
You may need to provide user-agent in the headers. Something along these lines:
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36");
like this:
public class DiscConsumer
{
//https://www.discogs.com/developers#page:authentication,header:authentication-discogs-auth-flow
//curl "https://api.discogs.com/database/search?q=Nirvana" -H "Authorization: Discogs key=foo123, secret=bar456"
private const string _urlQuery = "https://api.discogs.com/database/search?q={query}";
private const string _key = "<....your key....>";
private const string _secret = "<....your secret...>";
private System.Net.Http.HttpClient _httpClient;
public async Task InitilizeClient()
{
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
var sslhandler = new HttpClientHandler()
{
//...in System.Security.Authentication.SslProtocols
SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls
};
_httpClient = new System.Net.Http.HttpClient(sslhandler);
string authorization = $"Discogs key={_key}, secret={_secret}";
_httpClient.DefaultRequestHeaders.Add("Authorization", authorization);
_httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36");
}
public async Task QueryDataBaseAsync(string query)
{
if (String.IsNullOrWhiteSpace( query ))
{
throw new Exception("query is empty");
}
string url = "";
url = _urlQuery.Replace("{query}", query);
if (_httpClient == null)
{
await InitilizeClient();
}
using (HttpResponseMessage response = await _httpClient.GetAsync(url))
{
if (response.IsSuccessStatusCode)
{
string s = await response.Content.ReadAsStringAsync();
Console.WriteLine(s);
}
else
{
throw new Exception(response.ReasonPhrase + " \n" + response.RequestMessage.ToString());
}
}
}
}
Per https://www.discogs.com/developers#page:authentication,header:authentication-discogs-auth-flow you can supply key+secret on every request along with search.
Related
I'm attempting to upload an image file from the phone camera to a BuddyPress API from my Xamarin app (the API call documentation can be found here - https://developer.buddypress.org/bp-rest-api/reference/attachments/member-avatar/)
I can do this successfully using RestSharp as follows;
public string PostMediaFile(MediaFile data, string path, bool https = false, string authorisationToken = "")
{
var requestMethod = "http://";
if (https)
{
requestMethod = "https://";
}
var serverString = requestMethod + path;
var client = new RestClient(serverString)
{
Timeout = Convert.ToInt32(timeOut)
};
client.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer " + authorisationToken);
request.AddHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36");
request.AddFile("file", data.Path);
request.AddParameter("action", "bp_avatar_upload");
IRestResponse response = client.Execute(request);
return response.Content;
}
However, all my other requests in the application are performed using HttpClient and I'd like to keep it consistent, so I came up with the follow function to replace this;
public async Task<string> PostMediaFile(MediaFile data, string path, bool https = false, string authorisationToken = "")
{
var memoryStream = new MemoryStream();
data.GetStream().CopyTo(memoryStream);
byte[] fileAsBytes = memoryStream.ToArray();
var fileContent = new ByteArrayContent(fileAsBytes);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
Name = "file",
FileName = Path.GetFileName(data.Path),
};
fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
var content = new MultipartFormDataContent
{
{ fileContent, "file", Path.GetFileName(data.Path) },
{ new StringContent("action"), "bp_avatar_upload" }
};
var requestMethod = "http://";
if (https)
{
requestMethod = "https://";
}
var clientHandler = new HttpClientHandler()
{
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; }
};
httpClient = new HttpClient(clientHandler);
if (!string.IsNullOrWhiteSpace(authorisationToken))
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authorisationToken);
httpClient.DefaultRequestHeaders.UserAgent.TryParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36");
}
httpClient.Timeout = TimeSpan.FromMilliseconds(timeOut);
var serverString = requestMethod + path;
HttpResponseMessage response = await httpClient.PostAsync(serverString, content);
HttpContent Content = response.Content;
var json = await Content.ReadAsStringAsync();
response.Dispose();
return json;
}
The problem is, obviously it doesn't work, and I don't know why. I just get the following response;
{"code":"bp_rest_attachments_user_avatar_upload_error","message":"Upload failed! Error was: Invalid form submission..","data":{"status":500,"reason":"upload_error"}}
I feel like I'm really close, but not sure where my mistake is.
Ah! it was so simple! I had part of the form data the wrong way around;
{ new StringContent("action"), "bp_avatar_upload" }
should be
{ new StringContent("bp_avatar_upload"), "action" }
I am developing an application using C # that calls a RESTApi de laravel. Through Postman it works correctly, but instead of C# no, it returns error 401.
If I remove the following if in the Laravel controller it works fine:
if ($ request-> isJson ()) {
The header Content-Type is set to application/json
Laravel Code
function getResult(Request $request, $id)
{
if ($request->isJson()) {
// Eloquent
$times = Result::selectRaw('THE SELECT')
->where('ID', $Id)
->get();
$result = [];
foreach($times as $key => $time)
{
...........
}
sort($result);
return response()->json(['results'=>$result], 200);
}
return response()->json(['error' => 'Unauthorized'], 401, []);
}
C#
public static async Task<dynamic> GETTimes(int eventID, int stageID)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseUrl);
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
client.DefaultRequestHeaders.TryAddWithoutValidation("cache-control", "no-cache");
client.DefaultRequestHeaders.Add("User-Agent", #"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36");
// Add the Authorization header with the AccessToken.
//client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
// create the URL string.
string url = string.Format("api/v1/events/{0}/results/{1}", eventID, stageID);
// make the request
HttpResponseMessage response = await client.GetAsync(url);
// parse the response and return the data.
string jsonString = await response.Content.ReadAsStringAsync();
object responseData = JsonConvert.DeserializeObject(jsonString);
return (dynamic)responseData;
}
}
I try to get some data from a web, but always get 401 Unauthorized error. I guess this is caused by my request header setting is wrong.
Could we can set Accept, ContentType by using TryAddWithoutValidation?
How can I set the correct request header in HttpClient?
And I try to set the header like as following:
public static async Task<ResultInfo> Get(string url, string cookie = null)
{
url =$"https://www.zhihu.com/api/v4/questions/46508954/answers?sort_by=default&include=data%5B%2A%5D.is_normal%2Cis_sticky%2Ccollapsed_by%2Csuggest_edit%2Ccomment_count%2Ccan_comment%2Ccontent%2Ceditable_content%2Cvoteup_count%2Creshipment_settings%2Ccomment_permission%2Cmark_infos%2Ccreated_time%2Cupdated_time%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%2Cupvoted_followees%3Bdata%5B%2A%5D.author.badge%5B%3F%28type%3Dbest_answerer%29%5D.topics&limit=20&offset=20";
; var result = new ResultInfo()
{
IsSuccessStatusCode = false
};
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
using (var client = new HttpClient(handler))
{
try
{
cookie = "_zap=bb597634-86d0-4636-a516-89e76b4b5335; q_c1=b2e3af8dde034209a6948fcd9fd0e70f|1515131469000|1509512040000; d_c0=\"AJBrsuC5AA2PTqu9qOLgytIZlpXzmzgRgcE=|1516167026\"; _xsrf=ec351d2e-f0b2-4b2e-9eff-a3262a9faf10; capsion_ticket=\"2|1:0|10:1516261057|14:capsion_ticket|44:NzU1ZGRjYTA3Y2U3NGVjZWE4MWIzMzllNjA1NjMxZGQ=|b73bb13fe6a623db85478f5eb46ed51906674b89f29e4ef1a067fce6dcd90f54\"; z_c0=\"2|1:0|10:1516261068|4:z_c0|92:Mi4xMzMwVEFBQUFBQUFBa0d1eTRMa0FEU1lBQUFCZ0FsVk56SnhOV3dETFF5VGlla1ZDUllwcUVMRVhMWk4wV1duOVJn|f2fcc1750b966a19dd202ddc2eb42dca9dc9f573421bc3a8675a072e603ca897\"; __utma=51854390.1320208938.1517560249.1517560249.1517560249.1; __utmb=51854390.0.10.1517560249; __utmc=51854390; __utmz=51854390.1517560249.1.1.utmcsr=zhihu.com|utmccn=(referral)|utmcmd=referral|utmcct=/question/38824940; __utmv=51854390.100-1|2=registration_date=20130816=1^3=entry_date=20130816=1";
var replace = cookie.Replace("\"", "");
client.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "*/*");
client.DefaultRequestHeaders.TryAddWithoutValidation("ContentType", "application/x-www-form-urlencoded");
client.DefaultRequestHeaders.TryAddWithoutValidation("UserAgent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36");
client.DefaultRequestHeaders.TryAddWithoutValidation("Cookie", replace);
client.DefaultRequestHeaders.TryAddWithoutValidation("accept-encoding", "gzip/deflate");
//client.DefaultRequestHeaders.TryAddWithoutValidation("accept-language", "en-US,en;q=0.9");
client.DefaultRequestHeaders.TryAddWithoutValidation("AllowAutoRedirect","false");
if (!string.IsNullOrEmpty(url))
{
var data = await client.GetAsync(url);
if (data.IsSuccessStatusCode)
{
var content = await data.Content.ReadAsStringAsync();
result.IsSuccessStatusCode = true;
result.Data = await data.Content.ReadAsStringAsync();
}
else
{
result.Message = data.StatusCode.ToString();
}
}
}
catch (Exception e)
{
result.Message = e.Message;
throw;
}
}
return result;
}
I am trying to download a webpage with HttpClient, that's my code:
private async Task<string> _doRequest(string url)
{
string result = string.Empty;
var client = HttpClient;
using(var request = new HttpRequestMessage()
{
RequestUri = new Uri(url),
Method = HttpMethod.Get
}){
using (HttpResponseMessage response = client.SendAsync(request).Result)
if (response.Headers.Location == null)
{
using (HttpContent content = response.Content)
{
result = await content.ReadAsStringAsync();
}
}
else
{
result = await _doRequest(response.Headers.Location.ToString());
}
};
return result;
}
HttpClient is a static variable initialized as follow:
var handler = new HttpClientHandler();
handler.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
handler.AllowAutoRedirect = false;
HttpClient = new HttpClient(handler);
HttpClient.DefaultRequestHeaders.Add("User-Agent", #"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36");
When I try to execute the code with url = "https://www.gls-italy.com/?option=com_gls&view=track_e_trace&mode=search&numero_spedizione=TE170187747&tipo_codice=nazionale"
I get the following:
Which is what lead me to try with curl:
And here I am lost. To me it looks like a valid 302 with location, but for some reasons HttpClient believe otherwise and just throw an exception.
To be clear initially I was relying on AllowAutoRedirect default value and thrust HttpClient to do the redirect, it didn't work, I was getting this same exception which lead me to try to manage it myself. But with no success.
Anyone knows what's happening? How to make it work?
Thanks in advance.
Objects at Class level:
HttpClientHandler Http_Handler = new HttpClientHandler();
HttpClient Http_Client = new HttpClient();
CookieContainer HttpClCookieJar = new CookieContainer();
HttpClient setup stub:
private void HttpClient_Setup()
{
Http_Handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
Http_Handler.AllowAutoRedirect = false;
Http_Handler.CookieContainer = HttpClCookieJar;
Http_Handler.UseCookies = true;
Http_Handler.UseDefaultCredentials = true;
Http_Client.Timeout = new TimeSpan(30000);
Http_Client = new HttpClient(Http_Handler);
Http_Client.DefaultRequestHeaders.Add("User-Agent", #"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0");
Http_Client.DefaultRequestHeaders.Add("Accept-Language", "it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3");
Http_Client.DefaultRequestHeaders.Add("Accept", "*/*");
Http_Client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
}
Async HttpClient request:
public async Task<string> HttpClient_Request(string RequestURL)
{
string _responseHtml = string.Empty;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 |
SecurityProtocolType.Tls11 |
SecurityProtocolType.Tls12;
try
{
using (HttpRequestMessage _requestMsg = new HttpRequestMessage())
{
_requestMsg.Method = HttpMethod.Get;
_requestMsg.RequestUri = new Uri(RequestURL);
using (HttpResponseMessage _response = await Http_Client.SendAsync(_requestMsg))
{
using (HttpContent _content = _response.Content)
{
_responseHtml = await _content.ReadAsStringAsync();
};
};
};
}
catch (HttpRequestException eW)
{
Console.WriteLine("Message: {} Source: {1}", eW.Message, eW.Source);
}
catch (Exception eX)
{
Console.WriteLine("Message: {} Source: {1}", eX.Message, eX.Source);
}
return _responseHtml;
}
I've created HttpClient that I'm using for sending requests:
public static void Initialize()
{
handler = new HttpClientHandler() { UseCookies = false, AllowAutoRedirect = true };
http = new HttpClient(handler) { BaseAddress = new Uri("http://csgolounge.com/mytrades") };
http.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36");
}
After that I'm creating instance of custom class that stores the cookies string for an account (something like id=xxxxxxxx; tkz=xxxxxxxxxx; token=xxxxxxxxxxx.
That's how I'm sending a post request:
public async Task Bump()
{
//if (Bumpable)
//{
var req = new HttpRequestMessage(HttpMethod.Post, "http://www.csgolounge.com/ajax/bumpTrade.php");
req.Headers.Add("Cookie", cookieString);
req.Headers.Add("X-Requested-With", "XMLHttpRequest");
req.Headers.Add("Referer", "http://csgolounge.com/mytrades"); //Not really sure if this does anything but I've run out of smart ideas long time ago
/*Dictionary<string, string> postData = new Dictionary<string, string>()
{
{"trade", offer_id}
};
var encoded = new FormUrlEncodedContent(postData);
*/
req.Content = new StringContent("&trade="+Offer_id, Encoding.UTF8, "application/x-www-form-urlencoded"); //Desperation.. decided to change the encoded dictionary to StringContent
var res = await SteamAccount.http.SendAsync(req);
var html = await res.Content.ReadAsStringAsync();
//}
}
I don't get what's wrong with this code. It seems correct to me.
Also, when I set AllowAutoRedirect = false it returns 301: Moved Permanently error, while normally it returns 200 with no HTML no matter what I pass as content.
What am I doing wrong?
Edit: Here's the JavaScript function I'm basing my request on:
function bumpTrade(trade) {
$.ajax({
type: "POST",
url: "ajax/bumpTrade.php",
data: "trade=" + trade
});
}
I've worked with more complex AJAX before, but this just doesn't seem to work no matter what I do.
Edit: I've lost my patience and switched to HttpWebRequest instead.
Now the method looks like this:
public async Task BumpLegacy()
{
while (true)
{
try
{
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create("http://csgolounge.com/ajax/bumpTrade.php");
var cc = new CookieContainer();
MatchCollection mc = Regex.Matches(Account.CookieString, #"\s?([^=]+)=([^;]+);");
foreach (Match m in mc)
cc.Add(new Cookie(m.Groups[1].Value, m.Groups[2].Value, "/", "csgolounge.com"));
httpWebRequest.CookieContainer = cc;
byte[] bytes = Encoding.ASCII.GetBytes("trade=" + Offer_id);
httpWebRequest.Referer = "http://csgolounge.com/mytrades";
httpWebRequest.Headers.Add("X-Requested-With", "XMLHttpRequest");
httpWebRequest.Method = "POST";
httpWebRequest.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
httpWebRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36";
httpWebRequest.ContentLength = (long)bytes.Length;
var g = await httpWebRequest.GetRequestStreamAsync();
await g.WriteAsync(bytes, 0, bytes.Count());
g.Close();
var res = await httpWebRequest.GetResponseAsync();
res.Close();
break;
}
catch
{
}
}
}
Maybe I'm just dumb but for me it doesn't seem all that different. Are there some key differences that can be the cause?
Here is code from one of my working systems that submits a POST request through an HTTPClient.
[Route("resource")]
public async Task<dynamic> CreateResource([FromBody]Resource resource)
{
if (resource == null) return BadRequest();
dynamic response = null;
resource.Topic = GetDataFromSomewhereElse();
var message = new PostMessage(resource).BodyContent;
dynamic postRequest = new
{
Message = message
};
var post = JsonConvert.SerializeObject(postRequest);
HttpContent content = new StringContent(post, Encoding.UTF8, "application/json");
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromMinutes(1);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
try
{
client.BaseAddress = #"http://localhost:51145/";
HttpResponseMessage postResponse = await client.PostAsync("Resource", content); //"Resource" is a route exposed on the remote host
string json = await postResponse.Content.ReadAsStringAsync();
if (postResponse.StatusCode == HttpStatusCode.BadRequest) return BadRequest();
if (postResponse.StatusCode == HttpStatusCode.InternalServerError) return InternalServerError();
if (postResponse.StatusCode == HttpStatusCode.NotFound) return NotFound();
return json;
}
catch(Exception ex)
{
return InternalServerError(ex);
}
}
}
[Edit]
The "PostMessage" was modified to remove domain-specific details. Here is how BodyContent is defined inside the real "PostMessage" from my solution, to provide you enough context to understand what that "message" actually is and how it works into the sample.
public string BodyContent
{
get
{
string content = "";
Type type = this.GetType();
Assembly assembly = Assembly.GetExecutingAssembly();
string resource = String.Format("{0}.{1}", type.Namespace, this.EmbeddedResourceName);
Stream stream = assembly.GetManifestResourceStream(resource);
StreamReader reader = new StreamReader(stream);
content = reader.ReadToEnd();
return content;
}
}
...and here is PostRequest (again, with domain-specific details trimmed)
public class PostRequest
{
public string Message { get;set; }
}