65.9K
CodeProject 正在变化。 阅读更多。
Home

使用确定的交互模式在 WCF 中实现服务警告 - 第一部分

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2010年9月30日

CC (ASA 2.5)

4分钟阅读

viewsIcon

15765

本文将介绍如何在 SOA 系统中生成、传递和处理警告。

本文的完整源代码可在以下地址下载:http://www.udooz.net/file-drive/doc_download/16-determinedinteraction.html

阅读我关于确定交互模式的文章,以便跟进本文。

引言

在 SOA 系统中处理和传播错误是众所周知的,并且已经有一些模式可用。交互(意味着当消费者调用服务时)可能因请求数据不正确或服务层本身存在问题而失败。这会导致交互出现故障。在某些业务场景中,当消费者接受失败原因时,交互可能不需要故障。这意味着覆盖该失败。这种类型的失败称为警告。确定交互是一种用于处理和传播 SOA 系统中警告的模式。本文将介绍基于我之前的 WCF 模式“**确定交互**”的 WCF 服务中公开警告的实现。在此处阅读该模式。我在本文中采用了相同的药物处方

下图显示了 SOA 系统各层处理警告的职责。

Layer Responsibilities

服务层的核心对象

下图所示的类图显示了传递警告所需的核心对象。

Core Object

在具有请求和响应消息交换模式的服务中,需要一种媒介来传达在交互过程中是否发生任何警告。确认(Acknowledgement)充当了传递以下信息的媒介:

  • 状态 - 交互的状态,可以是成功或失败。我将其定义为整数,并模拟 HTTP 状态码 200(成功)和 301(警告)。
  • 时间戳 - 结果发生的时间
  • 警告 - 包含警告(如果有)

警告包含代码,用于唯一标识警告类型,例如,我为药物过敏使用了 12345,并附带相关的消息,其中包含警告的描述。相关状态 (CorrelationState) 包含交互完整性所需数据的哈希值。

可能发生两种交互,一种是向消费者传达警告详细信息,然后是具有相同信息以及相关状态的批准交互,如果消费者想覆盖警告。这两种交互都必须由域层中的单个代码路径处理。Acknowledgement 类的 AddWarning() 方法处理这两种交互,并将结果作为 WarningElevation 返回。WarningElevation.Admonish 表示交互应中止并将警告详细信息传达给消费者。Override 表示这是第二次交互(即确定交互),并且消费者想要覆盖警告。让我们一步一步地查看 AddWarning() 的实现。

探索 AddWarning()

此方法的签名是

public static WarningElevation AddWarning
  (int code, string message, DomainBase[] admonishedObjects, object[] otherIntegrities)

前两个参数是不言自明的。域对象可能是域层中可以在每个项目级别传达相关状态的位置。因此,我声明了一个基类(尽管我倾向于 POCO)DomainBase,并在域层中带有相关状态数组,如下面的代码所示。

[Serializable]
public class DomainBase
{
	[NonSerialized]
	public string[] CorrelationStates;
}

你可能会惊讶于 CorrelationStates 是一个数组,因为交互过程中可能出现不止一种警告。让我们看看 AddWarning() 方法的第一部分。

string generatedCorrelationState = null;
int eludeCount = 0;
int admonishedCount = 0;

if (admonishedObjects != null && admonishedObjects.Length > 0)
{
	string[] cstates = admonishedObjects[0].CorrelationStates;
	bool verifyMode = (cstates != null && cstates.Length > 0 && 
		!string.IsNullOrEmpty(cstates[0])) ? true : false;
	
	generatedCorrelationState = new ObjectBytifier(verifyMode, code, 
		admonishedObjects, otherIntegrities).Stringified;
	admonishedCount = admonishedObjects.Length;
	eludeCount = admonishedObjects.Count(admonishedObj =>
	{
		return admonishedObj != null &&
			admonishedObj.CorrelationStates != null &&
			admonishedObj.CorrelationStates.Length > 0 &&
			admonishedObj.CorrelationStates.Contains
				(generatedCorrelationState);
	});
}

admonishedObjects 中至少有一个对象时,将执行此部分。如果 admonishedObject 中的任何对象包含 CorrelationState,则此交互将被确定为确定交互。每次都会通过 ObjectBytifier 生成并保存在 generatedCorrelationState 变量中的相关状态。这将在第一次交互中传达给消费者。在确定交互期间,此用于验证来自消费者的内容。eludeCount 存储在确定交互期间包含相关状态的 admonishedObjects 的数量。让我们看看 AddWarning() 的其余部分。

if (eludeCount == 0 && admonishedCount != eludeCount)
{
	string language = string.Empty;
	Acknowledgement currentAck = Acknowledgement.Current;         
					
	if (currentAck.Warnings == null)
		Acknowledgement.Current.Warnings = new List<Warning>();
	
	Warning fault = new Warning
	{
		Code = code,
		Message = message,
		CorrelationState = generatedCorrelationState
	};

	Acknowledgement.Current.Warnings.Add(fault);
	Acknowledgement.Current.Status = 301;
	return WarningElevation.Admonish;
}else return WarningElevation.Admonish;

admonishedObjects 中没有相关状态可用或没有匹配的相关状态时,将生成警告并将其添加到 Acknowledgement。基于此,将返回适当的 WarningElevation。让我们看看生成相关状态的另一个重要对象。

探索 ObjectBytifier

ObjectBytifier class

ObjectBytifier 包含用于设置所有交互完整性元素的属性:AdmonishedObjectsOtherIntegritiesUserIdWarningCodeOtherIntegrities 是一个占位符,如果你想放置域对象之外的任何内容,例如,在我的示例中,我用它来放置患者 ID,它只是一个 string,但对于集成完整性而言是必需的。

探索 BytifyBaseObject()

Bytifier 属性将所有交互完整性元素转换为字节数组,Stringified 元素将该字节数组转换为固定大小的字符串。这就是我们称之为 CorrelationState 的。BytifyBaseObjects() 是这里的关键方法。让我们看看它最初的部分。

string salt = string.Format("{0}{1}{2}", "SALT",
	UserId, WarningCode);
_bytified = ASCIIEncoding.UTF8.GetBytes(salt);

if (AdmonishedObjects != null && AdmonishedObjects.Length > 0)
{
	BinaryFormatter serializer = new BinaryFormatter();
	MemoryStream memStream = null;

	for(int i = 0; i < AdmonishedObjects.Length; i++)
	{
		if (AdmonishedObjects[i] != null)
		{
			using (memStream = new MemoryStream())
			{
				serializer.Serialize(memStream, AdmonishedObjects[i]);
				_bytified = _bytified.Concat
					(memStream.ToArray()).ToArray();
				memStream.Close();
			}
		}
	}                
}

初始 string 由 salt、用户 ID 和警告代码组成,然后所有 AdmonishedObjects 都通过 BinaryFormatter 序列化并存储在 _bytified 字段中。

if (OtherIntegrities != null && OtherIntegrities.Length > 0)
{
	BinaryFormatter serializer = new BinaryFormatter();
	MemoryStream memStream = null;


	for (int i = 0; i < OtherIntegrities.Length; i++)
	{
		if (OtherIntegrities[i] != null)
		{
			using (memStream = new MemoryStream())
			{
				serializer.Serialize(memStream, OtherIntegrities[i]);
				_bytified = _bytified.Concat
					(memStream.ToArray()).ToArray();
				memStream.Close();
			}
		}
	} 
}
_bytified = new MD5CryptoServiceProvider().ComputeHash(_bytified)

admonishedObjects 之后,OtherIntegrities 被字节化。最后,使用 System.Security.Cryptography.MD5CryptoServiceProvider 生成一个固定哈希,并再次存储在 _bytified 字段中。

让我们在本文的第 2 部分中看看其余部分。

© . All rights reserved.