[英]Handling 404 in WCF Rest Service
我在IIS 7.5上有一個wcf rest服務。 當某人訪問不存在的端點的一部分時(即http://localhost/rest.svc/DOESNOTEXIST與http:// localhost / EXISTS ),他們將看到帶有狀態碼的通用WCF灰色和藍色錯誤頁面404.但是,我想返回如下內容:
<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 />
我的默認端點行為。
謝謝,
傑弗里·凱文·普瑞
首先,創建一個自定義行為,該行為將WebHttpBehavior子類化-在這里,您將刪除默認的Unhandled Dispatch Operation處理程序,並附加您自己的行為:
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();
}
}
然后。 使您的未知操作處理程序。 此類將處理未知的操作請求並生成“ Message”作為響應。 我已經展示了如何創建純文本消息。 為您的目的對其進行修改應該很簡單:
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; }
}
}
此時,您必須將新行為與您的服務相關聯。
有幾種方法可以做到這一點,所以只要問一下您是否還不知道,我會很樂意進一步闡述。
我遇到了類似的問題,其他答案的確使我最終取得了成功,但這並不是最清晰的答案。 以下是我解決此問題的方法。
我的項目設置是作為IIS中托管的svc托管的WCF服務。 我無法采用添加行為的配置路線,因為由於持續集成,我的程序集版本會更改每個簽入。
為了克服這個困難,我創建了一個自定義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”可以序列化,它的序列化表示就將被發送回客戶端。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.