HttpPostedFileBase 与 HttpPostedFileWrapper 的关系 [英] HttpPostedFileBase's relationship to HttpPostedFileWrapper

查看:28
本文介绍了HttpPostedFileBase 与 HttpPostedFileWrapper 的关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我了解 HttpPostedFileBaseHttpPostedFileWrapper 之间的关系,就两者的需求而言(即在单元测试/模拟中).但是,为什么当我在 HttpPostedFileBase 的返回上放置断点时,它是否将其显示为 HttpPostedFileWrapper?

I understand the relationship between HttpPostedFileBase and HttpPostedFileWrapper, in terms of the need for both of them (i.e. in unit testing/mocking). But why, when I put a breakpoint on the return for HttpPostedFileBase, does it show it as HttpPostedFileWrapper?

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

Furthermore, HttpPostedFileBase doesn't implement the ContentType property. So why does it return a value when my code only references HttpPostedFileBase, and not HttpPostedFileWrapper? What kind of trickery is this?

编辑 #1:

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

Thanks for the great reply @lawliet29. I have written out the structure as suggested.

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; } }
}

为了让它工作,我需要像这样传递参数:

In order for this to work though, I would need to pass the parameter like this:

GetFiles(new MyHttpPostedFileWrapper(new MyHttpPostedFile());

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

This seems to be where the trickery I am questioning exists. How does .NET know that the bytes being passed to it is a class of type MyHttpPostedFile and that it should take that object and pass it into my constructor's as a parameter?

编辑 #2:

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

I didn't realise the ASP.NET MVC binder would do more than just pass bytes by passing these higher level objects. This is the trickery I was wondering about! Thanks for the great responses.

推荐答案

其实很简单.HttpPostedFileBase 是一个抽象类,仅用于派生的目的.使用它是为了使密封类 HttpPostedFile 中的某些内容可以模拟.

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.

然而,在现实生活中,HttpPostedFile 是处理已发布文件的工具,为了保持一致,创建了 HttpPostedFileWrapper.此类通过包装 HttpPostedFile 来提供 HttpPostedFileBase 的实现.

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.

所以HttpPostedFileBase是统一的抽象,HttpPostedFile是表示发布文件的类,HttpPostedFileWrapper是HttpPostedFileBase的实现,它封装了HttpPostedFile.HttpPostedFileWrapper 的 ContentType 属性实现从底层 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.

某种解释

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

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.

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

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

public abstract class HttpPostedFileBase

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

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...
}

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

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
}

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

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
}

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

ANOTHER 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.

重点是 - 您无需担心.这里有很多事情在幕后发生,我们真的需要感谢 ASP.NET MVC 团队消除了所有这些低级的事情.

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())

这篇关于HttpPostedFileBase 与 HttpPostedFileWrapper 的关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆