You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Web Api返回HTML内容发布至IIS 8后序列化异常如何解决?

解决ASP.NET Web API发布到IIS8后返回HTML时的序列化错误

我之前也碰到过类似的问题,本地调试好好的,一发布到IIS就出序列化错误,咱们来一步步解决它。

先看你写的API代码:

[HttpGet]
public HttpResponseMessage test()
{
    var response = new HttpResponseMessage(HttpStatusCode.OK);
    response.Content = new StringContent("<html><body>HELLO</body></html>");
    response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
    return response;
}

发布到Windows Server 2012的IIS8后出现的错误信息是:

<Error>
  <script/>
  <script id="tinyhippos-injected"/>
  <Message>An error has occurred.</Message>
  <ExceptionMessage>
    The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
  </ExceptionMessage>
  <ExceptionType>System.InvalidOperationException</ExceptionType>
  <StackTrace/>
  <InnerException>
    <Message>An error has occurred.</Message>
    <ExceptionMessage>
      Type 'System.Net.Http.StringContent' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
    </ExceptionMessage>
    <ExceptionType>
      System.Runtime.Serialization.InvalidDataContractException
    </ExceptionType>
    <StackTrace>
      at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.ThrowInvalidDataContractException(String message, Type type)
      at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type)
      at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
      at System.Runtime.Serialization.XmlObjectSerializerContext.GetDataContract(RuntimeTypeHandle typeHandle, Type type)
      at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
      at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
      at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerializeReference(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
      at WriteHttpResponseMessageToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract )
      at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
      at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
      at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
      at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
      at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
      at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
      at System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph)
      at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content)
      at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
      --- End of stack trace from previous location where exception was thrown ---
      at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
      at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__22.MoveNext()
    </StackTrace>
  </InnerException>
</Error>

问题原因

这个错误的核心是Web API框架没有直接返回你设置的HTML内容,反而尝试序列化HttpResponseMessage对象本身。本地调试正常是因为本地请求的Accept头大概率优先接受text/html,框架直接返回了内容;但IIS环境下的请求可能默认Accept是application/xml,触发了框架的XML序列化逻辑,而StringContent类型本身不支持XML序列化,所以报错了。

解决方法

给你三种靠谱的解决方式,按需选择:

方法一:改用IHttpActionResult返回(最推荐)

ASP.NET Web API推荐用IHttpActionResult来封装响应,它会自动处理内容类型,避免序列化问题:

[HttpGet]
public IHttpActionResult Test()
{
    var htmlContent = "<html><body>HELLO</body></html>";
    // 直接指定内容类型为text/html
    return Content(HttpStatusCode.OK, htmlContent, new MediaTypeHeaderValue("text/html"));
}

方法二:用ResponseMessageResult包装HttpResponseMessage

如果你习惯用HttpResponseMessage,可以用ResponseMessage方法告诉框架直接返回这个响应,不要序列化:

[HttpGet]
public IHttpActionResult Test()
{
    var response = new HttpResponseMessage(HttpStatusCode.OK);
    // 这里最好加上编码,避免中文乱码
    response.Content = new StringContent("<html><body>HELLO</body></html>", Encoding.UTF8, "text/html");
    return ResponseMessage(response);
}

方法三:全局禁用XML格式化器(适合全API不需要XML响应的场景)

如果你的API主要返回HTML或JSON,不需要XML格式,可以在WebApiConfig.cs里移除XML格式化器:

public static void Register(HttpConfiguration config)
{
    // 移除XML格式化器,框架就不会尝试用XML序列化响应
    config.Formatters.Remove(config.Formatters.XmlFormatter);
    
    // 其他路由配置
    config.MapHttpAttributeRoutes();
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

优先选方法一或方法二,它们不会影响其他API的行为;方法三适合整个API都不需要XML响应的场景。

内容的提问来源于stack exchange,提问作者Passa4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:17:12