HttpPostedFileBase与HttpPostedFileWrapper的关系

我理解HttpPostedFileBaseHttpPostedFileWrapper之间的关系,就两者的需求而言(即在unit testing/模拟中)。 但是,为什么当我在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; } } } 

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

 GetFiles(new MyHttpPostedFileWrapper(new MyHttpPostedFile()); 

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

编辑#2:

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

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

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

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

编辑:某种解释

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

 public sealed class HttpPostedFile 

这基本上意味着它不能被inheritance,也不能被单独测试模拟。

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

 public abstract class HttpPostedFileBase 

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

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

问题是,在下面的某个地方,表示已发布文件的唯一方法是旧的刚性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 } 

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

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

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

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

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

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

 myController.PostFile(new MockPostedVideoFile())