C# 如何使用反射设置HttpRequest.InputStream值

C# 如何使用反射设置HttpRequest.InputStream值,c#,.net,asp.net-mvc-3,reflection,asp.net-web-api,C#,.net,Asp.net Mvc 3,Reflection,Asp.net Web Api,我正在为一个WebApi控制器编写一个单元测试,该控制器从Request.InputStream读取一个POST主体。我需要设置HttpContext.Current.Request.inputstream的inputstream属性,或者设置inputstream的内容。以下是我到目前为止的单元测试代码,但它一直抛出异常: var originalStream = HttpContext.Current.Request.InputStream; Stream newStream = new M

我正在为一个WebApi控制器编写一个单元测试,该控制器从Request.InputStream读取一个POST主体。我需要设置HttpContext.Current.Request.inputstream的inputstream属性,或者设置inputstream的内容。以下是我到目前为止的单元测试代码,但它一直抛出异常:

var originalStream = HttpContext.Current.Request.InputStream;
Stream newStream = new MemoryStream(ASCIIEncoding.Default.GetBytes("Test String"));

var propInfo = originalStream.GetType().GetProperty("CanWrite");
propInfo.SetValue(originalStream, true);

newStream.CopyTo(originalStream);

propInfo.SetValue(originalStream, false);
我在SetValue行上得到以下异常:

ArgumentException: Property set method not found

我这样做完全错了吗?我的控制器读取输入流并将其反序列化为JSON,因此我需要能够将数据插入该流。我只是不知道怎么做。非常感谢。

公共摘要布尔可以写{get;}
。该属性上没有setter。。这就是你的错误

在您的示例中,
originalStream
的类型为
Stream
。将其包装到另一个流中以进行测试。您不是在测试HttpRequest.InputStream,而是在测试反序列化

var originalStream = new StreamReader(HttpContext.Current.Request.InputStream);
var content = originalStream.ReadToEnd();
。。等等

你甚至可以考虑跳过使用请求输入,因为你没有真正的测试它。

编辑:

再扩展一点。您应该将其移出控制器操作。。执行以下操作:

public class YourController : Controller {
    private readonly IStreamWrapper _streamWrapper;

    public YourController(IStreamWrapper wrapper) {
        _streamWrapper = wrapper;
    }

    public ActionResult MethodYouAreTesting() {
        var result = _streamWrapper.Process(HttpRequest.InputStream);
    }
}

public class Tests {
    public void YourTestMethod() {
        var controller = new YourController(new FakeStreamWrapper()); // mock perhaps?
        // Asserts here for the controller action
    }

    public void YourWrapperTester() {
        var wrapper = new RealStreamWrapper();
        // test Process method here..
    }
}
然后可以单独测试流读取和反序列化


这有意义吗?还是我把它弄得更复杂了/

输入流是只读流

有几种方法。从最简单的开始:

创建StreamReader的实例,并在InputStream上调用ReadToEnd()以获取要发送的数据

一旦有了内容,就可以在进行JSON转换之前根据需要进行修改


同样,这是做你想做的事情的最简单、最不优雅的方法,但它应该能工作。

我正在测试我的控制器的动作。为了获得请求主体,我的控制器执行Context.Current.request.InputStream.Read(基本上),所以我需要能够设置它。我没有办法让身体进入我的行动。我看不出你的方法会起什么作用。不过这是我的观点。我会将逻辑转移到它自己的类中。将其注入控制器。。并用它来测试动作。您可以将
InputStream
传递到这个单独的类中,该类将它封装在一个更具体的实现中。你所做的比它需要的要困难得多。我会更新我的答案。谢谢,但是我如何让InputStream读取我在测试方法中定义的内容?我知道你的方法是如何工作的,但我不明白如何告诉InputStream读什么。它不必在你的测试中。您的伪/模拟可以实例化一个新的流来进行测试。在实际实现中,它将使用
InputStream
(由于注入的依赖关系,这是可能的)。在测试期间,这些模拟实例将以空流、空流等形式传递。这很好(我认为),因为您没有测试流。。您正在测试内容。因此,无论测试中是否有
InputStream
。。无关紧要。@SimonWhitehead布道-这是一个完美的测试场景-OP测试了太多的实现细节,只需要注入一些依赖项来处理