open311プロトコルでは、次の形式のエンドポイントをサポートする必要があります。
- domain / requests.xml
- domain / requests.json
最初のエンドポイントはxmlリクエストを受け入れ、2番目のエンドポイントは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
}