Asp.net web api 如何在使用HttpServer的测试中使用格式化程序?
在我的Web API应用程序中,我使用Asp.net web api 如何在使用HttpServer的测试中使用格式化程序?,asp.net-web-api,Asp.net Web Api,在我的Web API应用程序中,我使用HttpServer在单元测试中包含我的控制器,并使用HttpClient直接调用它,例如: [Fact] public void TestMyController() { var config = new HttpConfiguration(); config.Routes.MapHttpRoute("default", "api/{controller}/{action}/{id}", new { id = RouteParameter.
HttpServer
在单元测试中包含我的控制器,并使用HttpClient
直接调用它,例如:
[Fact]
public void TestMyController()
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute("default", "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });
var server = new HttpServer(config);
var client = new HttpClient(server);
var response = client.GetAsync("http://localhost/api/test/values").Result;
}
我注意到(通过单步调试,并在其他SO帖子中确认),JsonFormatter
并没有真正运行-它已经初始化,但没有运行。由于此测试没有打开套接字,HttpClient
通过HttpMessageHandler
API直接调用HttpServer
,因此不运行格式化/序列化是有意义的,因为不需要它
在我的例子中,我有一些自定义的格式化/序列化/反序列化代码,这些代码在这些测试中不会被命中,但在真正的web服务器中运行时会被命中。我想在这些测试中使用这些代码;而且,在测试时排除序列化/反序列化代码路径似乎也有风险。对此有什么建议吗?下面是一个快速示例,说明如何强制格式化程序进行序列化/反序列化。这里我们将
ObjectContent
转换为StreamContent
。在下面的代码中,对CopyToAsync
的调用会触发一个路径,在该路径中格式化程序被强制序列化。在反序列化的情况下,为了确保我们通过格式化程序,我们希望内容的类型不是ObjectContent
,因为ReadAsAsync
具有内部逻辑,在特殊情况下ObjectContent
我们希望绕过它
HttpClient client = new HttpClient(new InMemoryHttpContentSerializationHandler(new HttpServer(config)));
MemoryHttpContentSerializationHandler中的公共类:DelegatingHandler { public InMemoryHttpContentSerializationHandler(HttpMessageHandler innerHandler) :base(innerHandler) { } 受保护的覆盖异步任务SendAsync(HttpRequestMessage请求,CancellationToken CancellationToken) { request.Content=等待ConvertToStreamContentAsync(request.Content); HttpResponseMessage response=await base.SendAsync(请求,取消令牌); response.Content=等待ConvertToStreamContentAsync(response.Content); 返回响应; } 专用异步任务ConvertToStreamContentAsync(HttpContent原始内容) { if(originalContent==null) { 返回null; } StreamContent StreamContent=作为StreamContent的原始内容; if(streamContent!=null) { 返回流内容; } MemoryStream ms=新的MemoryStream(); 等待原始内容。复制到同步(ms); //将流位置重置回0,与上一次CopyToAsync()调用相同, //例如,格式化程序可以将位置设置为末尾 ms.Position=0; streamContent=新的streamContent(毫秒); //从原始内容复制标题 foreach(原始内容标题中的KeyValuePair标题) { streamContent.Headers.TryAddWithoutValidation(header.Key,header.Value); } 返回流内容; } }
您不能直接调用response.Content.LoadIntoBufferAsync()吗.Wait?
LoadIntoBufferAsync
只会导致序列化通过格式化程序…但是如果我们也要执行格式化程序反序列化,那么内容类型必须不同于ObjectContent
,因为ReadAsAsync
具有特殊的大小写,它只在其中检索对象内容..非常好的回答-非常感谢。我找到了你的相关博文:在你的回答中,该类被更新为使用async/await。@crimbo:我接受你的编辑时出错了……你能再次提交吗?
public class InMemoryHttpContentSerializationHandler : DelegatingHandler
{
public InMemoryHttpContentSerializationHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Content = await ConvertToStreamContentAsync(request.Content);
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
response.Content = await ConvertToStreamContentAsync(response.Content);
return response;
}
private async Task<StreamContent> ConvertToStreamContentAsync(HttpContent originalContent)
{
if (originalContent == null)
{
return null;
}
StreamContent streamContent = originalContent as StreamContent;
if (streamContent != null)
{
return streamContent;
}
MemoryStream ms = new MemoryStream();
await originalContent.CopyToAsync(ms);
// Reset the stream position back to 0 as in the previous CopyToAsync() call,
// a formatter for example, could have made the position to be at the end
ms.Position = 0;
streamContent = new StreamContent(ms);
// copy headers from the original content
foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers)
{
streamContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
return streamContent;
}
}