tags:

views:

290

answers:

1

I will first show the code that works in a non-ssl (http) environment. This code uses a custom json error handler, and all errors thrown, do get bubbled up to the client javascript (ajax).

        // Create webservice endpoint
        WebHttpBinding binding = new WebHttpBinding();

        ServiceEndpoint serviceEndPoint = new ServiceEndpoint(ContractDescription.GetContract(Type.GetType(svcHost.serviceContract + ", " + svcHost.assemblyName)), binding, new EndpointAddress(svcHost.hostUrl));

        // Add exception handler
        serviceEndPoint.Behaviors.Add(new FaultingWebHttpBehavior());

        // Create host and add webservice endpoint
        WebServiceHost webServiceHost = new WebServiceHost(svcHost.obj, new Uri(svcHost.hostUrl));
        webServiceHost.Description.Endpoints.Add(serviceEndPoint);

        webServiceHost.Open();

I'll also show you what the FaultingWebHttpBehavior class looks like:

public class FaultingWebHttpBehavior : WebHttpBehavior
{
    public FaultingWebHttpBehavior()
    {         
    }

    protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new ErrorHandler());
    }

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

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            // Build an object to return a json serialized exception
            GeneralFault generalFault = new GeneralFault();
            generalFault.BaseType = "Exception";
            generalFault.Type = error.GetType().ToString();
            generalFault.Message = error.Message;                

            // Create the fault object to return to the client
            fault = Message.CreateMessage(version, "", generalFault, new DataContractJsonSerializer(typeof(GeneralFault)));
            WebBodyFormatMessageProperty wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);
            fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);

        }
    }
}

[DataContract]
public class GeneralFault
{
    [DataMember]
    public string BaseType;

    [DataMember]
    public string Type;

    [DataMember]
    public string Message;
}

The AddServerErrorHandlers() method gets called automatically, once webServiceHost.Open() gets called. This sets up the custom json error handler, and life is good :-)

The problem comes, when we switch to and SSL (https) environment. I'll now show you endpoint creation code for SSL:

        // Create webservice endpoint
        WebHttpBinding binding = new WebHttpBinding();
        ServiceEndpoint serviceEndPoint = new ServiceEndpoint(ContractDescription.GetContract(Type.GetType(svcHost.serviceContract + ", " + svcHost.assemblyName)), binding, new EndpointAddress(svcHost.hostUrl));

        // This exception handler code below (FaultingWebHttpBehavior) doesn't work with SSL communication for some reason, need to resarch...
        // Add exception handler
        serviceEndPoint.Behaviors.Add(new FaultingWebHttpBehavior());

        //Add Https Endpoint
        WebServiceHost webServiceHost = new WebServiceHost(svcHost.obj, new Uri(svcHost.hostUrl));
        binding.Security.Mode = WebHttpSecurityMode.Transport;
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
        webServiceHost.AddServiceEndpoint(svcHost.serviceContract, binding, string.Empty);

Now, with this SSL endpoint code, the service starts up correctly, and wcf hosted objects can be communicated with just fine via client javascript. However, the custom error handler doesn't work. The reason is, the AddServerErrorHandlers() method never gets called when webServiceHost.Open() is run.

So, can anyone tell me what is wrong with this picture? And why, is AddServerErrorHandlers() not getting called automatically, like it does when I'm using non-ssl endpoints?

Thanks!

A: 

I will refer you to MSDN docs

If the Transport value is specified by the WebHttpBinding(WebHttpSecurityMode), then the settings provided by the Transport property become effective for the service endpoint. The value of WebHttpSecurityMode can only be set in the WebHttpBinding constructor that takes it as an explicit parameter and its value cannot be set again after the binding instance is created.

see : http://msdn.microsoft.com/en-us/library/bb348328.aspx

So you need to pass this value

binding.Security.Mode = WebHttpSecurityMode.Transport;

into your .ctor() like that

WebHttpBinding binding = new WebHttpBinding(WebHttpSecurityMode.Transport);

I have never used this before as I always declare my bindings into web.config file but according to MSDN, this is what you should do.

Developer IT
Well, I will say that is a good find on your part. The bad news is, it still doesn't work. The service behaves exactly the same. It starts up correcty, but the AddServerErrorHandlers() is never called, therefore the errors are never handled...
bpatrick100
Du you debug usign Casini or IIS ? Remember that Casini is not the same as IIS (ex. It is not multi-threaded)
Developer IT
Neither are in the picture here. The AddServerErrorHandlers() method in FaultingWebHttpBehavior() should be called automatically upon the service starting during the call to webServiceHost.Open() (This is exactly what happens with non-SSL (http) endpoints, and it works perfectly. So, to test, I simply start the service with a breakpoint in AddServerErrorHandlers() - it is hit with http endpoints, and not hit with https endpoints...
bpatrick100