2011-06-16 147 views
5

處理404我有IIS 7.5 WCF休息服務。當用戶訪問不存在(即http://localhost/rest.svc/DOESNOTEXIST VS http://localhost/EXISTS),他們都帶有一個通用WCF灰色和藍色的錯誤頁面的狀態代碼:404。然而端點的一部分,我想回類似以下內容:在WCF REST服務

<service-response> 
    <error>The url requested does not exist</error> 
</service-response> 

我嘗試在IIS中配置自定義錯誤,但只有在請求其餘服務之外的頁面(例如http://localhost/DOESNOTEXIST)時才能工作。

有誰知道如何做到這一點?

編輯 後低於我的答案是能找出我需要創建一個實現BehaviorExtensionElement一個WebHttpExceptionBehaviorElement類。

public class WebHttpExceptionBehaviorElement : BehaviorExtensionElement 
{ 
    /// 
    /// Get the type of behavior to attach to the endpoint 
    /// 
    public override Type BehaviorType 
    { 
     get 
     { 
      return typeof(WebHttpExceptionBehavior); 
     } 
    } 

    /// 
    /// Create the custom behavior 
    /// 
    protected override object CreateBehavior() 
    { 
     return new WebHttpExceptionBehavior(); 
    } 
} 

當時我能夠通過引用它在我的web.config文件:

<extensions> 
    <behaviorExtensions> 
    <add name="customError" type="Service.WebHttpExceptionBehaviorElement, Service"/> 
    </behaviorExtensions> 
</extensions> 

,然後加入

<customError /> 

到我的默認端點的行爲。

感謝,

傑弗裏·凱文撬

+0

您是否使用REST入門套件或WCF Web API?調用部分中的 – 2011-06-16 12:34:52

回答

5

首先,創建該子類WebHttpBehavior一個自定義的行爲 - 在這裏你會刪除默認的未處理的調度操作的處理程序,並附上自己:

public class WebHttpBehaviorEx : WebHttpBehavior 
{ 
    public override void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
    { 
     base.ApplyDispatchBehavior(endpoint, endpointDispatcher); 

     endpointDispatcher.DispatchRuntime.Operations.Remove(endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation); 
     endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation = new DispatchOperation(endpointDispatcher.DispatchRuntime, "*", "*", "*"); 
     endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation.DeserializeRequest = false; 
     endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation.SerializeReply = false; 
     endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation.Invoker = new UnknownOperationInvoker(); 

    } 
} 

然後。讓你未知的操作處理程序。這個類將處理未知的操作請求並生成一個「消息」,這是響應。我已經展示瞭如何創建一個純文本消息。修改它爲您的目的應該是相當直接:

internal class UnknownOperationInvoker : IOperationInvoker 
{ 
    public object[] AllocateInputs() 
    { 
     return new object[1]; 
    } 


    private Message CreateTextMessage(string message) 
    { 
     Message result = Message.CreateMessage(MessageVersion.None, null, new HelpPageGenerator.TextBodyWriter(message)); 
     result.Properties["WebBodyFormatMessageProperty"] = new WebBodyFormatMessageProperty(WebContentFormat.Raw); 
     WebOperationContext.Current.OutgoingResponse.ContentType = "text/html"; 
     return result; 
    } 

    public object Invoke(object instance, object[] inputs, out object[] outputs) 
    { 
     // Code HERE 

       StringBuilder builder = new System.Text.StringBuilder(); 

       builder.Append("..."); 

       Message result = CreateTextMessage(builder.ToString()); 

       return result; 
    } 

    public System.IAsyncResult InvokeBegin(object instance, object[] inputs, System.AsyncCallback callback, object state) 
    { 
     throw new System.NotImplementedException(); 
    } 

    public object InvokeEnd(object instance, out object[] outputs, System.IAsyncResult result) 
    { 
     throw new System.NotImplementedException(); 
    } 

    public bool IsSynchronous 
    { 
     get { return true; } 
    } 
} 

在這一點上,你必須與你的服務的新的行爲聯繫起來。

有幾種方法可以做到這一點,所以如果你不知道的就問,我會高興地進一步闡述。

+1

我將什麼分配給輸入和輸出? – 2011-06-16 13:01:52

+0

另外,我在哪裏關聯配置中的網絡行爲?這就是我現在有... ... <行爲NAME = 「網絡」> ... 感謝您的幫助! – 2011-06-16 13:04:30

+0

我會通過更多的細節更新答案:您的評論 - 但總之,請參閱我如何「返回結果」;在invoke方法中?它返回一種「消息」...這是你想要的。此鏈接:http://bit.ly/AwBaK介紹瞭如何使用Web配置來添加新的客戶行爲。 – Steve 2011-06-16 14:04:43

1

我也有類似的問題,對方的回答確實引起了我的最終成功,這不是最清晰的答案。以下是我解決這個問題的方式。

我的項目設置是託管在IIS託管的SVC的WCF服務。我無法用於添加行爲的配置路線走,因爲我的程序集版本每籤變化,由於持續集成。

克服這個obsticle,我創建了一個自定義的ServiceHostFactory:

using System.ServiceModel; 
using System.ServiceModel.Activation; 

namespace your.namespace.here 
{ 
    public class CustomServiceHostFactory : WebServiceHostFactory 
    { 
     protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) 
     { 
      ServiceHost host = base.CreateServiceHost(serviceType, baseAddresses); 
      //note: these endpoints will not exist yet, if you are relying on the svc system to generate your endpoints for you 
      // calling host.AddDefaultEndpoints provides you the endpoints you need to add the behavior we need. 
      var endpoints = host.AddDefaultEndpoints(); 
      foreach (var endpoint in endpoints) 
      { 
       endpoint.Behaviors.Add(new WcfUnkownUriBehavior()); 
      } 

      return host; 
     } 
    } 
} 

正如你可以在上面看到,我們還添加了新的行爲:WcfUnknownUriBehavior。這種新的定製行爲的靈魂責任是取代UnknownDispatcher。下面是執行:

using System.ServiceModel.Dispatcher; 
using System.ServiceModel.Channels; 
using System.ServiceModel.Web; 
namespace your.namespace.here 
{ 
    public class UnknownUriDispatcher : IOperationInvoker 
    { 
     public object[] AllocateInputs() 
     { 
      //no inputs are really going to come in, 
      //but we want to provide an array anyways 
      return new object[1]; 
     } 

     public object Invoke(object instance, object[] inputs, out object[] outputs) 
     { 
      var responeObject = new YourResponseObject() 
      { 
       Message = "Invalid Uri", 
       Code = "Error", 
      }; 
      Message result = Message.CreateMessage(MessageVersion.None, null, responeObject); 
      WebOperationContext.Current.OutgoingResponse.ContentType = "text/html"; 
      outputs = new object[1]{responeObject}; 
      return result; 
     } 

     public System.IAsyncResult InvokeBegin(object instance, object[] inputs, System.AsyncCallback callback, object state) 
     { 
      throw new System.NotImplementedException(); 
     } 

     public object InvokeEnd(object instance, out object[] outputs, System.IAsyncResult result) 
     { 
      throw new System.NotImplementedException(); 
     } 

     public bool IsSynchronous 
     { 
      get { return true; } 
     } 
    } 
} 

一旦指定了這些對象,你現在可以使用新的工廠內的SVC的「標記」:

<%@ ServiceHost Language="C#" Debug="true" Service="your.service.namespace.here" CodeBehind="myservice.svc.cs" 
       Factory="your.namespace.here.CustomServiceHostFactory" %> 

這應該是它。只要你的對象「YourResponseObject」可以被序列化,它的序列化表示就會被髮送回客戶端。

+1

大聲笑...你從一年前發佈了我的答案的變體,然後下了我的答案?我覺得可以吧。 – Steve 2012-07-24 17:02:48

+0

哎呀。抱歉。並不意味着降低你的答案。我必須有脂肪指責它。我很抱歉。 – 2014-06-23 15:43:28