我正在将HttpContent转换成以下dto:
public class ContentDto { public string ContentType {get; set;} public string Headers {get; set; } public object Data { get; set; } public ContentDto(HttpContent content) { Headers = content.Headers.Flatten(); // rest of the setup } }
我正在运行一些单元测试:
[Fact] public void CanBuild() { var content = new StringContent("some json",Enconding.UTF8,"application/json"); var dto = new ContentDto(content); var contentHeaders = content.Headers.Flatten(); Assert.Equal(contentHeaders,dto.Headers); }
而且测试失败,因为Content-Length头没有在我的dto上被捕获.但是,如果我这样做:
[Fact] public void CanBuild() { var content = new StringContent("some json","application/json"); var contentHeaders = content.Headers.Flatten(); var dto = new ContentDto(content); Assert.Equal(contentHeaders,dto.Headers); }
测试通过,并且捕获所有标题.更多的我也尝试过:
[Fact] public void CanBuild() { var content = new StringContent("some json","application/json"); var dto = new ContentDto(content); var contentHeaders = content.Headers.Flatten(); var dto1 = new ContentDto(content); Assert.Equal(contentHeaders,dto.Headers); Assert.Equal(contentHeaders,dto1.Headers); }
并且它失败,因为dto没有Content-Length头,但dto1没有.我甚至尝试将标头连接到类似Factory的方法,如下所示:
public static ContentDto FromContent<T>(T content) where T : HttpContent { // same as the constructor }
看看关于Content-Length头文件的StringContent类是否有特别的东西,但是没有什么区别,无论我是使用构造函数(使用基类HttpContent)还是通用方法FromContent(使用实际的StringContent in这种情况)结果是一样的.
所以我的问题是:
这是HttpContent.Headers的预期行为吗?
有没有特定于实际HttpContent类型的头文件?
我在这里缺少什么?
public static string Flatten(this HttpHeaders headers) { var data = headers.ToDictionary(h => h.Key,h => string.Join("; ",h.Value)) .Select(kvp => $"{kvp.Key}: {kvp.Value}"); return string.Join(Environment.NewLine,data) }
解决方法
你的例子不完整在调用扩展方法之前,当我访问ContentLength属性时,我只能重新创建您的问题.您代码中的某个地方(最可能是//其余的安装程序),您直接或间接地调用该属性,该属性最可能遵循一个延迟加载模式,然后在下一次调用扩展方法时将其包含在标题中,并将其包含在构造的字符串中.它们不匹配,因为您在访问内容长度属性之前生成手动字符串.
在HttpContentHeaders.ContentLength的源代码中
public long? ContentLength { get { // 'Content-Length' can only hold one value. So either we get 'null' back or a Boxed long value. object storedValue = GetParsedValues(HttpKnownHeaderNames.ContentLength); // Only try to calculate the length if the user didn't set the value explicitly using the setter. if (!_contentLengthSet && (storedValue == null)) { // If we don't have a value for Content-Length in the store,try to let the content calculate // it's length. If the content object is able to calculate the length,we'll store it in the // store. long? calculatedLength = _calculateLengthFunc(); if (calculatedLength != null) { SetParsedValue(HttpKnownHeaderNames.ContentLength,(object)calculatedLength.Value); } return calculatedLength; } if (storedValue == null) { return null; } else { return (long)storedValue; } } set { SetOrRemoveParsedValue(HttpKnownHeaderNames.ContentLength,value); // Box long value _contentLengthSet = true; } }