Unable to create a shared link using the Box API V2 - c#

UPDATE: I figured it out and posted the answer below.
All I'm trying to do is update any file attribute. Description, name, anything, but no matter how I format it I get a 403.
I need to be able to modify a file so it can be shared via the Box API from a cloud app. I'm updating someone else's code from V1, but they are no longer available... I've tried many things but mostly just get 403 Forbidden errors.
There are no issues with OAuth2, that works fine and I can list files and folders, but can not modify them. This question is about sharing, but I can't change a description either. The box account is mine and I authenticate with my admin credentials. Any suggestions would be appreciated.
Here is the method I am using. I pass in the fileId and token and I've left out try/catch etc. for brevity.
string uri = string.Format("https://api.box.com/2.0/files/{0}", fileId);
string body = "{\"shared_link\": {\"access\": \"open\"}}";
byte[] postArray = Encoding.ASCII.GetBytes(body);
using (var client = new WebClient())
{
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
client.Headers.Add("Authorization: Bearer " + token);
var response = client.UploadData(uri, postArray);
var responseString = Encoding.Default.GetString(response);
}
Thanks.

Okay, My Homer Simpson moment...
UploadData is a POST, I needed to do a PUT. Here is the solution.
string uri = String.Format(UriFiles, fileId);
string response = string.Empty;
string body = "{\"shared_link\": {\"access\": \"open\"}}";
byte[] postArray = Encoding.ASCII.GetBytes(body);
try
{
using (var client = new WebClient())
{
client.Headers.Add("Authorization: Bearer " + token);
client.Headers.Add("Content-Type", "application/json");
response = client.UploadString(uri, "PUT", body);
}
}
catch (Exception ex)
{
return null;
}
return response;

try changing your content type to 'multipart/form-data'?
I just looked up the api at: https://developers.box.com/docs/#files-upload-a-file
and it looks like the server is expecting a multipart post
here is stack overflow post on posting multipart data:
ASP.NET WebApi: how to perform a multipart post with file upload using WebApi HttpClient

Related

Bing Webmaster Tools API OAuth code exchange issues, changes?

This is part of a desktop application.
Based on https://learn.microsoft.com/en-us/bingwebmaster/oauth2
The following code to exchange the authorization code for the access and refresh tokens was working as of a few months ago...
try
{
HttpWebRequest req = WebRequest.CreateHttp("https://www.bing.com/webmasters/oauth/token");
req.Method = WebRequestMethods.Http.Post;
req.ContentType = "application/x-www-form-urlencoded";
StringBuilder content = new StringBuilder();
content.AppendFormat("code={0}&", Uri.EscapeDataString(code));
content.AppendFormat("client_id={0}&", Uri.EscapeDataString(clientId));
content.AppendFormat("client_secret={0}&", Uri.EscapeDataString(clientSecret));
content.AppendFormat("redirect_uri={0}&", Uri.EscapeDataString(redirectUri));
content.AppendFormat("grant_type={0}", Uri.EscapeDataString("authorization_code"));
var data = Encoding.ASCII.GetBytes(content.ToString());
using (var stream = await req.GetRequestStreamAsync())
{
await stream.WriteAsync(data, 0, data.Length);
}
string json;
using (var res = await req.GetResponseAsync())
{
using (var stream = res.GetResponseStream())
using (var sr = new StreamReader(stream))
{
json = await sr.ReadToEndAsync();
}
}
if (!string.IsNullOrWhiteSpace(json))
{
tokenResponse = JsonConvert.DeserializeObject<TokenResponse>(json);
}
}
catch (WebException wex)
{
using (var stream = wex.Response.GetResponseStream())
using (var sr = new StreamReader(stream))
{
var t = await sr.ReadToEndAsync();
}
}
catch (Exception ex)
{
}
However, await req.GetResponseAsync() now returns
400 Bad Request, Origin and Referer request headers are both
absent/empty
I tried adding req.Referer = redirectUri; and then it returns
400 Bad Request, Could not extract expected anti-forgery token
I've tried passing a random state parameter to the authorization endpoint, and received the same in the callback. I've both included it in, and excluded it from, the token exchange with no change in the above results.
I'm not an OAuth expert, but I've done a few integrations and I haven't seen this before.
The user grants authorization via a Window with a WebView2 control, which returns the code. This part still works well. I did some quick poking around in the response to see if anything related to anti-forgery/CSRF was being returned from the server, but I didn't notice anything. And anyway, the documentation hasn't change regarding what is needed to request the tokens so everything is basically trial and error at this point.
So my question is, if you have seen this referer/anti-forgery problem in any OAuth implementation how did you fix it or work around it? Or if you're using a Bing Webmaster Tools API solution (custom or otherwise) is it still working?
Beyond that, I'm open to ideas and I appreciate your time.

Translating RestSharp request to HttpClient request

I'm programmatically uploading files to a remote server. The files are moderately large and I'd like to present a progress report to my users so they can see something happening. I was able to implement the upload using Postman which helpfully translated the whole thing to RestSharp.
But RestSharp does not provide any kind of progress tracking. I tried to implement the same functionality using HttpClient but it goes wrong somewhere the and server just throws a "400 - Bad Request" without telling exactly what is bad about it (its API documentation is also not for the faint of heart).
So, here's what Postman / RestSharp provide and which is working:
var client = new RestClient("https://opencast/ingest/addMediaPackage");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Basic FooBarBaz=");
request.AddParameter("creator", file.Creator);
request.AddParameter("title", file.Title);
request.AddParameter("flavor", "presentation/source");
request.AddParameter("description", file.Description);
try
{
request.AddFile("BODY", path);
IRestResponse response = await client.ExecuteAsync(request);
_logger.LogInformation($"Response after file upload: {response.StatusCode}");
File.Delete(path);
}
catch (Exception ex)
{
_logger.LogError(ex, "Exception when uploading files: {Message}", ex.Message);
}
and here's what I tried to do with HttpClient (without try-catch):
var request = new HttpRequestMessage(HttpMethod.Post, $"https://opencast/ingest/addMediaPackage");
request.Headers.Add("Authorization", "Basic FooBarBaz=");
using var form = new MultipartFormDataContent();
using var fileContent = new ByteArrayContent(await File.ReadAllBytesAsync(path));
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
form.Add(fileContent, "BODY", Path.GetFileName(path));
form.Add(new StringContent(file.Creator), "creator");
form.Add(new StringContent(file.Title), "title");
form.Add(new StringContent("presentation/source"), "flavor");
form.Add(new StringContent(file.Description), "description");
request.Content = form;
var client = clientFactory.CreateClient(); //which is a IHttpClientFactory
var response = await client.SendAsync(request);
This code sends the file to the server which, after completing the upload, throws a 400.
Currently not seeing the difference. I could intercept the requests to see where they differ but maybe someone here can see the problem right away?
Update: It gets weirder. If I just use clientFactory.PostAsync(form) and add the Auth headers through form.Add then I get a 200 (i.e. Success) but the server simply swallows the file.
Okay, I found the solution. I'm not sure whether the WTF is me or the guys behind the server but...
... you need to add the fileContent last.
Yes, the order of the parameters matters for this.

API PUT /marketing/contacts/imports with restsharp

Due to internal reason, I need to recode my servlet from Java to c#.
I am trying to upload a CSV file using the API PUT /marketing/contacts/imports with restsharp.
I cannot manage to send the file properly.
Code Snippet
Please fine below my java piece of code working:
File file = new File(CSV);
byte[] data;
try {
data = Files.readAllBytes(file.toPath());
HttpResponse<String> response2 = Unirest.put(URLSengrid)
.header(processSendgridHeader(headerFromSengrid).get(0), processSendgridHeader(headerFromSengrid).get(1))
//("x-amz-server-side-encryption", "aws:kms")
.body(data)
.asString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
And here the non working c# code:
byte[] file = System.IO.File.ReadAllBytes(testPath);
var clientSecondCall = new RestClient(URLSendgrid);
var requestSecondCall = new RestRequest(Method.PUT);
requestSecondCall.AddHeader("content -type", "application/json");
requestSecondCall.AddHeader("x-amz-server-side-encryption", "aws:kms");
requestSecondCall.AddParameter("application/json", "{"file_type":"csv","field_mappings":["e1_T","e2_T","_rf2_T","e4_T","e5_T","e12_T","e13_T","e14_T","e15_T","e16_T"]}", ParameterType.RequestBody);
requestSecondCall.AddFile("file", file, testPath);
I spent a long time looking for an answer without success. Any help would be appreciated
Technical details:
sendgrid-csharp version: 9.*
csharp version: v4.0.303190
I believe the problem is the way you send the file in your c# code.
The Java code is clearly using the Body of the request, while the c# code is using RestSharp.
Restsharp is sending files in as a Multipart form, which your server is probably not qualified to handle.
I would recommend using HttpClient object:
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage();
request.Method = HttpMethod.Put;
request.RequestUri = new Uri( "Your Url");
request.Content = new StringContent(File.ReadAllText(yourFilePath));
request.Headers.Add("your header name", "your header value");
var response = client.SendAsync(request).Result;

get slack channel history in .net web api

I have fetch channel history in my .Net Web API.
The slack reference https://api.slack.com/methods/channels.history it states that we need to post the request.
Please if someone could help me with the code.
Part of Code I have implemented:
#region create json payload to send to slack
GetLatestMessage payload = new GetLatestMessage()
{
channel = "###",//value.channel_name,
token = "############################"//added the token i have generated
// user_name = value.user_name,
//text = value.text
};
#endregion
string payloadJson = JsonConvert.SerializeObject(payload);
using (WebClient client = new WebClient())
{
NameValueCollection data = new NameValueCollection();
data["payload"] = payloadJson;
var response = client.UploadValues("https://slack.com/api/channels.history", "POST", data);
//The response text is usually "ok"
string responseText = _encoding.GetString(response);
LogFileWriter("response=" + responseText);
return Request.CreateResponse(HttpStatusCode.OK);
}
I figured out the issue I was facing.I was trying to sent the post json data in to Slack url. However The Slack Web API doesn't accept JSON data.Now when I post data using standard HTTP form attributes it accepts and returns proper response.
New code:
var response = client.UploadValues("https://slack.com/api/channels.history", "POST", new NameValueCollection() {
{"token","###################"},
{"channel","######"}});
//The response text is usually "ok"
string responseText = _encoding.GetString(response);
LogFileWriter("response=" + responseText);
return Request.CreateResponse(HttpStatusCode.OK);
}

Upload file via POST call with C#, RestSharp, Redmine API

I'm developing a C# app that uses Redmine REST API, it uses RestSharp Client. All other REST calls I make work fine but I cannot find a way to upload attachments. I've widely searched the web and tried many solutions but nothing worked.
Redmine documentiation on attachments: http://www.redmine.org/projects/redmine/wiki/Rest_api#Attaching-files
The code actually looks like:
RestClient client = new RestClient("http://myclient/redmine/");
client.Authenticator = new HttpBasicAuthenticator("myuser", "mypsw");
var request2 = new RestRequest("uploads.json", Method.POST);
request2.AddHeader("Content-Type", "application/octet-stream");
request2.RequestFormat = RestSharp.DataFormat.Json;
byte[] dataToSend = File.ReadAllBytes(AddIssue.attach.Text);
request2.AddBody(dataToSend);
IRestResponse response2 = client.Execute(request2);
resultbox.Text = response2.Content;
If I execute it above nothing happens and the response is empty. If I remove line 7 (the AddBody), it actually works but of course nothing is uploaded, JSON response:
{
"upload": {
"token": "11."
}
}
So actually, the real question is what to punt in AddBody() to send the file as application/octet-stream. Since RestSharp also has a request.AddFile() method, I tried it too in different ways but nothing...
Any help much appreciated!
As I mentioned in my comment, it sounds like Redmine might have requirements similar to Dropbox. Here is the solution that worked for me (based on the question Upload to dropbox using Restsharp PCL):
public static void UploadFileToDropbox(string filePath)
{
RestClient client = new RestClient("https://api-content.dropbox.com/1/");
IRestRequest request = new RestRequest("files_put/auto/{path}", Method.PUT);
FileInfo fileInfo = new FileInfo(filePath);
long fileLength = fileInfo.Length;
request.AddHeader("Authorization", "Bearer INSERT_DEVELOPER_TOKEN_HERE");
request.AddHeader("Content-Length", fileLength.ToString());
request.AddUrlSegment("path", string.Format("Public/{0}", fileInfo.Name));
byte[] data = File.ReadAllBytes(filePath);
var body = new Parameter
{
Name = "file",
Value = data,
Type = ParameterType.RequestBody,
};
request.Parameters.Add(body);
IRestResponse response = client.Execute(request);
}
Also published as a Gist.
I know this isn't your exact situation, but hopefully it gives you some ideas.

Categories