步骤 6:实现 Echo 适配器的元数据解析处理程序

步骤 6/9

完成时间: 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 方法

  1. 在解决方案资源管理器中,双击 EchoAdapterMetadataResolverHandler.cs 文件。

  2. 在 Visual Studio 编辑器中,右键单击编辑器中的任意位置,在上下文菜单中,指向“大纲”,然后单击“停止大纲”。

  3. 在 Visual Studio 编辑器中,在此方法中找到 IsOperationMetadataValid 方法,将现有的 替换为以下单个语句,以指示每个指定的操作元数据都有效。

    return true;  
    

实现 IsTypeMetadataValid 方法

  • 在 Visual Studio 编辑器中,找到 IsTypeMetadataValid 方法,在此方法中,将现有 替换为以下单个语句,以指示每个指定的类型元数据都有效。

    return true;  
    

实现 ResolveOperationMetadata 方法

  1. 在 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;  
    
  2. 继续添加以下内容以解析 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;  
    
  3. 继续添加以下逻辑以解析 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;  
    
  4. 继续添加以下逻辑以解析 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;  
    
    
  5. 继续添加以下内容来处理默认情况。

        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);  
    }  
    
    

定义自定义问候语类型元数据类

  1. 在“解决方案资源管理器”中,右键单击“回显适配器”项目,指向“添加”,然后单击“新建项”。

  2. 在“ 添加新项 ”对话框的 “模板”下,单击“ ”。

  3. “名称” 文本框中,键入 CustomGreetingTypeMetadata

  4. 单击“添加”。

  5. 在 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;  
                }  
            }  
        }  
    }  
    
  6. 在 Visual Studio 的“ 文件 ”菜单中,单击“ 全部保存”。

创建自定义问候语 XML 架构定义

  1. 在“解决方案资源管理器”中,右键单击“回显适配器”项目,指向“添加”,然后单击“新建项”。

  2. 在“ 添加新项 ”对话框的 “模板”下,单击“ XML 架构”。

  3. “名称” 文本框中,键入 CustomGreeting

  4. 单击“添加”。

  5. 在“解决方案资源管理器”中,右键单击“CustomGreeting.xsd”文件,然后选择“查看代码”。

  6. 在 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">  
    
  7. 添加以下内容以定义 CustomGreeting 元素:

    <xsd:element name="greeting" type="CustomGreeting" />  
    
  8. 现在,添加 CustomGreeting 复杂类型的定义:

    <xsd:complexType name="CustomGreeting">  
      <xsd:sequence>  
        <xsd:element name="address" type="UsAddress" />  
        <xsd:element name="greetingText" type="xsd:string" />  
      </xsd:sequence>  
    </xsd:complexType>  
    
  9. 通过添加 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>  
    
  10. 通过为架构添加 PostalCode 简单类型和结束标记,完成 CustomGreeting 架构的定义:

      <xsd:simpleType name="PostalCode">  
        <xsd:restriction base="xsd:positiveInteger">  
          <xsd:pattern value="\d{5}" />  
        </xsd:restriction>  
      </xsd:simpleType>  
    </xsd:schema>  
    
  11. 现在,请更新此文件的生成操作,使其被视为嵌入资源。 为此,在 Visual Studio 解决方案窗格中,右键单击文件并选择“属性”。 将生成操作从 “无” 更改为 “嵌入资源”。

  12. 在 Visual Studio 的“ 文件 ”菜单中,单击“ 全部保存”。

注意

保存所做的工作。 此时可以安全地关闭 Visual Studio,也可以转到下一步 ,即步骤 7:实现 Echo 适配器的同步出站处理程序

我刚才做了些什么?

你刚刚实现了回显适配器的元数据解析功能。

后续步骤

在下一步中,你将实现 Echo 适配器的同步出站处理程序。 然后实现同步入站处理程序,然后生成并部署回显适配器。

另请参阅

步骤 5:实现 Echo 适配器的元数据搜索处理程序
步骤 7:实现 Echo 适配器的同步出站处理程序
教程 1:开发 Echo 适配器