I am trying to upload an image to our S3 service, but aside from the
seamless execution of the following code, I can't access the file I have uploaded and the file itself isn't on the bucket either.
Another including problem is that I don't have any actual progress response aside from the percentage it has done.
private AmazonUploader()
{
_access = MyKey###";
_secret = "MySecret###";
AmazonS3Config config = new AmazonS3Config ();
config.ServiceURL = "s3-eu-west-1.amazonaws.com";
config.UseHttp = true;
config.RegionEndpoint = Amazon.RegionEndpoint.EUWest1;
_client = new AmazonS3Client (_access, _secret, config);
_trans = new TransferUtility (_client);
}
public async void UploadImage(string path, string key)
{
TransferUtilityUploadRequest up = new TransferUtilityUploadRequest();
up.BucketName = "myapp/uploads";
up.FilePath = path;
up.Key = key;
up.UploadProgressEvent += up_UploadProgressEvent;
await _trans.UploadAsync(up);
}
private void up_UploadProgressEvent(object sender, UploadProgressArgs e)
{
if (e.PercentDone == 100)
{
System.Diagnostics.Debug.WriteLine ("Done uploading");
if (OnUploadComplete != null) OnUploadComplete ();
}
}
Your BucketName seems invalid. Bucketnames cant contain slashes. Maybe you want "uploads" to be part of Key?
Related
I am trying to attach large files to a ToDoTask using the Graph Api using the example in the docs for attaching large files for ToDoTask and the recommend class LargeFileUploadTask for uploading large files.
I have done this sucessfully before with attaching large files to emails and sending so i used that as base for the following method.
public async Task CreateTaskBigAttachments( string idList, string title, List<string> categories,
BodyType contentType, string content, Importance importance, bool isRemindOn, DateTime? dueTime, cAttachment[] attachments = null)
{
try
{
var _newTask = new TodoTask
{
Title = title,
Categories = categories,
Body = new ItemBody()
{
ContentType = contentType,
Content = content,
},
IsReminderOn = isRemindOn,
Importance = importance
};
if (dueTime.HasValue)
{
var _timeZone = TimeZoneInfo.Local;
_newTask.DueDateTime = DateTimeTimeZone.FromDateTime(dueTime.Value, _timeZone.StandardName);
}
var _task = await _graphServiceClient.Me.Todo.Lists[idList].Tasks.Request().AddAsync(_newTask);
//Add attachments
if (attachments != null)
{
if (attachments.Length > 0)
{
foreach (var _attachment in attachments)
{
var _attachmentContentSize = _attachment.ContentBytes.Length;
var _attachmentInfo = new AttachmentInfo
{
AttachmentType = AttachmentType.File,
Name = _attachment.FileName,
Size = _attachmentContentSize,
ContentType = _attachment.ContentType
};
var _uploadSession = await _graphServiceClient.Me
.Todo.Lists[idList].Tasks[_task.Id]
.Attachments.CreateUploadSession(_attachmentInfo).Request().PostAsync();
using (var _stream = new MemoryStream(_attachment.ContentBytes))
{
_stream.Position = 0;
LargeFileUploadTask<TaskFileAttachment> _largeFileUploadTask = new LargeFileUploadTask<TaskFileAttachment>(_uploadSession, _stream, MaxChunkSize);
try
{
await _largeFileUploadTask.UploadAsync();
}
catch (ServiceException errorGraph)
{
if (errorGraph.StatusCode == HttpStatusCode.InternalServerError || errorGraph.StatusCode == HttpStatusCode.BadGateway
|| errorGraph.StatusCode == HttpStatusCode.ServiceUnavailable || errorGraph.StatusCode == HttpStatusCode.GatewayTimeout)
{
Thread.Sleep(1000); //Wait time until next attempt
//Try again
await _largeFileUploadTask.ResumeAsync();
}
else
throw errorGraph;
}
}
}
}
}
}
catch (ServiceException errorGraph)
{
throw errorGraph;
}
catch (Exception ex)
{
throw ex;
}
}
Up to the point of creating the task everything goes well, it does create the task for the user and its properly shown in the user tasks list. Also, it does create an upload session properly.
The problem comes when i am trying to upload the large file in the UploadAsync instruction.
The following error happens.
Code: InvalidAuthenticationToken Message: Access token is empty.
But according to the LargeFileUploadTask doc , the client does not need to set Auth Headers.
param name="baseClient" To use for making upload requests. The client should not set Auth headers as upload urls do not need them.
Is not LargeFileUploadTask allowed to be used to upload large files to a ToDoTask?
If not then what is the proper way to upload large files to a ToDoTask using the Graph Api, can someone provide an example?
If you want, you can raise an issue for the same with the details here, so that they can have look: https://github.com/microsoftgraph/msgraph-sdk-dotnet-core/issues.
It seems like its a bug and they are working on it.
Temporarily I did this code to deal with the issue of the large files.
var _task = await _graphServiceClient.Me.Todo.Lists[idList].Tasks.Request().AddAsync(_newTask);
//Add attachments
if (attachments != null)
{
if (attachments.Length > 0)
{
foreach (var _attachment in attachments)
{
var _attachmentContentSize = _attachment.ContentBytes.Length;
var _attachmentInfo = new AttachmentInfo
{
AttachmentType = AttachmentType.File,
Name = _attachment.FileName,
Size = _attachmentContentSize,
ContentType = _attachment.ContentType
};
var _uploadSession = await _graphServiceClient.Me
.Todo.Lists[idList].Tasks[_task.Id]
.Attachments.CreateUploadSession(_attachmentInfo).Request().PostAsync();
// Get the upload URL and the next expected range from the response
string _uploadUrl = _uploadSession.UploadUrl;
using (var _stream = new MemoryStream(_attachment.ContentBytes))
{
_stream.Position = 0;
// Create a byte array to hold the contents of each chunk
byte[] _chunk = new byte[MaxChunkSize];
//Bytes to read
int _bytesRead = 0;
//Times the stream has been read
var _ind = 0;
while ((_bytesRead = _stream.Read(_chunk, 0, _chunk.Length)) > 0)
{
// Calculate the range of the current chunk
string _currentChunkRange = $"bytes {_ind * MaxChunkSize}-{_ind * MaxChunkSize + _bytesRead - 1}/{_stream.Length}";
//Despues deberiamos calcular el next expected range en caso de ocuparlo
// Create a ByteArrayContent object from the chunk
ByteArrayContent _byteArrayContent = new ByteArrayContent(_chunk, 0, _bytesRead);
// Set the header for the current chunk
_byteArrayContent.Headers.Add("Content-Range", _currentChunkRange);
_byteArrayContent.Headers.Add("Content-Type", _attachment.ContentType);
_byteArrayContent.Headers.Add("Content-Length", _bytesRead.ToString());
// Upload the chunk using the httpClient Request
var _client = new HttpClient();
var _requestMessage = new HttpRequestMessage()
{
RequestUri = new Uri(_uploadUrl + "/content"),
Method = HttpMethod.Put,
Headers =
{
{ "Authorization", bearerToken },
}
};
_requestMessage.Content = _byteArrayContent;
var _response = await _client.SendAsync(_requestMessage);
if (!_response.IsSuccessStatusCode)
throw new Exception("File attachment failed");
_ind++;
}
}
}
}
}
I am working on an app that plays audio using the MediaPlayer. It works when the audio file to play is already in the Assets folder. However, my goal is to use the FilePicker plugin for the user to pick a file from their device to be played.
From the FilePicker, I am able to get a path (which seems to be a Uri), like content://com.android.providers.downloads.documents/document/6531. However, attempting use the MediaPlayer with this path (both as a string and as a Uri) results in Java.IO.IOException: 'setDataSource failed.: status=0x80000000'.
I'm assuming it's not possible to use the MediaPlayer on a file outside of the Assets folder. So my question becomes is there a way to add an asset to a project's asset folder when a path is provided? Or am I wrong, and is there a way to use the MediaPlayer given the Uri?
Here is the code of the button that handles importing:
Button browse = FindViewById<Button>(Resource.Id.browse);
browse.Click += async delegate
{
var fileImp = await CrossFilePicker.Current.PickFile();
if (fileImp != null)
{
path = fileImp.FilePath;
}
};
And after sending the path to another class:
public void load()
{
player = new MediaPlayer();
player.SetDataSource(path);
player.Prepare();
}
This other attempt at setting the data source does not work either, and gets the same error:
public void load()
{
player = new MediaPlayer();
Android.Net.Uri uri = Android.Net.Uri.Parse(songFileString);
player.SetDataSource(Application.Context, uri);
player.Prepare();
}
Any help is appreciated, thanks.
content://com.android.providers.downloads.documents/document/6531
You could try to convert the uri to the file path.
string filePath = null;
Android.Net.Uri uri = Android.Net.Uri.Parse(path);
if (DocumentsContract.IsDocumentUri(this, uri))
{
string docId = DocumentsContract.GetDocumentId(uri);
if (uri.Authority.Equals("com.android.providers.media.documents"))
{
string id = docId.Split(":")[1];
string selection = MediaStore.Video.Media.InterfaceConsts.Id + "=" + id;
filePath = getfilePath(MediaStore.Video.Media.ExternalContentUri, selection);
}
else if (uri.Authority.Equals("com.android.providers.downloads.documents"))
{
Android.Net.Uri contentUri = ContentUris.WithAppendedId(Android.Net.Uri.Parse("content://downloads/public_downloads"), long.Parse(docId));
filePath = getfilePath(contentUri, null);
}
}
else if (uri.Scheme.Equals("content", StringComparison.OrdinalIgnoreCase))
{
filePath = getfilePath(uri, null);
}
else if (uri.Scheme.Equals("file", StringComparison.OrdinalIgnoreCase))
{
filePath = uri.Path;
}
getfilePath method:
private string getfilePath(Android.Net.Uri uri, string selection)
{
string path = null;
var cursor = ContentResolver.Query(uri, null, selection, null, null);
if (cursor != null)
{
if (cursor.MoveToFirst())
{
path = cursor.GetString(cursor.GetColumnIndex(MediaStore.Video.Media.InterfaceConsts.Data));
}
cursor.Close();
}
return path;
}
i have one call back function in my model. i.e void method.
how to pass that result to view.
my problem is while uploading file to amazon s3, it's returning progress value. i need to get that value in view.
my code as follows
public bool sendMyFileToS3(EmployeeModel e, string bucketName, string subDirectoryInBucket)
{
IAmazonS3 client = new AmazonS3Client(RegionEndpoint.USEast2);
TransferUtility utility = new TransferUtility(client);
TransferUtilityUploadRequest request = new TransferUtilityUploadRequest();
if (subDirectoryInBucket == "" || subDirectoryInBucket == null)
{
request.BucketName = bucketName; //no subdirectory just bucket name
}
else
{ // subdirectory and bucket name
request.BucketName = bucketName + #"/" + subDirectoryInBucket;
}
try
{
request.Key = RandomString() + Path.GetExtension(e.File.FileName); //file name up in S3
request.InputStream = e.File.InputStream;
request.CannedACL = S3CannedACL.PublicRead;
request.UploadProgressEvent += new EventHandler<UploadProgressArgs>(UploadFile_ProgressBar); //call bcak function
utility.Upload(request);
}
catch(AmazonS3Exception)
{
throw;
}
//commensing the transfer
//Generate link with expiry date.
Amazon.S3.Model.GetPreSignedUrlRequest aa = new Amazon.S3.Model.GetPreSignedUrlRequest();
aa.BucketName = request.BucketName;
aa.Key = request.Key;
aa.Expires = new DateTime().AddDays(2);
string url = client.GetPreSignedURL(aa);
url = url.Remove(url.IndexOf('?'));
return true;
}
public void UploadFile_ProgressBar(object sender, UploadProgressArgs e)
{
int pctProgress = (int)(e.TransferredBytes * 100 / e.TotalBytes);
}
every second "pctProgress" this parameter is replacing with new value. when ever replacing with new value it should pass to view.
how to do this.
please any suggestions.
i try to open a existing PDF file on a iOS device.
This file have to be open with the default PDF reader.
In this moment i use the "dependency service" to run native code.
public void Save(string filename, byte[] byPDF)
{
string strPfad = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), filename);
if(File.Exists(strPfad))
{
File.Delete(strPfad);
File.WriteAllBytes(strPfad, byPDF);
}
else
File.WriteAllBytes(strPfad, byPDF);
var viewer = UIDocumentInteractionController.FromUrl(NSUrl.FromFilename(strPfad));
var controller = GetVisibleViewController();
viewer.PresentOpenInMenu(controller.View.Frame, controller.View, true);
}
private UIViewController GetVisibleViewController(UIViewController controller = null)
{
controller = controller ?? UIApplication.SharedApplication.KeyWindow.RootViewController;
if (controller.PresentedViewController == null)
return controller;
if (controller.PresentedViewController is UINavigationController)
{
return ((UINavigationController)controller.PresentedViewController).VisibleViewController;
}
if (controller.PresentedViewController is UITabBarController)
{
return ((UITabBarController)controller.PresentedViewController).SelectedViewController;
}
return GetVisibleViewController(controller.PresentedViewController);
}
If I run this code is nothing happend (only the file becomes written).
I just used a standard UIViewController and passed the path (where the pdf is saved on the device) to the controller and loaded it up in a UIWebview.
public class PdfController : UIViewController
{
public PdfController(string pdfPath)
{
NavigationItem.LeftBarButtonItem = new NavBarButton("Back", (sender, args) =>
{
NavigationController.PopViewController(true);
});
var webView = new UIWebView(View.Bounds);
View.AddSubview(webView);
webView.LoadRequest(new NSUrlRequest(new NSUrl(pdfPath, false)));
webView.ScalesPageToFit = true;
}
}
But you will need to download it first and pass it to this controller
This snippit will allow you download the pdf and save it.
Public void DownloadPDF()
{
Utility.AddNetworkConnection();
var webClient = new WebClient();
loadingView = new LoadingView();
loadingView.Show("Downloading PDF");
webClient.DownloadDataCompleted += (s, e) =>
{
Utility.RemoveNetworkConnection();
File.WriteAllBytes(_pdfPathLocation, e.Result); // writes to local storage
InvokeOnMainThread(() =>
{
loadingView.Hide();
_pdfImageElement.SetValueAndUpdate("Open PDF");
var a = new UIAlertView("Done", "File downloaded and saved", null, "OK", "Open PDF");
a.Show();
a.Clicked += OpenPdf;
});
};
var url = new Uri(_wreck.PdfURL);
webClient.Encoding = Encoding.UTF8;
webClient.DownloadDataAsync(url);
}
I'm creating an app that access the Microsoft Cloud API to get health data. It uses OAuth to log in when you hit the Sign In Button
private void signinButton_Click(object sender, RoutedEventArgs e)
{
UriBuilder uri = new UriBuilder("https://login.live.com/oauth20_authorize.srf");
var query = new StringBuilder();
query.AppendFormat("redirect_uri={0}", Uri.EscapeDataString(RedirectUri));
query.AppendFormat("&client_id={0}", Uri.EscapeDataString(ClientId));
query.AppendFormat("&scope={0}", Uri.EscapeDataString(Scopes));
query.Append("&response_type=code");
uri.Query = query.ToString();
this.webView.Visibility = Visibility.Visible;
this.webView.Navigate(uri.Uri);
}
This brings up a webView with the page to log in using Microsoft credentials. Once completed, it leads to this:
private async void WebView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
//
// When the web view navigates to our redirect URI, extract the authorization code from
// the URI and use it to fetch our access token. If no authorization code is present,
// we're completing a sign-out flow.
//
if (args.Uri.LocalPath.StartsWith("/oauth20_desktop.srf", StringComparison.OrdinalIgnoreCase))
{
WwwFormUrlDecoder decoder = new WwwFormUrlDecoder(args.Uri.Query);
var code = decoder.FirstOrDefault((entry) => entry.Name.Equals("code", StringComparison.OrdinalIgnoreCase));
var error = decoder.FirstOrDefault((entry) => entry.Name.Equals("error", StringComparison.OrdinalIgnoreCase));
var errorDesc = decoder.FirstOrDefault((entry) => entry.Name.Equals("error_description", StringComparison.OrdinalIgnoreCase));
// Check the code to see if this is sign-in or sign-out
if (code != null)
{
// Hide the browser again, no matter what happened...
sender.Visibility = Visibility.Collapsed;
if (error != null)
{
this.responseText.Text = string.Format("{0}\r\n{1}", error.Value, errorDesc.Value);
return;
}
var tokenError = await this.GetToken(code.Value, false);
if (string.IsNullOrEmpty(tokenError))
{
this.responseText.Text = "Successful sign-in!";
this.signoutButton.IsEnabled = true;
this.signinButton.IsEnabled = false;
this.getProfileButton.IsEnabled = true;
this.getDevicesButton.IsEnabled = true;
this.getActivitiesButton.IsEnabled = true;
this.getDailySummaryButton.IsEnabled = true;
this.getHourlySummaryButton.IsEnabled = true;
}
else
{
this.responseText.Text = tokenError;
}
}
else
{
this.responseText.Text = "Successful sign-out!";
this.signoutButton.IsEnabled = false;
this.signinButton.IsEnabled = true;
this.getProfileButton.IsEnabled = false;
this.getDevicesButton.IsEnabled = false;
this.getActivitiesButton.IsEnabled = false;
this.getDailySummaryButton.IsEnabled = true;
this.getHourlySummaryButton.IsEnabled = false;
}
}
}
private async Task<string> GetToken(string code, bool isRefresh)
{
UriBuilder uri = new UriBuilder("https://login.live.com/oauth20_token.srf");
var query = new StringBuilder();
query.AppendFormat("redirect_uri={0}", Uri.EscapeDataString(RedirectUri));
query.AppendFormat("&client_id={0}", Uri.EscapeDataString(ClientId));
query.AppendFormat("&client_secret={0}", Uri.EscapeDataString(ClientSecret));
if (isRefresh)
{
query.AppendFormat("&refresh_token={0}", Uri.EscapeDataString(code));
query.Append("&grant_type=refresh_token");
}
else
{
query.AppendFormat("&code={0}", Uri.EscapeDataString(code));
query.Append("&grant_type=authorization_code");
}
uri.Query = query.ToString();
var request = WebRequest.Create(uri.Uri);
try
{
using (var response = await request.GetResponseAsync())
{
using (var stream = response.GetResponseStream())
{
using (var streamReader = new StreamReader(stream))
{
var responseString = streamReader.ReadToEnd();
var jsonResponse = JObject.Parse(responseString);
this.creds.AccessToken = (string)jsonResponse["access_token"];
this.creds.ExpiresIn = (long)jsonResponse["expires_in"];
this.creds.RefreshToken = (string)jsonResponse["refresh_token"];
string error = (string)jsonResponse["error"];
return error;
}
}
}
}
catch (Exception ex)
{
return ex.Message;
}
}
I don't want users to have to accept the permissions every time the app is launched. Is there a way to save credentials locally so that it automatically authenticates on launch? Thanks!
You can use
Windows.Storage.ApplicationData.Current.LocalSettings
This process good described by this answer Best Way to keep Settings for a WinRT App?
The code in link identity to UWP
Store the needed oauth parts in the credential locker API. Never store these kind of information in the normal settings API.
On start read the oauth information and use the refreshtoken to get a new access token.
More Information here.
https://msdn.microsoft.com/en-us/library/windows/apps/mt270189.aspx