Get full path of a file stored in sharepint documentlibrary - asp.net-mvc

I have a file stored in a sharepoint libarary like
filePathAndName = "http://spstore/sites/appsitename/documentlibraryname/abc.xls"
I need to be able to open the the abc.xls file using
byte[] buffer = System.IO.File.ReadAllBytes(filePathAndName);
but i get an error stating. uri formats are not supported. How do I get the full path to the file?

You have to download the file first. For example you could use a WebClient to send an HTTP request to the remote server and retrieve the file contents:
using (var client = new WebClient())
{
byte[] file = client.DownloadData("http://spstore/sites/appsitename/documentlibraryname/abc.xls");
// TODO: do something with the file data
}

Related

creating CSV file in local drive with asp.net in azure

I have a webapp in which i can create csv file and locate it in my c drive,
It works fine when running locally, but once i deploy the application to Azure
I'm getting :
UnauthorizedAccessException: Access to the path 'C:\Tuesday_HH19_MI6.csv' is denied.
How can i allow the website to access and create a file in the user's local drive?
I attached the entire log exception from azure if this helps,
Thank you
A Web App running in Azure can't directly save it to your user's local drive, but it can generate the CSV and then prompt them to download it via the browser. You can use a few options depending on if you are trying to send that already exists on the filesystem or if you have generated it dynamically and have it as a byte array or stream.
Here are some sample controller methods to give you and idea. Your controller could be doing a bunch of stuff before the return statement, these examples are simplified.
Existing file on filesystem, use a FileResult:
public FileResult DownloadFile()
{
// create the file etc and save to FS
return File("/Files/File Result.pdf", "text/csv", "MyFileName.csv");
}
If the file is generated in memory and you have it as a byte array:
public FileContentResult DownloadContent()
{
// Create CSV as byte array
var myfile = MyMethodtoCreateCSV();
return new FileContentResult(myfile, "text/csv") {
FileDownloadName = "MyFileName.csv"
};
}

Dart Html - Convert Blob to File

I'm attempting to write a test for some dart:html code.
I have a method with a File parameter (html File, not io File).
testFile(File file)
I'm able to create a Blob with the needed data for the file (minus file name, date, etc.), but it appears there is no way to create File objects in dart:html, as it's reserved for internal use in html_dartium.dart.
factory File._() { throw new UnsupportedError("Not supported"); }
Is there any other way to create an HTML File object?
I've seen FileReaders mentioned, but the results from those is either a String or uint8list.
After further research, I achieved what I was looking for with the following:
List<String> file_contents = ["test\n"];
Blob blob = new Blob(file_contents, 'text/plain', 'native');
FileSystem _filesystem = await window.requestFileSystem(1024 * 1024, persistent: false);
FileEntry fileEntry = await _filesystem.root.createFile('dart_test.csv');
FileWriter fw = await fileEntry.createWriter();
fw.write(blob);
File file = await fileEntry.file();
Something like
Blob response = _downloadRequest.response;
final FileReader reader = new FileReader();
reader.onLoad.listen((e) {
_handleData(reader);
});
reader.readAsArrayBuffer(response);
See Downloading a file using Dart GDrive api with authorized GET request

Azure blob authorization header

I am trying to use refit to upload to azure blob storage from a Xamarin iOS application. This is the interface configuration I am using for Refit:
[Headers("x-ms-blob-type: BlockBlob")]
[Put("/{fileName}")]
Task<bool> UploadAsync([Body]byte[] content, string sasTokenKey,
[Header("Content-Type")] string contentType);
Where the sasTokenKey parameter looks like this:
"/content-default/1635839001660743375-66f93195-e923-4c8b-a3f1-5f3f9ba9dd32.jpeg?sv=2015-04-05&sr=b&sig=Up26vDxQikFqo%2FDQjRB08YtmK418rZfKx1IHbYKAjIE%3D&se=2015-11-23T18:59:26Z&sp=w"
This is how I am using Refit to call the azure blob server:
var myRefitApi = RestService.For<IMyRefitAPI>("https://myaccount.blob.core.windows.net");
myRefitApi.UploadAsync(photoBytes, sasTokenKey, "image/jpeg"
However I am getting the follow error:
Response status code does not indicate success: 403 (Server failed to
authenticate the request. Make sure the value of Authorization header is
formed correctly including the signature.)
The SAS url is working fine if I call it directly like this
var content = new StreamContent(stream);
content.Headers.Add("Content-Type", "jpeg");
content.Headers.Add("x-ms-blob-type", "BlockBlob");
var task = HttpClient.PutAsync(new Uri(sasTokenUrl), content);
task.Wait();
So basically I am just trying to do the same thing using Refit.
Any idea how to get Refit working with Azure Blob Storage?
Thanks!
[UPDATE] I am now able to upload the bytes to the azure blob server but something seems to be wrong with the byte data because I am not able to view the image. Here is the code I am using to convert to byte array.
byte[] bytes;
using (var ms = new MemoryStream())
{
stream.Position = 0;
stream.CopyTo(ms);
ms.Position = 0;
bytes = ms.ToArray();
}
[UPDATE] Got it fixed by using stream instead of byte array!
I see %2F and %3D and I'm curious if refit is encoding those a second time. Try sending the token without encoding it.
This is incorrect use of Authorization header. You use Authorization header when you want to authorize the requests using account key. If you have the Shared Access Signature then you really don't need this header as the authorization information is included in the SAS itself. You can simply use the SAS URL for uploading files.

Azure download blob to users computer

I was working on my download blob function when I ran into some problems..
I want the user to be able to download a blob and I want a specific filename on that item when its downloaded to the users computer. I also want the user to decide which folder the item should be saved to.
This is my not so good looking code so far:
var fileName = "tid.txt9c6b412a-270a-4f67-8e65-7ce2bf87503d";
var containerName = "uploads";
CloudStorageAccount account = CloudStorageAccount.DevelopmentStorageAccount;
var blobClient = account.CreateCloudBlobClient();
var container = blobClient.GetContainerReference(containerName);
var blob = container.GetBlockBlobReference(fileName);
using (var filestream = System.IO.File.OpenWrite(#"C:\Info\tid.txt9c6b412a-270a-4f67-8e65-7ce2bf87503d"))
{
blob.DownloadToStream(filestream);
}
fileName = the blob name
Is it possible to change the name? The file ending gets all messed up with my guid.
At the moment the download to folder is C:\Info.. How would this work when the website is published? How can I let the user decide which folder the item should be saved to? Am i doing this right?
thank you in advance
/Filip
How would this work when the website is published?
Slow for the user and expensive for you. You are streaming the BLOB through your app, so you'll bottleneck. Use Shared Access Signatures and download the blob directly from the browser. Use Content-Disposition as part of the URL to have the browser prompt the user with a Save As dialog. See Javascript download a URL - Azure Blob Storage.
Your question: Is it possible to change the name?
The name of the blob and the name on the user's disk are your/his choice. There is no need for them to match, except perhaps to avoid confusion. On the off chance that your user will upload it again (with changes, perhaps?) save some metadata so the original file and the updated file can be related in blob storage.
Once you execute the line:
var blob = container.GetBlockBlobReference(fileName);
... you have told Azure all it needs to know to locate the blob.
In the line:
using (var filestream = System.IO.File.OpenWrite...
... you tell your code where to put the file on the disk. You say it's a website, so this statement will put the file onto the web server's disk, not your user's. To get the file onto the user's disk, you need one more step - download the file from the web server (web role instance) to your user's computer. You can give him control of the folder and file name. Here is the relevant section in MSDN:
Downloading and Uploading Files
Is this download function acceptable? Slow/expensive or is it as good as it gets?
public void DownloadFile(string blobName)
{
CloudBlobContainer blobContainer = CloudStorageServices.GetCloudBlobsContainer();
CloudBlockBlob blob = blobContainer.GetBlockBlobReference(blobName);
MemoryStream memStream = new MemoryStream();
blob.DownloadToStream(memStream);
Response.ContentType = blob.Properties.ContentType;
Response.AddHeader("Content-Disposition", "Attachment; filename=" + blobName.ToString());
Response.AddHeader("Content-Length", (blob.Properties.Length - 1).ToString());
Response.BinaryWrite(memStream.ToArray());
Response.End();
}

Google data API for .Net allows Sharing outside organization in Google apps account

I am using Google Data API for .Net(version 1.9) in my application.
I have created a Google apps account and i have set the "Users cannot share documents outside this organization" setting under Google Docs.
When i try to share a file outside of the domain(organization) from Google docs web, i get a error saying the file cannot be shared outside of my domain.
But when i try the same thing from the API, it succeeds. I get a 200 success from the API. When i try to access the file from the share link it says 'You need permission to access this resource'. My question is shouldn't the API return with a error? how can i handle this case?
Here is the code that I am using:
DocumentsRequest request = null;
/* request initialization */
string csBatchReqBody = "<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:gAcl="http://schemas.google.com/acl/2007" xmlns:batch="http://schemas.google.com/gdata/batch"><category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/acl/2007#accessRule"/><entry><id>https://docs.google.com/feeds/default/private/full/document:1DsELtiNwq-ogOrp8cAONdMpGR4gBF79PjijTae-vVNg/acl/user:myusername#mydomain.com</id><batch:operation type="query"/></entry><entry><batch:id>1</batch:id><batch:operation type="insert"/><gAcl:role value="reader"/><gAcl:scope type="user" value="myusername#gmail.com"/></entry>"
string Url = "https://docs.google.com/feeds/default/private/full/document:1DsELtiNwq-ogOrp8cAONdMpGR4gBF79PjijTae-vVNg/acl/batch";
byte[] byteArray = Encoding.ASCII.GetBytes(csBatchReqBody);
MemoryStream inputStream = new MemoryStream(byteArray);
AtomEntry reply = request.Service.Insert(new Uri(Url), inputStream, "application/atom+xml", "");
MemoryStream stream = new MemoryStream();
reply.SaveToXml(stream);
The API actually returns a 400 if you try to share a file outside the domain and the admins have set the "Users cannot share documents outside this organization" flag.
Your code sends a batch request (even if for a single element), you'd have to check the batch response to notice the error.
Instead, use the following code to share a document to a single user, it assumes that entry is the DocumentEntry you want to share:
AclEntry acl = new AclEntry();
acl.Scope = new AclScope("username#gmail.com", "user");
acl.Role = new AclRole("reader");
acl = service.Insert(new Uri(entry.AccessControlList), acl);

Resources