WebAPI File Upload MultipartFormDataStreamProvider cleanup access denied - asp.net-web-api

I am unable to cleanup the temporary file after the user uploads a file using
MultipartFormDataStreamProvider. I get "access to the path '...' is denied". However, it can delete old temporary files.
I based my cleanup on the example given here MultipartFormDataStreamProvider Cleanup.
I checked the windows identity and it has Read&Execute/read/write access to the folder. I think, something has locked by the file somehow, but I can't tell what. I tried moving the delete to the end and adding a sleep, but neither helped.
What is the correct way to cleanup these files? I need to do it immediately after I am done using the file. There really should be a setting so it does it for you.
[HttpPost]
[Route("UploadFile")]
public async Task<HttpResponseMessage> UploadFile(string toolToken,
int Publication_ID,
string externalKey,
int dataTypeID,
int toolProject_ID,
string cngDesc)
{
Logger logger = LogManager.GetCurrentClassLogger();
logger.Info("application pool user - " + System.Security.Principal.WindowsIdentity.GetCurrent().Name);
try
{
string tempDir = Config.ServerTempDataDir; // is ~/App_Data";
var provider = new MultipartFormDataStreamProvider(tempDir); //using this instead of ReadAsMultipartAsync because of memory constraints
await Request.Content.ReadAsMultipartAsync(provider);
MultipartFileData file = provider.FileData.FirstOrDefault(); //only one file is sent
if (file != null)
{
var dir = Path.GetDirectoryName(file.LocalFileName);
string begStr = Path.GetFileName(file.LocalFileName).Substring(0, 8);
//will do something with file
//delete file this fails every time, access denied
try
{
File.Delete(file.LocalFileName);
}
catch (Exception e)
{
logger.Error("Cleanup Failed" + e.Message);
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e.Message);
}
//delete any lingering files - this works
foreach (var curFilePath in Directory.GetFiles(dir, begStr + "*"))
{
if (File.GetCreationTime(curFilePath) < (DateTime.Now.AddHours(-3)))
{
try
{
File.Delete(curFilePath);
}
catch { }
}
}
}
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content.Headers.ContentType = new MediaTypeWithQualityHeaderValue(#"application/json");
return response;
}
catch (Exception e)
{
logger.Error("Upload File Exception" + e.Message);
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e.Message);
}

Our network guys had Read&Execute/read/write access but did not have "modify" access on the App_Data folder.

Related

How to move (not copy) a file with JCIFS?

I'm wondering how I can move a file from one folder to another on an SMB share, using JCIFS.
First, there is no move() method whatsoever.
Then, this approach:
SmbFile smbFromFile = new SmbFile("smb://...pool/from-here/the-file.pdf", auth);
SmbFile smbToFile = new SmbFile("smb://...pool/to-here/the-file.pdf", auth);
smbFromFile.renameTo(smbToFile);
throws an Exception, "The system cannot find the path specified."
Rename only works in the same path. Altering the parameters doesn't help.
Right now, I'm using
smbFromFile = new SmbFile("smb://...pool/from-here/the-file.pdf", auth);
smbToFile = new SmbFile("smb://...pool/to-here", auth);
smbFromFile.copyTo(smbToFile);
smbFromFile.delete();
This feels somehow wrong.
Unfortunately, in the docu I don't find anything about moving a file.
Does somebody have a bit more information? It should be a part of SMB, right (SMB_COM_MOVE)?
Turned out I was a muppet as I had messed up my configuration parameters.
Both ways are working fine:
Method 1:
SmbFile smbFromFile = new SmbFile("smb://...pool/from-here/the-file.pdf", auth);
SmbFile smbToFile = new SmbFile("smb://...pool/to-here/the-file.pdf", auth);
smbFromFile.renameTo(smbToFile);
Method 2:
smbFromFile = new SmbFile("smb://...pool/from-here/the-file.pdf", auth);
smbToFile = new SmbFile("smb://...pool/to-here/the-file.pdf", auth);
smbFromFile.copyTo(smbToFile);
smbFromFile.delete();
There are two possible Scenarios:
1.) The file needs to be moved on the same server ( That is, the authentication details for Input folder and Output folder are same).
Use renameTo() method.
public boolean moveFile(SmbFile file) {
log.info("{"Started Archiving or Moving the file");
String targetFilePath = this.archiveDir + file.getName(); //Path where we need to move that file.
try {
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("", userId, userPassword);
log.info("targetFilePath: {} , currentFile : {}",targetFilePath, file);
SmbFile targetFile = new SmbFile(targetFilePath, auth);
//authenticate the SmbFile
try {
file.renameTo(targetFile); //Use renameTo method for same server
log.info("Archived File : {} to: {}", file.getName(),
targetFile.getName());
return true;
} catch (SmbException e) {
log.error("Unable to Archive File: {}", file.getName());
return false;
}
} catch (MalformedURLException e) {
log.error("Connection failed to Server Drive: {}", targetFilePath);
}
return false;
}
2.) The file needs to be moved on Different server ( That is, the authentication details for Input folder and Output folder are NOT same).
Use copyTo() method.
Here I will suggest, You can firstly authenticate the first server on which file is present, And check if the File exists, If it is existing then add that in a list :
public List<SmbFile> xmlFiles = new ArrayList<>(); //Here we will add all the files which are existing.
public boolean isFileExists() throws MalformedURLException, SmbException {
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("",
userID, userPassword); //authenticating input folder.
SmbFile smbFile = new SmbFile(inputFolder, auth);
SmbFile[] smbFiles = smbFile.listFiles();
boolean isFilePresent = false;
if (smbFiles.length > 0) {
for (SmbFile file : smbFiles) {
if (file.getName().toLowerCase(Locale.ENGLISH)
.contains(AppConstant.FILE_NAME.toLowerCase(Locale.ENGLISH))) {
xmlFiles.add(file);
isFilePresent = true;
}
}
}
if (isPlanFilePresent) {
log.info("Number of files present on Server: {}",smbFiles.length);
return true;
}
return false;
}
This will give you the files in the list. Go ahead to copy it to another server. Note that you need to authenticate here for the output Folder only.
public boolean moveFile(SmbFile file) {
log.info("Started Moving or Archiving the file");
String toFilePath = this.outputFolder + file.getName(); //path where you need to copy the file from input folder.
try {
NtlmPasswordAuthentication auth1 = new NtlmPasswordAuthentication("", outputFolderUserId, outputFolderPassword); //authenticating output folder
log.info("targetFilePath: {} and currentFile : {}", toFilePath, file);
SmbFile targetFile = new SmbFile(toFilePath, auth1);
try {
file.copyTo(targetFile);
file.delete(); //delete the file which we copied at our desired server
log.info("Archived File : {} to: {}", file.getName(), targetFile.getName());
return true;
} catch (SmbException e) {
log.error("Unable to Archive File: {}", file.getName());
return false;
}
} catch (MalformedURLException e) {
log.error("Connection failed to Server Drive: {}", toFilePath);
}
return false;
}

Transferring multiple files from ftps server to Liferay Portal

We have a client FTP server where they uploads multiple number of pdf files in /dev directory. The pattern of pdf files are [ORGANAIZATION_NAME]_CR.pdf . We are retrieving these files and uploading it our Liferay document library based on the [ORGANAIZATION_NAME].
We are facing issue while retrieving the multiple files using a single ftp connection. First time it retrieves the list of files of current directory (/dev) and uploads in Liferay document library. But when it trying to retrieve the second file, it returns the length of files as zero and throwing error as Exception sending alert: java.net.SocketException: Connection reset by peer: socket write error:
Connection closed without indication.
Please refer the below code.
public static void importReports() {
InputStream is = null;
System.setProperty("javax.net.debug", "ssl");
FTPSClient ftpClient = new FTPSClient();
try
{
// Store file on host
ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
// Connect to host
ftpClient.connect(hostname);
int reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftpClient.disconnect();
System.exit(1);
}
if (!ftpClient.login(loginname), PortletProps.get(password))) {
ftpClient.logout();
System.exit(1);
}
// Set protection buffer size
ftpClient.execPBSZ(0);
// Set data channel protection to private
ftpClient.execPROT("P");
try{
List<Organization> orgList = OrganizationLocalServiceUtil.getOrganizations(-1, -1);
for (Organization organization : orgList) {
String folderPath ="/dev";
String ftpfileName = organization.getName();
String ftpFilePath = folderPath+StringPool.FORWARD_SLASH+ftpfileName;
ftpClient.changeWorkingDirectory(folderPath);
// Enter local passive mode
ftpClient.enterLocalPassiveMode();
ftpClient.setRemoteVerificationEnabled(false);
FTPFile[] files = ftpClient.listFiles(folderPath);
for(FTPFile file : files)
{
if(file.isFile() && file.getSize() > 0 && file.getName().equalsIgnoreCase(ftpfileName))
{
try{
is = ftpClient.retrieveFileStream(ftpFilePath);
if (Validator.isNotNull(is)) {
ftpClient.completePendingCommand();
}catch(SocketException se)
{
LOGGER.info("SocketException :"+se.getMessage());
}
}
}
}
// Logout
ftpClient.logout();
// Disconnect
ftpClient.disconnect();
}
catch(PortalException e)
{
LOGGER.info(e.getMessage());
} catch (SystemException e) {
LOGGER.info(e.getMessage());
}
} catch (IOException ioe) {
LOGGER.info(ioe.getMessage());
}
finally
{
try {
// Logout
ftpClient.logout();
// Disconnect
ftpClient.disconnect();
} catch (IOException e) {
LOGGER.info(e.getMessage());
}
}
}

MVC 3 The process cannot access the file because it is being used by another process

I upload a file in my MVC 3 project.
[HttpPost]
public ActionResult MyUpload(HttpPostedFileBase file)
{
string filePath = string.Empty;
string path = "C:\\";
string filePath = string.Empty;
try
{
if (file != null && file.ContentLength > 0)
{
filePath = path + file.FileName;
file.SaveAs(filePath);
file.InputStream.Dispose();
GC.Collect();
// other operations, where can occur an exception
// (because the uploaded file can have a bad content etc.)
}
}
catch (Exception e)
{
if (file.InputStream != null)
file.InputStream.Dispose();
GC.Collect();
if (!string.IsNullOrEmpty(filePath))
{
if (System.IO.File.Exists(filePath))
System.IO.File.Delete(filePath); //here is the error
}
}
}
in that code, if an exception occured after I saved the file I can't delete it (also I cann't upload it again) because I get the error
The process cannot access the file
'[filePath]' because it is being used by another process.
What's wrong with that code ?
edit
I had to change the file.InputStream.Dispose(); to
file.InputStream.Close();
file.InputStream.Dispose();
file.InputStream = null;
And, now it's working fine.
Instead of checking if the file.InputStream is not null inside the catch block, you should dispose it inside the finally block, like this:
if (file != null && file.ContentLength > 0)
{
try
{
filePath = path + file.FileName;
file.SaveAs(filePath);
// other operations, where can occur an exception
// (because the uploaded file can have a bad content etc.)
}
catch (Exception e)
{
if (!string.IsNullOrEmpty(filePath))
{
if (System.IO.File.Exists(filePath))
System.IO.File.Delete(filePath); //here is the error
}
}
finally
{
file.InputStream.Close();
file.InputStream.Dispose();
GC.Collect();
}
}
By the way, the InputStream property is a read-only property. You can't set it to null.

How to make a save action that checks whether a 'save-as' has already been performed

I have researched and tried to refer back to my fileChooser.getSeletedFile() in my save as action but can not work out how to check whether or not a file has been created. Here is my attempted code so far:
Save as code(works well):
public void Save_As() {
fileChooserTest.setApproveButtonText("Save");
int actionDialog = fileChooserTest.showOpenDialog(this);
File fileName = new File(fileChooserTest.getSelectedFile() + ".txt");
try {
if (fileName == null) {
return;
}
BufferedWriter outFile = new BufferedWriter(new FileWriter(fileName));
outFile.write(this.jTextArea2.getText());//put in textfile
outFile.flush(); // redundant, done by close()
outFile.close();
} catch (IOException ex) {
}
}
"Save" code doesn't work:
private void SaveActionPerformed(java.awt.event.ActionEvent evt) {
File f = fileChooserTest.getSelectedFile();
try {
if (f.exists()) {
BufferedWriter bw1 = new BufferedWriter(new FileWriter(fileChooserTest.getSelectedFile() + ".txt"));
bw1 = new BufferedWriter(new FileWriter(fileChooserTest.getSelectedFile() + ".txt"));
String text = ((JTextArea) jTabbedPane1.getSelectedComponent()).getText();
bw1.write(text);
bw1.close();
} else {
Save_As();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
Instead of storing an instance to the JFileChooser rather store an instance to the File (wich will be null before any save has been performed). In your SaveActionPerformed method check if the file is null. If it is null then do a Save_As and store the selected file in your file variable, if it is not null then do a normal save into the file.

WP7: Delete IsolatedStorageFile

I would really appreciate some help with deleting a file from IsolatedStorage on WP7. I am basically downloading a file from the web, storing it in Isolated Storage and then uploading it to my Downloads folder in my Dropbox. Once I have uploaded it, I would like to delete the file from Isolated Storage, but am getting Exception errors when trying to do so.
Here is my code :
public void readCompleteCallback(Object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
try
{
//string fileName = txtUrl.Text.Substring(txtUrl.Text.LastIndexOf("/") + 1).Trim();
string fileName = searchBox.Text + fileExt;
//string fileName = "DownloadedNZB.nzb";
bool isSpaceAvailable = IsSpaceIsAvailable(e.Result.Length);
if (isSpaceAvailable)
{
// Save mp3 to Isolated Storage
using (var isfs = new IsolatedStorageFileStream(fileName,
FileMode.CreateNew,
IsolatedStorageFile.GetUserStoreForApplication()))
{
long fileLen = e.Result.Length;
byte[] b = new byte[fileLen];
var numberOfBytesRead = e.Result.Read(b, 0, b.Length);
isfs.Write(b, 0, numberOfBytesRead);
isfs.Flush();
isfs.Close();
isf = IsolatedStorageFile.GetUserStoreForApplication();
stream = isf.OpenFile(fileName, FileMode.Open);
MessageBox.Show("File downloaded successfully");
App.GlobalClient.UploadFileAsync("/Public/", fileName, stream, (response) =>
{
MessageBox.Show("Uploaded file to Dropbox OK.");
},
(error) =>
{
MessageBox.Show(error + "Cannot upload file to dropbox.");
});
}
//stream.Close();
isf.DeleteFile(searchBox.Text + fileExt);
}
else
{
MessageBox.Show("Not enough to space available to download the file");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
else
{
MessageBox.Show(e.Error.Message);
}
}
I cannot think where I am going wrong, but if someone could point me in the right direction, I would appreciate it.
You are trying to delete file inside using statement, where file is not closed yet
UPD: Your upload is async, so you can delete file only when it completed. Put your code near MessageBox.Show("Uploaded file to Dropbox OK.");

Resources