HttpPostedFileBase与HttpPostedFileWrapper的关系

Bea*_*kie 13 c# asp.net-mvc file-upload httppostedfilebase

我理解之间的关系HttpPostedFileBase,并HttpPostedFileWrapper为他们两个(即在单元测试/嘲讽)的,在需要方面.但是,为什么,当我在回报中设置断点时HttpPostedFileBase,它是否显示为HttpPostedFileWrapper

此外,HttpPostedFileBase不实现ContentType属性.那么为什么当我的代码引用时它返回一个值HttpPostedFileBase,而不是HttpPostedFileWrapper?这是什么样的诡计?

在此输入图像描述

编辑#1:

感谢@ lawliet29的精彩回复.我按照建议书写了结构.

public sealed class MyHttpPostedFile
{
    public string ContentType { get { return "123"; } }
}

public abstract class MyHttpPostedFileBase
{
}

public class MyHttpPostedFileWrapper : MyHttpPostedFileBase
{
    private MyHttpPostedFile _myHttpPostedFile;    

    public MyHttpPostedFileWrapper(MyHttpPostedFile myHttpPostedFile) { 
        _myHttpPostedFile = myHttpPostedFile;
    }

    public string ContentType { get { return _myHttpPostedFile.ContentType; } }
}
Run Code Online (Sandbox Code Playgroud)

为了使其工作,我需要传递这样的参数:

GetFiles(new MyHttpPostedFileWrapper(new MyHttpPostedFile());
Run Code Online (Sandbox Code Playgroud)

这似乎是我质疑的诡计存在的地方..NET如何知道传递给它的字节是一个类型的类MyHttpPostedFile,它应该采用该对象并将其作为参数传递给我的构造函数?

编辑#2:

我没有意识到ASP.NET MVC绑定器不仅仅通过传递这些更高级别的对象来传递字节.这是我想知道的诡计!感谢您的好评.

law*_*t29 19

实际上,这很简单.HttpPostedFileBase是一个抽象类,仅用于派生的目的.它被使用,以便密封类HttpPostedFile中的某些东西是可模拟的.

但是,在现实生活中,HttpPostedFile是处理已发布文件的方法,为了保持一致,创建了HttpPostedFileWrapper.该类通过包装HttpPostedFile为HttpPostedFileBase提供实现.

因此HttpPostedFileBase是一个统一的抽象,HttpPostedFile是一个表示发布文件的类,HttpPostedFileWrapper是HttpPostedFileBase的实现,它包装了HttpPostedFile.HttpPostedFileWrapper的ContentType属性的实现从底层HttpPostedFile读取内容类型.

编辑:某种解释

ASP.NET MVC收到了一个文件,在其下方的某个地方创建了一个HttpPostedFile实例,因为这是.NET Framework 1.0以来的工作方式.HttpPostedFile的定义如下:

public sealed class HttpPostedFile
Run Code Online (Sandbox Code Playgroud)

这基本上意味着它不能被继承,也不能被单独测试模拟.

为解决此问题,ASP.NET MVC开发人员创建了一个可模拟的抽象 - HttpPostedFileBase,其定义如下:

public abstract class HttpPostedFileBase
Run Code Online (Sandbox Code Playgroud)

所以现在,您可以定义MVC操作,以便它们接受HttpPostedFileBase而不是不可模拟的HttpPostedFile:

[HttpPost]
public ActionResult PostFile(HttpPostedFileBase file)
{
    // some logic here...
}
Run Code Online (Sandbox Code Playgroud)

问题是,在下面的某个地方,表示已发布文件的唯一方法是旧的刚性HttpPostedFile.因此,为了支持这种抽象,MVC开发人员创建了一个名为HttpPostedFileWrapper的装饰器,其外观大致如下:

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
}
Run Code Online (Sandbox Code Playgroud)

所以现在HttpPostedFileWrapper是您在使用已发布文件执行真正的HTTP POST请求时实际获得的.由于多态性,您可以将派生类的实例 - HttpPostedFileWrapper - 传递给接受基类的方法 - HttpPostedFileBase.

一直以来,您可以创建自己的模拟实现,例如,看起来像是一个发布的视频文件.你这样做

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

    // rest of implementation here
}
Run Code Online (Sandbox Code Playgroud)

另一个编辑: HttpPostedFile的实际实例化全部由System.Web为您处理.ASP.NET MVC绑定器对发布的表单数据非常智能.它会自动检测某些post值实际上是文件的字节,因此为了正确表示它们,它可以使用System.Web框架中的旧东西来创建实例HttpPostedFile.

其重点是 - 你不必担心它.幕后有很多事情发生在这里,我们真的需要感谢ASP.NET MVC团队放弃所有那些低级别的东西.

您需要担心的唯一地方是单元测试.在您的测试中,您可以使用模拟实现调用您的操作,如下所示:

myController.PostFile(new MockPostedVideoFile())
Run Code Online (Sandbox Code Playgroud)

  • 我认为我理解......实施.但他们是如何"创造"这个的呢?如何在检查/实现它时创建一个显示不同包装类的抽象类? (2认同)
  • 它只是它的主要的多态性:)嗯,就使用而言,你可以有一个派生类的实例,你期望一个基类.因此,ASP.NET MVC使您更容易,允许期望基类,以便可以为单元测试创​​建各种实现.但是,在现实生活中,HttpPostedFileWrapper是您最有可能获得的实现. (2认同)