在web服务中,我得到“未找到密钥”.当我尝试序列化到JSON消息时,会出现异常
本文关键字:JSON 序列化 消息 异常 未找到密钥 服务 web 密钥 | 更新日期: 2023-09-27 18:07:50
我有一个web服务,它使用对System.ServiceModel.Dispatcher.SerializeReply消息的调用(特别是MultiplexingDispatchMessageFormatter实现)。当我进行此调用时,我得到一个"未找到键"异常,我跟踪到System.ServiceModel.Dispatcher.MultiplexingDispatchMessageFormatter中的一行,它试图基于键获取"defaultContentType"。
不幸的是,我无法看到关键是什么,但defaultContentType集合似乎没有任何项目在它。
我需要做什么才能让SerializeReply工作?
代码:
public System.ServiceModel.Channels.Message SerializeReply(System.ServiceModel.Channels.MessageVersion messageVersion, object[] parameters, object result)
{
System.Web.HttpRequest requestMessage = System.Web.HttpContext.Current.Request;
string format = requestMessage.QueryString["format"];
if (!string.IsNullOrEmpty(format) && string.Compare(format, "json", true) == 0)
{
return jsonResponseDispatchMessageFormatter.SerializeReply(messageVersion, parameters, result);
}
//[UNRELATED CODE]
}
这是在System.ServiceModel.Dispatcher.MultiplexingDispatchMessageFormatter中出现的行(关键是"json", defaultContentTypes没有条目):
outgoingResponse.ContentType = this.defaultContentTypes[key];
我得到的例外是:
System.Collections.Generic.KeyNotFoundException occurred
Message=The given key was not present in the dictionary.
Source=mscorlib
StackTrace:
at System.ThrowHelper.ThrowKeyNotFoundException()
InnerException:
我有这个问题,并找出了如何解决它为我的情况与良好的ol' Reflector。原因是OutgoingResponse的ContentType为空。在对jsonResponseDispatchMessageFormatter调用"SerializeReply"之前立即添加以下代码可能会奏效:
WebOperationContext.Current.OutgoingResponse.ContentType = "application/json";
接受的答案有效。但是,如果您希望端点支持XML和JSON(取决于配置的属性),则下面的代码对这两种场景都更健壮。
/// <summary>
/// Try to set the content type as close to the user's preference as we can get.
/// </summary>
private void SetContentType()
{
if (WebOperationContext.Current == null)
{
throw new InvalidOperationException("There is no WebOperationContext. This class expects to operate within a WCF context.");
}
WebMessageFormat contentType = WebMessageFormat.Json;
//first let's grab the default, if possible
if (_serviceEndpoint.EndpointBehaviors.Contains(typeof (WebHttpBehavior)))
{
var behavior = (WebHttpBehavior)_serviceEndpoint.EndpointBehaviors[typeof (WebHttpBehavior)];
contentType = behavior.DefaultOutgoingResponseFormat;
}
else if (_serviceEndpoint.EndpointBehaviors.Contains(typeof(WebHttpByteResponseBehavior)))
{
var behavior = (WebHttpByteResponseBehavior)_serviceEndpoint.EndpointBehaviors[typeof(WebHttpByteResponseBehavior)];
contentType = behavior.DefaultOutgoingResponseFormat;
}
//then let's see if an explicit override is available
if (_operationDescription.OperationBehaviors.Contains(typeof (WebInvokeAttribute)))
{
var behavior = (WebInvokeAttribute)_operationDescription.OperationBehaviors[typeof(WebInvokeAttribute)];
if (behavior.IsResponseFormatSetExplicitly)
{
contentType = behavior.ResponseFormat;
}
}
else if (_operationDescription.OperationBehaviors.Contains(typeof(WebGetAttribute)))
{
var behavior = (WebGetAttribute)_operationDescription.OperationBehaviors[typeof(WebGetAttribute)];
if (behavior.IsResponseFormatSetExplicitly)
{
contentType = behavior.ResponseFormat;
}
}
//finally set the content type based on whatever we found
WebOperationContext.Current.OutgoingResponse.ContentType = MapToStringContentType(contentType);
}
/// <summary>
/// Maps from a WebMessageFormat to a valid Content-Type header value.
/// </summary>
/// <param name="contentType"></param>
/// <returns></returns>
private string MapToStringContentType(WebMessageFormat contentType)
{
switch (contentType)
{
case WebMessageFormat.Xml:
return TEXT_XML;
break;
case WebMessageFormat.Json:
return APPLICATION_JSON;
break;
default:
return APPLICATION_JSON;
break;
}
}
那么,请确保在呼叫SerializeReply(...)
之前先呼叫SetContentType()
。这主要适用于在调用内置WCF格式化程序的情况下,有时调用自己的格式化程序,否则调用内置WCF格式化程序。