210 lines
9.1 KiB
C#
210 lines
9.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Runtime.Serialization;
|
|
using System.ServiceModel;
|
|
using System.ServiceModel.Channels;
|
|
using System.ServiceModel.Dispatcher;
|
|
using System.ServiceModel.Web;
|
|
using System.Text;
|
|
using WcfRestContrib.ServiceModel.Channels;
|
|
using WcfRestContrib.ServiceModel.Description;
|
|
using WcfRestContrib.ServiceModel.Dispatcher;
|
|
using WcfRestContrib.ServiceModel.Web;
|
|
using WebException = WcfRestContrib.ServiceModel.Web.Exceptions.WebException;
|
|
|
|
namespace Taloyhtio.GeneralApi.WcfService
|
|
{
|
|
// Custom error handler shows error message instead of generic Internal Server Error.
|
|
// NOTE: this error handler doesn't help when exception occurs in http module (e.g. UnitOfWork).
|
|
// In this case generic Internal Server Error is shown
|
|
public class CustomWebHttpErrorHandler : IErrorHandler
|
|
{
|
|
// [DataContract(Name = "Error", Namespace = "")]
|
|
// private class WebExceptionContract : IWebExceptionDataContract
|
|
// {
|
|
// public void Init(WebException exception)
|
|
// {
|
|
// this.Message = exception.Message;
|
|
// this.Status = (int)exception.Status;
|
|
// }
|
|
//
|
|
// Properties
|
|
// [DataMember(Name = "Message")]
|
|
// public string Message { get; set; }
|
|
// [DataMember(Name = "Status")]
|
|
// public int Status { get; set; }
|
|
// }
|
|
|
|
bool IErrorHandler.HandleError(Exception error)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Wraps all exceptions thrown in the service in common wrapper (FaultException<CustomFaultException>)
|
|
// so clients will be able to get exception details
|
|
/*void IErrorHandler.ProvideFault(Exception error, MessageVersion version, ref Message fault)
|
|
{
|
|
string errorMsg = error != null ? error.Message : "";
|
|
|
|
var faultException = new FaultException<CustomFaultException>(
|
|
new CustomFaultException{Reason = errorMsg});
|
|
|
|
var msgFault = faultException.CreateMessageFault();
|
|
|
|
fault = Message.CreateMessage(version, msgFault, faultException.Action);
|
|
|
|
var statusCode = HttpStatusCode.InternalServerError;
|
|
if (error is WebException)
|
|
{
|
|
statusCode = ((WebException)error).Status;
|
|
}
|
|
var rmp = new HttpResponseMessageProperty {StatusCode = statusCode};
|
|
fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);
|
|
}*/
|
|
|
|
void IErrorHandler.ProvideFault(Exception error, MessageVersion version, ref Message fault)
|
|
{
|
|
var statusCode = HttpStatusCode.InternalServerError;
|
|
// 2011-06-12: although it is real REST to provide StatusCode, it is not easy to do
|
|
// with json endpoints because WebScriptEnablingBehavior is sealed and we can't do the same
|
|
// thing for it. So for consistentcy I disabled it for pox as well
|
|
// if (error is WebException)
|
|
// {
|
|
// statusCode = ((WebException) error).Status;
|
|
// }
|
|
|
|
string errorMsg = error != null ? error.Message : "";
|
|
|
|
//string body = ErrorBodyWriter.GetBody(statusCode, error.Message);
|
|
fault = Message.CreateMessage(version, null,
|
|
new ErrorBodyWriter {Code = statusCode, Message = errorMsg});
|
|
|
|
var rmp = new HttpResponseMessageProperty();
|
|
|
|
rmp.StatusCode = statusCode;
|
|
|
|
// 2011-06-12: if we use custom status description it will causes "protocol violation" error
|
|
// use body as description. On client side WCF will use this property for exception.Message
|
|
//rmp.StatusDescription = string.Format("{0}: {1}", statusCode, error.Message);
|
|
|
|
// convert error msg to base64 and store it in custom header. Client will read it via custom message inspector
|
|
if (!string.IsNullOrEmpty(errorMsg))
|
|
{
|
|
rmp.Headers[Common.Constants.HttpHeaders.Error] = Convert.ToBase64String(Encoding.UTF8.GetBytes(errorMsg));
|
|
}
|
|
fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);
|
|
}
|
|
|
|
/*void IErrorHandler.ProvideFault(Exception error, MessageVersion version, ref System.ServiceModel.Channels.Message fault)
|
|
{
|
|
WebException webException;
|
|
WebErrorHandlerConfigurationBehavior behavior;
|
|
if (error != null)
|
|
{
|
|
if (error is WebException)
|
|
{
|
|
webException = (WebException) error;
|
|
}
|
|
else
|
|
{
|
|
// string unhandledErrorMessage;
|
|
// behavior = GetWebErrorHandlerConfiguration();
|
|
// if (behavior.ReturnRawException)
|
|
// {
|
|
// unhandledErrorMessage = error.ToString();
|
|
// }
|
|
// else
|
|
// {
|
|
// unhandledErrorMessage = ((behavior != null) && (behavior.UnhandledErrorMessage != null)) ? behavior.UnhandledErrorMessage : "An error has occured processing your request.";
|
|
// }
|
|
webException = new WebException(error, HttpStatusCode.InternalServerError, error.Message,
|
|
new object[0]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
webException = new WebException(HttpStatusCode.InternalServerError, "An error has occured processing request.");
|
|
}
|
|
webException.UpdateHeaders(WebOperationContext.Current.OutgoingResponse.Headers);
|
|
WebOperationContext.Current.OutgoingResponse.StatusCode = webException.Status;
|
|
WebOperationContext.Current.OutgoingResponse.StatusDescription = webException.Status.ToString();
|
|
WebDispatchFormatter webDispatchFormatter = null;
|
|
if (OperationContext.Current.OutgoingMessageProperties.ContainsKey("WebDispatcherFormatter"))
|
|
{
|
|
webDispatchFormatter = OperationContext.Current.OutgoingMessageProperties["WebDispatcherFormatter"] as WebDispatchFormatter;
|
|
}
|
|
if (webDispatchFormatter != null)
|
|
{
|
|
IWebExceptionDataContract exceptionContract = new WebExceptionContract();
|
|
// behavior = GetWebErrorHandlerConfiguration();
|
|
// if ((behavior != null) && behavior.HasExceptionDataContract)
|
|
// {
|
|
// exceptionContract = behavior.CreateExceptionDataContract();
|
|
// }
|
|
// else
|
|
// {
|
|
// exceptionContract = new WebExceptionContract();
|
|
// }
|
|
exceptionContract.Init(webException);
|
|
fault = webDispatchFormatter.Serialize(exceptionContract, typeof(WebExceptionContract), WebOperationContext.Current.IncomingRequest.GetAcceptTypes());
|
|
}
|
|
else
|
|
{
|
|
WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
|
|
fault = Message.CreateMessage(MessageVersion.None, (string)null, (BodyWriter)new BinaryBodyWriter(GenerateResponseText(webException.Message)));
|
|
fault.SetWebContentFormatProperty(WebContentFormat.Raw);
|
|
}
|
|
fault.UpdateHttpProperty();
|
|
|
|
}*/
|
|
|
|
// private static WebErrorHandlerConfigurationBehavior GetWebErrorHandlerConfiguration()
|
|
// {
|
|
// return OperationContext.Current.Host.Description.FindBehavior<WebErrorHandlerConfigurationBehavior, WebErrorHandlerConfigurationAttribute>(delegate(WebErrorHandlerConfigurationAttribute x)
|
|
// {
|
|
// return x.BaseBehavior;
|
|
// });
|
|
// }
|
|
|
|
// private static string GenerateResponseText(string message)
|
|
// {
|
|
// return string.Format("<html><body style=\"font-family:Arial;font-size:11pt;\">{0}</body></html>", message);
|
|
// }
|
|
}
|
|
|
|
|
|
|
|
internal class ErrorBodyWriter : BodyWriter
|
|
{
|
|
public HttpStatusCode Code { get; set; }
|
|
public string Message { get; set; }
|
|
|
|
public ErrorBodyWriter()
|
|
: base(true)
|
|
{
|
|
}
|
|
|
|
protected override void OnWriteBodyContents(System.Xml.XmlDictionaryWriter writer)
|
|
{
|
|
string errorMsg = GetBody(Code, Message);
|
|
System.Xml.Linq.XElement xElement = System.Xml.Linq.XElement.Load(new System.IO.StringReader(errorMsg));
|
|
|
|
xElement.WriteTo(writer);
|
|
}
|
|
|
|
public static string GetBody(HttpStatusCode statusCode, string msg)
|
|
{
|
|
string format = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
|
|
format += "<error>";
|
|
format += " <code>{0}</code>";
|
|
format += " <msg>{1}</msg>";
|
|
format += "</error>";
|
|
|
|
string errorMsg = string.Format(format, statusCode, msg);
|
|
return errorMsg;
|
|
}
|
|
}
|
|
}
|