3

I am working on an ASP.NET MVC 4 application and there are many views where the user can upload a file which I save on the server. Along with that I have a separate entity that holds different data for the uploaded file like :

  string fileExtension = System.IO.Path.GetExtension(uploadFile.FileName);
  string uniqueGuid = Helper.GetUniqueName(Server.MapPath("~/Content/Files"));
  string newFileName = uniqueGuid + fileExtension;

this is just to get the impression. There is a number of operations that I do for each file uploaded from the user and after I'm done I make new record in the database with the info and save the file on the server.

My Solution has two projects - one is the MVC 4 application, and the other is used as data access layer. Where using Entity Framework 5 I've implemented Repository pattern and UnitOfWork.

what I want to do is to create new method in my repository. Something like:

 public bool ManageFile(HttpPostedFileBase file ); 

and call this method from my controllers instead writing the same logic the same time.

A standard Action in my controller that accepts HttpPostedFileBase file looks like:

public ActionResult Edit(SomeViewModel model, HttpPostedFileBase uploadFile)

inside this action I want to call:

unitOfWork.SomeModelRepository.ManageFile(uploadFile);

the problem is that my data access layer project doesn't recognize the HttpPostedFileBase. Maybe I can add some reference to the project, I'm not sure since I've had some problem using Server.MapPath for example outside the Action but even if I can reference it I'm still not sure if it's the better approach. After all my data access layer is only this - a layer of abstraction I don't think that HttpPostedFileBase has a place there.

In my controller Action I've tried to parse HttpPostedFileBase uploadFile to File uploadFile but I couldn't do that. But basically what I need is the ability to perform the same operations that one could perform on file - get extension, get name and so on... So how can pass HttpPostedFileBase uploadFile to my DAL project?

Leron
  • 9,546
  • 35
  • 156
  • 257
  • possible duplicate of [How to construct HttpPostedFileBase?](http://stackoverflow.com/questions/3428276/how-to-construct-httppostedfilebase) – Tomas Kubes Mar 01 '14 at 19:20

1 Answers1

2

HttpPostedFileBase is in the System.Web assembly, which you can reference from your DAL project.

Another option, if you want to decouple your ManageFile() method from HttpPostedFileBase, is just pass in the file's MemoryStream and any other required parameters:

public bool ManageFile(Stream file, string fileName) 
{

}  

I think it's easier for unit testing, and if you allow the caller to supply path information, you can reuse the ManageFile() with different naming schemes.

Also for what it's worth, if

string uniqueGuid = Helper.GetUniqueName(Server.MapPath("~/Content/Files"));

just generates a unique Guid based on existing files, you can probably skip this logic. Guid's will pretty much always be unique, so doing Guid.NewGuid() is sufficient.

public bool ManageFile(Stream file, string fileName) 
{
    string extension = System.IO.Path.GetExtension(fileName);
    string newFileName = Guid.NewGuid() + extension;
}  

Edited to add:

Here's how I structure things like this in my project. I have a IFileRepository interface:

interface IFileRepository
{
    SaveFile(Stream stream, string fileName);
}

And then I create a concrete type depending on where I want to save the file

public AzureFileRepository : IFileRepository
{
    public void SaveFile(Stream stream, string fileName) 
    {   
        ...
        CloudBlob.UploadFromStream(stream);
        ...
    }
}

or

public DiskFileRepository : IFileRepository
{
    public void SaveFile(Stream stream, string fileName) 
    {   
        File file = // create a File() object and save the stream
    }
}

And now the controller knows nothing about the file repository. It just calls SaveFile() and magic happens.

Community
  • 1
  • 1
mfanto
  • 14,168
  • 6
  • 51
  • 61
  • Is there, anyway, an option to cast `HttpPostedFileBase` to `File`? For example - if I decide later on to get use of some other option I won't have to add another argument to my method but just write it in the method itstelf. – Leron Dec 11 '13 at 18:18
  • I don't believe so. I don't know how correct this is, but I tend to think of HttpPostedFile as a wrapper around the stream, with some additional properties like the FileName. What you do with that stream can differ (maybe you store it as a File, maybe you upload to to Azure blob storage, etc.). – mfanto Dec 11 '13 at 18:23
  • This is sort of a tangent, but I think you should decouple your ManageFile() implementation from any specific instance of a File or HttpPostedFile. Let the caller supply everything that ManageFile() needs, so that you end up with a generic repository. Then, it doesn't matter where your content came from (uploaded from the user, read from disk, pulled from the cloud), your repository can still act on it. File is for files on the disk. There are a lot of properties that wouldn't make sense for an HttpPostedFile. – mfanto Dec 11 '13 at 18:30
  • Thanks for the advice. Thinking about it I might do just what you say. – Leron Dec 11 '13 at 18:36
  • Edited to add an example of how I do this in my project. Hope it makes sense. – mfanto Dec 11 '13 at 18:50