WCF一步一步往前爬(三)

第三步:

在客户端捕获WCF服务异常。

如果是Debug过程,简单的方法就是在宿主项目ProductsServiceHost中的app.config文件中,设置<serviceDebug includeExceptionDetailInFaults="true"/>,或则直接在service

的实现类上添加ServiceBehavior特性,如下

[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
public class ProductsServiceImpl : IProductsService
{
......
}

但是对于Release后的部署的系统,为了增加健壮性。建议在Service端抛出SOAP Faults,客户端捕获。拿上一步的ProductsServiceLibrary项目为示例。

public List<string> ListProducts()
{
List<string> p;
try
{
p = ps.Select(item => item.ProductNumber).ToList();

int i = 0;
int j = 100 / i;
}
catch (Exception e)
{
// Edit the Initial Catalog in the connection string in app.config
// to trigger this exception
if (e.InnerException is System.DivideByZeroException)
{
throw new FaultException(
"Exception Divide By Zero: " +
e.InnerException.Message, new FaultCode("Divide"));
}
else
{
throw new FaultException(
"Exception reading product numbers: " +
e.Message, new FaultCode("Iterate through products"));
}
}

return p;
}

客户端:


try
{
// Obtain a list of all products
...
// Fetch the details for a specific product
...
// Query the stock level of this product
...
// Modify the stock level of this product
...
// Disconnect from the service
...
}
catch (FaultException e)
{
Console.WriteLine("{0}: {1}", e.Code.Name, e.Reason);
}


如何实现强类型的Faults呢?

namespace ProductsService
{
// Classes for passing fault information back to client applications
[DataContract]
public class SystemFault
{
[DataMember]
public string SystemOperation { get; set; }
[DataMember]
public string SystemReason { get; set; }
[DataMember]
public string SystemMessage { get; set; }
}
[DataContract]
public class DatabaseFault
{
[DataMember]
public string DbOperation { get; set; }
[DataMember]
public string DbReason { get; set; }
[DataMember]
public string DbMessage { get; set; }
}
// Data contract describing the details of a product
....
// Service contract describing the operations provided by the WCF service
....
}

namespace ProductsService
{
// Service contract describing the operations provided by the WCF service
[ServiceContract]
public interface IProductsService
{
// Get the product number of every product
[FaultContract(typeof(SystemFault))]
[FaultContract(typeof(DatabaseFault))]
[OperationContract]
List<string> ListProducts();
// Get the details of a single product
....
// Get the current stock level for a product
....
// Change the stock level for a product
....
}
}


public List<string> ListProducts()
{
try
{
......
}
catch (Exception e)
{
// Edit the Initial Catalog in the connection string in app.config
// to trigger this exception
if (e.InnerException is System.Data.SqlClient.SqlException)
{
DatabaseFault dbf = new DatabaseFault
{
DbOperation = "Connect to database",
DbReason = "Exception accessing database",
DbMessage = e.InnerException.Message
};
throw new FaultException<DatabaseFault>(dbf);
}
else
{
SystemFault sf = new SystemFault
{
SystemOperation = "Iterate through products",
SystemReason = "Exception reading product numbers",
SystemMessage = e.Message
};
throw new FaultException<SystemFault>(sf);
}
}
}


客户端--

static void Main(string[] args)
{
...
try
{
...
}
catch (FaultException<SystemFault> sf)
{
Console.WriteLine("SystemFault {0}: {1}\n{2}",
sf.Detail.SystemOperation, sf.Detail.SystemMessage,
sf.Detail.SystemReason);
}
catch (FaultException<DatabaseFault> dbf)
{
Console.WriteLine("DatabaseFault {0}: {1}\n{2}",
dbf.Detail.DbOperation, dbf.Detail.DbMessage,
dbf.Detail.DbReason);
}
catch (FaultException e)
{
Console.WriteLine("{0}: {1}", e.Code.Name, e.Reason);
}
...
}

宿主应用程序中ServiceHost的状态,如图

WCF一步一步往前爬(三)

在宿主应用程序中处理Faults

// ServiceHost object for hosting a WCF service
ServiceHost productsServiceHost;
productsServiceHost = new ServiceHost(...);
...
// Subscribe to the Faulted event of the productsServiceHost object
productsServiceHost.Faulted += (eventSender, eventArgs) =>
{
// FaultHandler method
// Runs when productsServiceHost enters the Faulted state
// Examine the properties of the productsServiceHost object
// and log the reasons for the fault
...
// Abort the service
productsServiceHost.Abort();
// Recreate the ServiceHost object
productsServiceHost = new ServiceHost(...);
// Start the service
productsServiceHost.Open();
};
...

在宿主应用程序中处理客户端发送过来未知的message

// ServiceHost object for hosting a WCF service
ServiceHost productsServiceHost;
productsServiceHost = new ServiceHost(...);
...
// Subscribe to the UnknownMessageReceived event of the
// productsServiceHost object
productsServiceHost.UnknownMessageReceived += (eventSender, eventArgs) =>
{
// UnknownMessageReceived event handler
// Log the unknown message
...
// Display a message to the administrator
MessageBox.Show(string.Format(
"A client attempted to send the message: {0} ",
eventArgs.Message.Headers.Action));
};
...