I have written a small method that uploads files on Dropbox and that method is working absolutely fine but the issue is how can I get the URL of the uploaded image so that I hit that URL on browser and it shows me the image.
Here is the code of uploading files:
public static async Task Run()
{
var accessToken = ConfigurationManager.AppSettings["DropBoxAccessToken"];
using (var dbx = new DropboxClient(accessToken))
{
//var full = await dbx.Users.GetCurrentAccountAsync();
await Upload(dbx, "/Test", "Test Image.jpg");
}
}
static async Task Upload(DropboxClient dbx, string folder, string file)
{
var readContent = System.IO.File.ReadAllBytes(#"D:\Images\IMG_20161127_204200968.jpg");
using (var mem = new MemoryStream(readContent))
{
var updated = await dbx.Files.UploadAsync(
folder + "/" + file,
WriteMode.Overwrite.Instance,
body: mem);
var mediaInfo = updated.MediaInfo;
}
}
I have tried to get details of uploaded image by hovering on var updated but didn't get the URL.
Any help?
To get a link to a file via the Dropbox API, you have two options:
GetTemporaryLinkAsync: this returns a temporary link, but isn't meant for being displayed in the browser directly.
CreateSharedLinkWithSettingsAsync: this returns a shared link that points to a preview page for the file that can be displayed in the browser.
Related
Using DynamicPDF's Cloud API, instead of generating a pdf back to the local file system, I would like it to directly open in another browser tab to be available for printing immediately. How do I accomplish that?
The method I am using (.NET Core 6 / Blazor) is below:
public async Task CallDynPDFCloudAPI()
{
var basePath = #"JSONFiles\";
var apiKey = "foo";
var cloudPath = "bar.dlex";
Pdf pdf = new Pdf();
pdf.ApiKey = apiKey;
LayoutDataResource layoutDataResource = new LayoutDataResource(basePath + "FooBar.json");
pdf.AddDlex(cloudPath, layoutDataResource);
PdfResponse pdfResponse = pdf.Process();
if (pdfResponse.IsSuccessful)
{
File.WriteAllBytes(basePath + "Manifest_" + manifestBranch + ".pdf", pdfResponse.Content);
}
else
{
Console.WriteLine(pdfResponse.ErrorJson);
}
}
Reread article on https://learn.microsoft.com/en-us/aspnet/core/blazor/file-downloads?view=aspnetcore-6.0
#page "/file-download-1"
#using System.IO
#inject IJSRuntime JS
<h1> File Download Example</h1>
<button #onclick = "DownloadFileFromStream" >
Download File From Stream
</button>
#code {
private Stream CallDynPDFCloudAPI()
{
var basePath = #"JSONFiles\";
var apiKey = "foo";
var cloudPath = "bar.dlex";
Pdf pdf = new Pdf();
pdf.ApiKey = apiKey;
LayoutDataResource layoutDataResource = new LayoutDataResource(basePath + "FooBar.json");
pdf.AddDlex(cloudPath, layoutDataResource);
PdfResponse pdfResponse = pdf.Process();
if (pdfResponse.IsSuccessful)
{
return new MemoryStream(pdfResponse.Content);
}
else
{
throw new Exception("");
}
}
private async Task DownloadFileFromStream()
{
var fileStream = CallDynPDFCloudAPI();
var fileName = "file.pdf";
using var streamRef = new DotNetStreamReference(stream: fileStream);
await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
}
}
You won't be able to access the PDF content for this request from another browser tab. I'd recommend opening the new tab before making the call and then streaming it there. If you're using an 'a href' link, you can accomplish this by setting the 'target="_blank"' property of the 'a href'. If this is a form submission, you can set the 'target="_blank"' property of the 'form'.
The other option would be to store the PDF somewhere temporarily (as a file, in a DB or in BLOB storage) then stream it to the other tab once it's opened.
Ive impletented #Mihal's answer, with modified code suggested by #DynamicPDF to achieve the result I was looking for. My two goals were:
Not clutter the client device with excessive dowloaded files
Not needing to save the file in Server or DB
Javascript:
<script>
window.downloadFileFromStream = async (fileName,
contentStreamReference) => {
const arrayBuffer = await contentStreamReference.arrayBuffer();
const blob = new Blob([arrayBuffer], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
//--Opens PDF file in new Tab
fetch(url)
.then(response => response.blob())
.then(data => window.open(URL.createObjectURL(data), '_blank'))
//--Downloads file to Browser (uncomment if desired)
//const anchorElement = document.createElement('a');
//anchorElement.href = url;
//anchorElement.download = fileName ?? 'Manifest';
//anchorElement.click();
//anchorElement.remove();
//URL.revokeObjectURL(url);
}
</script>
*NOTE! My application is purely internal-facing to our organization. Our Windows client machines and browsers are managed by Group Policy. I have not yet tested this on Mac / Safari clients yet.
We have two applications: A C# REST-API, and a Kotlin Android application, we are using Google Platform Cloud Bucket to host the images.
A picture will be uploaded on the Android application, but the C# REST-API needs to upload it to the Google Cloud Platform.
This is the working C# code to upload a file to the Google Cloud Buckets:
[HttpPost]
[Route("upload")]
public IActionResult Upload()
{
var storageClient = StorageClient.Create(google_credentials);
string fileToUpload ="/Users/niel/Downloads/new_cat.jpg";
using (var fileStream = new FileStream(fileToUpload, FileMode.Open,
FileAccess.Read, FileShare.Read))
{
storageClient.UploadObject("test_storage_fotos", "new_cat", "image/jpeg", fileStream);
}
Console.WriteLine("uploaded the file successfully");
return Ok();
}
Now I need to replace fileToUpload with the content from a POST-request. Is there a way to do this? Picture from Android app > C# API > Google Buckets? The link from the C# API to Google Buckets is already working.
Is there a way in Kotlin to somehow get the byte-string of an image, post it to my C# API who takes the content and puts it in a FileStream? I than can upload the FileStream using storageClient.UploadObject? Is this a possibility?
Thanks!
Yes, you can definitely do this. Just send the file over to the server via http protocol with multipart/form-data content type.
In kotlin you can use ktor or any other http library to do that.
For ktor you'll need to add an implementation dependency
implementation "io.ktor:ktor-client-android:1.5.4"
And you might also need to add additional permission in AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
Then you can send a file with this snippet. Notice that imageUri is a content uri, for file uri the code would be a bit different
private fun getFileName(resolver: ContentResolver, uri: Uri): String {
val returnCursor: Cursor = resolver.query(uri, null, null, null, null)!!
val nameIndex: Int = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
returnCursor.moveToFirst()
val name: String = returnCursor.getString(nameIndex)
returnCursor.close()
return name
}
suspend fun postAndImage(imageUri: Uri, uploadEndPoint: String) {
val client = HttpClient(Android)
val cr = applicationContext.contentResolver
if(cr.getType(imageUri) == null) {
//process error
return
}
val stream = cr.openInputStream(imageUri)
if(stream == null) {
//process error
return
}
val response: HttpResponse = client.submitFormWithBinaryData(
url = uploadEndPoint,
formData = formData {
append("image", InputProvider { stream.asInput() }, Headers.build {
append(HttpHeaders.ContentType, cr.getType(imageUri)!!)
append(HttpHeaders.ContentDisposition, "filename=${getFileName(cr, imageUri)}")
})
}
)
stream.close()
//process response
}
And you'll need to modify you upload function slightly
[HttpPost]
[Route("upload")]
//the name of the argument must match the key that you pass in "append" function
public async Task<IActionResult> Post(IFormFile image)
{
var storageClient = StorageClient.Create(google_credentials);
using (var stream = image.OpenReadStream())
{
//it's also possible to get original file name from file name property
var fileName = Guid.NewGuid() + "." + Path.GetExtension(image.FileName);
//assuming bucket is already created
var storageObject = await storageClient
.UploadObjectAsync("test_storage_fotos", fileName, "image/jpeg", stream);
//save information about a storage object in database
}
return Ok();
}
I am trying to download files from azure to computer via an web app. It works when I run locally the project, but when uploaded to ftp server it does not download.
I have tried Environment.SpecialFolder.Peronal, Desktop, etc.
public async Task<bool> DownloadBlobAsync(string file, string fileExtension, string directory)
{
string downlaodPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
_container = _client.GetContainerReference(containerName);
_directoy = _container.GetDirectoryReference(directory);
CloudBlockBlob blockBlob = _directoy.GetBlockBlobReference(file + "." + fileExtension);
using (var fileStream = File.OpenWrite(downlaodPath + "/"+ file + "." + fileExtension))
{
await blockBlob.DownloadToStreamAsync(fileStream);
return true;
}
}
The expected output should be on the documents or desktop.
The issue that you are seeing is due to the fact that your code is executing on the webserver, not on the clients (users) machine.
In other words, when you try to save to Environment.SpecialFolder.Personal, you're trying to save it to that folder on the web server, not the users desktop computer.
What you need to do is return the content of the blob in the request, and let the browser save the file - the user is likely to be prompted (depending on their browser settings) where exactly to save it. You should not be specifying this.
Here is an example of how to do this:
public async Task<HttpResponseMessage> DownloadBlobAsync(string file, string fileExtension, string directory)
{
_container = _client.GetContainerReference(containerName);
_directoy = _container.GetDirectoryReference(directory);
CloudBlockBlob blockBlob = _directoy.GetBlockBlobReference(file + "." + fileExtension);
using (var ms = new MemoryStream())
{
await blockBlob.DownloadToStreamAsync(ms);
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(ms.ToArray())
};
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "somefilename.ext"
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue(blockBlob.Properties.ContentType);
return result;
}
}
Note that this is inefficient, as it will download the blob first to the webserver, and then return that to the client. It should be enough to get started.
When this endpoint is hit by the browser, the user will be prompted to save the file somewhere on their PC.
We're developing mobile application in Xamarin. How can next be accomplished in iOS:
user downloads file from url (http request is made to REST API, secured with Authentication Basic username:secretKey)
file is saved to iOS
user opens a file (allowed are jpg, png, pdf, doc, docx, png)
file is opened in default application (e.g. for images image viewer)
As file operations are platform specific, here's interface definition:
public interface IFileHelper
{
void DownloadFileAndSave(Models.DocumentModel document);
}
Android implementation:
public class FileHelper : IFileHelper
{
// download file and view status in download manager
public void DownloadFileAndSave(Models.DocumentModel document)
{
DownloadManager dm = (DownloadManager)Android.App.Application.Context.GetSystemService(Context.DownloadService);
string url = WebApiUtils.GetBaseUrl() + string.Format("Api/v1/Dms/{0}", document.UniqueId);
DownloadManager.Request request = new Android.App.DownloadManager.Request(Android.Net.Uri.Parse(url)));
request.AddRequestHeader("Authorization", "Basic " + WebApiUtils.GetEncodedCredentials(Auth.Users.Current));
var downloadFile = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads);
string path = Path.Combine(downloadFile.AbsolutePath, document.FileName);
request.SetDestinationUri(Android.Net.Uri.FromFile(new Java.IO.File(path)));
request.SetMimeType(document.ContentType);
request.SetNotificationVisibility(DownloadVisibility.VisibleNotifyCompleted);
dm.Enqueue(request);
}
In Android file is simply stored on the filesystem and with File Explorer which is by default installed on any Android (i.e. My Files -> device storage -> Download), the file is opened in default application for file's mime type. Everything fine on Android.
Apple iOS implementation:
public class FileHelper : IFileHelper
{
public void DownloadFileAndSave(Models.DocumentModel document)
{
WebClient webClient = new WebClient();
webClient.Headers.Add(HttpRequestHeader.Authorization, "Basic " + WebApiUtils.GetEncodedCredentials(Auth.Users.Current));
webClient.DownloadDataAsync(new System.Uri(WebApiUtils.GetBaseUrl() + string.Format(Consts.ApiUrls.GetDocument, document.UniqueId)));
webClient.DownloadDataCompleted += (sender, e) =>
{
byte[] content = e.Result;
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), document.FileName);
// doesn't throw exception therefore saved ok
File.WriteAllBytes(path, content);
Uri uri = new Uri(String.Format("file://{0}", path));
// doesn't work.
Device.OpenUri(uri);
};
}
}
Is there any other way to open downloaded file in default application. If I open url e.g. http://example.com/files/file1.png it opens the file in safari, but I can't put Authorization: Basic headers in Device.OpenUri.
I read about Load Non-Web Documents with WebView but you would have to build each file as BundleResource.
As Code Warrior commented there is one approach posted on link: https://forums.xamarin.com/discussion/36964/why-is-it-that-nothing-is-working-to-open-an-existing-local-pdf-file-in-the-ios-portion-of-my-pcl.
But Save image action doesn't work, everything else seems to work.
public void DownloadFileAndSave(Models.DocumentModel document)
{
WebClient webClient = new WebClient();
webClient.Headers.Add(HttpRequestHeader.Authorization, "Basic " + WebApiUtils.GetEncodedCredentials(Auth.Users.Current));
string tempPath = Path.GetTempPath();
string localFilename = Path.GetFileName(document.FileName);
string localPath = Path.Combine(tempPath, localFilename);
webClient.DownloadFileCompleted += (sender, e) =>
{
Device.BeginInvokeOnMainThread(() =>
{
QLPreviewItemFileSystem prevItem = new QLPreviewItemFileSystem(localFilename, localPath); // ql = quick look
QLPreviewController previewController = new QLPreviewController()
{
DataSource = new PreviewControllerDS(prevItem)
};
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(previewController, true, null);
});
};
// download file
Uri uri = new System.Uri(WebApiUtils.GetBaseUrl() + string.Format(Consts.ApiUrls.GetDocument, document.UniqueId));
webClient.DownloadFileAsync(uri, localPath);
}
When Save image is triggered I get next error:
2017-10-03 13:45:56.797 MyApp.iOS[477:61030] Video
/private/var/mobile/Containers/Data/Application/33D7139A-53E0-4A2E-8C78-D3D13A2259B0/tmp/water-h2o-md.png
cannot be saved to the saved photos album: Error
Domain=AVFoundationErrorDomain Code=-11828 "Cannot Open"
UserInfo={NSUnderlyingError=0x1c0445d60 {Error
Domain=NSOSStatusErrorDomain Code=-12847 "(null)"},
NSLocalizedFailureReason=This media format is not supported.,
NSURL=file:///private/var/mobile/Containers/Data/Application/33D7139A-53E0-4A2E-8C78-D3D13A2259B0/tmp/water-h2o-md.png,
NSLocalizedDescription=Cannot Open}
iOS treates image as video? Is this a bug on iOS or am I something missing.
UPDATE
It turns out that next permissions was missing in Info.plist file:
<key>NSPhotoLibraryUsageDescription</key>
<string>Application needs to access photos</string>
<!-- for iOS 11 -->
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Application needs to access photos</string>
Now Save Image action is working ok. But seriously Apple could return more appropriate error than Video image.jpg cannot be saved ...
I'm working in a function to download pdfs from DropBox, I'm using ASP.net Core , everything works good. The only thing is that when you click in the download link it doesn't show any message and downloads the file. I would like to show the download progress like usually happens when we download something from Internet, I don't want any dialog to appear, just to show that the file was downloaded like normally happens in any browser like Chrome or IE and then have the choices 'Show in Folder' and things like that, what would I need to add?
public async Task DownloadPdf()
{
DropboxClient client2 = new DropboxClient("cU5M-a4exaAAAAAAAAABDVZsKdpPteNmwHslOeFEo-HByuOr4v4ONvXoAMCFyOXH");
string folder = "MyFolder";
string file = "Test PDF.pdf";
using (var response = await client2.Files.DownloadAsync("/" + folder + "/" + file))
{
using (var fileStream = System.IO.File.Create(#"C:\Users\User\Downloads\Test.pdf"))
{
(await response.GetContentAsStreamAsync()).CopyTo(fileStream);
}
}
}
I have a asp.net core project with an API that returns a file:
[HttpGet("{id}")]
public IActionResult Get(int id) {
byte[] fileContent = READ_YOUR_FILE();
FileContentResult result = new FileContentResult(fileContent, "application/octet-stream") {
FileDownloadName = id.ToString()
};
return result;
}
If I access in my browser the URL from this API (myapp/api/mycontroller/id), then I can see the file downloading.