数据表示、异常处理与持久化服务详解
发布时间: 2025-08-15 00:57:34 订阅数: 4 

### 数据表示、异常处理与持久化服务详解
在开发服务时,数据表示、异常处理和持久化服务是几个关键的方面。下面将详细介绍这些内容。
#### 数据表示与继承注意事项
在操作调用中,若要使用派生类型的参数替代基类型的参数,就需要使用 `System.ServiceModel.ServiceKnownType` 属性。这意味着应避免使用继承来对数据契约进行版本控制。例如,若期望接收基类型,但实际收到派生类型,除非在代码中添加 `System.ServiceModel.ServiceKnownType` 属性以预期该派生类型,否则派生类型的序列化将会失败。
Windows 通信基础(Windows Communication Foundation)会隐式使用 `System.Runtime.Serialization.DataContractSerializer`。以下示例代码展示了如何单独使用它将数据序列化为 XML:
```csharp
MemoryStream stream = new MemoryStream();
DataContractSerializer serializer = new DataContractSerializer(typeof(ClientViewOfData));
serializer.WriteObject(stream, calculation);
Console.WriteLine(UnicodeEncoding.UTF8.GetChars(stream.GetBuffer()));
```
#### 异常处理
数据契约有助于向客户端通知服务中可能发生的异常。以下是具体的操作步骤:
1. 在之前提到的序列化项目的 `Program.cs` 模块中添加 `SomeError` 类:
```csharp
public class SomeError
{
public string Content;
}
```
2. 使用 `System.Runtime.Serialization.DataContract` 和 `System.Runtime.DataMember` 属性为该类创建数据契约:
```csharp
[DataContract]
public class SomeError
{
[DataMember]
public string Content;
}
```
这会生成一个数据契约,用于指定服务可能发送给客户端的简单错误消息的格式。
3. 在定义服务契约的 `IServiceViewOfService` 接口中添加一个操作:
```csharp
[OperationContract(Name="Faulty")]
decimal DivideByZero(decimal input);
```
4. 使用 `System.ServiceModel.FaultContract` 属性为该操作添加错误契约,告知客户端该服务可能返回 `SomeError` 数据契约定义形式的错误消息,而非预期结果:
```csharp
[OperationContract(Name="Faulty")]
[FaultContract(typeof(SomeError))]
decimal DivideByZero(decimal input);
```
5. 在实现 `IServiceViewOfService` 接口定义的 `DerivativesCalculator` 服务契约的 `DerivativesCalculator` 类中添加 `DivideByZero()` 方法的实现:
```csharp
public class DerivativesCalculator : IServiceViewOfService
{
public decimal DivideByZero(decimal input)
{
try
{
decimal denominator = 0;
return input / denominator;
}
catch (Exception exception)
{
SomeError error = new SomeError();
error.Content = exception.Message;
throw new FaultException<SomeError>(error);
}
}
}
```
当服务在 `DivideByZero()` 方法中捕获到异常时,会创建一个 `SomeError` 类的实例,将异常的选定信息传达给调用者,并使用 Windows 通信基础的泛型 `System.ServiceModel.FaultException<T>` 将该信息发送给调用者。
6. 由于 `DivideByZero()` 方法上有 `System.ServiceModel.FaultContract` 属性,如果使用服务元数据工具下载服务的元数据并生成客户端代码,客户端版本的契约将自动包含 `DivideByZero()` 方法及其关联的错误契约的定义。这里,直接将该方法和错误契约添加到客户端版本的契约(`IClientViewOfService` 接口)中:
```csharp
[ServiceContract(Name="DerivativesCalculator")]
[KnownType(typeof(DerivedData))]
public interface IClientViewOfService
{
[OperationContract(Name = "Faulty")]
[FaultContract(typeof(SomeError))]
decimal DivideByZero(decimal input);
}
```
7. 在 `Program` 类的静态 `Main()` 方法中添加代码,让客户端使用 `Faulty` 操作。由于操作的 `FaultContract` 表明可能会收到错误消息,客户端代码需要处理这种可能性。使用 Windows 通信基础的 `System.ServiceModel.FaultException<T>` 泛型来捕获和处理错误:
```csharp
public class Program
{
public static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(DerivativesCalculator), new Uri[] { new Uri("http://localhost:8000/Derivatives") }))
{
host.AddServiceEndpoint(typeof(IServiceViewOfService), new BasicHttpBinding(), "Calculator");
host.Open();
Console.WriteLine("The service is available.");
string address = "http://localhost:8000/Derivatives/Calculator";
ChannelFactory<IClientViewOfService> factory = new ChannelFactory<IClientViewOfService>(new BasicHttpBinding(), new EndpointAddress(new Uri(address)));
IClientViewOfService proxy = factory.CreateChannel();
try
{
Decimal quotient = proxy.DivideByZero(9);
}
catch (FaultException<SomeError> error)
{
Console.WriteLine("Error: {0}", error.Detail.Content);
}
}
}
}
```
8. 若要查看这些更改的效果,可从 Visual Studio 2005 菜单中选择“调试” -> “开始执行(不调试)”。
9. 在应用程序的控制台中输入一个按键以终止程序。
这种异常处理方法具有多个优点:
- 服务开发者可以轻松定义要传输给客户端程序员的错误消息的结构。
- 能够向客户端程序员告知服务的哪些操作可能返回特定的错误消息,而非预期结果。
- 服务程序员可以轻松地制定并向客户端传输错误消息,客户端程序员则可以使用类似普通异常处理的简单语法来接收和检查错误消息。
- 服务程序员可以决定将服务中发生的错误的哪些信息传达给客户端。
不过,Windows 通信基础的设计也考虑到了在调试服务时,将服务中可能发生的任何意外异常的完整信息返回给客户端的实用性。可以通过设置 `System.ServiceModel.Description.ServiceDebugBehavior` 的 `IncludeExceptionDetailInFaults` 属性来实现这一点。以下是相应的配置示例:
```xml
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="DerivativesCalculator.DerivativesCalculatorServiceType, DerivativesCalculatorService" behaviorConfiguration="DerivativesCalculatorBehavior">
<endpoint address="" binding="basicHttpBinding" contract="DerivativesCalculator.IDerivativesCalculator" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<b
```
0
0
相关推荐










