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) // 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( 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(delegate(WebErrorHandlerConfigurationAttribute x) // { // return x.BaseBehavior; // }); // } // private static string GenerateResponseText(string message) // { // return string.Format("{0}", 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 = ""; format += ""; format += " {0}"; format += " {1}"; format += ""; string errorMsg = string.Format(format, statusCode, msg); return errorMsg; } } }