open311 协议需要支持以下格式的端点:
- 域/requests.xml
- 域/requests.json
第一个端点接受 xml 请求,第二个 json 请求。
协议进一步指定错误应该以请求格式(xml 或 json)返回。
在实现 ServiceBehaviorErrorHandler 时,我发现无法在 ProvideFault 方法中确定请求格式(xml 或 json)。所有示例都返回 json或xml。
如何确定请求格式,以便以相同格式返回错误消息?我的实现:
/// <summary>
/// From http://www.codeproject.com/Articles/43621/Extending-WCF-Part-I
/// </summary>
public class ExtendedServiceErrorHandler : IErrorHandler, IServiceBehavior
{
#region IErrorHandler Members
bool IErrorHandler.HandleError( Exception error )
{
return ( error is Open311Exception );
}
/*
* TODO: HTTP error codes are required, but the code in the response body shouldn't necessarily match the HTTP error code,
* so that more specific and unique error code identifiers can be used.
* The HTTP error codes should always be 404 for resources that don't exist,
* 403 for errors because of wrong or missing api_key and basically
* 400 for any other error where the request can not be fulfilled as expected.
* Multiple errors codes and descriptions can be returned in the body (the response is an array).
*/
void IErrorHandler.ProvideFault( Exception error, MessageVersion version, ref Message fault )
{
var ajaxErrors = new AjaxErrors();
var open311Error = error as Open311Exception;
if( null != open311Error )
{
ajaxErrors.Add( new AjaxError()
{
Code = open311Error.Code,
Message = open311Error.Message
} );
}
else
{
ajaxErrors.Add( new AjaxError()
{
Code = 400,
Message = error.Message
} );
}
var contentType = "application/json"; // TODO: how do we know?
// WebOperationContext.Current.IncomingRequest.ContentType doesn't work
WebContentFormat webContentFormat;
switch( contentType )
{
case "application/json":
fault = Message.CreateMessage( version, string.Empty, ajaxErrors, new DataContractJsonSerializer( ajaxErrors.GetType() ) );
webContentFormat = WebContentFormat.Json;
break;
case "application/xml":
fault = Message.CreateMessage( version, string.Empty, ajaxErrors, new DataContractSerializer( ajaxErrors.GetType() ) );
webContentFormat = WebContentFormat.Xml;
break;
default:
fault = Message.CreateMessage( version, string.Empty, ajaxErrors, new DataContractSerializer( ajaxErrors.GetType() ) );
webContentFormat = WebContentFormat.Raw;
break;
}
var wbf = new WebBodyFormatMessageProperty( webContentFormat );
fault.Properties.Add( WebBodyFormatMessageProperty.Name, wbf );
WebOperationContext.Current.OutgoingResponse.ContentType = contentType;
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.OK; // HttpStatusCode.BadRequest;
}
#endregion
#region IServiceBehavior Members
void IServiceBehavior.AddBindingParameters( ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters )
{
// nothing to do?
}
void IServiceBehavior.ApplyDispatchBehavior( ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase )
{
var errorHandler = new ExtendedServiceErrorHandler();
foreach( ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers )
{
channelDispatcher.ErrorHandlers.Add( errorHandler );
}
}
void IServiceBehavior.Validate( ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase )
{
// nothing to do?
}
#endregion
}