cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Announcements
What’s new: end-to-end encryption, Replay and Dash updates. Find out more about these updates, new features and more here.

Dropbox API Support & Feedback

Find help with the Dropbox API from other developers.

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Integrate Dropbox with .Net Core 6 web application

Integrate Dropbox with .Net Core 6 web application

dhodges351
Explorer | Level 4

Dear Community Experts,

 

I have created a .NET Core 6 web application for my husband's stamp collecting hobby [SNIP] and I would like to  display some of his stamp images in the application from his Dropbox folder "Gourmet Philatelist". I went through all the samples in the .NET SDK for Dropbox in my Dropbox Api Test application, but I cannot get it to work in the stamp collecting web application. Here are the results of my attempts:


1. Using PKCEOAuthFlow();
var OAuthFlow = new PKCEOAuthFlow();
var redirect = OAuthFlow.GetAuthorizeUri(OAuthResponseType.Code,
AppKey,
RedirectUri.ToString(),
state: state,
tokenAccessType: TokenAccessType.Offline,
scopeList: scopeList,
includeGrantedScopes: IncludeGrantedScopes.None);


AcquireAccessToken: blows up trying to process the authorizeUri. I have tried registering many,  many, different redirect urls using localhost with different ports like (https://localhost:7184/authorize and https://localhost:7184/gallery/auth) in the App center, but I cannot get it to work. (There is a file in the web application "index.html" like in the PKCEOAuthFlow sample).  I also have the handler methods in the code.


// var state = Guid.NewGuid().ToString("N");
// var OAuthFlow = new PKCEOAuthFlow();
// var authorizeUri = OAuthFlow.GetAuthorizeUri(OAuthResponseType.Code, AppKey, null, state: state, tokenAccessType: TokenAccessType.Offline, scopeList: scopeList, includeGrantedScopes: includeGrantedScopes);
// var http = new HttpListener();
// http.Prefixes.Add(LoopbackHost);
// http.Start();
// System.Diagnostics.Process.Start(authorizeUri.ToString());  BLOWS UP HERE
// // Handle OAuth redirect and send URL fragment to local server using JS.
// await HandleOAuth2Redirect(http);
// // Handle redirect from JS and process OAuth response.
// var redirectUri = await HandleJSRedirect(http);
// Console.WriteLine("Exchanging code for token");
// var tokenResult = await OAuthFlow.ProcessCodeFlowAsync(redirectUri, AppKey, RedirectUri.ToString(), state);
// Console.WriteLine("Finished Exchanging Code for Token");


2.) Using PKCEOAuthFlow() with /Gallery/Auth redirect Url instead of url fragment in the index.html file.
I do get the AccessToken and the RefreshToken, but when I call dbx.Sharing.CreateSharedLinkWithSettingsAsync using the RefreshToken I get an error saying it is an invalid token.
 
3.) Tried again using DropboxOAuth2Helper  - BLOWS UP HERE: SaveGalleryItem() - await dbx.Sharing.CreateSharedLinkWithSettingsAsync 
ERROR: Invalid Grant
private string RedirectUri
{
get
{
var host = _httpContextAccessor.HttpContext.Request.Host;
var port = _httpContextAccessor.HttpContext.Request.Host.Port;
if (host.Host.ToLower(CultureInfo.InvariantCulture) == "localhost")
{
return "https://localhost:7184/Gallery/Auth";
}
var builder = new UriBuilder(
Uri.UriSchemeHttps,
host.Host);
builder.Path = "/Gallery/Auth";
return builder.ToString();
}
}


var state = Guid.NewGuid().ToString("N");
string[] scopeList = new string[4] { "files.metadata.read", "files.content.read", "sharing.read", "sharing.write" };
var redirect = DropboxOAuth2Helper.GetAuthorizeUri(OAuthResponseType.Code,
AppKey,
RedirectUri,
state: state,
tokenAccessType: TokenAccessType.Offline,
scopeList: scopeList,
includeGrantedScopes: IncludeGrantedScopes.None);
return Redirect(redirect.ToString());


[Authorize]
public async Task<ActionResult> AuthAsync(string code, string state)
{
try
{
var response = await DropboxOAuth2Helper.ProcessCodeFlowAsync(
code,
AppKey,
AppSecret,
RedirectUri);


TempData["AuthToken"] = response.AccessToken;
TempData["TokenExpires"] = response.ExpiresAt;
TempData["RefreshToken"] = response.RefreshToken;
_refreshToken = response.RefreshToken;
string? refUrl = TempData["Referrer"]?.ToString();
string? galleryItemId = TempData["GalleryItemId"]?.ToString();
if (!string.IsNullOrEmpty(refUrl) && refUrl.Contains("Add"))
{
return RedirectToAction("AddGalleryItem", "Gallery");
}
else if (!string.IsNullOrEmpty(refUrl) && refUrl.Contains("Edit"))
{
return RedirectToAction("EditGalleryItem", "Gallery", new { galleryItemId = galleryItemId });
}
return RedirectToAction("Index", "Home");
}
catch (Exception e)
{
var message = e.Message;
return RedirectToAction("Index");
}
}


SaveGalleryItem() - blows up on this call: await dbx.Sharing.CreateSharedLinkWithSettingsAsync 
error: Invalid Grant
if (TempData != null && TempData.ContainsKey("RefreshToken"))
{
refreshToken = TempData["RefreshToken"]?.ToString();
}
using (var dbx = new DropboxClient(refreshToken))
{
var sharedLinkUrl = string.Empty;
var sharedLink = await dbx.Sharing.CreateSharedLinkWithSettingsAsync($"/Gourmet Philatelist/{ItemUrl}");

//(ItemUrl is the file name in the Dropbox folder).


if (sharedLink != null)
{
sharedLinkUrl = sharedLink.Url;
model.ImageUrl = sharedLinkUrl.Replace("dl=0", "raw=1");
}
}


I have been trying to do this for 3 days now with no success. I emailed Dropbox Support and they told me to try to find help in the Dropbox Community. Any help you can provide is greatly appreciated. Thank you.


Best Regards,
Debra Hodges for Bob Hodges Dropbox

 

1 Accepted Solution

Accepted Solutions

Greg-DB
Dropbox Staff

From the code you shared, it looks like you're working from the OAuthPKCE example included with the .NET SDK. That's meant as an example of a client-side application though. Since you're building a server-side web app, the SimpleBlogDemo example would be more relevant.

 

I suggest running that SimpleBlogDemo example as provided first to see how that works. There's setup instructions here, but I suggest not otherwise modifying that code to make sure that example runs successfully for you. Once you have that working as an example, use that as a reference for building your web app.

 

If either the example or your app aren't working, please print out and share the exact/entire error output and the corresponding piece of code.

View solution in original post

2 Replies 2

Greg-DB
Dropbox Staff

From the code you shared, it looks like you're working from the OAuthPKCE example included with the .NET SDK. That's meant as an example of a client-side application though. Since you're building a server-side web app, the SimpleBlogDemo example would be more relevant.

 

I suggest running that SimpleBlogDemo example as provided first to see how that works. There's setup instructions here, but I suggest not otherwise modifying that code to make sure that example runs successfully for you. Once you have that working as an example, use that as a reference for building your web app.

 

If either the example or your app aren't working, please print out and share the exact/entire error output and the corresponding piece of code.

dhodges351
Explorer | Level 4

Greg - Thank you so much for answering my post and for the great tips you gave for how to get my .NET Core 6 web application to work with Dropbox client. I finally accomplished it by using the SimpleBlogDemo example as you suggested. I added a Dropbox Chooser control and some code to check the expiration date of the online token and regenerate the token if it was expired. Below is the code which worked that created shared urls for displaying Dropbox images in the views. 

_GalleryLayout: 

<script>
var options = {

// Required. Called when a user selects an item in the Chooser.
success: function(files) {
//console.log("Here's the file link: " + files[0].link)
//console.log("Here's the file name: " + files[0].name)
$("#ItemUrl").val(files[0].name);
},

 

Add/Edit Views - 

<div style="display:none;">
<input id="ItemUrl" name="ItemUrl">
@Html.ActionLink(
linkText: "Connect",
actionName: "Connect",
routeValues: new { referrer = "Add", galleryItemId = 0 },
htmlAttributes: new { @ID="btnConnect", @Class = "btn btn-lg btn-primary" })
</div>

@IF (!TempData.ContainsKey("TokenOk"))
{
<script type="text/javascript">
document.getElementById("btnConnect").click();
</script>
}

Gallery Controller -

public IActionResult Connect(string referrer, string galleryItemId)
{
TempData["Referrer"] = referrer;
TempData["GalleryItemId"] = galleryItemId;
Uri redirect = null;

string? authToken = TempData["AuthToken"]?.ToString();
if (!TempData.ContainsKey("AuthToken") || string.IsNullOrEmpty(authToken))
{
redirect = GetDropboxAuthUrl();

return Redirect(redirect.ToString());
}

if (TempData.ContainsKey("TokenExpires"))
{
string? tokenExpires = TempData["TokenExpires"]?.ToString();
CultureInfo culture = new CultureInfo("en-US");
DateTime? tempDate = Convert.ToDateTime(tokenExpires, culture);
if (!tempDate.HasValue || tempDate.HasValue && DateTime.Now > tempDate)
{
redirect = GetDropboxAuthUrl();

return Redirect(redirect.ToString());
}
}

TempData["TokenOk"] = true;
TempData.Keep("TokenOk");

if (referrer == "Add")
{
return RedirectToAction("AddGalleryItem", "Gallery");
}
else
{
return RedirectToAction("EditGalleryItem", "Gallery", new { galleryItemId = galleryItemId});
}
}

public Uri GetDropboxAuthUrl()
{
var state = Guid.NewGuid().ToString("N");
string[] scopeList = new string[4] { "files.metadata.read", "files.content.read", "sharing.read", "sharing.write" };

var redirect = DropboxOAuth2Helper.GetAuthorizeUri(OAuthResponseType.Code,
AppKey,
RedirectUri,
state: state,
tokenAccessType: TokenAccessType.Online,
scopeList: scopeList,
includeGrantedScopes: IncludeGrantedScopes.None);

return redirect;
}

[Authorize]
public async Task<ActionResult> AuthAsync(string code, string state)
{
try
{
var response = await DropboxOAuth2Helper.ProcessCodeFlowAsync(
code,
AppKey,
AppSecret,
RedirectUri);

TempData["AuthToken"] = response.AccessToken;
TempData["TokenExpires"] = response.ExpiresAt;

string? refUrl = TempData["Referrer"]?.ToString();
string? galleryItemId = TempData["GalleryItemId"]?.ToString();

if (!string.IsNullOrEmpty(refUrl) && refUrl.Contains("Add"))
{
return RedirectToAction("AddGalleryItem", "Gallery");
}
else if (!string.IsNullOrEmpty(refUrl) && refUrl.Contains("Edit"))
{
return RedirectToAction("EditGalleryItem", "Gallery", new { galleryItemId = galleryItemId });
}

return RedirectToAction("Index", "Home");
}
catch (Exception e)
{
var message = e.Message;
return RedirectToAction("Index");
}
}

SaveGalleryItem method

[Authorize]
[HttpPost]
public async Task<IActionResult> SaveGalleryItem(GalleryItemModel model)
{
if (TempData.ContainsKey("Referrer") && TempData["Referrer"].ToString().Contains("Add"))
{
model.GalleryItemSequenceId = model.GetLastGalleryItemSequenceId(_galleryItemService, model.CategoryId) + 1;
if (model.GalleryItemSequenceId == 0)
{
model.GalleryItemSequenceId = 1;
}
}

if (Upload != null)
{
if (User.Identity.IsAuthenticated)
{
var fileName = Upload.FileName;

var file = Path.Combine(_environment.WebRootPath, "assets\\images", Upload.FileName);

using var fileStream = new FileStream(file, FileMode.Create);
await Upload.CopyToAsync(fileStream);
if (model.CategoryId == 4)
{
if (!string.IsNullOrEmpty(model.ImageUrl))
{
model.ImageUrl += ",assets/images/" + fileName;
}
else
{
model.ImageUrl = "assets/images/" + fileName;
}
}
else
{
model.ImageUrl = "assets/images/" + fileName;
}
}
}
else
{
if (!string.IsNullOrEmpty(ItemUrl))
{
model.ImageUrl = ItemUrl;
}
}

if (User.Identity.IsAuthenticated)
{
var authToken = string.Empty;

if (TempData != null && TempData.ContainsKey("AuthToken"))
{
authToken = TempData["AuthToken"]?.ToString();
}

if (!string.IsNullOrEmpty(authToken) && !string.IsNullOrEmpty(ItemUrl) && !ItemUrl.Contains("https"))
{
using (var dbx = new DropboxClient(authToken))
{
var sharedLinkUrl = string.Empty;
var sharedLink = await dbx.Sharing.CreateSharedLinkAsync($"/Gourmet Philatelist/{ItemUrl}");
if (sharedLink != null)
{
sharedLinkUrl = sharedLink.Url;
model.ImageUrl = sharedLinkUrl.Replace("dl=0", "raw=1");
}
}
}
await model.AddUpdateGalleryItem(_galleryItemService, _categoryItemService, model);
}

if (TempData != null && TempData.ContainsKey("TokenOk"))
{
TempData.Remove("TokenOk");
}

return RedirectToAction("ManageGalleryItems", "Gallery");
}

 

Need more support?
Who's talking

Top contributors to this post

  • User avatar
    dhodges351 Explorer | Level 4
  • User avatar
    Greg-DB Dropbox Staff
What do Dropbox user levels mean?