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





0/5 (0投票)
本文将介绍如何在 SOA 系统中生成、传递和处理警告。
本文的完整源代码可在以下地址下载:http://www.udooz.net/file-drive/doc_download/16-determinedinteraction.html。
阅读我关于确定交互模式的文章,以便跟进本文。
引言
在 SOA 系统中处理和传播错误是众所周知的,并且已经有一些模式可用。交互(意味着当消费者调用服务时)可能因请求数据不正确或服务层本身存在问题而失败。这会导致交互出现故障。在某些业务场景中,当消费者接受失败原因时,交互可能不需要故障。这意味着覆盖该失败。这种类型的失败称为警告。确定交互是一种用于处理和传播 SOA 系统中警告的模式。本文将介绍基于我之前的 WCF 模式“**确定交互**”的 WCF 服务中公开警告的实现。在此处阅读该模式。我在本文中采用了相同的药物处方。
下图显示了 SOA 系统各层处理警告的职责。
服务层的核心对象
下图所示的类图显示了传递警告所需的核心对象。
在具有请求和响应消息交换模式的服务中,需要一种媒介来传达在交互过程中是否发生任何警告。确认(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
包含用于设置所有交互完整性元素的属性:AdmonishedObjects
、OtherIntegrities
、UserId
和 WarningCode
。OtherIntegrities
是一个占位符,如果你想放置域对象之外的任何内容,例如,在我的示例中,我用它来放置患者 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 部分中看看其余部分。