2011-06-16 14 views
5

Tengo un servicio de descanso wcf en IIS 7.5. Cuando alguien visita una parte del punto final que no existe (es decir, http://localhost/rest.svc/DOESNOTEXIST frente a http://localhost/EXISTS) se le presenta una página de error genérico WCF gris y azul con código de estado 404. Sin embargo, me gustaría devolver algo como lo siguiente:Manejo 404 en WCF Servicio de descanso

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

Intenté configurar los errores personalizados en IIS, pero solo funcionan si se solicita una página fuera del servicio de reposo (es decir, http://localhost/DOESNOTEXIST).

¿Alguien sabe cómo hacer esto?

Editar Después de la respuesta a continuación que era capaz de averiguar lo que necesitaba para crear una clase que implementa WebHttpExceptionBehaviorElement BehaviorExtensionElement.

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(); 
    } 
} 

Luego pude hacer referencia a ella en mi archivo web.config a través de:

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

Y a continuación, añadir

<customError /> 

a mis comportamientos de punto final predeterminado.

Gracias,

Jeffrey Kevin palanca

+0

¿Utiliza REST Starter kit o WCF Web API? –

Respuesta

5

En primer lugar, crear un comportamiento personalizado, que subclases WebHttpBehavior - aquí podrá quitar el defecto manejador no controlada operación de despacho, y adjuntar su propia:

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(); 

    } 
} 

Entonces. crea tu manejador de operaciones desconocido Esta clase manejará la solicitud de operación desconocida y generará un "Mensaje" que es la respuesta. He mostrado cómo crear un mensaje de texto sin formato. Modificándolo para sus propósitos debe ser bastante sencilla:

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; } 
    } 
} 

En este punto hay que asociar el nuevo comportamiento con su servicio.

Hay varias formas de hacerlo, así que solo pregúntale si aún no lo sabes, y estaré feliz de seguir explicando.

+1

en la sección Invocar, ¿qué asigno a las entradas y salidas? –

+0

¿También dónde asocio el comportamiento web en la configuración? esto es lo que tengo ahora ... ... ... Gracias por su ayuda! –

+0

Actualizaré la respuesta con más detalles sobre sus comentarios, pero, en resumen, veré cómo "devuelvo el resultado"; en el método de invocación? Devuelve un tipo de "Mensaje" ... esto es lo que quieres. Este enlace: http://bit.ly/AwBaK tiene una descripción del uso de la configuración web para agregar el comportamiento de su nuevo cliente. – Steve

1

Tuve un problema similar, y la otra respuesta me condujo a mi éxito final, no fue la más clara de las respuestas. Debajo está la manera que resolví este problema.

La configuración de mis proyectos es un servicio WCF alojado como un servidor hospedado en IIS. No pude ir con la ruta de configuración para agregar el comportamiento, porque mis versiones de ensamblaje cambian cada checkin debido a la integración continua.

para superar este obsticle, creé una ServiceHostFactory personalizado:

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; 
     } 
    } 
} 

Como se puede ver arriba, estamos añadiendo un nuevo comportamiento: WcfUnknownUriBehavior. El deber del alma de este nuevo comportamiento personalizado es reemplazar el DesconocidoDispatcher.La siguiente es la aplicación:

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; } 
     } 
    } 
} 

Una vez que haya especificado estos objetos, ahora se puede utilizar la nueva fábrica dentro del SVC "markup":

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

y que debe ser la misma. siempre que su objeto "YourResponseObject" se pueda serializar, se enviará una representación serializada al cliente.

+1

LOL ... publicaste una variación de mi respuesta de hace un año y votaste mi respuesta? OK, eso creo. – Steve

+0

Whoops. lo siento. no significó rechazar tu respuesta. Debo haberlo tocado con la grasa. mis disculpas. –