我了解HttpPostedFileBaseHttpPostedFileWrapper之间的关系,就两者的需求而言(即在单元测试/模拟中)。但是为什么当我在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绑定(bind)器不仅仅可以通过传递这些更高级别的对象来传递字节,还可以做更多的事情。这是我想知道的骗术!感谢您的好评。

最佳答案

实际上,这真的很简单。 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

这基本上意味着它不能被继承,也不能被模拟用于单元测试。

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

因此,现在,您可以定义MVC Action ,以便它们接受HttpPostedFileBase而不是不可 mock 的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的方法。

一直以来,您都可以创建自己的模拟实现,例如,看起来像正在发布的视频文件。你会这样
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团队,他们放弃了所有这些底层的知识。

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

关于c# - HttpPostedFileBase与HttpPostedFileWrapper的关系,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24910982/

10-12 12:42