When I write to a file and upload the same file to FTP site, I get Thread was being aborted error.
FileIoUtility.WriteDataToFile(skillsSummaryData, SkillSummaryFileLocation);
if (!IsFileLocked(SkillSummaryFileLocation))
{
using (WebClient myWebClient = new WebClient())
{
myWebClient.Credentials = new NetworkCredential(FtpUsername, FtpPassword);
var uri = new Uri($"{FtpHost}SkillSummary.txt", UriKind.RelativeOrAbsolute);
byte[] responseArray = myWebClient.UploadFile(uri, WebRequestMethods.Ftp.UploadFile,
SkillSummaryFileLocation);
var response = Encoding.ASCII.GetString(responseArray);
}
}
Here is my WriteDataToFile method:
public static void WriteDataToFile(string data, string fileLocation, bool append = false)
{
if (!File.Exists(fileLocation))
{
File.Create(fileLocation).Dispose();
}
lock (Locker)
{
using (FileStream file =
new FileStream(fileLocation, FileMode.Append, FileAccess.Write, FileShare.Read))
{
using (StreamWriter writer = new StreamWriter(file, Encoding.Unicode))
{
writer.Write(data);
}
}
}
}
If I skip the following line and run the upload then it works.
FileIoUtility.WriteDataToFile(skillsSummaryData, SkillSummaryFileLocation);
Exception doesn't give anything more than Thread was being aborted. How can I make this work?
Related
I am trying to write the stream resulting from compressing several files in a ZIP but I can't. The ZIP file does, but when I want to write the resulting stream, the copyto method does nothing and my http request never ends.
I don't know why my logic doesn't work, I hope you can help me please.
public async Task<HttpResponseMessage> downloadFile3(string filePath, System.Threading.CancellationToken token)
{
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = new PushStreamContent(async (streamout, context, transportContext) =>
{
try
{
using (var ms = new MemoryStream())
{
using (var zipArchive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
var entry = zipArchive.CreateEntry(filePath);
using (var fileStream = File.OpenRead(filePath))
{
using (var entryStream = entry.Open())
{
await fileStream.CopyToAsync(entryStream);
}
}
}
ms.Position = 0;
ms.CopyTo(streamout); //THIS LINE DOESN'T WORK
}
}
catch (Exception ex)
{
}
finally
{
streamout.Close();
}
}, "application/zip"),
};
response.Content.Headers.ContentLength = new FileInfo(filePath).Length;
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
Size = new FileInfo(filePath).Length,
FileName = Path.GetFileName(filePath)
};
return response;
}
I want to store the zip file which is retrieved by the ToRetrieve method and store it on the local machine using SaveFileDialog controller in a Windows application writtein in C#.
This is my code:
if (!string.IsNullOrEmpty(FileName))
{
APIOrderMethods objAPIOrderMethods = new APIOrderMethods();
saveFileDialog1.Filter = "zip files (*.zip)|*.zip|All files (*.*)|*.*";
saveFileDialog1.Title = FileName;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
Stream stream = objAPIOrderMethods.ToRetrieve(FileName, ServicelURL, useName, password);
Stream streamToWriteTo = File.Open(saveFileDialog1.FileName, FileMode.Create, FileAccess.ReadWrite);
stream.CopyToAsync(streamToWriteTo);
}
label12.ForeColor = Color.Green;
}
But I get this error:
Exception :'Cannot access a closed Stream.'
ToRetrieve method for getting the Zip file:
public Stream ToRetrieve(string Filename, string serviceURL, string Username, string Password)
{
Stream Result = null;
var _saveDir = System.Configuration.ConfigurationManager.AppSettings["Save"];
try
{
using (HttpClient client = new HttpClient())
{
string url = "https://codeload.github.com/tugberkugurlu/ASPNETWebAPISamples/zip/master";
using (HttpResponseMessage response = client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead).Result)
using (Stream streamToReadFrom = response.Content.ReadAsStreamAsync().Result)
{
Result = streamToReadFrom;
}
}
}
catch (Exception ex)
{
throw;
}
return Result;
}
The problem lies in the method, ToRetrieve.
With streamToReadFrom being in a using statement, the Dispose method will be called.
Since result contains the reference, you are returning a closed stream.
I have the following code to write a file. The problem is that if I want to overwrite the same file, it is "locked". The file is opened by another process.
using (FileStream fs = new FileStream("C:\\New\\" + fileName, FileMode.Create, FileAccess.ReadWrite))
using (StreamWriter str = new StreamWriter(fs))
{
str.Write(jsonFile);
str.Dispose();
str.Close();
}
I send a json string to an API, which then generates the file. So I guess it might be a problem in IIS.
EDIT:
By research I have still tried the following code, but which leads to the same result
using (FileStream fs = new FileStream("C:\\New\\" + fileName, FileMode.Create, FileAccess.ReadWrite))
{
StreamWriter sw = new StreamWriter(fs);
sw.Write(jsonFile);
fs.Flush();
fs.Close();
}
EDIT 2:
After reading the comments, it probably has nothing to do with the Filestream to itself. Here is more information about my application:
I have a WPF application which sends a post to my API through a ButtonClick. This is triggered as follows:
private async void btnSend_Click(object sender, RoutedEventArgs e)
{
await Seal();
}
The Seal method says the following:
private async System.Threading.Tasks.Task Seal()
{
var result = await RequestManager.DoPost<bool>("FOO", foo);
}
The RequestManager says the following:
public static async Task<R> DoPost<R>(String route, Object payload, String contenttype)
{
var serializer = new JavaScriptSerializer();
route = route.StartsWith("/") ? route : "/" + route;
var content = new StringContent(serializer.Serialize(payload), Encoding.UTF8, contenttype);
var response = await client.PostAsync(RequestManager.API_URL + route, content);
if (response.StatusCode == HttpStatusCode.OK)
{
var result = await response.Content.ReadAsStringAsync();
return (R)serializer.Deserialize(result, typeof(R));
}
else
{
throw new ResponseException(response.StatusCode, response.Content.ReadAsStringAsync().Result);
}
}
I really do not know where my error is, or where the request must be closed.
This error could occur when multiple threads are attempting to write at the same file. Your code above works with a little modification
private static object lk = new object();
lock (lk)
{
using (FileStream fs = new FileStream("C:\\New\\" +fileName,FileMode.Create, FileAccess.ReadWrite))
using (StreamWriter str = new StreamWriter(fs))
{
str.Write(jsonFile);
str.Dispose();
str.Close();
}
}
I have a requirement to pass a file through an MVC action method.
To download it from a Web API method and return it as a result.
The code I have is assembled from a few answers here on SO and some other references.
The problem is that the file seems to be locked by the download process when I try to return it as a result. I thought that the tsk.Wait() wold solve the problem.
Perhaps someone knows of a better solution?
using (var client = HttpClientProvider.GetHttpClient())
{
client.BaseAddress = new Uri(baseAddress);
await client.GetAsync("api/Documents/" + fileName).ContinueWith(
(requestTask) =>
{
HttpResponseMessage response = requestTask.Result;
response.EnsureSuccessStatusCode();
fileName = response.Content.Headers.ContentDisposition.FileName;
if (fileName.StartsWith("\"") && fileName.EndsWith("\""))
{
fileName = fileName.Trim('"');
}
if (fileName.Contains(#"/") || fileName.Contains(#"\"))
{
fileName = Path.GetFileName(fileName);
}
path = Path.Combine(GetDocsMapPath(), fileName);
System.Threading.Tasks.Task tsk = response.Content.ReadAsFileAsync(path, true).ContinueWith(
(readTask) =>
{
Process process = new Process();
process.StartInfo.FileName = path;
process.Start();
});
tsk.Wait();
HttpResponseMessage resp = new HttpResponseMessage(HttpStatusCode.OK);
resp.Content = new StreamContent(new FileStream(path, FileMode.Open, FileAccess.Read));
resp.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
resp.Content.Headers.ContentDisposition.FileName = fileName;
return resp;
});
}
public static Task ReadAsFileAsync(this HttpContent content, string filename, bool overwrite)
{
string pathname = Path.GetFullPath(filename);
if (!overwrite && File.Exists(filename))
{
throw new InvalidOperationException(string.Format("File {0} already exists.", pathname));
}
FileStream fileStream = null;
try
{
fileStream = new FileStream(pathname, FileMode.Create, FileAccess.Write, FileShare.None);
return content.CopyToAsync(fileStream).ContinueWith(
(copyTask) =>
{
fileStream.Close();
fileStream.Dispose();
});
}
catch
{
if (fileStream != null)
{
fileStream.Close();
fileStream.Dispose();
}
throw;
}
}
first, I don't see any useful function achieved by the process you launch, apart from locking your file, which you don't want.
try removing these lines and retrying.
.ContinueWith(
(readTask) =>
{
Process process = new Process();
process.StartInfo.FileName = path;
process.Start();
});
Edit: Using FilePathResult
I don't know about your exact requirements, but if your goal is to return a file that you have the path for; then the easiest is to return a FilePathResult which will take care of reading and returning the contents of the file to the requester.
public FilePathResult GetFile()
{
//put your logic to determine the file path here
string name = ComputeFilePath();
//verify that the file actually exists and retur dummy content otherwise
FileInfo info = new FileInfo(name);
if (!info.Exists)
{
using (StreamWriter writer = info.CreateText())
{
writer.WriteLine("File Not Found");
}
}
return File(name, "application/octet-stream");
}
if you are sure of what type your content is , change the mime type accordingly, otherwise it's better to leave it as a binary data.
public bool ReadFile()
{
string fname = "text.txt";
FileStream fs = null;
fs = new FileStream(fname, FileMode.OpenOrCreate,FileAccess.Read);
StreamReader sr = new StreamReader(fs);
string res = sr.ReadToEnd();
if (res == "1")
return true;
else
return false;
}
public void WriteToFile()
{
string fname = "text.txt";
FileStream fs = null;
fs = new FileStream(fname, FileMode.Open,FileAccess.Write);
StreamWriter sw = new StreamWriter(fs);
sw.Write("1");
}
So it should work like if ReadFile returns false than i do WriteFile.
But when it reaches writefile, it throws IO expection:
The process cannot access the file ... because it is being used by another process
You aren't closing the file when you read it.
Put your FileStream and StreamReader objects in using statements:
using (var fs = new FileStream(fname, FileMode.OpenOrCreate,FileAccess.Read)) {
using (var sr = new StreamReader(fs)) {
//read file here
}
}
Make sure you do the same when you write to the file.
You need to dispose the StreamReader object in the ReadFile method. The StreamReader inherits from IDisposable and therfor you need to dispose the object.
Check this link for more info:StreamReader Class