Managing user-uploaded files with an ASP.NET websi

2019-06-05 19:29发布

问题:

I know that somewhere in the history of the internet this must have been asked somewhere, but I just can't seem to nail down the right terminology to get the answer I need. This question comes close: What is the best way to store user uploaded files in a website? But I need a little bit more detail.

Basically, how are you supposed to effectively manage files that users have uploaded, such as a profile picture? What I want to know are some "best practices" regarding WHERE to make the directory structure.

The second answer in the above question offers some options, such as storing them outside of the web root, which is what I originally thought about doing. But then I started thinking...

1) How do we save the paths in the database? Absolute? Relative? Each user has a column for "ProfilePicPath". What if we want to completely uproot the entire project from one server to another, and for whatever reason we can't put the files in the same place on the new server? Every link would be broken.

2) How should this be handled in terms of security? Say we have our web application deployed to like C:\websites\site1, but we store the user profile pictures in like C:\usercontent\profilepictures\? On a page where we load the profile picture, how do we safely access that programmatically in the code behind? We don't want to put them in like C:\websites\site1\usercontent\profilepictures\, right? I'm not a fan of putting an absolute path into the database, and I also don't want to hardcode a path in anywhere in the code behind.

We originally DID try with the files inside the web project, but then it became kind of a risk, because these user files were part of our project. One wrong copy/paste when updating/modifying the site and we might overwrite a file a user has uploaded since we last checked out the project from the repository, etc. It was a huge hassle, and the whole scenario just screamed to me, "you idiot, you're doing this all wrong..." but I just can't seem to find a proper guide to doing it "right."

Just to be clear, our needs are minimal --- this is just a small project for internal use, no more than maybe 30 users, and it all needs to be contained on one IIS 7 server.

回答1:

1) How do we save the paths in the database? Absolute? Relative? Each user has a column for "ProfilePicPath". What if we want to completely uproot the entire project from one server to another, and for whatever reason we can't put the files in the same place on the new server? Every link would be broken.

Relative. In ProfilePicPath simply store the filename if you wish to do it that way. I've a web application where I found it easier to store the picture in a SQL column with data type "image". The reasoning goes that the picture is part of the application's data rather than the application's code, so therefore store it in the database.

2) How should this be handled in terms of security? Say we have our web application deployed to like C:\websites\site1, but we store the user profile pictures in like C:\usercontent\profilepictures\? On a page where we load the profile picture, how do we safely access that programmatically in the code behind? We don't want to put them in like C:\websites\site1\usercontent\profilepictures\, right? I'm not a fan of putting an absolute path into the database, and I also don't want to hardcode a path in anywhere in the code behind.

In your web.config have an appSetting like so:

<add key="ProfilePicturePath" value="C:\usercontent\profilepictures\" />

And your code can use Path.Combine(s1, s2) to combine the AppSetting with the database ProfilePicPath value for the user. To serve the image file you can reference a HTTP Handler e.g. <img src="Pic.ashx" />. The code I use to get the image from the database is below, but if you were getting the data from the a folder you can use System.IO.File.Open() to get the stream from the file system instead.

public class Pic : IHttpHandler
{
    #region Properties

    public bool IsReusable
    {
        get
        {
            return true;
        }
    }

    #endregion

    #region Implemented Interfaces

    #region IHttpHandler

    public void ProcessRequest(HttpContext context)
    {
        var userRecord = DAL.GetCurrentUser();

        if (userRecord != null)
        {
            byte[] picture = userRecord.ProfilePicture.ToArray();

            context.Response.ContentType = "image/jpeg";
            context.Response.OutputStream.Write(picture, 0, picture.Length);
            context.Response.OutputStream.Close();
        }
    }

    #endregion

    #endregion
}


回答2:

What i did with my Web Site

  1. I created a subdomain to where i can access the files (e.g static.domain.com)
  2. In my main site, I added some appSettings in the web.config for the file paths like these

       <add key="MainPath" value="http://static.domain.com/ImageDatabase/" />
       <add key="Profile" value="Profile/" />         
       <add key="Advertisements" value="Ads/" />         
    
  3. I created a class that returns the directory i need to get a specific file. I serialized my files to be linked to the profiles in my database having names like photo_1.png which could be found for example under Profile Directory so when im looking for a photo for a profile for account id 1 i will just call my class like these

string ProfileDir = clsDirectory.GetProfileDirectory();

string filePath = ProfileDir + "photo_" + UserId + ".png";