I'm using the DropNetRT library and I can't find a way to create a working DropNetClient using just the Generated Access Token from my app page in my Dropbox account.
If I use my User Secret and User Token it works:
public static async Task UploadStuff()
{
DropNetClient client = new DropNetClient("APIKey", "AppSecret");
client.SetUserToken(new UserLogin() { Secret = "mySecret", Token = "myToken" });
// Then upload the data with the client
}
But, instead of my UserToken and UserSecret, I just want to use my Generated Access Token.
It looks something like this, just to be sure:
jfjfDkFkdfikAAAAAAAAAADkfkDJSJFJISjofdjFjjfoJOIDJSOjsFKPFKPEJKfjiksfd3_thD
Now, I tried using a UserLogin with just my Access Token as the Token and without a UserSecret, but the client threw an exception, so I guess that's not the right way to do that.
How can I do that? Is there a way to create a client with the access token with this library, or do I have to upload the file manually using an HttpClient? If so, I really have no idea on how to do that.
Thanks!
Sergio
Edit: this is what I tried (it's not working):
public static async Task TestUploadGeneratedToken()
{
// Create the client
DropNetClient client = new DropNetClient("APIKey", "AppSecret");
client.SetUserToken("MyGeneratedAccessToken", String.Empty);
// Get a test file
StorageFile tempFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("test.txt", CreationCollisionOption.OpenIfExists);
await FileIO.WriteTextAsync(tempFile, "This is a simple test file");
// Convert the file to a byte array
IRandomAccessStream stream = await tempFile.OpenAsync(FileAccessMode.Read);
stream.Seek(0);
byte[] bytes = new byte[stream.Size];
await stream.ReadAsync(bytes.AsBuffer(), (uint)stream.Size, InputStreamOptions.None);
// Upload the file
await client.Upload(CrashReportPath, "tokenTest.txt", bytes);
}
the Upload method throws a DropboxException.
That looks right. Try setting the secret to string.empty instead of null?
I'm not sure if I have used a generated token before but can't see why it wouldn't work.
Related
I'm a complete noob at c# and know very little about azure apis and a current cs student doing a project for work. I built some middleware with youtube tutorials that authenticates a with a storage account using a string connection and it enumerates, uploads, downloads, and deletes blobs within a container. The issue i'm having lies with ONLY the downloading functionality and ONLY when the storage account access is set to private. This function works fine with anon access. I suspect the issue is with appending the url, and I'm not sure how to fix it. The blobs are mainly csv data if that matters. Any help or direction to resources would be greatly appreciated 🙂 here is the relevant code:
url function
public async Task<string> GetBlob(string name, string containerName)
{
var containerClient = _blobClient.GetBlobContainerClient(containerName);
var blobClient = containerClient.GetBlobClient(name);
return blobClient.Uri.AbsoluteUri;
}
The config file
"AllowedHosts": "*",
"BlobConnection" : "<mystringconnection>******==;EndpointSuffix=core.windows.net"
action request
[HttpGet]
public async Task<IActionResult> ViewFile(string name)
{
var res = await _blobService.GetBlob(name, "<mystorageacc>");
return Redirect(res);
}
The reason you are not able to download the blobs from a private container is because you are simply returning the blob's URL from your method without any authorization information. Request to access blobs in a private container must be authorized.
What you would need to do is create a Shared Access Signature (SAS) with at least Read permission and then return that SAS URL. The method you would want to use is GenerateSasUri. Your code would be something like:
public async Task<string> GetBlob(string name, string containerName)
{
var containerClient = _blobClient.GetBlobContainerClient(containerName);
var blobClient = containerClient.GetBlobClient(name);
return blobClient.GenerateSasUri(BlobSasPermissions.Read, DateTime.UtcNow.AddMinutes(5)).Uri.AbsoluteUri;
}
This will give you a link which is valid for 5 minutes from the time of creation and has the permission to read (download) the blob.
If you want to download from the blob service;
public async Task<byte[]> ReadFileAsync(string path)
{
using var ms = new MemoryStream();
var blob = _client.GetBlobClient(path);
await blob.DownloadToAsync(ms);
return ms.ToArray();
}
If you want to download the file byte array from controllers, you can check this;
https://stackoverflow.com/a/3605510/3024129
If you want to set a blob file public access level;
https://learn.microsoft.com/en-us/azure/storage/blobs/anonymous-read-access-configure.
Pay attention to the images please;
Or you can connect with Azure Storage Explorer and choose the easy way.
I found the images on the Google, there may be differences. :)
This worked for me by returning a byte array:
byte[] base64ImageRepresentation = new byte[] { };
BlobClient blobClient = new BlobClient(blobConnectionString,
blobContainerUserDocs,+ "/" + fileName);
if (await blobClient.ExistsAsync())
{
using var ms = new MemoryStream();
await blobClient.DownloadToAsync(ms);
return ms.ToArray();
}
I am running an OAuth Dialog that allows user to sign in. I am looking to get this Auth token from DialogsClass.cs to my Bot.Cs class file and use it to make Graph calls.
I have tried to save token as string in local file within my dialog class and then read it back in main bot class but this solution does not seems as a right way of doing it.
AuthDialog.cs in Waterfall step:
var tokenResponse = (TokenResponse)stepContext.Result;
Expected result. Transfer this token from Dialog class to MainBot.cs class and use as string to make Graph calls.
Are you using one waterfall step to get token with OAuthPrompt and then another step to call a different class (in which you do graph api calls)?
Why can't you just pass the token to the down stream class?
If there are other steps in the middle, there are multiple ways to resolve it:
Use WaterfallStepContext Values
Save to your own UserState
Microsoft suggests not to store token in the system but make a call to oAuth prompt
return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);
and get latest token whenever you have to call Graph API. Once you receive the token in var tokenResponse = (TokenResponse)stepContext.Result;
you can make a call to GraphClient class which will create the Graph API client using the token in Authorization attribute.
var client = new GraphClientHelper(tokenResponse.Token);
Graph Client implementation:
public GraphClientHelper(string token)
{
if (string.IsNullOrWhiteSpace(token))
{
throw new ArgumentNullException(nameof(token));
}
_token = token;
}
private GraphServiceClient GetAuthenticatedClient()
{
var graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
requestMessage =>
{
// Append the access token to the request.
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", _token);
// Get event times in the current time zone.
requestMessage.Headers.Add("Prefer", "outlook.timezone=\"" + TimeZoneInfo.Local.Id + "\"");
return Task.CompletedTask;
}));
return graphClient;
}
Once graph client is created you can make a call to the intended graph api:
await client.CreateMeeting(meetingDetails).ConfigureAwait(false);
Please refer this sample code:
Graph Sample
I'm developing a website with ASP.NET MVC 5 + Web API. One of the requirements is that users must be able to download a large zip file, which is created on the fly.
Because I immediately want to show progress of the user, my idea was to use a PushStreamContent with a callback in the resonse. The callback creates the zipfile and streams it to the response.
When I implement this as follows, starting from an empty ASP.NET MVC + Web API project, it works as expected. As soon as the result is returned to the client, the callback gets invoked and
the zipfile is streamed to the client. So the user can see progress as soon as the callback creates the zip archive and add files to it.
[RoutePrefix("api/download")]
public class DownloadController : ApiController
{
[HttpGet]
public HttpResponseMessage Get()
{
var files = new DirectoryInfo(#"c:\tempinput").GetFiles();
var pushStreamContent = new PushStreamContent(async (outputStream, httpContext, transportContext) =>
{
using (var zipOutputStream = new ZipOutputStream(outputStream))
{
zipOutputStream.CompressionLevel = CompressionLevel.BestCompression;
foreach (var file in files)
{
zipOutputStream.PutNextEntry(file.Name);
using (var stream = File.OpenRead(file.FullName))
{
await stream.CopyToAsync(zipOutputStream);
}
}
}
});
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = pushStreamContent
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment") {FileName = "MyZipfile.zip"};
return response;
}
}
Now, I have to integrate this in an existing website, which is configured to use Microsoft.Owin.OwinMiddleware. I used the same code as pasted above, but now the behavior is different: during the creation of the zipfile, it 's not streamed to the response, but only downloaded when the creation of the zip has finished. So the user doesn't see any progress during the creation of the file.
I also tried a different approach in my Web API + Owin project, as described here: (generate a Zip file from azure blob storage files).
In an empty Asp.NET MVC project (without OWIN middleware), this works exactly as expected, but when OWIN is involved, I get this HTTPException and stacktrace:
System.Web.HttpException: 'Server cannot set status after HTTP headers have been sent.'
System.Web.dll!System.Web.HttpResponse.StatusCode.set(int value) Unknown
System.Web.dll!System.Web.HttpResponseWrapper.StatusCode.set(int value) Unknown
Microsoft.Owin.Host.SystemWeb.dll!Microsoft.Owin.Host.SystemWeb.OwinCallContext.Microsoft.Owin.Host.SystemWeb.CallEnvironment.AspNetDictionary.IPropertySource.SetResponseStatusCode(int value) Unknown
It seems that OWIN wants to set a response status, although that was already done in my Get() method (HttpResponseMessage(HttpStatusCode.OK)).
Any suggestions how to fix this or ideas for a different approach?
Thanks a lot!
I am currently trying to allow a user to upload a file to the bot during a dialog flow. From there the bot will take the file and upload it to blob storage. When the file comes in the content property is null, however the content url, name, and type all have the correct values.
public virtual async Task StackTraceGathered(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
var message = await argument;
FileName = message.Attachments[0].Name;
HttpPostedFileBase file = (HttpPostedFileBase)message.Attachments[0].Content;
string filePath = HttpContext.Current.Server.MapPath("~/Files/" + file.FileName);
file.SaveAs(filePath);
if (message.Attachments != null && message.Attachments.Any())
{
var attachment = message.Attachments.First();
using (HttpClient httpClient = new HttpClient())
{
// Skype & MS Teams attachment URLs are secured by a JwtToken, so we need to pass the token from our bot.
if ((message.ChannelId.Equals("skype", StringComparison.InvariantCultureIgnoreCase) || message.ChannelId.Equals("msteams", StringComparison.InvariantCultureIgnoreCase))
&& new Uri(attachment.ContentUrl).Host.EndsWith("skype.com"))
{
var token = await new MicrosoftAppCredentials().GetTokenAsync();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
var responseMessage = await httpClient.GetAsync(attachment.ContentUrl);
var contentLenghtBytes = responseMessage.Content.Headers.ContentLength;
await context.PostAsync($"Attachment of {attachment.ContentType} type and size of {contentLenghtBytes} bytes received.");
}
}
else
{
await context.PostAsync("Hi there! I'm a bot created to show you how I can receive message attachments, but no attachment was sent to me. Please, try again sending a new message including an attachment.");
}
PromptDialog.Text(context, ProblemStartDuration, "How long has this been an issue? (Provide answer in days, if issue has been occurring for less than one day put 1).");
context.Wait(this.StackTraceGathered);
}
I don't see the issue, but I guess you are expecting the Content property to have something. It won't but you just need the Url. Two alternatives:
Download the attachment in the bot (as the code you are using in the question) and upload to blob storage
Try to upload the attachment directly from the Url using something like StartCopyFromBlob (check this)
Hi guys im trying to use dropnet as means to be using dropbox as a cloud storage for my application, and following the 3 step process using the normal 0auth
1.Get Request Token[done]
2.Send user for authorization, and get back verifier[done]
3.Get Access token using the original Request Token and the verifier[issue!]
if i understand the api correctly since i want to use a single account for my storage i need api key,api secret,token and secret.the token and secret seems to be accessible from the third steps and its my trouble.
from the second step i get this url
https://www.dropbox.com/1/oauth/authorize?oauth_token=xxxxxxxxxx
before pressing authenticate to allow my app to use dropbox
from the documentation i read that you need to use this method
UserLogin GetAccessToken(string code, string redirectUri);
i am assuming here xxxxx is the string code
to validate that is the original
so i made code as follows
var accessToken = client.GetAccessToken("xxxxxxx","https://www.dropbox.com/1/oauth/authorize?oauth_token=xxxxxxxxxx);
var ats =accessToken.Secret;
var att = accessToken.Token;
Console.Writeline(ats);
Console.Writeline(att):
in hopes of getting the console to print my secret and token for my acct but it dosent work ?Giving me the error of
An unhandled exception of type 'DropNet.Exceptions.DropboxRestException' occurred in DropNet.dll
help please !
Solved the problem myself,here is the full code
DropNetClient client = new DropNetClient(variable.ApiKey, variable.ApiSecret);
]
var response =client.GetToken();
var t = response.Token;
var s = response.Secret;
Console.WriteLine(s);
Console.WriteLine(t);
var authorizeUrl = client.BuildAuthorizeUrl(new DropNet.Models.UserLogin
{
Secret = s,
Token = t
}
);
DropNetClient client2= new DropNetClient(variable.ApiKey, variable.ApiSecret,t,s);
// Prompt for user to auth
Process.Start(authorizeUrl);
// PRESS KEY AFTER authorization AFTER
Console.ReadKey();
// If the user authed, let's get that token
try
{
var Token = client2.GetAccessToken();
var userToken = Token.Token;
var userSecret = Token.Secret;
Console.WriteLine(userSecret);//ACCESS TOKEN SECRET
Console.WriteLine(userToken);//ACCESS TOKEN
Console.ReadKey();
}
catch (Exception e)
{
Console.WriteLine("Exception! " + e.Message);
Console.ReadKey();
}
// save for later