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

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

问题描述

我理解 HttpPostedFileBase HttpPostedFileWrapper 之间的关系,就两者的需求而言单元测试/嘲弄)。但是为什么当我在 HttpPostedFileBase 的返回上放置一个断点时,是否显示为 HttpPostedFileWrapper



此外, HttpPostedFileBase 不会实现ContentType属性。那为什么当我的代码 引用 HttpPostedFileBase 而不是 HttpPostedFileWrapper ?这是什么样的诡计?


编辑#1:

感谢您的回复@ lawliet29 。

  public sealed class MyHttpPostedFile 
{
public string ContentType {得到{return123; }}
}

公共抽象类MyHttpPostedFileBase
{
}

公共类MyHttpPostedFileWrapper:MyHttpPostedFileBase
{
私人MyHttpPostedFile _myHttpPostedFile;

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

public string ContentType {get {return _myHttpPostedFile.ContentType;为了使这个工作,虽然,我需要通过这个工作,但我不知道为什么。参数是这样的:

 的GetFiles(新MyHttpPostedFileWrapper(新MyHttpPostedFile()); 

这似乎是我所质疑的技巧存在的地方.net如何知道被传递给它的字节是一个类型为 MyHttpPostedFile ,它应该采取该对象,并将其作为参数传递给我的构造函数?
$ b

编辑#2: 我没有意识到ASP.NET MVC绑定器不仅仅是传递这些更高级别的对象来传递字节,这是我不知道该怎么做!谢谢你的回复。

解决方案

其实很简单,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 

这意味着它不能被继承,不能被单元测试模拟。



解决这个问题ASP.NET MVC开发人员创建了一个可嘲讽的抽象 - HttpPostedFileBase,它是这样定义的:
$ b $ pre $公共抽象类HttpPostedFileBase $所以现在,你可以定义你的MVC动作,以便它们接受HttpPostedFileBase而不是不可撼动的HttpPostedFile:

/ p>

  [HttpPost] 
public ActionResult PostFile(HttpPostedFileBase文件)
{
//逻辑这里...



$ b $ p
$ b

问题是,在某种深度以下,唯一的方法代表一个张贴的文件是好老的刚性HttpPostedFile。因此,为了支持这个抽象,MVC开发人员创建了一个名为HttpPostedFileWrapper装饰,看起来大致是这样的:

 公共类HttpPostedFileWrapper:HttpPostedFileBase 
{
私人HttpPostedFile _httpPostedFile;

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

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

//执行其他HttpPostedFileBase成员
}

所以现在HttpPostedFileWrapper是你用POST文件执行真正的HTTP POST请求时实际得到的。感谢多态,你可以通过派生类的一个实例 - HttpPostedFileWrapper - 以法接受基类 - HttpPostedFileBase



在这期间,你可以创建自己的模拟实现,会说,看起来像一个视频文件被张贴。你可以这样做:

  public class MockPostedVideoFile:HttpPostedFileBase 
{
public string ContentType {get {returnvideo / mp4; }}

//这里的其余部分
}

其他编辑:
HttpPostedFile的实际实例都是由System.Web为您处理的。 ASP.NET MVC binder对发布的表单数据非常智能。它会自动检测到某些文章的值实际上是一个文件的字节,所以为了正确表示它们,可以使用System.Web框架中的一些旧的来创建一个HttpPostedFile实例。



<这个要点是 - 你不必担心。在这里幕后有很多事情要做,我们真的需要感谢ASP.NET MVC团队为了避开所有这些低层次的事情。



你唯一需要担心的地方是单元测试。在你的测试中,你可以使用模拟实现来调用你的动作,就像这样:

  myController.PostFile(new MockPostedVideoFile()) 


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?

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?

Edit #1:

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

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?

Edit #2:

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.

解决方案

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

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

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