C#: copying Assets on Android - c#

I try to use Xamarin for the development of an Android app. I built APK but can't get access to Assets where are saved some folders and files.
I need to copy these folders and files from Assets to an application directory of an android device and have access to them any time.
Please, help( I need a simple CSharp function of copy Assets files to an android device. I will grateful for any support.

You could look at File Storage and Access with Xamarin.Android and Using Android Assets first.
And here is a simple sample :
public static async Task CopyFile(Activity activity)
{
var filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "YOUR_FILENAME");
if (!File.Exists(filePath))
{
try
{
using (var fileAssetsStream = activity.Assets.Open("YOUR_FILENAME"))
using (var fileStream = new FileStream(filePath, FileMode.OpenOrCreate))
{
var buffer = new byte[1024];
int b = buffer.Length;
int length;
while ((length = await fileAssetsStream.ReadAsync(buffer, 0, b)) > 0)
{
await fileStream.WriteAsync(buffer, 0, length);
}
}
}
catch (Exception ex)
{
//Handle exceptions
}
}
}
Don't forget to request WRITE_EXTERNAL_STORAGE runtime permissions.

[assembly: Dependency(typeof(FileCopyingService))]
namespace Mypp.Droid.Services
{
public class FileCopyingService : IFileCopyingService
{
Context _context;
public FileCopyingService()
{
this._context = Android.App.Application.Context;
}
public string CopyFiles(string folderName)
{
string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
var fileFolder = Path.Combine(path, folderName);
if (Directory.Exists(fileFolder))
Directory.Delete(fileFolder, true);
Directory.CreateDirectory(fileFolder);
foreach (var fItemName in this._context.Assets.List(folderName))
{
var dbFile = Path.Combine(fileFolder, fItemName);
if (File.Exists(dbFile))
{
File.Delete(dbFile);
}
if (!File.Exists(dbFile))
{
using (FileStream writeStream = new FileStream(dbFile, FileMode.OpenOrCreate, FileAccess.Write))
{
var assetsMapFile = folderName + "/" + fItemName;
this._context.Assets.Open(assetsMapFile).CopyTo(writeStream);
}
}
}
return fileFolder;
}
}
}
Add permission in AndroidManifest.xml source
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Related

How to force delete a file used by another process in Asp.net core

I'm working on an ASP.NET Core 5 project. I have this action method:
public async Task<IActionResult> CreateV3EnterCheckFile(IFormFile MarksFile)
{
var filesCount = Directory.GetFiles("Uploads").Length;
string path = Path.Combine("Uploads", filesCount + 1 + ".xlsx");
await MarksFile.SaveToAsync(path);
var xlImporter = new XLImporter();
var importedData = await xlImporter.ImportSheetAsync(path, 0);
var r = (from x in importedData select new { ID = x[0], StudentId = x[1] }).ToList();
System.IO.File.Delete(path);
return View();
}
I tried to get IFormFile uploaded file by the user to save it on the server and querying it using one of my projects (that uses LinqToExcel library).
I am querying the data and everything is perfect I still have just one problem it is this line of code:
System.IO.File.Delete(path);
It throws an exception and the message is I can't delete that file because it is still being used by another process.
I'm very sure that the process is related to the LinqToExcel library.
More details :
SaveToAsync is an extension method created by me that is its definition
public static Task SaveToAsync(this IFormFile file, string pathToSaveTo)
{
return Task.Factory.StartNew(() =>
{
using (Stream fileStream = File.Open(pathToSaveTo, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
{
file.CopyTo(fileStream);
}
});
}
Please - is there any way or method or solution to delete this file even if it is being used by another process?
Massive thanks in advance.
Based on the source code of ExcelQueryFactory (https://github.com/paulyoder/LinqToExcel/blob/master/src/LinqToExcel/ExcelQueryFactory.cs) I would try the following:
ExcelQueryFactory has a ReadOnly Property. For read only access (if applicable) I would set it to true when creating the instance.
More important: IExcelQueryFactory implements IDisposable, so you can (should) use a using block:
using (var excelFile = new ExcelQueryFactory(pathToExcelFile) {ReadOnly = true})
{
// Do your work.
}
Of course you can use using var ..., but if you need a more reduced scope, the "old" using syntax allows more control.
I assumed that your Uploads folder is under webroot.
You can try this:-
public YourControllerName(IHostingEnvironment he) //input parameter
{
_he = he;
}
public async Task<IActionResult> CreateV3EnterCheckFile(IFormFile MarksFile)
{
try
{
var filesCount = Directory.GetFiles("Uploads").Length;
string contentRootPath = _he.ContentRootPath;
string path = Path.Combine(contentRootPath +"\\Uploads", filesCount + 1 + ".xlsx");
await MarksFile.SaveToAsync(path);
var xlImporter = new XLImporter();
var importedData = await xlImporter.ImportSheetAsync(path, 0);
var r = (from x in importedData select new { ID = x[0], StudentId = x[1] }).ToList();
//System.IO.File.Delete(path);
if (File.Exists(path))
{
File.Delete(path);
}
else
{
Debug.WriteLine("File does not exist.");
}
return View();
}
catch(Exception e)
{
Console.WriteLine(e);
}
Or you can try another process:-
try
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.IO.File.Delete(path);
}
catch(Exception e){
}
}
Or this:-
if (System.IO.File.Exists(path))
{
try
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.IO.File.Delete(path);
}
catch (Exception e) { }
}
it should resolve your issue I hope. by the way, if your Upload folder is not under the webroot path. you can find your path using your process.

There is no file with ID 1. The file list may have changed Blazor

When I try to upload files from a list I get this error
"Error: There is no file with ID 1. The file list may have changed"
Its working when I attach one file but, when the list has more than one file, I get the error
The phone Im using to send is
calling function
foreach (var item in fileList)
{
var Enow = item.GetMultipleFiles();
foreach (var _item in Enow)
{
output = await _IfileUpload.Upload(_item, NewGuid.ToString());
}
}
called function
public async Task<string> Upload(IBrowserFile entry, string UploadGuid)
{
try
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "Uploads/" + UploadGuid, entry.Name);
var _path = Path.Combine(Directory.GetCurrentDirectory(), "Uploads/" + UploadGuid);
if (!Directory.Exists(_path))
{
System.IO.Directory.CreateDirectory(_path);
}
Stream stream = entry.OpenReadStream();
FileStream fs = File.Create(path);
await stream.CopyToAsync(fs);
stream.Close();
fs.Close();
return path;
}
catch (Exception ex)
{
throw ex;
}
}
BlazorInputFile results in error: "There is no file with ID 1".
On re-add new files all previously created objects belonging to previous files aren't saved. Meantime the index starts with unsaved objects that no longer exist.
Saving files at each selection step gives an correct index.
The Chrome inside debugger indicates a problem in inputfile.js
I ran into similar problem and the solution was to create image data list that is populated each time new file is added from browser. In this case you can have proper grasp on data
private List<byte[]> _imageData = new List<byte[]>();
private void UploadFiles(InputFileChangeEventArgs e)
{
foreach (var file in e.GetMultipleFiles())
{
_files.Add(file);
_imageData.Add(GetImageBytes(file).Result);
}
}
private async Task<byte[]> GetImageBytes(IBrowserFile file)
{
var path = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
await using var fileStream = new FileStream(path, FileMode.Create);
await file.OpenReadStream(file.Size).CopyToAsync(fileStream);
var bytes = new byte[file.Size];
fileStream.Position = 0;
await fileStream.ReadAsync(bytes);
fileStream.Close();
File.Delete(path);
return bytes;
}
And finally
if (_imageData != null && _imageData.Count() > 0)
{
foreach (var photo in _imageData)
{
var result = await _uploadService.UploadImage(photo);
}
}
I would try this sample from the [docs][1]
<h3>Upload PNG images</h3>
<p>
<InputFile OnChange="#OnInputFileChange" multiple />
</p>
#if (imageDataUrls.Count > 0)
{
<h4>Images</h4>
<div class="card" style="width:30rem;">
<div class="card-body">
#foreach (var imageDataUrl in imageDataUrls)
{
<img class="rounded m-1" src="#imageDataUrl" />
}
</div>
</div>
}
#code {
IList<string> imageDataUrls = new List<string>();
private async Task OnInputFileChange(InputFileChangeEventArgs e)
{
var maxAllowedFiles = 3;
var format = "image/png";
foreach (var imageFile in e.GetMultipleFiles(maxAllowedFiles))
{
var resizedImageFile = await imageFile.RequestImageFileAsync(format,
100, 100);
var buffer = new byte[resizedImageFile.Size];
await resizedImageFile.OpenReadStream().ReadAsync(buffer);
var imageDataUrl =
$"data:{format};base64,{Convert.ToBase64String(buffer)}";
imageDataUrls.Add(imageDataUrl);
}
}
}

Cannot access disposed object application connecting to WebAPI

I have content of video and object being created an pass into a http client web api. When ever I pass the image to the client it works find it gets to the post method, but when it comes to the video the client has trouble posting the video. I checked the video size length to make sure it meets the content length and it well under the specific ranges. The error that I receive is that the object has been disposed. If you look at the code the object is never disposed.
Here's the code on the app
public async Task<bool> AddToQueueAsync(Incident i, ContentPage page, MediaFile file)
{
HttpResponseMessage result = null;
Uri webserviceURL = i.IncidentType == IncidentType.Trooper ? trooperURL : gspURL;
var fileStream = File.Open(file.Path, FileMode.Open);
try
{
using (var client = new HttpClient())
{
using (fileStream)
{
using (var stream = new StreamContent(fileStream))
{
using (var content = new MultipartFormDataContent("----MyBoundary"))
{
if(i.MediaType == "Video")
{
content.Add(stream,"file", Guid.NewGuid().ToString() + ".mp4");
}
else
{
content.Add(stream, "file", Guid.NewGuid().ToString() + ".png");
}
content.Add(new StringContent(JsonConvert.SerializeObject(i)), "metadata");
result = await client.PostAsync(webserviceURL, content);
}
}
}
}
Here is the code on the web api:
[HttpPost]
public IHttpActionResult StarGSPDATA() {
try {
if(!Request.Content.IsMimeMultipartContent()) {
Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
}
starGSPDATAinfo suspicousInfo;
string homeDir = AppDomain.CurrentDomain.BaseDirectory;
string dir = $"{homeDir}/uploads/";
Directory.CreateDirectory(dir);
var file = HttpContext.Current.Request.Files.Count > 0 ?
HttpContext.Current.Request.Files[0] : null;
if(HttpContext.Current.Request.Form.Count > 0) {
suspicousInfo = MetaDataFromRequest(HttpContext.Current.Request.Form);
} else {
suspicousInfo = new starGSPDATAinfo();
}
if(file != null && file.ContentLength > 0) {
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(dir, fileName);
suspicousInfo.MediaFilePath = fileName;
try {
file.SaveAs(path);
} catch(Exception e) {
Console.WriteLine($"not saving: {e.ToString()}");
}
} else {
throw new HttpResponseException(
new HttpResponseMessage(
HttpStatusCode.NoContent));
}
CleanData(suspicousInfo);
db.starGSPDATAinfoes.Add(suspicousInfo);
db.SaveChanges();
return Created("http://localhost:50641/api/StarGSPDATA/", JsonConvert.SerializeObject(suspicousInfo));
} catch(Exception e) {
return InternalServerError(e);
}
}
It works for an image but not for a video Please help thank you!
Here is a picture of the error

Uploading objects to google cloud storage buckets in c#

Can someone please provide an example of how to use Google.Apis.Storage.v1 for uploading files to google cloud storage in c#?
I found that this basic operation is not as straight forward as you might expect. Google's documentation about it's Storage API is lacking in information about using it in C# (or any other .NET language). Searching for 'how to upload file to google cloud storage in c#' didn't exactly help me, so here is my working solution with some comments:
Preparation:
You need to create OAuth2 account in your Google Developers Console - go to Project/APIs & auth/Credentials.
Copy Client ID & Client Secret to your code. You will also need your Project name.
Code (it assumes that you've added Google.Apis.Storage.v1 via NuGet):
First, you need to authorize your requests:
var clientSecrets = new ClientSecrets();
clientSecrets.ClientId = clientId;
clientSecrets.ClientSecret = clientSecret;
//there are different scopes, which you can find here https://cloud.google.com/storage/docs/authentication
var scopes = new[] {#"https://www.googleapis.com/auth/devstorage.full_control"};
var cts = new CancellationTokenSource();
var userCredential = await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets,scopes, "yourGoogle#email", cts.Token);
Sometimes you might also want to refresh authorization token via:
await userCredential.RefreshTokenAsync(cts.Token);
You also need to create Storage Service:
var service = new Google.Apis.Storage.v1.StorageService();
Now you can make requests to Google Storage API.
Let's start with creating a new bucket:
var newBucket = new Google.Apis.Storage.v1.Data.Bucket()
{
Name = "your-bucket-name-1"
};
var newBucketQuery = service.Buckets.Insert(newBucket, projectName);
newBucketQuery.OauthToken = userCredential.Result.Token.AccessToken;
//you probably want to wrap this into try..catch block
newBucketQuery.Execute();
And it's done. Now, you can send a request to get list of all of your buckets:
var bucketsQuery = service.Buckets.List(projectName);
bucketsQuery.OauthToken = userCredential.Result.Token.AccessToken;
var buckets = bucketsQuery.Execute();
Last part is uploading new file:
//enter bucket name to which you want to upload file
var bucketToUpload = buckets.Items.FirstOrDefault().Name;
var newObject = new Object()
{
Bucket = bucketToUpload,
Name = "some-file-"+new Random().Next(1,666)
};
FileStream fileStream = null;
try
{
var dir = Directory.GetCurrentDirectory();
var path = Path.Combine(dir, "test.png");
fileStream = new FileStream(path, FileMode.Open);
var uploadRequest = new Google.Apis.Storage.v1.ObjectsResource.InsertMediaUpload(service, newObject,
bucketToUpload,fileStream,"image/png");
uploadRequest.OauthToken = userCredential.Result.Token.AccessToken;
await uploadRequest.UploadAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (fileStream != null)
{
fileStream.Dispose();
}
}
And bam! New file will be visible in you Google Developers Console inside of selected bucket.
You can use Google Cloud APIs without SDK in the following ways:
Required api-key.json file
Install package Google.Apis.Auth.OAuth2 in order to authorize the
HTTP web request
You can set the default configuration for your application in this
way
I did the same using .NET core web API and details are given below:
Url details:
"GoogleCloudStorageBaseUrl": "https://www.googleapis.com/upload/storage/v1/b/",
"GoogleSpeechBaseUrl": "https://speech.googleapis.com/v1/operations/",
"GoogleLongRunningRecognizeBaseUrl": "https://speech.googleapis.com/v1/speech:longrunningrecognize",
"GoogleCloudScope": "https://www.googleapis.com/auth/cloud-platform",
public void GetConfiguration()
{
// Set global configuration
bucketName = _configuration.GetValue<string>("BucketName");
googleCloudStorageBaseUrl = _configuration.GetValue<string>("GoogleCloudStorageBaseUrl");
googleSpeechBaseUrl = _configuration.GetValue<string>("GoogleSpeechBaseUrl");
googleLongRunningRecognizeBaseUrl = _configuration.GetValue<string>("GoogleLongRunningRecognizeBaseUrl");
// Set google cloud credentials
string googleApplicationCredentialsPath = _configuration.GetValue<string>("GoogleCloudCredentialPath");
using (Stream stream = new FileStream(googleApplicationCredentialsPath, FileMode.Open, FileAccess.Read))
googleCredential = GoogleCredential.FromStream(stream).CreateScoped(_configuration.GetValue<string>("GoogleCloudScope"));
}
Get Oauth token:
public string GetOAuthToken()
{
return googleCredential.UnderlyingCredential.GetAccessTokenForRequestAsync("https://accounts.google.com/o/oauth2/v2/auth", CancellationToken.None).Result;
}
To upload file to cloud bucket:
public async Task<string> UploadMediaToCloud(string filePath, string objectName = null)
{
string bearerToken = GetOAuthToken();
byte[] fileBytes = File.ReadAllBytes(filePath);
objectName = objectName ?? Path.GetFileName(filePath);
var baseUrl = new Uri(string.Format(googleCloudStorageBaseUrl + "" + bucketName + "/o?uploadType=media&name=" + objectName + ""));
using (WebClient client = new WebClient())
{
client.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + bearerToken);
client.Headers.Add(HttpRequestHeader.ContentType, "application/octet-stream");
byte[] response = await Task.Run(() => client.UploadData(baseUrl, "POST", fileBytes));
string responseInString = Encoding.UTF8.GetString(response);
return responseInString;
}
}
In order to perform any action to the cloud API, just need to make a HttpClient get/post request as per the requirement.
Thanks
This is for Google.Cloud.Storage.V1 (not Google.Apis.Storage.v1), but appears to be a bit simpler to perform an upload now. I started with the Client libraries "Getting Started" instructions to create a service account and bucket, then experimented to find out how to upload an image.
The process I followed was:
Sign up for Google Cloud free trial
Create a new project in Google Cloud (remember the project name\ID for later)
Create a Project Owner service account - this will result in a json file being downloaded that contains the service account credentials. Remember where you put that file.
The getting started docs get you to add the path to the JSON credentials file into an environment variable called GOOGLE_APPLICATION_CREDENTIALS - I couldn't get this to work through the provided instructions. Turns out it is not required, as you can just read the JSON file into a string and pass it to the client constructor.
I created an empty WPF project as a starting point, and a single ViewModel to house the application logic.
Install the Google.Cloud.Storage.V1 nuget package and it should pull in all the dependencies it needs.
Onto the code.
MainWindow.xaml
<StackPanel>
<Button
Margin="50"
Height="50"
Content="BEGIN UPLOAD"
Click="OnButtonClick" />
<ContentControl
Content="{Binding Path=ProgressBar}" />
</StackPanel>
MainWindow.xaml.cs
public partial class MainWindow
{
readonly ViewModel _viewModel;
public MainWindow()
{
_viewModel = new ViewModel(Dispatcher);
DataContext = _viewModel;
InitializeComponent();
}
void OnButtonClick(object sender, RoutedEventArgs args)
{
_viewModel.UploadAsync().ConfigureAwait(false);
}
}
ViewModel.cs
public class ViewModel
{
readonly Dispatcher _dispatcher;
public ViewModel(Dispatcher dispatcher)
{
_dispatcher = dispatcher;
ProgressBar = new ProgressBar {Height=30};
}
public async Task UploadAsync()
{
// Google Cloud Platform project ID.
const string projectId = "project-id-goes-here";
// The name for the new bucket.
const string bucketName = projectId + "-test-bucket";
// Path to the file to upload
const string filePath = #"C:\path\to\image.jpg";
var newObject = new Google.Apis.Storage.v1.Data.Object
{
Bucket = bucketName,
Name = System.IO.Path.GetFileNameWithoutExtension(filePath),
ContentType = "image/jpeg"
};
// read the JSON credential file saved when you created the service account
var credential = Google.Apis.Auth.OAuth2.GoogleCredential.FromJson(System.IO.File.ReadAllText(
#"c:\path\to\service-account-credentials.json"));
// Instantiates a client.
using (var storageClient = Google.Cloud.Storage.V1.StorageClient.Create(credential))
{
try
{
// Creates the new bucket. Only required the first time.
// You can also create buckets through the GCP cloud console web interface
storageClient.CreateBucket(projectId, bucketName);
System.Windows.MessageBox.Show($"Bucket {bucketName} created.");
// Open the image file filestream
using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open))
{
ProgressBar.Maximum = fileStream.Length;
// set minimum chunksize just to see progress updating
var uploadObjectOptions = new Google.Cloud.Storage.V1.UploadObjectOptions
{
ChunkSize = Google.Cloud.Storage.V1.UploadObjectOptions.MinimumChunkSize
};
// Hook up the progress callback
var progressReporter = new Progress<Google.Apis.Upload.IUploadProgress>(OnUploadProgress);
await storageClient.UploadObjectAsync(
newObject,
fileStream,
uploadObjectOptions,
progress: progressReporter)
.ConfigureAwait(false);
}
}
catch (Google.GoogleApiException e)
when (e.Error.Code == 409)
{
// When creating the bucket - The bucket already exists. That's fine.
System.Windows.MessageBox.Show(e.Error.Message);
}
catch (Exception e)
{
// other exception
System.Windows.MessageBox.Show(e.Message);
}
}
}
// Called when progress updates
void OnUploadProgress(Google.Apis.Upload.IUploadProgress progress)
{
switch (progress.Status)
{
case Google.Apis.Upload.UploadStatus.Starting:
ProgressBar.Minimum = 0;
ProgressBar.Value = 0;
break;
case Google.Apis.Upload.UploadStatus.Completed:
ProgressBar.Value = ProgressBar.Maximum;
System.Windows.MessageBox.Show("Upload completed");
break;
case Google.Apis.Upload.UploadStatus.Uploading:
UpdateProgressBar(progress.BytesSent);
break;
case Google.Apis.Upload.UploadStatus.Failed:
System.Windows.MessageBox.Show("Upload failed"
+ Environment.NewLine
+ progress.Exception);
break;
}
}
void UpdateProgressBar(long value)
{
_dispatcher.Invoke(() => { ProgressBar.Value = value; });
}
// probably better to expose progress value directly and bind to
// a ProgressBar in the XAML
public ProgressBar ProgressBar { get; }
}
Use of Google.Apis.Storage.v1 for uploading files using SDK to google cloud storage in c#:
Required api-key.json file
Install the package Google.Cloud.Storage.V1; and Google.Apis.Auth.OAuth2;
The code is given below to upload the file to the cloud
private string UploadFile(string localPath, string objectName = null)
{
string projectId = ((Google.Apis.Auth.OAuth2.ServiceAccountCredential)googleCredential.UnderlyingCredential).ProjectId;
try
{
// Creates the new bucket.
var objResult = storageClient.CreateBucket(projectId, bucketName);
if (!string.IsNullOrEmpty(objResult.Id))
{
// Upload file to google cloud server
using (var f = File.OpenRead(localPath))
{
objectName = objectName ?? Path.GetFileName(localPath);
var objFileUploadStatus1 = storageClient.UploadObject(bucketName, objectName, null, f);
}
}
}
catch (Google.GoogleApiException ex)
{
// Error code =409, means bucket already created/exist then upload file in the bucket
if (ex.Error.Code == 409)
{
// Upload file to google cloud server
using (var f = File.OpenRead(localPath))
{
objectName = objectName ?? Path.GetFileName(localPath);
var objFileUploadStatus2 = storageClient.UploadObject(bucketName, objectName, null, f);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
return objectName;
}
To set the credentials
private bool SetStorageCredentials()
{
bool status = true;
try
{
if (File.Exists(credential_path))
{
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", credential_path);
using (Stream objStream = new FileStream(Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS"), FileMode.Open, FileAccess.Read))
googleCredential = GoogleCredential.FromStream(objStream);
// Instantiates a client.
storageClient = StorageClient.Create();
channel = new Grpc.Core.Channel(SpeechClient.DefaultEndpoint.Host, googleCredential.ToChannelCredentials());
}
else
{
DialogResult result = MessageBox.Show("File " + Path.GetFileName(credential_path) + " does not exist. Please provide the correct path.");
if (result == System.Windows.Forms.DialogResult.OK)
{
status = false;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
status = false;
}
return status;
}
I used SDK in one of my window application. You can use the same code according to your needs/requirements.
You'll be happy to know it still works in 2016...
I was googling all over using fancy key words like "google gcp C# upload image", until I just plain asked the question: "How do I upload an image to google bucket using C#"... and here I am. I removed the .Result in the user credential, and this was the final edit that worked for me.
// ******
static string bucketForImage = ConfigurationManager.AppSettings["testStorageName"];
static string projectName = ConfigurationManager.AppSettings["GCPProjectName"];
string gcpPath = Path.Combine(Server.MapPath("~/Images/Gallery/"), uniqueGcpName + ext);
var clientSecrets = new ClientSecrets();
clientSecrets.ClientId = ConfigurationManager.AppSettings["GCPClientID"];
clientSecrets.ClientSecret = ConfigurationManager.AppSettings["GCPClientSc"];
var scopes = new[] { #"https://www.googleapis.com/auth/devstorage.full_control" };
var cts = new CancellationTokenSource();
var userCredential = await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets, scopes, ConfigurationManager.AppSettings["GCPAccountEmail"], cts.Token);
var service = new Google.Apis.Storage.v1.StorageService();
var bucketToUpload = bucketForImage;
var newObject = new Google.Apis.Storage.v1.Data.Object()
{
Bucket = bucketToUpload,
Name = bkFileName
};
FileStream fileStream = null;
try
{
fileStream = new FileStream(gcpPath, FileMode.Open);
var uploadRequest = new Google.Apis.Storage.v1.ObjectsResource.InsertMediaUpload(service, newObject,
bucketToUpload, fileStream, "image/"+ ext);
uploadRequest.OauthToken = userCredential.Token.AccessToken;
await uploadRequest.UploadAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (fileStream != null)
{
fileStream.Dispose();
}
}
// ******
Here is the link to their official C# example of ".NET Bookshelf App" using Google Cloud storage.
https://cloud.google.com/dotnet/docs/getting-started/using-cloud-storage
Source on github:
https://github.com/GoogleCloudPlatform/getting-started-dotnet/blob/master/aspnet/3-binary-data/Services/ImageUploader.cs
https://github.com/GoogleCloudPlatform/getting-started-dotnet/tree/master/aspnet/3-binary-data
Nuget
https://www.nuget.org/packages/Google.Cloud.Storage.V1/
Here are 2 examples that helped me to upload files to a bucket in Google Cloud Storage with Google.Cloud.Storage.V1 (not Google.Apis.Storage.v1):
Upload files to Google cloud storage using c#
Uploading .csv Files to Google Cloud Storage using C# .Net
I got both working on a C# Console Application just for testing purposes.
#February 2021
string _projectId = "YOUR-PROJECT-ID-GCP"; //ProjectID also present in the json file
GoogleCredential _credential = GoogleCredential.FromFile("credential-cloud-file-123418c9e06c.json");
/// <summary>
/// UploadFile to GCS Bucket
/// </summary>
/// <param name="bucketName"></param>
/// <param name="localPath">my-local-path/my-file-name</param>
/// <param name="objectName">my-file-name</param>
public void UploadFile(string bucketName, string localPath, string objectName)
{
var storage = StorageClient.Create(_credential);
using var fileStream = File.OpenRead(localPath);
storage.UploadObject(bucketName, objectName, null, fileStream);
Console.WriteLine($"Uploaded {objectName}.");
}
You get the credentials JSON file from the google cloud portal where you create a bucket under your project..
Simple, with auth:
private void SaveFileToGoogleStorage(string path, string? fileName, string ext)
{
var filePath = Path.Combine(path, fileName + ext);
var gcCredentialsPath = Path.Combine(Environment.CurrentDirectory, "gc_sa_key.json");
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", gcCredentialsPath);
var gcsStorage = StorageClient.Create();
using var f = File.OpenRead(filePath);
var objectName = Path.GetFileName(filePath);
gcsStorage.UploadObject(_bucketName, objectName, null, f);
Console.WriteLine($"Uploaded {objectName}.");
}

How to download/upload files from/to SharePoint 2013 using CSOM?

I am developing a Win8 (WinRT, C#, XAML) client application (CSOM) that needs to download/upload files from/to SharePoint 2013.
How do I do the Download/Upload?
Upload a file
Upload a file to a SharePoint site (including SharePoint Online) using File.SaveBinaryDirect Method:
using (var clientContext = new ClientContext(url))
{
using (var fs = new FileStream(fileName, FileMode.Open))
{
var fi = new FileInfo(fileName);
var list = clientContext.Web.Lists.GetByTitle(listTitle);
clientContext.Load(list.RootFolder);
clientContext.ExecuteQuery();
var fileUrl = String.Format("{0}/{1}", list.RootFolder.ServerRelativeUrl, fi.Name);
Microsoft.SharePoint.Client.File.SaveBinaryDirect(clientContext, fileUrl, fs, true);
}
}
Download file
Download file from a SharePoint site (including SharePoint Online) using File.OpenBinaryDirect Method:
using (var clientContext = new ClientContext(url))
{
var list = clientContext.Web.Lists.GetByTitle(listTitle);
var listItem = list.GetItemById(listItemId);
clientContext.Load(list);
clientContext.Load(listItem, i => i.File);
clientContext.ExecuteQuery();
var fileRef = listItem.File.ServerRelativeUrl;
var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileRef);
var fileName = Path.Combine(filePath,(string)listItem.File.Name);
using (var fileStream = System.IO.File.Create(fileName))
{
fileInfo.Stream.CopyTo(fileStream);
}
}
This article describes various options for accessing SharePoint content. You have a choice between REST and CSOM. I'd try CSOM if possible. File upload / download specifically is nicely described in this article.
Overall notes:
//First construct client context, the object which will be responsible for
//communication with SharePoint:
var context = new ClientContext(#"http://site.absolute.url")
//then get a hold of the list item you want to download, for example
var list = context.Web.Lists.GetByTitle("Pipeline");
var query = CamlQuery.CreateAllItemsQuery(10000);
var result = list.GetItems(query);
//note that data has not been loaded yet. In order to load the data
//you need to tell SharePoint client what you want to download:
context.Load(result, items=>items.Include(
item => item["Title"],
item => item["FileRef"]
));
//now you get the data
context.ExecuteQuery();
//here you have list items, but not their content (files). To download file
//you'll have to do something like this:
var item = items.First();
//get the URL of the file you want:
var fileRef = item["FileRef"];
//get the file contents:
FileInformation fileInfo = File.OpenBinaryDirect(context, fileRef.ToString());
using (var memory = new MemoryStream())
{
byte[] buffer = new byte[1024 * 64];
int nread = 0;
while ((nread = fileInfo.Stream.Read(buffer, 0, buffer.Length)) > 0)
{
memory.Write(buffer, 0, nread);
}
memory.Seek(0, SeekOrigin.Begin);
// ... here you have the contents of your file in memory,
// do whatever you want
}
Avoid working with the stream directly, read it into the memory first. Network-bound streams are not necessarily supporting stream operations, not to mention performance. So, if you are reading a pic from that stream or parsing a document, you may end up with some unexpected behavior.
On a side note, I have a related question re: performance of this code above, as you are taking some penalty with every file request. See here. And yes, you need 4.5 full .NET profile for this.
File.OpenBinaryDirect may cause exception when you are using Oauth accestoken
Explained in This Article
Code should be written as below to avoid exceptions
Uri filename = new Uri(filepath);
string server = filename.AbsoluteUri.Replace(filename.AbsolutePath,
"");
string serverrelative = filename.AbsolutePath;
Microsoft.SharePoint.Client.File file =
this.ClientContext.Web.GetFileByServerRelativeUrl(serverrelative);
this.ClientContext.Load(file);
ClientResult<Stream> streamResult = file.OpenBinaryStream();
this.ClientContext.ExecuteQuery();
return streamResult.Value;
A little late this comment but I will leave here my results working with the library of SharePoin Online and it is very easy to use and implement in your project, just go to the NuGet administrator of .Net and Add Microsoft.SharePoint.CSOM to your project .
[https://developer.microsoft.com/en-us/office/blogs/new-sharepoint-csom-version-released-for-office-365-may-2017/][1]
The following code snippet will help you connect your credentials to your SharePoint site, you can also read and download files from a specific site and folder.
using System;
using System.IO;
using System.Linq;
using System.Web;
using Microsoft.SharePoint.Client;
using System.Security;
using ClientOM = Microsoft.SharePoint.Client;
namespace MvcApplication.Models.Home
{
public class SharepointModel
{
public ClientContext clientContext { get; set; }
private string ServerSiteUrl = "https://somecompany.sharepoint.com/sites/ITVillahermosa";
private string LibraryUrl = "Shared Documents/Invoices/";
private string UserName = "someone.surname#somecompany.com";
private string Password = "********";
private Web WebClient { get; set; }
public SharepointModel()
{
this.Connect();
}
public void Connect()
{
try
{
using (clientContext = new ClientContext(ServerSiteUrl))
{
var securePassword = new SecureString();
foreach (char c in Password)
{
securePassword.AppendChar(c);
}
clientContext.Credentials = new SharePointOnlineCredentials(UserName, securePassword);
WebClient = clientContext.Web;
}
}
catch (Exception ex)
{
throw (ex);
}
}
public string UploadMultiFiles(HttpRequestBase Request, HttpServerUtilityBase Server)
{
try
{
HttpPostedFileBase file = null;
for (int f = 0; f < Request.Files.Count; f++)
{
file = Request.Files[f] as HttpPostedFileBase;
string[] SubFolders = LibraryUrl.Split('/');
string filename = System.IO.Path.GetFileName(file.FileName);
var path = System.IO.Path.Combine(Server.MapPath("~/App_Data/uploads"), filename);
file.SaveAs(path);
clientContext.Load(WebClient, website => website.Lists, website => website.ServerRelativeUrl);
clientContext.ExecuteQuery();
//https://somecompany.sharepoint.com/sites/ITVillahermosa/Shared Documents/
List documentsList = clientContext.Web.Lists.GetByTitle("Documents"); //Shared Documents -> Documents
clientContext.Load(documentsList, i => i.RootFolder.Folders, i => i.RootFolder);
clientContext.ExecuteQuery();
string SubFolderName = SubFolders[1];//Get SubFolder 'Invoice'
var folderToBindTo = documentsList.RootFolder.Folders;
var folderToUpload = folderToBindTo.Where(i => i.Name == SubFolderName).First();
var fileCreationInformation = new FileCreationInformation();
//Assign to content byte[] i.e. documentStream
fileCreationInformation.Content = System.IO.File.ReadAllBytes(path);
//Allow owerwrite of document
fileCreationInformation.Overwrite = true;
//Upload URL
fileCreationInformation.Url = ServerSiteUrl + LibraryUrl + filename;
Microsoft.SharePoint.Client.File uploadFile = documentsList.RootFolder.Files.Add(fileCreationInformation);
//Update the metadata for a field having name "DocType"
uploadFile.ListItemAllFields["Title"] = "UploadedCSOM";
uploadFile.ListItemAllFields.Update();
clientContext.ExecuteQuery();
}
return "";
}
catch (Exception ex)
{
throw (ex);
}
}
public string DownloadFiles()
{
try
{
string tempLocation = #"c:\Downloads\Sharepoint\";
System.IO.DirectoryInfo di = new DirectoryInfo(tempLocation);
foreach (FileInfo file in di.GetFiles())
{
file.Delete();
}
FileCollection files = WebClient.GetFolderByServerRelativeUrl(this.LibraryUrl).Files;
clientContext.Load(files);
clientContext.ExecuteQuery();
if (clientContext.HasPendingRequest)
clientContext.ExecuteQuery();
foreach (ClientOM.File file in files)
{
FileInformation fileInfo = ClientOM.File.OpenBinaryDirect(clientContext, file.ServerRelativeUrl);
clientContext.ExecuteQuery();
var filePath = tempLocation + file.Name;
using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Create))
{
fileInfo.Stream.CopyTo(fileStream);
}
}
return "";
}
catch (Exception ex)
{
throw (ex);
}
}
}
}
Then to invoke the functions from the controller in this case MVC ASP.NET is done in the following way.
using MvcApplication.Models.Home;
using System;
using System.Web.Mvc;
namespace MvcApplication.Controllers
{
public class SharepointController : MvcBoostraBaseController
{
[HttpPost]
public ActionResult Upload(FormCollection form)
{
try
{
SharepointModel sharepointModel = new SharepointModel();
return Json(sharepointModel.UploadMultiFiles(Request, Server), JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return ThrowJSONError(ex);
}
}
public ActionResult Download(string ServerUrl, string RelativeUrl)
{
try
{
SharepointModel sharepointModel = new SharepointModel();
return Json(sharepointModel.DownloadFiles(), JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return ThrowJSONError(ex);
}
}
}
}
If you need this source code you can visit my github repository
https://github.com/israelz11/MvcBoostrapTestSharePoint/
Private Sub DownloadFile(relativeUrl As String, destinationPath As String, name As String)
Try
destinationPath = Replace(destinationPath + "\" + name, "\\", "\")
Dim fi As FileInformation = Microsoft.SharePoint.Client.File.OpenBinaryDirect(Me.context, relativeUrl)
Dim down As Stream = System.IO.File.Create(destinationPath)
Dim a As Integer = fi.Stream.ReadByte()
While a <> -1
down.WriteByte(CType(a, Byte))
a = fi.Stream.ReadByte()
End While
Catch ex As Exception
ToLog(Type.ERROR, ex.Message)
End Try
End Sub
Though this is an old post and have many answers, but here I have my version of code to upload the file to sharepoint 2013 using CSOM(c#)
I hope if you are working with downloading and uploading files then you know how to create Clientcontext object and Web object
/* Assuming you have created ClientContext object and Web object*/
string listTitle = "List title where you want your file to upload";
string filePath = "your file physical path";
List oList = web.Lists.GetByTitle(listTitle);
clientContext.Load(oList.RootFolder);//to load the folder where you will upload the file
FileCreationInformation fileInfo = new FileCreationInformation();
fileInfo.Overwrite = true;
fileInfo.Content = System.IO.File.ReadAllBytes(filePath);
fileInfo.Url = fileName;
File fileToUpload = fileCollection.Add(fileInfo);
clientContext.ExecuteQuery();
fileToUpload.CheckIn("your checkin comment", CheckinType.MajorCheckIn);
if (oList.EnableMinorVersions)
{
fileToUpload.Publish("your publish comment");
clientContext.ExecuteQuery();
}
if (oList.EnableModeration)
{
fileToUpload.Approve("your approve comment");
}
clientContext.ExecuteQuery();
And here is the code for download
List oList = web.Lists.GetByTitle("ListNameWhereFileExist");
clientContext.Load(oList);
clientContext.Load(oList.RootFolder);
clientContext.Load(oList.RootFolder.Files);
clientContext.ExecuteQuery();
FileCollection fileCollection = oList.RootFolder.Files;
File SP_file = fileCollection.GetByUrl("fileNameToDownloadWithExtension");
clientContext.Load(SP_file);
clientContext.ExecuteQuery();
var Local_stream = System.IO.File.Open("c:/testing/" + SP_file.Name, System.IO.FileMode.CreateNew);
var fileInformation = File.OpenBinaryDirect(clientContext, SP_file.ServerRelativeUrl);
var Sp_Stream = fileInformation.Stream;
Sp_Stream.CopyTo(Local_stream);
Still there are different ways I believe that can be used to upload and download.
Just a suggestion SharePoint 2013 online & on-prem file encoding is UTF-8 BOM.
Make sure your file is UTF-8 BOM, otherwise your uploaded html and scripts may not rendered correctly in browser.
I would suggest reading some Microsoft documentation on what you can do with CSOM. This might be one example of what you are looking for, but there is a huge API documented in msdn.
// Starting with ClientContext, the constructor requires a URL to the
// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");
// Assume that the web has a list named "Announcements".
List announcementsList = context.Web.Lists.GetByTitle("Announcements");
// Assume there is a list item with ID=1.
ListItem listItem = announcementsList.Items.GetById(1);
// Write a new value to the Body field of the Announcement item.
listItem["Body"] = "This is my new value!!";
listItem.Update();
context.ExecuteQuery();
From: http://msdn.microsoft.com/en-us/library/fp179912.aspx

Categories