Copying file from sharepoint in a web app - c#

Currently our application is working with a Word Document which is stored locally in the file system. It reads it and manipulate it, returning the updated document to the user. I have the following code:
var tempFileName = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".docx");
File.Copy(fileName, tempFileName);
if (!File.Exists(tempFileName))
throw new ArgumentException("Unable to create file: " + tempFileName);
using (var doc = WordprocessingDocument.Open(tempFileName, true))
it was creating a temp file and copying the word doc and then manipulating the temp file. This way the original word doc is untouched.
We were recently asked to move the word doc into sharepoint, i'm able to connect using the WebClient class and verify the file exists, but I'm not able to figure out how to copy the file from Sharepoint. I've tried:
var client = new WebClient { Credentials = CredentialCache.DefaultCredentials };
// Create a request for the URL.
WebRequest request = WebRequest.Create(fileName);
// If required by the server, set the credentials.
request.Credentials = CredentialCache.DefaultCredentials;
// Get the response.
var response = (HttpWebResponse)request.GetResponse();
//check response status
if (String.Compare(response.StatusDescription, "OK", StringComparison.OrdinalIgnoreCase) == 0)
{
client.DownloadFile(fileName, Guid.NewGuid() + ".docx");
//URL exists so that means file exists
return true;
}
throw new ArgumentException("File \"" + fileName + "\" do not exists");
Problem is when I call DownloadFile it works, but I don't know where that file is sent. Is there a way to connect to the file in sharepoint and just copy it over to the users tempath as the original way?

Related

How to get the file extension of a downloaded file in One Drive Graph API

I have written a console app in c# following this tutorial: https://learn.microsoft.com/en-gb/training/modules/msgraph-access-file-data/3-exercise-access-files-onedrive
Now when I download a file from my OneDrive via the console app using Microsoft Graph API, all the files get downloaded in type "File". However, the files are of type "Docx".
So how do I ensure that the files get downloaded in their original extension format? (.docx, .ppt, .csv, etc.)
var fileId = "01HLTXGBVIH3R6ILTKF5FKB2EMZKFG3MQ6";
var request = client.Me.Drive.Items[fileId].Content.Request();
var stream = request.GetAsync().Result;
var driveItemPath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "driveItem_" + fileId + ".file");
var driveItemFile = System.IO.File.Create(driveItemPath);
stream.Seek(0, SeekOrigin.Begin);
stream.CopyTo(driveItemFile);
Console.WriteLine("Saved file to: " + driveItemPath);
Make a request to get file and read name property which represents the name of the item (filename and extension).
var fileId = "01HLTXGBVIH3R6ILTKF5FKB2EMZKFG3MQ6";
// make a request to get the file
var file = client.Me.Drive.Items[fileId].Request().GetAsync().Result;
var fileName = file.Name;
var request = client.Me.Drive.Items[fileId].Content.Request();
var stream = request.GetAsync().Result;
// create a file with the same name
var driveItemPath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), fileName);
var driveItemFile = System.IO.File.Create(driveItemPath);
stream.Seek(0, SeekOrigin.Begin);
stream.CopyTo(driveItemFile);
Console.WriteLine("Saved file to: " + driveItemPath);

Receiving errors when retrieving a file via FTP and delivering to multiple servers

To start with, my goal is to use FTP to retrieve a file and put it on multiple servers. This is intended as a backup procedure where we're taking a file and putting it onto two different backup servers then removing it from the FTP server.
In case this is relevant, the program runs as a service on a server.
I have tried two different methods and gotten 3 different errors so I will detail those. I am open to trying different libraries, whole different methods, and that's why I'm focusing on the overall goal instead of the specific code and errors.
So the first method worked successfully when I tested it locally on my dev laptop; I was able to do everything I wanted. It's worth noting that I debugged as the same domain account that the service runs on in the environments. When I deployed to test I received the error "The underlying connection was closed: The server committed a protocol violation."
I have (of course) trimmed this code down to what I believe are the relevant parts.
This gets called for each path that's being delivered to. They read similar to:
first case: \\fqdn\directory
second case: \\192.168.123.123\directory$
private bool CopyFTPToPath(string file, string path)
{
try
{
string filePath = "ftp://" + Settings["Host"].Value + "/" + Settings["Path"].Value + "/" + file;
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(filePath);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential("user", "pass");
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(responseStream))
{
using (StreamWriter writer = new StreamWriter(path + "/" + file, false))
{
writer.Write(reader.ReadToEnd());
}
}
}
}
return File.Exists(path + "/" + file);
catch(Exception ex)
{
Utility.LogError(ErrorType.Alert, ex);
}
}
Again this is successful when I run it locally, it fails when run on the server with the same credentials, with the above protocol violation error. The error occurs when it attempts to create the StreamWriter.
So I tried using a library to handle the connection and grabbed the WinSCP library because I've seen it recommended on here frequently. The code I wrote for that is this:
private bool CopyFTPToPath(string file, string path)
{
try
{
string filePath = "ftp://" + Settings["Host"].Value + "/" + Settings["Path"].Value + "/" + file;
SessionOptions sessionOptions = new SessionOptions() {
Protocol = Protocol.Ftp,
HostName = Settings.Settings["Host"].Value,
UserName = "user",
Password = "pass"
};
using(Session session = new Session())
{
session.Open(sessionOptions);
TransferOptions transferOptions = new TransferOptions();
transferOptions.TransferMode = TransferMode.Binary;
TransferEventArgs result = session.GetFileToDirectory(filePath, path,false,transferOptions);
}
return File.Exists(path + "/" + file);
catch(Exception ex)
{
Utility.LogError(ErrorType.Alert, ex);
}
}
Now this block of code fails at the session.GetFileToDirectory call, throwing a System.IO.DirectoryNotFoundException on the path. In this case I'm wondering if WinSCP is unable to handle a network path as the local directory path.
Here is a sanitized stacktrace from the error, for what that's worth. If the local directory parameter is actually local it seems to work, so I think that's what's going on there.
{System.IO.DirectoryNotFoundException: \\192.***.***.***\Path\Path
at WinSCP.Session.DoGetFilesToDirectory(String remoteDirectory, String localDirectory, String filemask, Boolean remove, TransferOptions options, String additionalParams)
at WinSCP.Session.GetEntryToDirectory(String remoteFilePath, String localDirectory, Boolean remove, TransferOptions options, String additionalParams)
at WinSCP.Session.GetFileToDirectory(String remoteFilePath, String localDirectory, Boolean remove, TransferOptions options)
at Program.RoutineTasks.Backup.CopyFTPToPath(String file, String path) in C:\Projects\Program\RoutineTasks\Backup.cs:line 114}
FTP is my only option to access this file. The file is 130gb, I don't have disk space on the server that runs this to copy it local to hand out. Both of those are outside of my control.
EDIT: I have found a solution that will definitely work if I can figure out how to manage the streams better, because the files are huge so I need to break them up to prevent running out of memory.
That code is this, in place of the using Session block above
using(Session session = new Session())
{
session.Open(sessionOptions);
TransferOptions transferOptions = new TransferOptions();
transferOptions.TransferMode = TransferMode.Binary;
using (StreamReader reader = new StreamReader(session.GetFile(filePath, transferOptions)))
{
using (StreamWriter writer = new StreamWriter(path + "/" + file, false))
{
while (!reader.EndOfStream)
{
writer.Write(reader.Read());
}
}
}
}
In the end this wound up being related to permissions on the account. When I presented to the sysadmin that the service account's access to the path was behaving inconsistently between my laptop and the test environment here is what he said:
"you have to configure all non windows shares through the mmc snapin"
The paths I am delivering to are non-windows. He made a change there and the SA was then able to access the paths from the test server. This was not something that could have been solved simply by code.

Download XML file using .net core API to local machine

I am facing issue while downloading/exporting XML file from C# model to local machine of browser(I have front end for it).
However I am able to download/export the file from C# model to XML and save it on directory on server.
I am using below code for it :
var gradeExportDto = Mapper.Map<GradeExportDto>(responseGradeDto);
System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(gradeExportDto.GetType());
var path = _configuration.GetValue<string>(AppConstants.IMPORT_EXPORT_LOCAL_URL) + "\\"+ responseGradeDto.Code+"_"+DateTime.UtcNow.ToString("yyyy-MM-dd") + ".xml";
System.IO.FileStream file = System.IO.File.Create(path);
writer.Serialize(file, gradeExportDto);
file.Close();
Angular Code :
onExport(selectedData: any): void{
this.apiService.post(environment.api_url_master, 'ImportExport/ExportGrade/', selectedData).subscribe(result => {
this.translateService.get('GradeExportSuccess').subscribe(value => this.toastr.success(value));
}, err => {
this.toastr.error(err.message);
});
}
I need help in getting this file downloaded to local system on which browser is running.
Please let me know if more information is required from my side.
NOTE : I am not trying to download existing file. I have model in C# which I need to convert in XML and then download it to my local. However I am able to convert it to XML but not able to download on local.
You cannot save anything directly to a client machine. All you can do is provide the file as a response to a request, which will then generally prompt a download dialog on the client, allowing them to choose to save it somewhere on their local machine.
What #croxy linked you to is how to return such a response. If the issue is that the answer is using an existing file, you can disregard that part. The idea is that you're returning a byte[] or stream, regardless of where that's actually coming from. If you're creating the XML in memory, then you can simply do something like:
return File(memoryStream.ToArray(), "application/xml", "file.xml");
Instead of serializing your data into a file, serialize it into a stream eg. MemoryStream and return a File() from your action:
public IActionResult GetXml()
{
var gradeExportDto = Mapper.Map<GradeExportDto>(responseGradeDto);
var writer = new System.Xml.Serialization.XmlSerializer(gradeExportDto.GetType());
var stream = new MemoryStream();
writer.Serialize(stream, gradeExportDto);
var fileName = responseGradeDto.Code + "_" + DateTime.UtcNow.ToString("yyyy-MM-dd") + ".xml";
return File(stream.ToArray(), "application/xml", fileName);
}

Copy file from URI format path to local path

I am trying to copy a file which is on a server and all I've got is it's URI format path.
I've been trying to implement copying in C# .NET 4.5, but seems like CopyFile is not good with handling URI formats.
So I've used IronPython with shutil, but seems like it is also not good with URI format paths.
How do I get that file local?
private string CopyFile(string from, string to, string pythonLibDir, string date)
{
var dateTime = DateTime.Today;
if (dateTime.ToString("yy-MM-dd") == date)
{
return "";
}
var pyEngine = Python.CreateEngine();
var paths = pyEngine.GetSearchPaths();
paths.Add(pythonLibDir);
pyEngine.SetSearchPaths(paths);
pyEngine.Execute("import shutil\n" +
"shutil.copyfile('" + from + "', '" + to + "')");
return dateTime.ToString("yy-MM-dd");
}
I take all paths from xml config file.
you can use a webclient and then get the file on a particular folder.
using (WebClient wc = new WebClient())
wc.DownloadFile("http://sitec.com/web/myfile.jpg", #"c:\images\xyz.jpg");
or you can also use: HttpWebRequest inc ase you just want to read the content from a file from a server.
var http = (HttpWebRequest)WebRequest.Create("http://sitetocheck.com");
var response = http.GetResponse();
var stream = response.GetResponseStream();
var sr = new StreamReader(stream);
var content = sr.ReadToEnd();
With Python
import urllib
urllib.urlretrieve("http://www.myserver.com/myfile", "myfile.txt")
urlretrieve
Copy a network object denoted by a URL to a local file, if necessary. If the URL points to a local file, or a valid cached copy of the object exists, the object is not copied.

Download PDF file from Web location and Prompt user SaveAs box on client in web-Application ASP C#

I have link of a PDF file located on a website e.g. (https://www.mysite.com/file.pdf).
What I need is prompt the user (on Client side) the SaveAs box to choose the file location to save the file.
I tried the SaveFileDialog , but got know that it is only for Windows Forms. and my application is web based.
C# Code
var fileNumber = lblFileNumber.Text;
string fileDownloadLink = "http://www.mysite.com/" + fileNumber + ".pdf";
string fileName = fileNumber + ".pdf";
bool exist = false;
try
{
var request = (HttpWebRequest)System.Net.WebRequest.Create(fileDownloadLink);
using (var response = (HttpWebResponse)request.GetResponse())
{
exist = response.StatusCode == HttpStatusCode.OK;
}
}
catch
{
}
if (exist)
{
var wClient = new WebClient();
wClient.DownloadFile(fileDownloadLink, fileName);
}
I wrote the above code, it does check if the file is exist on the file location, but
how to prompt user to choose the location to where he want to save file and save on his local hard drive?
It is not possible to do that. When the user wants to download a file, the browser will decide how to show it to the user.
Write a file from disk directly:
HttpContext.Current.Response.TransmitFile(#"C:\yourfile.pdf");
Or from another source, loaded as a byte array:
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.BinaryWrite(bytesOfYourFile);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();

Categories