ASP.NET MVC Website Read File from Disk Problem - c#

I'm reading a text file containing an insert statement for SQL using C# in an MVC Website I'm working on. When debugging the function I'm using works fine and the insert occurs. But once I publish the site and run it on my local machine (with IIS set-up to use asp.net 4.0 even) it doesn't seem to work.
if (Request.Files != null && Request.Files["txtImportFile"] != null)
{
//newFilePath = Server.MapPath("\\" + DateTime.Now.Ticks + Request.Files["txtImportFile"].FileName);
string[] temp_string = Request.Files["txtImportFile"].FileName.Split(new char[] { '\\' });
string temp_filename = temp_string[temp_string.Count() - 1];
//newFilePath = Server.MapPath("\\temp\\" + DateTime.Now.Ticks + Request.Files["txtImportFile"].FileName);
newFilePath = Server.MapPath("\\temp\\" + DateTime.Now.Ticks + temp_filename);
Request.Files["txtImportFile"].SaveAs(newFilePath);
StreamReader reader = new StreamReader(newFilePath);
string contents = reader.ReadToEnd();
reader.Close();
Models.WingsRemoteDbLibrary dbLib = new Models.WingsRemoteDbLibrary();
string update_message = dbLib.UpdateSlaveItemsTable(contents);
if (System.IO.File.Exists(newFilePath))
System.IO.File.Delete(newFilePath);
RandomPopupView(update_message);
}
I hope my explanation doesn't sound vague. I'll try my best to answer any further questions. Thanks.

Workaround:
Instead of using
Server.MapPath("\\temp\\"...
Create folder under root with name "temp" and use
System.Web.HttpContext.Current.Request.MapPath("~\\temp....

Well, "it doesn't seem to work" is pretty vague - a bit more detail would be nice! But it sounds like a permissions issue. The default profile in IIS has very little access to the disk, especially write access. It isn't really a good idea to write inside your own site anyway (I'd use an unrelated part of the disk, myself), but you will need to configure IIS to run the application in a specific named identity, with access to the disk. Configuring the account itself (not IIS - the account; for example granting "logon as a service") to run as an ASP.NET account is not particularly trivial, unfortunately.
Another thought: is your app a sub-application, i.e. is your app-root /, or is it /MyApp/ ? The reason I ask is your use of MapPath might be better expressed relative to the app-root, i.e. ~/temp/ - but again I stress; writing inside the app is risky. You really want that folder to be non-executing.

There may be an alternative solution to this problem. You can avoid messing with path and file system altogether if you can 'bake' the file into assembly at build time. Here is how you can do this:
In Visual Studio solution explorer right click on a file and go to Properties.
Set Build Action to 'Embedded Resource'.
Later you can read the file using GetManifestResourceStream:
var stream = GetType()
.Assembly
.GetManifestResourceStream("YourNameSpace.Folder.YourFile.txt");
using (var reader = new StreamReader(stream)) {
var fileContent = reader.ReadToEnd();
}
More info here.

Related

C# SharpZipLib extract .TGZ NotSupportedException

I'm new to programming so please be patient.
I am currently developing a small Program in Visual C# 2010 Express, .NET Framework 4.0, which starts a Script on a Linux Machine (what creates the File /tmp/logs.tgz), downloads the File and then I want to extract it. Running the Script and downloading the File via Renci.SshNet works flawlessly.
But when I want to extract it, it gives me an Error "NotSupportedException" my Filepath Format is incorrect (which is not the case, I think?).
I copy and pasted the Code directly from here (Simple full extract from a TGZ (.tar.gz)) and edited it for my Needs:
using System.IO;
using System.IO.Compression;
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Tar;
//it executed the Script and created the file on the Linux Machine /tmp/logs.tgz
//now I want to download it
string myTime = DateTime.Now.ToString("yyyyMMdd");
var pathWithEnv = (#"%USERPROFILE%\Desktop\logs" + myTime + ".tgz");
var filePath = Environment.ExpandEnvironmentVariables(pathWithEnv);
string localFile = filePath;
//then downloads /tmp/logs.tgz to ..\Desktop\logs+ myTime +.tgz
//everything great until now. here I want to extract .TGZ:
var pathWithEnv2 = (#"%USERPROFILE%\Desktop\logs" + myTime);
var fileDir = Environment.ExpandEnvironmentVariables(pathWithEnv2);
string localDir = fileDir;
Stream inStream = File.OpenRead(localFile);
Stream gzipStream = new GZipInputStream(inStream);
TarArchive tarArchive = TarArchive.CreateInputTarArchive(gzipStream);
//ERROR OCCURS HERE:
tarArchive.ExtractContents(localDir);
tarArchive.Close();
gzipStream.Close();
inStream.Close();
I even tried to set the localFile and localDir string without the EnviromentVariable, but that didnt help. I tried:
- download and extract it directly on C:\ (or on a mapped Network Drive U:) to prevent too long filenames (which should not be the case as it should never get longer than 86 characters).
- string = #"C:..\logs", string = "C:\..\logs", string = #"C:..\logs\", etc.
- tried it without myTime
- using ICSharpCode.SharpZipLib.Core;
I did a MessageBox.Show(localDir); before the tarArchive.ExtractContents(localDir); and it showed "C:\Users\Baumann\Desktop\logs20140530" which is correct, thats the Directory I want to extract it to. Even creating the Directory before executing it doesn't help.
I also created a new Project with just one button which should start the Extraction and the same error occurs.
I tried, doing it separately, first extract the GZip and then the .tar, but it also gives me the same Error when extracting the GZip (using ICSharpCode.SharpZipLib.Core; of course).
What drives me even more crazy about it, is, that it starts to extract it, but not everything, before it fails. And always the same Files, whats not clear for me why these and why not the others.
I'm on Windows 8.1, using SharpZipLib 0.86.0.518, downloaded directly from the Website.
Thanks in advance.
well, I finally fixed the Problem. The Linux machine is creating a file which includes the MAC-Adress and since Windows can't handle ":" in a Filename, it crashes.
I am now extracting file by file and checking each file for ":" and replacing it with "_", works flawlessly.

Why are permissions wonky when my IIS worker saves a file in ASP.NET?

IIS 8, ASP.NET MVC 4, .NET 4.5
private static string SaveProfilePicFile(UserProfileViewModel model)
{
var tempFilename = Path.GetTempFileName();
model.ProfilePic.Profile.UploadedFile.SaveAs(tempFilename);
var staticContentFilename = Helpers.GetStaticContentFilename(
StaticContentType.Avatar, model.ProfilePic.Profile.UserId);
var destinationFilename = Path.Combine(
ConfigurationManager.AppSettings["StaticContentPath"],
"profile",
staticContentFilename);
if (File.Exists(destinationFilename))
File.Delete(destinationFilename);
if (!HasJpegHeader(tempFilename)) // convert temp file into JPG
{
using (var image = new Bitmap(tempFilename))
image.Save(destinationFilename, ImageFormat.Jpeg);
File.Delete(tempFilename);
}
else
{
File.Move(tempFilename, destinationFilename);
}
return staticContentFilename;
}
I'm not interested in a code review, I know things could be done better. Right now I've hit an unusual problem. StaticContentPath points to c:\inetpub\wwwroot\static.domain.com, which is being served by a different application pool which is configured to disable scripting and cache things heavier. If I manually place a file in the static content folder, it will serve correctly. If the above code (from a different application pool) saves a file there, the permissions are very unusual. I'll attach screenshots.
The "default" file is one I pasted manually. It properly inherited permissions from the parent folder. The hashed filename was saved by the above code, and it does not inherit permissions properly. When I attempt to access the file, I get a very basic error message from IIS, the entirety of which is "The page cannot be displayed because an internal server error has occurred." No styling, nothing I'm used to seeing with IIS errors. If I manually add read permissions to the IIS_IUSRS account everything works as I'd expect.
Why is this happening, what can I do to mitigate it, and does my code need to be updated?
I suspect the problem is with the use of Path.GetTempFileName followed by File.Move. When the uploaded file is saved to tempFilename, the temporary file gets whatever permissions are assigned to the temporary folder. Moving the file preserves those permissions as is instead of recalculating the inheritable permissions based on the destination.
Instead of File.Move, try using File.Copy followed by File.Delete:
//File.Move(tempFilename, destinationFilename);
File.Copy(tempFilename, destinationFilename);
File.Delete(tempFilename);

Relative path changing?

I have a log object that writes daily log files with a relative path. It's fairly simple (.NET 4.0, VS 2010).
public void LogLine(string txt)
{
DateTime dt = DateTime.Now;
if (CurrentDay != dt.Day)
{
string newFileName = "..\\Log\\" + programName + dt.Day + ".log";
fs = new FileStream(newFileName, FileMode.Create, FileAccess.Write);
sw = new StreamWriter(fs);
CurrentDay = dt.Day;
}
sw.WriteLine(txt);
}
This works well almost all the time. However, sometimes I get what seems to be a random DirectoryNotFoundException with a totally different path. For example, when I first run the program, it creates a file:
C:\MyFiles\Log\MyApp19.log
After using the program some and letting it run overnight so a new file and stream are created (at the first log after midnight), I come back to the DirectoryNotFoundException stating something like:
C:\MyFiles\MyOtherFiles\Resources\Log\MyApp20.log
The only thing that I can think of is: I use an OpenFileDialog and SaveFileDialog a couple times throughout the life of the software, and one of those open/save dialogs access a file within
C:\MyFiles\MyOtherFiles\Resources\SavedFiles\
So it seems to me that when I use the dialogs, I open/save something into the SavedFiles directory and when it creates the new log, the relative file path ..\ goes up to Resources (from SavedFiles), then can't find the directory Log within Resources and throws an exception. However, I can't reproduce the problem using dialogs, and I thought the relative path is relative to the executable? Can the Open/Save File Dialogs alter how the software calculates the relative file path? Anyone have any thoughts? Thanks for your time!
Alng i think that the following link can help you:
http://msdn.microsoft.com/en-us/library/system.windows.forms.filedialog.aspx
Pay attention to the following part:
Important:
If the user of your application changes the folder in the FileDialog, then the current working directory for your application is set to the location specified in the FileDialog. To prevent this, set the RestoreDirectory property to true.
Try to use the Microsoft proposed methodologies for paths as described in the above link.
This can help you also
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.executablepath.aspx
regards
A relative path always works on the current directory of the application. That can easily change, for example when you show a save dialog.
It is always better to create a path relative to your executable.
var assembly = Assembly.GetEntryAssembly() ?? Assembly.GetCallingAssembly();
var path = Path.GetDirectoryName(assembly.Location);
newFileName = Path.Combine(path, "..\\Log\\" + programName + dt.Day + ".log");
I'm making a guess that the application changes the current working directory at some point. As a result, on that basis, I'd use a fully-qualified path for the log file. You could use the assembly's startup path, eg Application.StartupPath, which should not change even if the app changes folders for some reason.

w3wp.exe (NETWORK SERVICE user) is locking a newly created file and preventing access to it

I have a Web application. It sends a series of images to the server (no problem there) and then uses code from this tutorial to create a PowerPoint presentation. The presentation is saved in a directory on the web server and the URL is returned to the user.
However, the file is still in use and attempting to access it generates a 500.0 error in IIS 7.5.
If I open the task manager and kill the w3wp.exe process that belongs to the NETWORK SERVICE user everything works as intended (the file can be downloaded and viewed). I also have another w3wp process belonging to DefaultAppPool, but it doesn't seem to cause a problem.
I'm new to this .Net coding, so it is very possible I forgot to close something down in code. Any ideas?
Edit: This is the method that creates a series of png's from image data that is encoded into a string. It uses a Guid to create a unique bit of a directory path, and checks to make sure it doesn't exist and then creates the directory and places the images there.
It looks like the offending method is this one:
So the offending method is this one:
public void createImages(List<String> imageStrings)
{
UTF8Encoding encoding = new UTF8Encoding();
Decoder decoder = encoding.GetDecoder();
Guid id = Guid.NewGuid();
String idString = id.ToString().Substring(0, 8);
while (Directory.Exists(imageStorageRoot + idString))
{
id = Guid.NewGuid();
idString = id.ToString().Substring(0, 8);
}
String imageDirectoryPath = imageStorageRoot + idString + "\\";
DirectoryInfo imagePathInfo = Directory.CreateDirectory(imageDirectoryPath);
for (int i = 0; i < imageStrings.Count; i++)
{
String imageString = imageStrings[i];
Byte[] binary = Convert.FromBase64String(imageString);
using (FileStream stream = new FileStream(imageDirectoryPath + idString + i.ToString() + ".png", FileMode.Create))
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(binary);
}
}
}
}
Edit 2: If there is a better to about doing things please let me know. I am trying to learn here!
Edit 3: So upon further examination, I can comment out all this code. In fact, the second instance of w3wp.exe starts up as soon as a browser hits the website. I am now wondering if this might have something else to do with our stack? Its a Flex app, that uses WebOrb for remoting to some C# classes.
Does anyone know why this second open instance of w3wp.exe (owned by NETWORK SERVICE) would prevent the file from opening properly? Is there some way to get it release it's hold on the file in question?
Make sure you've closed the file after using it (better yet put the code that accesses your files in using statements). Post some code if you need help figuring out where the issue is.
The sample looks good. Did you deviate from the code structure?
using (Package pptPackage =
Package.Open(fileName, FileMode.Open, FileAccess.ReadWrite))
{
// your code goes inside there
}
If your code does contain the using statement you should be fine. If not add a Dispose call to your Package object when you are done or you will leave the file open for a long time until (possibly) the finalizer will kill it.

The SaveAs method is configured to require a rooted path, and the path <blah> is not rooted

OK I've seen a few people with this issue - but I'm already using a file path, not a relative path. My code works fine on my PC, but when another developer goes to upload an image they get this error. I thought it was a security permission thing on the folder - but the system account has full access to the folder (though I get confused about how to test which account the application is running under). Also usually running locally doesn't often give you too many security issues :)
A code snippet:
Guid fileIdentifier = Guid.NewGuid();
CurrentUserInfo currentUser = CMSContext.CurrentUser;
string identifier = currentUser.UserName.Replace(" ", "") + "_" + fileIdentifier.ToString();
string fileName1 = System.IO.Path.GetFileName(fileUpload.PostedFile.FileName);
string Name = System.IO.Path.GetFileNameWithoutExtension(fileName1);
string renamedFile = fileName1.Replace(Name, identifier);
string path = ConfigurationManager.AppSettings["MemberPhotoRepository"];
String filenameToWriteTo = path + currentUser.UserName.Replace(" ", "") + fileName1;
fileUpload.PostedFile.SaveAs(filenameToWriteTo);
Where my config settings value is:
Again this works fine on my PC! (And I checked the other person has the folder on their PC).
Any suggestions would be appreciated - thanks :)
Obviously what it says is that your filenameToWriteTo is not a rooted path... ie it is a relative path, and your server configuration doesn't like that. Use Server.MapPath to obtain real paths... something like...
string realPhysicalPath = Path.Combine(Server.MapPath(" "), filenameToWriteTo);
fileUpload.PostedFile.SaveAs(realPhysicalPath);
Just in case print out your filenameToWriteTo to see if its relative or physical path. If it's relative use the approach above.
Not sure what the issue was as it sorted itself out. We didn't end up debugging it as it was on a non developer's PC and I had a workaround for him to continue his work whilst I investigated potential causes. So maybe was the way he updated/ran the site or file permissions fixed by grabbing a copy of my directory.
At least I know it needs physical file paths so hopefully won't come across this again!
Please, make sure that folder where you are saving the file exists. If folder does not exist, it will not be created for you and SaveAs method will throw exception you are having now.
Thank you.

Categories