P
Peter Bradley
Hi,
I hope this is the correct group in which to raise this question. If
not, please just point me to where I should go.
I'm developing some in-house standards for WCF projects, but have a
problem with the Windows Service hosted WCF service that I'm building as
an example project. It's a version of the well-known Calculator Service
much loved as an example by all and sundry.
Everything works fine except that when a fault is thrown, only the
default message makes it to the client side, "The creator of this fault
did not specify a Reason", even though the fault most definitely does
have a message contained within it. Here's some details:
The fault is declared as a DataContract with a single DataMember on the
server side like this:
namespace Peter.Calculator.Service
{
[DataContract]
public class CalculatorFault
{
public CalculatorFault(string msg)
{
FaultMessage = msg;
}
[DataMember]
public string FaultMessage { get; set; }
}
}
The Service Contract uses the fault like this:
namespace Peter.Calculator.Service
{
[ServiceContract]
public interface ICalculatorService
{
[OperationContract]
CalculationHolder Add(CalculationHolder calculation);
[OperationContract]
CalculationHolder Subtract(CalculationHolder calculation);
[OperationContract]
CalculationHolder Multiply(CalculationHolder calculation);
[OperationContract]
[FaultContract(typeof(CalculatorFault))]
CalculationHolder Divide(CalculationHolder calculation);
}
}
In the implementation of the contract, the fault is thrown as follows:
namespace Peter.Calculator.Service
{
public class CalculatorService : ICalculatorService
{
// Other methods that don't throw the fault ...
public CalculationHolder Divide(CalculationHolder holder)
{
CalculationHolder result = new CalculationHolder();
if ((int)holder.RightHandSide != 0)
{
result.LeftHandSide = holder.LeftHandSide;
result.RightHandSide = holder.RightHandSide;
result.Result = holder.LeftHandSide / holder.RightHandSide;
}
else
throw new FaultException<CalculatorFault>(new
CalculatorFault("Divide by zero error"));
return result;
}
}
}
The important line, obviously, is:
throw new FaultException<CalculatorFault>(new CalculatorFault("Divide by
zero error"));
On the client side, I'm catching the fault like this:
case "/":
try
{
holder = client.Divide(ConstructHolder());
resultTextBox.Text = holder.Result.ToString();
}
catch (FaultException<CalculatorFault> ex)
{
MessageBox.Show(ex.Message, "Calculator Fault", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
break;
}
I've tried looking at all the members in the CalculatorFault instance
(ex), but can't find anything useful. I've also looked at the
Calculator Service Reference in the object browser and can't see
anything helpful there either.
In the host's app.config file (located in the folder holding the Windows
Service host, I have:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the
config file must be added to the host's
app.config file. System.Configuration does not support config files
for libraries. -->
<system.serviceModel>
<services>
<service name="Peter.Calculator.Service.CalculatorService"
behaviorConfiguration="Peter.Calculator.Service.CalculatorServiceBehavior">
<host>
<baseAddresses>
<add baseAddress =
"http://localhost:8731/Peter.Calculator.Service/CalculatorService/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base
address supplied above -->
<endpoint address =""
binding="wsHttpBinding"
contract="Peter.Calculator.Service.ICalculatorService">
<!--
Upon deployment, the following identity element should be
removed or replaced to reflect the
identity under which the deployed service runs. If
removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to
describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be
secured or removed before deployment -->
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior
name="Peter.Calculator.Service.CalculatorServiceBehavior">
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint
above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging
purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
I have a feeling that I must be missing something blindingly obvious,
but I'm damned if I can fee what it is. So if anyone can put me out of
my misery, I'd be extremely grateful.
Best regards and thanks in advance
Peter
I hope this is the correct group in which to raise this question. If
not, please just point me to where I should go.
I'm developing some in-house standards for WCF projects, but have a
problem with the Windows Service hosted WCF service that I'm building as
an example project. It's a version of the well-known Calculator Service
much loved as an example by all and sundry.
Everything works fine except that when a fault is thrown, only the
default message makes it to the client side, "The creator of this fault
did not specify a Reason", even though the fault most definitely does
have a message contained within it. Here's some details:
The fault is declared as a DataContract with a single DataMember on the
server side like this:
namespace Peter.Calculator.Service
{
[DataContract]
public class CalculatorFault
{
public CalculatorFault(string msg)
{
FaultMessage = msg;
}
[DataMember]
public string FaultMessage { get; set; }
}
}
The Service Contract uses the fault like this:
namespace Peter.Calculator.Service
{
[ServiceContract]
public interface ICalculatorService
{
[OperationContract]
CalculationHolder Add(CalculationHolder calculation);
[OperationContract]
CalculationHolder Subtract(CalculationHolder calculation);
[OperationContract]
CalculationHolder Multiply(CalculationHolder calculation);
[OperationContract]
[FaultContract(typeof(CalculatorFault))]
CalculationHolder Divide(CalculationHolder calculation);
}
}
In the implementation of the contract, the fault is thrown as follows:
namespace Peter.Calculator.Service
{
public class CalculatorService : ICalculatorService
{
// Other methods that don't throw the fault ...
public CalculationHolder Divide(CalculationHolder holder)
{
CalculationHolder result = new CalculationHolder();
if ((int)holder.RightHandSide != 0)
{
result.LeftHandSide = holder.LeftHandSide;
result.RightHandSide = holder.RightHandSide;
result.Result = holder.LeftHandSide / holder.RightHandSide;
}
else
throw new FaultException<CalculatorFault>(new
CalculatorFault("Divide by zero error"));
return result;
}
}
}
The important line, obviously, is:
throw new FaultException<CalculatorFault>(new CalculatorFault("Divide by
zero error"));
On the client side, I'm catching the fault like this:
case "/":
try
{
holder = client.Divide(ConstructHolder());
resultTextBox.Text = holder.Result.ToString();
}
catch (FaultException<CalculatorFault> ex)
{
MessageBox.Show(ex.Message, "Calculator Fault", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
break;
}
I've tried looking at all the members in the CalculatorFault instance
(ex), but can't find anything useful. I've also looked at the
Calculator Service Reference in the object browser and can't see
anything helpful there either.
In the host's app.config file (located in the folder holding the Windows
Service host, I have:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the
config file must be added to the host's
app.config file. System.Configuration does not support config files
for libraries. -->
<system.serviceModel>
<services>
<service name="Peter.Calculator.Service.CalculatorService"
behaviorConfiguration="Peter.Calculator.Service.CalculatorServiceBehavior">
<host>
<baseAddresses>
<add baseAddress =
"http://localhost:8731/Peter.Calculator.Service/CalculatorService/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base
address supplied above -->
<endpoint address =""
binding="wsHttpBinding"
contract="Peter.Calculator.Service.ICalculatorService">
<!--
Upon deployment, the following identity element should be
removed or replaced to reflect the
identity under which the deployed service runs. If
removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to
describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be
secured or removed before deployment -->
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior
name="Peter.Calculator.Service.CalculatorServiceBehavior">
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint
above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging
purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
I have a feeling that I must be missing something blindingly obvious,
but I'm damned if I can fee what it is. So if anyone can put me out of
my misery, I'd be extremely grateful.
Best regards and thanks in advance
Peter