使用.NET 3.5在IIS 7.5中的RESTful WCF服务中进行错误处理

时间:2012-02-14 14:37:45

标签: c# .net wcf iis

我有一个REST WCF Web服务(.NET 3.5,不使用REST Starter Kit)我想为它创建一个自定义错误处理程序。它通过IIS 7.5在Web应用程序中作为.svc文件运行。 编辑:可能也值得一提;它正在通过HTTPS运行。

.svc.cs文件中的主要服务类:

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service
{
    [WebGet(UriTemplate = "/units/{id}", ResponseFormat = WebMessageFormat.Json,
        RequestFormat = WebMessageFormat.Json), OperationContract]
    public Unit GetUnit(string id) {
        ...
    }
    ...
}

的web.config:

<?xml version="1.0"?>
<configuration>
    <system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
        <services>
            <service name="WebReservationService.Service">
                <endpoint address="" binding="webHttpBinding" contract="WebReservationService.Service"/>
            </service>
        </services>
    </system.serviceModel>
    <connectionStrings configSource="WebSettingsConnectionStrings.config"/>
    <system.web>
        <compilation debug="true"/>
    </system.web>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true">
            <add name="AuthModule" type="WebReservationService.AuthModule"/>
        </modules>
    </system.webServer>
    <appSettings configSource="WebClientAuthentication.config"/>
</configuration>

我尝试创建一个IErrorHandler类,并尝试通过web.config使用它,但无法触发它。还尝试通过IHttpModule错误处理程序捕获错误,但这也不会触发。目前我在每个WebGet / WebInvoke中手动捕获错误,但是没有捕获序列化错误或未处理的URI等,更不用说它为代码添加了不必要的混乱。

我知道有一些显而易见的东西我不见了,但我遇到的答案似乎不适用于我的配置。有什么建议吗?

感谢。

修改 刚尝试使用自定义WebServiceHostFactory来应用自定义WebHttpBehavior。工厂和行为都运行并且错误处理程序正在创建 - HandleError和ProvideFault永远不会被调用:

public class ServiceFactory : WebServiceHostFactory
{
    public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
    {
        ServiceHost host = CreateServiceHost(typeof(Service), baseAddresses);
        host.Description.Endpoints[0].Behaviors.Add(new ServiceBehavior());
        return host;
    }

    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return base.CreateServiceHost(serviceType, baseAddresses);
    }
}

public class ServiceBehavior : WebHttpBehavior
{
    protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new ServiceErrorHandler());
    }
}

public class ServiceErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        return true;
    }

    public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
    {
        throw new NotImplementedException();
    }
}

1 个答案:

答案 0 :(得分:0)

解决了它。我需要创建一个自定义ServiceHost并在该ServiceHost的OnOpening方法中添加错误处理程序。还必须从我的web.config中取出服务。

public class ServiceFactory : WebServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        ServiceHost host = new RestServiceHost(typeof(Service), baseAddresses);
        host.AddServiceEndpoint(serviceType, new WebHttpBinding(), baseAddresses[0]);
        return host;
    }
}

public class RestServiceHost : WebServiceHost
{
    public RestServiceHost() : base() { }
    public RestServiceHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses) { }

    protected override void OnOpening()
    {
        base.OnOpening();

        foreach (var endpoint in base.Description.Endpoints)
        {
            if (endpoint.Behaviors.Find<ServiceBehavior>() == null)
            {
                endpoint.Behaviors.Add(new ServiceBehavior());
            }
        }
    }
}

public class ServiceBehavior : WebHttpBehavior
{
    protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new ServiceErrorHandler());
    }
}

public class ServiceErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        return true;
    }

    public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
    {
        Utils.HandleException(error, true);
    }
}