在面向服务的架构(SOA)系统中,处理和传播错误是一个众所周知的问题,已经有一些模式可以解决这个问题。当消费者调用服务时,交互可能会因为请求数据不正确或服务层本身的问题而失败,这使得交互出现故障。然而,在某些业务场景中,如果消费者接受失败的原因,那么交互可能不需要出现故障。这意味着可以覆盖该失败。这种类型的失败被称为警告。Determined Interaction是一种在SOA系统中处理和传播警告的模式。本文将解释如何在WCF服务中实现警告的暴露。
SOA系统的每个层次都有责任处理警告。以下类图显示了在服务层传达警告所需的核心对象。
在请求和响应消息交换模式的服务中,需要一种媒介来传达交互过程中是否发生了警告。确认(Acknowledgement)充当这种媒介,它传达以下信息:
警告包含:
CorrelationState包含用于交互完整性所需的数据的哈希值。
该方法的签名如下:
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 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包含设置所有交互完整性元素的属性AdmonishedObjects、OtherIntegrities、UserId和WarningCode。OtherIntegrities是一个占位符,如果想放置除域对象之外的任何东西,例如在示例中,使用它来放置患者ID,这是一个字符串,但需要用于集成完整性。
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();
}
}
}
}
初始字符串已经用盐、用户ID和警告代码形成,随后所有AdmonishedObjects都使用BinaryFormatter序列化并存储到_bytified字段中。