Felix D.
Felix D.

Reputation: 5093

WCF.ServiceChannel cannot communicate because of 'FaultedState' of Service

I am creating a selfhosted WCF Service.

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface IStateChecker
{
    [OperationContract]
    void SetState(string state);
}

This is my Service:

public class StateCheckerService : IStateChecker
{
    public void SetState(string state)
    {
        Console.WriteLine($"{DateTime.Now.ToString("dd.MM.yyyy HH:mm:sss")} : {state}");
    }
}

And this my Implementation:

//Define baseaddres:
Uri baseAddress = new Uri("http://localhost:8000/ServiceModelSamples/Service");

//create host:
ServiceHost selfHost = new ServiceHost(typeof(StateCheckerService), baseAddress);

try
{
     //Add endpoint to host:
     selfHost.AddServiceEndpoint(typeof(IStateChecker), new WSHttpBinding(), "StateCheckerService");

     //Add metadata exchange:
     ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
     smb.HttpGetEnabled = true;
     selfHost.Description.Behaviors.Add(smb);


     selfHost.Faulted += SelfHost_Faulted;

     //Start service
     selfHost.Open();

     Console.WriteLine("Starting Service...");
     if (selfHost.State == CommunicationState.Opened)
     {
         Console.WriteLine("The service is ready.");
     }

     Console.WriteLine("Press <ENTER> to terminate service.");
     Console.ReadLine();

     //Shutdown service
     selfHost.Close();
}
catch (CommunicationException ce)
{
    Console.WriteLine("An exception occurred: {0}", ce.Message);
    selfHost.Abort();
}

private static void SelfHost_Faulted(object sender, EventArgs e)
{
    ServiceHost host = sender as ServiceHost;
    Console.WriteLine(host?.State);
    Console.WriteLine(e?.ToString());

    host?.Open();
}

Now when it comes to the client I get an error.

try
{
    //Works using the ServiceReference (wsdl ... created by VisualStudio):
    using (StateCheckerServiceReference.StateCheckerClient client = new StateCheckerClient())
    {
        client.SetState("Test");
    }

    //Does not work:
    EndpointAddress endpointAddress = new EndpointAddress("http://localhost:8000/ServiceModelSamples/Service");
    using (ChannelFactory<IStateCheckerChannel> factory = new ChannelFactory<IStateCheckerChannel>("WSHttpBinding_IStateChecker", endpointAddress))
    {
        using (IStateCheckerChannel channel = factory.CreateChannel(endpointAddress))
        {
            channel?.SetState("Test");
        }
    }
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

Exception:

The communication object, "System.ServiceModel.Channels.ServiceChannel",
cannot be used for communication because it is in the Faulted state.

I never enter SelfHost_Faulted nor are there any Exceptions on my Service

I am doing this because I want to change the Endpoint the client should connect to at runtime.

If I'm doin it wrong please tell me. Otherwise any hints on what is wrong with my code are highly appreciated.

Upvotes: 3

Views: 15187

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205629

The issue is quite trivial, but hidden by the WCF infrastructure (strange implementation of a standard pattern).

If you change

channel?.SetState("Test");

to

try
{
    channel?.SetState("Test");
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

you will see 2 messages:

There was no endpoint listening at http://localhost:8000/ServiceModelSamples/Service that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.

and

The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.

The first one is the real exception (of type EndpointNotFoundException) caught by the inner catch.

The second (misleading) exception is of type CommunicationObjectFaultedException and is thrown by channel.Dispose() (?!) called at the end of your using block, hence hides the original one. WCF implementation simply is not following the rule that Dispose() should not throw!

With that being said, the problem is in your client endpoint. According to the service configuration, it should be "baseAddress/StateCheckerService" while currently it's just "baseAddress". So simply use the correct endpoint address

var endpointAddress = new EndpointAddress(
    "http://localhost:8000/ServiceModelSamples/Service/StateCheckerService");

and the issue will be solved.

Upvotes: 8

Related Questions