HttpPostedFileBase's relationship to HttpPostedFileWrapper

无人久伴 提交于 2019-11-28 06:59:03

It's really simple, actually. HttpPostedFileBase is an abstract class, used solely for the purpose of being derived from. It was used so that certain things in sealed class HttpPostedFile would be mockable.

In real life, however, HttpPostedFile is what you have for handling posted files, and to be consistent, HttpPostedFileWrapper was created. This class provides implementation for HttpPostedFileBase by wrapping HttpPostedFile.

So HttpPostedFileBase is a unified abstraction, HttpPostedFile is a class representing posted files, and HttpPostedFileWrapper is implementation of HttpPostedFileBase that wraps HttpPostedFile. Implementation of ContentType property for HttpPostedFileWrapper reads content type from underlaying HttpPostedFile.

EDIT: some kind of explanation

ASP.NET MVC recieved a file and somewhere deep down below it has created an instance of HttpPostedFile, because this is how things worked since .NET Framework 1.0. The definition of HttpPostedFile looks like this:

public sealed class HttpPostedFile

which basically means it can't be inherited and can't be mocked for unit testing.

To resolve this issue ASP.NET MVC developers created a mockable abstraction - HttpPostedFileBase, which is defined like this:

public abstract class HttpPostedFileBase

So now, you can define your MVC actions so that they accept HttpPostedFileBase and not un-mockable HttpPostedFile:

[HttpPost]
public ActionResult PostFile(HttpPostedFileBase file)
{
    // some logic here...
}

The problem is, somewhere deep down below, the only way to represent a posted file is good old rigid HttpPostedFile. So in order to support this abstraction, MVC developers created a decorator called HttpPostedFileWrapper that looks roughly like this:

public class HttpPostedFileWrapper : HttpPostedFileBase
{
    private HttpPostedFile _httpPostedFile;    

    public HttpPostedFileWrapper(HttpPostedFile httpPostedFile) { 
        _httpPostedFile = httpPostedFile;
    }

    public string ContentType { get { return _httpPostedFile.ContentType; } }

    // implementation of other HttpPostedFileBase members
}

So now HttpPostedFileWrapper is what you actually get when performing a real HTTP POST request with posted file. Thanks to polymorphism, you can pass an instance of derived class - HttpPostedFileWrapper - to method accepting base class - HttpPostedFileBase.

All the while, you can create your own mock implementation that would, say, look like a video file being posted. You'd do it like this

public class MockPostedVideoFile : HttpPostedFileBase
{
    public string ContentType { get { return "video/mp4"; } }

    // rest of implementation here
}

ANOTHER EDIT: The actual instantiation of HttpPostedFile is all handled by System.Web for you. ASP.NET MVC binder is quite intelligent about posted form data. It automatically detects that certain post values are actually bytes of a file, so in order to properly represent them it can use something old from System.Web framework to create an instance HttpPostedFile.

The main point of this is - you don't need to worry about it. There are a lot of things going on behind the scenes here and we really need to be grateful to ASP.NET MVC team for abstacting away all those low-level things.

The only place where you do need to worry about this is unit testing. In your test you can just call your action with a mock implementation, like this:

myController.PostFile(new MockPostedVideoFile())
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!