Custom WebServiceHost的自定义错误处理消息

时间:2010-10-01 00:02:14

标签: .net wcf rest

我有一个自定义WCF服务主机(webServicehost2)和Factory正在执行一些依赖注入(实现自定义IInstanceProvider)以及一些自定义身份验证(强制自定义RequestInterceptor

我遇到一个非常小的问题,当我导航到一个不存在的REST资源时。 例如

http://localhost/restservice.svc/
http://localhost/restservice.svc/blah/

我得到404 Error,确定无疑。

我想知道的是,无论如何我可以捕获返回的Http错误并将其格式化得更好。

2 个答案:

答案 0 :(得分:3)

我不确定是否有更简单的方法,但我在这里进行了一些快速原型设计,并发现实现此目的的一种方法是添加一个自定义IDispatchMessageInspector实现,该实现查看服务的响应消息并替换内容使用您自己的自定义HTML页面。

它基本上是这样的:

  • 实施IDispatchMessageInspector.BeforeSendReply()
  • 查看回复消息,并获取httpResponse属性,并根据StatusCode属性检查是否为错误。
  • 如果是错误,请创建一个全新的WCF消息,并将正文设置为您要投放的HTML内容。
  • 再次将httpResponse和webBodyFormatMessageProperty属性添加到新邮件中,并将其设置为回复。

我的样本成功完成了这个,但它很难看;在发布之前我需要稍微清理一下。

答案 1 :(得分:1)

以下是其他任何尝试此操作的代码snipets

首先是IDispatchMessageInspector

的一个实例
 public class CustomResponseFormatterMessageInspector : IDispatchMessageInspector
    {
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            return null;
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
            var prop = (HttpResponseMessageProperty)reply.Properties[HttpResponseMessageProperty.Name];
            if (prop.StatusCode == HttpStatusCode.NotFound)
            {
                ErrorResponse(ref reply);
            }
        }

        private void ErrorResponse(ref Message original)
        {
            const string ERROR_HTML = @"<html><HEAD><TITLE>Request Error</TITLE></HEAD><BODY> <H1>My Error processing request {1}</H1><P>{0}</P></BODY></html>";

            XElement response = XElement.Load(new StringReader(string.Format(ERROR_HTML, "A Resource does not exsist at this location.", HttpStatusCode.NotFound)));
            Message reply = Message.CreateMessage(original.Version, null, response);
            reply.Headers.CopyHeadersFrom(original);
            reply.Properties.CopyProperties(original.Properties);
            original = reply;
        }
    }

然后将此注入我添加的IServiceBehaviour

ed.DispatchRuntime.MessageInspectors.Add(new CustomResponseFormatterMessageInspector());

此处可能还有其他与我的实施相关的代码,但这就是我添加的内容。

 public class DependencyInjectionServiceBehavior : IServiceBehavior
    {
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
            {
                var cd = cdb as ChannelDispatcher;
                if (cd != null)
                {
                    foreach (EndpointDispatcher ed in cd.Endpoints)
                    {
                        ed.DispatchRuntime.InstanceProvider =
                            new DependencyInjectionInstanceProvider(serviceDescription.ServiceType);
                        ed.DispatchRuntime.MessageInspectors.Add(new CustomResponseFormatterMessageInspector());
                    }
                }
            }
        }

        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
        }
    }