步骤 6:实现 Echo 适配器的元数据解析处理程序
完成时间: 45 分钟
在此步骤中 Microsoft.ServiceModel.Channels.Common.IMetadataResolverHandler
,你将实现 接口以解析回显适配器的操作和类型元数据。 无论适配器的功能如何,都必须实现此接口。 适配器开发向导会自动生成名为 EchoAdapterMetadataResolverHandler 的派生类。
在下一部分中,将更新 EchoAdapterMetadataResolverHandler 类,以便更好地了解如何实现此接口。 完成此步骤后,将具有回显适配器的工作元数据解析处理程序。
必备条件
在开始此步骤之前,必须已成功完成 步骤 5:实现 Echo 适配器的元数据搜索处理程序。 还必须了解以下操作和类型类:
Microsoft.ServiceModel.Channels.Common.ParameterizedOperationMetadata
Microsoft.ServiceModel.Channels.Common.OperationMetadata
Microsoft.ServiceModel.Channels.Common.OperationParameter
Microsoft.ServiceModel.Channels.Common.OperationResult
Microsoft.ServiceModel.Channels.Common.TypeMetadata
Microsoft.ServiceModel.Channels.Common.StructuredTypeMetadata
Microsoft.ServiceModel.Channels.Common.TypeMember
Microsoft.ServiceModel.Channels.Common.SimpleQualifiedType
Microsoft.ServiceModel.Channels.Common.ComplexQualifiedType
IMetadataResolverHandler 接口
public interface IMetadataResolverHandler : IConnectionHandler, IDisposable
{
bool IsOperationMetadataValid(string operationId, DateTime lastUpdatedTimestamp, TimeSpan timeout);
bool IsTypeMetadataValid(string typeId, DateTime lastUpdatedTimestamp, TimeSpan timeout);
OperationMetadata ResolveOperationMetadata(string operationId, TimeSpan timeout, out TypeMetadataCollection extraTypeMetadataResolved);
TypeMetadata ResolveTypeMetadata(string typeId, TimeSpan timeout, out TypeMetadataCollection extraTypeMetadataResolved);
}
下表描述了每个方法的作用:
“方法名称” | 说明 |
---|---|
IsOperationMetadataValid | 如果类型元数据自指定的日期和时间以来未更改,则返回 true |
IsTypeMetadataValid | 返回一个布尔值,该值指示指定的类型元数据是否有效。 |
ResolveOperationMetadata | 将操作 ID 解析为相应的 Microsoft.ServiceModel.Channels.Common.OperationMetadata |
ResolveTypeMetadata | 将提供的元数据 typeId 解析为相应的 Microsoft.ServiceModel.Channels.Common.TypeMetadata 。 |
实现 IsOperationMetadataValid 方法
在解决方案资源管理器中,双击 EchoAdapterMetadataResolverHandler.cs 文件。
在 Visual Studio 编辑器中,右键单击编辑器中的任意位置,在上下文菜单中,指向“大纲”,然后单击“停止大纲”。
在 Visual Studio 编辑器中,在此方法中找到 IsOperationMetadataValid 方法,将现有的 替换为以下单个语句,以指示每个指定的操作元数据都有效。
return true;
实现 IsTypeMetadataValid 方法
在 Visual Studio 编辑器中,找到 IsTypeMetadataValid 方法,在此方法中,将现有 替换为以下单个语句,以指示每个指定的类型元数据都有效。
return true;
实现 ResolveOperationMetadata 方法
在 Visual Studio 编辑器中,找到 ResolveOperationMetadata 方法,在此方法中,将现有的 替换为以下内容来解析 OnReceiveEcho 操作,void OnReceiveEcho (Uri 路径,long fileLength) 。
extraTypeMetadataResolved = null; switch( operationId ) { case "Echo/OnReceiveEcho": ParameterizedOperationMetadata om = new ParameterizedOperationMetadata(operationId, "OnReceiveEcho"); om.OriginalName = "lobNotification"; om.Description = "This operation echoes the location and length of a file dropped in the specified file system."; om.OperationGroup = "EchoInboundContract"; om.OperationNamespace = EchoAdapter.SERVICENAMESPACE; // syntax: void OnReceiveEcho(Uri path, long fileLength) OperationParameter parmPath = new OperationParameter("path", OperationParameterDirection.In, QualifiedType.UriType, false); parmPath.Description = "Absolute path of the file"; OperationParameter parmLength = new OperationParameter("length", OperationParameterDirection.In, QualifiedType.LongType, false); parmLength.Description = "Length of the file received in this location."; om.Parameters.Add(parmPath); om.Parameters.Add(parmLength); om.OperationResult = OperationResult.Empty; return om;
继续添加以下内容以解析 Echo/EchoStrings 操作,string[] EchoStrings (字符串数据) 。
case "Echo/EchoStrings": om = new ParameterizedOperationMetadata(operationId, "EchoStrings"); om.OriginalName = "lobEchoStrings"; om.Description = "This operation echoes the incoming string COUNT number of times in a string array."; om.OperationGroup = "EchoOutboundContract"; om.OperationNamespace = EchoAdapter.SERVICENAMESPACE; // syntax: string[] EchoStrings(string data) OperationParameter parmData = new OperationParameter("data", OperationParameterDirection.In, QualifiedType.StringType, false); parmData.Description = "Input string"; om.Parameters.Add(parmData); om.OperationResult = new OperationResult(QualifiedType.StringType, true); return om;
继续添加以下逻辑以解析 Echo/EchoStrings 操作,string[] EchoStrings (字符串数据) 。
case "Echo/EchoGreetings": om = new ParameterizedOperationMetadata(operationId, "EchoGreetings"); om.OriginalName = "lobEchoGreetings"; om.Description = "This operation echoes the incoming Greeting object COUNT number of times in an array of type Greeting."; om.OperationGroup = "EchoOutboundContract"; om.OperationNamespace = EchoAdapter.SERVICENAMESPACE; // syntax: Greeting[] EchoGreetings(Greeting greeting) ComplexQualifiedType cqtGreeting = new ComplexQualifiedType("Types/GreetingType"); OperationParameter parmGreeting = new OperationParameter("greeting", OperationParameterDirection.In, cqtGreeting, false); parmGreeting.Description = "Input greeting"; om.Parameters.Add(parmGreeting); om.OperationResult = new OperationResult(cqtGreeting, true); return om;
继续添加以下逻辑以解析 CustomGreeting EchoCustomGreetingFromFile (Uri greetingInstancePath) 操作。
case "Echo/EchoCustomGreetingFromFile": om = new ParameterizedOperationMetadata(operationId, "EchoCustomGreetingFromFile"); om.OriginalName = "lobEchoGreetingUsePredefinedMetadata"; om.Description = "This operation echoes the incoming Greeting object COUNT number of times in an array of type Greeting. The Greeting type metadata is created using predefined XSD file."; om.OperationGroup = "EchoOutboundContract"; om.OperationNamespace = EchoAdapter.SERVICENAMESPACE; OperationParameter parmGreetingInstancePath = new OperationParameter("greetingInstancePath", OperationParameterDirection.In, QualifiedType.UriType, false); om.Parameters.Add(parmGreetingInstancePath); ComplexQualifiedType cqtGreetingXsd = new ComplexQualifiedType("Types/CustomGreetingFromXsdType"); om.OperationResult = new OperationResult(cqtGreetingXsd, false); // resolve extra typemetadata here extraTypeMetadataResolved = new TypeMetadataCollection(); // use a predefined schema to generate metadata for this type CustomGreetingTypeMetadata tmGreetingXsd = new CustomGreetingTypeMetadata("Types/CustomGreetingFromXsdType", "CustomGreeting"); extraTypeMetadataResolved.Add(tmGreetingXsd); return om;
继续添加以下内容来处理默认情况。
default: throw new AdapterException("Cannot resolve metadata for operation identifier " + operationId); }
实现 ResolveTypeMetadata 方法
在 Visual Studio 编辑器中,找到 ResolveTypeMetadata 方法,在此方法中,将现有的 替换为以下内容以返回 对象
Microsoft.ServiceModel.Channels.Common.TypeMetadata
。extraTypeMetadataResolved = null; string typeNamespaceForGreeting = EchoAdapter.SERVICENAMESPACE + "/Types"; switch (typeId) { case "Types/GreetingType": StructuredTypeMetadata tmGreeting = new StructuredTypeMetadata(typeId, "Greeting"); tmGreeting.TypeNamespace = typeNamespaceForGreeting; tmGreeting.Members.Add(new TypeMember("id", QualifiedType.GuidType, false)); tmGreeting.Members.Add(new TypeMember("sentDateTime", QualifiedType.DateTimeType, false)); ComplexQualifiedType cqtName = new ComplexQualifiedType("Types/NameType"); tmGreeting.Members.Add(new TypeMember("name", cqtName, false)); tmGreeting.Members.Add(new TypeMember("greetingText", QualifiedType.StringType, false)); return tmGreeting; case "Types/NameType": StructuredTypeMetadata tmName = new StructuredTypeMetadata(typeId, "Name"); tmName.TypeNamespace = typeNamespaceForGreeting; ComplexQualifiedType cqtSalutation = new ComplexQualifiedType("Types/SalutationType"); tmName.Members.Add(new TypeMember("salutation", cqtSalutation, false)); tmName.Members.Add(new TypeMember("firstName", QualifiedType.StringType, false)); tmName.Members.Add(new TypeMember("middleName", QualifiedType.StringType, false)); tmName.Members.Add(new TypeMember("lastName", QualifiedType.StringType, false)); return tmName; case "Types/SalutationType": EnumTypeMetadata tmSalutation = new EnumTypeMetadata(typeId, "Salutation", new string[] { "Mr.", "Mrs.", "Dr.", "Ms.", "Miss" }); tmSalutation.TypeNamespace = typeNamespaceForGreeting; return tmSalutation; default: throw new AdapterException("Cannot resolve metadata for type identifier " + typeId); }
定义自定义问候语类型元数据类
在“解决方案资源管理器”中,右键单击“回显适配器”项目,指向“添加”,然后单击“新建项”。
在“ 添加新项 ”对话框的 “模板”下,单击“ 类”。
在 “名称” 文本框中,键入 CustomGreetingTypeMetadata。
单击“添加”。
在 Visual Studio 编辑器中,将现有代码替换为以下内容:
using System; using System.Collections.Generic; using System.Text; using Microsoft.ServiceModel.Channels.Common; using System.Xml; using System.Xml.Schema; using System.IO; namespace Microsoft.Adapters.Samples.EchoV2 { public class CustomGreetingTypeMetadata : TypeMetadata { private const string CONST_METADATA_FILE_NAME = "Microsoft.Adapters.Samples.EchoV2.CustomGreeting.xsd"; public CustomGreetingTypeMetadata(string typeId, string typeName) : base(typeId, typeName) { this.TypeNamespace = EchoAdapter.SERVICENAMESPACE + "/PreDefinedTypes"; this.Description = " "; this.CanUseCommonCache = true; // if the nillable is not set to true, the generated proxy wraps the operation // with request and response objects this.IsNillable = true; } /// <summary> /// Override the base ExportXmlSchema to provide own /// custom XML Schema /// </summary> /// <param name="schemaExportContext"></param> /// <param name="metadataLookup"></param> /// <param name="timeout"></param> public override void ExportXmlSchema(XmlSchemaExportContext schemaExportContext, MetadataLookup metadataLookup, TimeSpan timeout) { if (schemaExportContext == null) { throw new AdapterException("Schema export context is null."); } // Read in XML Schema file or create XmlSchema object yourself Stream predefinedXsdFile = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(CONST_METADATA_FILE_NAME); XmlReader reader = XmlReader.Create(predefinedXsdFile); XmlSchema schema = XmlSchema.Read(reader, null); if (!IsComplexTypeAlreadyDefined(schemaExportContext.SchemaSet, schema)) { schemaExportContext.SchemaSet.Add(schema); if (!schemaExportContext.NamespacePrefixSet.ContainsKey(this.TypeNamespace)) { schemaExportContext.NamespacePrefixSet.Add(this.TypeNamespace, getUniqueNamespacePrefix(schemaExportContext, 0)); } } reader.Close(); } /// <summary> /// A default value cannot be set for this type metadata. /// </summary> public override bool CanSetDefaultValue { get { return false; } } /// <summary> /// Helper function to see if the schema is already defined in the /// XmlSchemaSet. /// </summary> /// <param name="oldschemaset"></param> /// <param name="newschema"></param> /// <returns></returns> public static bool IsComplexTypeAlreadyDefined(XmlSchemaSet oldschemaset, XmlSchema newschema) { // ensure correct namespace was defined in the passed-in schema foreach (XmlSchema schema in oldschemaset.Schemas(newschema.TargetNamespace)) { foreach (XmlSchemaObject newschemaObject in newschema.Items) { if (newschemaObject is XmlSchemaComplexType) { //check for the definition of complex type in the schemaset foreach (XmlSchemaObject schemaObject in schema.Items) { XmlSchemaComplexType complexType = schemaObject as XmlSchemaComplexType; // Definition of this Complex Type already exists if (complexType != null && String.Compare(complexType.Name, ((XmlSchemaComplexType)newschemaObject).Name, false, System.Globalization.CultureInfo.InvariantCulture) == 0) return true; } } } } return false; } /// <summary> /// Helper function to generate a unique namespace prefix /// </summary> /// <param name="schemaExportContext"></param> /// <param name="startSuffix"></param> /// <returns></returns> private string getUniqueNamespacePrefix(XmlSchemaExportContext schemaExportContext, int startSuffix) { string defaultPrefix = "ns"; string val = defaultPrefix + startSuffix; if (schemaExportContext.NamespacePrefixSet.ContainsValue(val)) { return getUniqueNamespacePrefix(schemaExportContext, ++startSuffix); } else { return val; } } } }
在 Visual Studio 的“ 文件 ”菜单中,单击“ 全部保存”。
创建自定义问候语 XML 架构定义
在“解决方案资源管理器”中,右键单击“回显适配器”项目,指向“添加”,然后单击“新建项”。
在“ 添加新项 ”对话框的 “模板”下,单击“ XML 架构”。
在 “名称” 文本框中,键入 CustomGreeting。
单击“添加”。
在“解决方案资源管理器”中,右键单击“CustomGreeting.xsd”文件,然后选择“查看代码”。
在 Visual Studio 编辑器中,首先将现有代码替换为开始 CustomGreeting 架构定义的以下代码:
<?xml version="1.0" encoding="utf-8" ?> <xs:schema id="XMLSchema1" targetNamespace="http://tempuri.org/XMLSchema1.xsd" elementFormDefault="qualified" xmlns="http://tempuri.org/XMLSchema1.xsd" xmlns:mstns="http://tempuri.org/XMLSchema1.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema"> </xs:schema>
使用以下代码开始定义 CustomGreeting 架构:
<?xml version="1.0" encoding="utf-16"?> <xsd:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003" xmlns="echov2://microsoft.adapters.samples.echov2/PreDefinedTypes" elementFormDefault="qualified" targetNamespace="echov2://microsoft.adapters.samples.echov2/PreDefinedTypes" xmlns:xsd ="http://www.w3.org/2001/XMLSchema">
添加以下内容以定义 CustomGreeting 元素:
<xsd:element name="greeting" type="CustomGreeting" />
现在,添加 CustomGreeting 复杂类型的定义:
<xsd:complexType name="CustomGreeting"> <xsd:sequence> <xsd:element name="address" type="UsAddress" /> <xsd:element name="greetingText" type="xsd:string" /> </xsd:sequence> </xsd:complexType>
通过添加 UsAddress 复杂类型继续 CustomGreeting 架构定义:
<xsd:complexType name="UsAddress"> <xsd:sequence> <xsd:element minOccurs="1" maxOccurs="1" name="street1" nillable="true" type="xsd:string" /> <xsd:element minOccurs="0" maxOccurs="1" name="street2" type="xsd:string" /> <xsd:element minOccurs="1" maxOccurs="1" name="city" type="xsd:string" /> <xsd:element minOccurs="1" maxOccurs="1" name="state" type="xsd:string" /> <xsd:element name="zip" type="PostalCode" /> </xsd:sequence> </xsd:complexType>
通过为架构添加 PostalCode 简单类型和结束标记,完成 CustomGreeting 架构的定义:
<xsd:simpleType name="PostalCode"> <xsd:restriction base="xsd:positiveInteger"> <xsd:pattern value="\d{5}" /> </xsd:restriction> </xsd:simpleType> </xsd:schema>
现在,请更新此文件的生成操作,使其被视为嵌入资源。 为此,在 Visual Studio 解决方案窗格中,右键单击文件并选择“属性”。 将生成操作从 “无” 更改为 “嵌入资源”。
在 Visual Studio 的“ 文件 ”菜单中,单击“ 全部保存”。
注意
保存所做的工作。 此时可以安全地关闭 Visual Studio,也可以转到下一步 ,即步骤 7:实现 Echo 适配器的同步出站处理程序。
我刚才做了些什么?
你刚刚实现了回显适配器的元数据解析功能。
后续步骤
在下一步中,你将实现 Echo 适配器的同步出站处理程序。 然后实现同步入站处理程序,然后生成并部署回显适配器。
另请参阅
步骤 5:实现 Echo 适配器的元数据搜索处理程序
步骤 7:实现 Echo 适配器的同步出站处理程序
教程 1:开发 Echo 适配器
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈