Basically, I'm building a website that allows user to upload file.
From the front end (JavaScript), the user will browse a file, I can get the site to send POST data (the parameter "UploadInput" and it's value, which the value is the file)
In the backend (C#), I want to make a copy of the file and save it in a specific path.
Below is the way I did it.
var files = Request.Files;
file[0].SaveAs("\temp\\" + file[0].FileName);
The problem I ran into is that I got the error message saying index out of range. I tried Response.Write(files.Count) and it gives me 0 instead of 1.
I'm wondering where I did wrong and how to fix it, or if there's a better way of doing it.
Thanks!
Edit:
I am using HttpFox to debug. From HttpFox, I can see that under POST data, parameter is "UploadInput" and the value is "test.txt"
Edit 2:
So I tried the way Marc provides, and I have a different problem.
I am able to create a new file, however, the content is not copied over. I tried opening the new created file in notepad and all it says is "UploadInput = test.txt"
If they simply posted the file as the body content, then there will be zero "files" involved here, so file[0] will fail. Instead, you need to look at the input-stream, and simply read from that stream. For example:
using(var file = File.Create(somePath)) {
Request.InputStream.CopyTo(file);
}
Related
Situation
I have two applications that both read and save images / documents to one specific folder. Example if the user uploads their image in one program, a user of program B is supposed to view and even edit that image.
What I have done
In one of my application I have created a setting in settings for the string of my path. So to save an image path I call
path = System.IO.Path.Combine(Properties.Settings.Default.imagePath, Fimage);
this works fine.
However, my issue is when I try to view the image in my edit view.
Controller
ViewBag.imagePath = Properties.Settings.Default.imagePath;
View
<img src="#ViewBag.imagePath/#Url.Content(#Model.image)" alt="Image" style="height: 255px; " />
Problem
The problem is upon attempting to view the image I get the error, Not allowed to load local resource: I have full access to the folder and when I attempt to browse to the file in the error message the picture is displayed. I was advised from other questions to use, server.MapPath however when I do Server.MapPath(Properties.Settings.Default.imagePath); I get the error physical path received, expected virtual path.
This viewbag holds the entire string of folder my files are stored with the EVERYONE user having full access. So i'm really unsure of why it's making a fuse.
P.S I cant say something like "~/content/images" because the path to that file is in an entirely different application, I think I need to give it the entire location.
Any assistance will be appreciated.
Gratitude
Looks like your defaultImage variable holds a physical path, which will work for saving the image since the API requires a path in the form e.g. c:\website\images\.... but for viewing, you need the VirtualPath, something of the form http://mycoolsite/images/image.jpg and this is what the error is telling you.
Your Controller; therefore, should return something like
ViewBag.imagePath = Properties.Settings.Default.imagePath.Replace(Request.ServerVariables["APPL_PHYSICAL_PATH"], String.Empty);
In order to get the Relative Path. See this other related question.
EDIT I just saw your "PS..."
If that's the case, then you need to pass the full URL to the other application: (e.g. http://someothersite.com/images/image.jpg).
I'm uploading file using Dropbox core API. I have written the upload code like-
RequestResult strReq = OAuthUtility.Put
(
"https://api-content.dropbox.com/1/files_put/auto/",
new HttpParameterCollection
{
{"access_token", "Token"},
{"path","/file.txt"},
{"overwrite", "false"},
{"autorename","false"},
{stream}
}
);
Suppose there is a existing file in root folder named file.txt and I'm again trying to upload the same name file to same folder.I have written
overwrite= false and autorename=false but surprisingly there is no error status code returning in the response.Always returning the success code 200 in the response.I need to show the proper error code.
Two things stand out:
Your URL is https://api-content.dropbox.com/1/files_put/auto/, but it should be (for this example) https://api-content.dropbox.com/1/files_put/auto/file.txt. The path parameter should be removed from the HttpParameterCollection.
I'm unfamiliar with the library you're using, but are you sure that those parameters are turned into query parameters and that stream becomes the HTTP body? I.e. the resulting URL should be https://api-content.dropbox.com/1/files_put/auto/file.txt?overwrite=false&autorename=false&access_token=<TOKEN>, and then the file content should go in the body of the request. Please make sure this is what's happening.
Please also share the body that comes back with the 200 response. It should tell you, for example, the path of the file that got written.
Note that if you upload the exact same file content to the same path, it doesn't count as a conflict, so when looking for a 409, make sure you're uploading different content to the file.
I am using DotNetZip 1.9.6 in my application which uses a file structure similar to e.g. *.docx: Zip file containing XML files.
Now every module of the application can store such XML files to my custom file management and on "save" they are serialized to streams which are then saved to the Zip file via DotNetZip.
To update the entries I use ZipFile.UpdateEntry(path, stream).
This works fine and the first time I save my file via calling ZipFile.Save() everything works.
But If I do this a second time (first some UpdateEntrycalls then Save) on the same instance the Zip file is corrupted: The file structure and meta-data (e.g. uncompressed size of each file) is still there, but all files are 0 byte in compressed size.
If I create a new instance from the just saved file after saving everything works fine, but shouldn't it be possible to avoid that and "reuse" the same instance?
The following example (also see https://dotnetfiddle.net/mHxEIy) can be used to reproduce the problem:
using System.IO;
using System.Text;
public class Program
{
public static void Main()
{
var zipFile = new Ionic.Zip.ZipFile();
var content1 = new MemoryStream(Encoding.Default.GetBytes("Content 1"));
zipFile.UpdateEntry("test.txt", content1);
zipFile.Save("test.zip"); // here the Zip file is correct
//zipFile = new Ionic.Zip.ZipFile("test.zip"); // uncomment and it works too
var content2 = new MemoryStream(Encoding.Default.GetBytes("Content 2"));
zipFile.UpdateEntry("test.txt", content2);
zipFile.Save(); // after that it is corrupt
}
}
To run this you need to add the "DotNetZip 1.9.6" NuGet package.
After the first save, this is what you get:
and after the second save:
This looks like it's a bug in the library, around removing an entry. If you just remove an entry and then save again, it correctly removes the file.
However, if you remove an entry and then add another one with the same name - which is what UpdateEntry is documented to do if the entry already exists - the old entry appears to be used instead.
The reason you're ending up with an empty file the second time is that the original MemoryStream is being read again - but by now, it's positioned at the end of the data, so there's no data to read. If you reset the position to the start of the stream (content1.Position = 0;) it will rewrite the original data. If you modify the data within content1, you end up with invalid compressed data.
The only workaround I can immediately think of is to keep your own map from filename to MemoryStream, and replace the contents of each MemoryStream when you want to update it... or just load the file each time, as per your existing workaround.
It's definitely worth filing a bug around this though, as it should work as far as I can tell.
As already suspected this was a bug in DotNetZip up to version 1.9.6.
I think I was able to fix this with THIS change which was just released as version 1.9.7 on NuGet. At least for me the problem does not happen anymore.
Some background what happend as far as I found out:
When you call Save the library sets an internal flag which remembers that the ZIP file was just save and on the second Save call instead of "recompressing" all entries in the ZIP file it copies them from the just saved file.
This works fine for adding/removing entries, but breaks when one of the entries was changed as then it "mixes" the old and the new entry and produces the inconsisten ZIP file.
My fix basically disables that "copy from old file" logic if an entry was changed.
In my application I'm saving an image and transferring to a server through the use of a php script whose sole job is to pass this image to the server which saves it in the root of the server.
The code I have for my upload is as follows:
NameValueCollection nvc = new NameValueCollection();
nvc.Add("id", "TTR");
nvc.Add("btn-submit-photo", "Upload");
UploadToServer.HttpUploadFile(Settings.Default.ServerAddress , sfd.FileName.ToString(), "file", "image/jpeg", nvc);
Settings.Default.ServerAddress holds the location of my upload php script which the following:
http://server.foo.com/images/upload.php
I have another php script that returns a string of all the file and folders held on my server that is returned and displayed in a text box.
I'm calling this like so:
using (var client = new WebClient())
{
result = client.DownloadString("http://server.foo.com/images/getDirectoryList.php");
}
What I need to do is have a way so that I can choose the location of where the my image is stored. My feeling is telling that I need to do is have a way so that when a user selects anything with .folder, the old string list disappears and the images and files is stored within that folder.
I believe the call I need to make is something like this:
http://server.foo.com/images/getDirectoyList.php?dir=test_folder
But I'm stuck on trying to implement what I want. For one, the list I get back is all highlight and say I get something like
Image 1
Image 2
Test_folder.folder
I have no way of being able to simply click on Image 2 and have it highlight the whole thing. Instead is simply places the cursor where I clicked. Likewise I have no idea of how I would pass this information over to the my upload code so that my chosen directory is used to store the image as opposed to the root.
Has anyone ever attempted something like this before?
Do you have any links or advice that could help me achieve what it is I want to achieve?
Additionally, but not important, would I be able to ever create a new directory / folder on my server through my C# winform application without having to touch either the php scripts or the server itself?
I have a FileUpload control (FileUpload1) on my web form, as well as a "Sumbit" button, a label, and a hidden field that contains a UserID. I have the following code in the button's click event:
string path = Server.MapPath("~/userfiles/");
if (FileUpload.HasFile)
{
try
{
FileUpload1.SaveAs(path + UserID.Value + "/image.jpg");
}
catch
{
Label1.Text = "* unable to upload file";
Label1.Visible = true;
}
}
It works great if I upload an actual file. However, if I type a non-existent filename (for example, "c:\a.jpg", which does not exist on my computer) into the FileUpload's textbox, and click the Sumbit button, HasFile still returns true. Furthermore, SaveAs() does not throw any exceptions, and it is a void function that returns no value indicating success or failure. How do I tell whether a file was actually uploaded?
Just check to see if it exists.
if(File.Exists(myFile)){
//it was uploaded.
}
You could check FileUpload.PostedFile.ContentLength property
You could check if the file exists using File.Exists before calling SaveAs.
Hmmm....
Not sure I understand. First, in your code, FileUpload.HasFile won't compile. If should be FileUpload1.HasFile.
When I correct this, and run your code, this line returns false if the file does not exist...
You can check if file exists after uploading using File.Exists(path); The file object is part of System.IO.
This is not about your actual question, but you should validate any user input, especially if you want users to upload files to a virtual folder on your webserver. You should at least check whether the content type of the file is the one you expect, or - even better, filter (resize) the image using the classes available in the .NET framework.
If you don't do so users may share arbitrary content via your site or place malicious files (e.g. images containing script which might get executed by certain web browsers) on your server.
With additional validation you will also be able to validate if there has actually been content sent.
AND: A really severe vulnerability opens up when you build the save path by concatenating input from a form field (I assume UserID.Value is the POST parameter you mention?). This allows users to decide where to store the content on your server, and, even worse, be able to overwrite existing files!!!