在WCF Rest Service中处理404
本文关键字:处理 Service WCF Rest | 更新日期: 2023-09-27 17:59:22
我在IIS 7.5上有一个wcf rest服务。当有人访问端点不存在的部分时(即。http://localhost/rest.svc/DOESNOTEXISTvshttp://localhost/EXISTS)则向它们呈现具有状态代码404的通用WCF灰色和蓝色错误页面。然而,我想返回如下内容:
<service-response>
<error>The url requested does not exist</error>
</service-response>
我尝试在IIS中配置自定义错误,但只有在请求rest服务之外的页面(即。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 />
到我的默认端点行为。
谢谢,
Jeffrey Kevin Pry
首先,创建一个自定义行为,该行为子类化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;
}
}
}
正如您在上面看到的,我们正在添加一个新的行为:WcfUnknownRiBehavior。这种新的风俗行为的灵魂职责是取代未知的破坏者。下面是实现:
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"可以序列化,它的序列化表示就会被发送回客户端。