美祺's profileEden of HexagonPhotosBlogListsMore Tools Help

Blog


    August 29

    『转载』解密美联储:私有背后的隐情

    讳莫如深的私有本质

    第一次听闻央行可以是私有,源自2006年关于外汇储备管理体制改革的讨论。
    2006年,我国外储先是跃居世界第一位,关于储备管理体制改革的讨论也热烈起来。有学者建议中国采取类似美国、英国、日本等国的财政主导型储备管理,所有权归财政部,央行负责储备的管理。
    中国社科院金融研究所所长李扬是储备管理体制改革的重要探索者之一,他在一次演讲中称,中国没有必要去区分财政主导还是央行主导,因为我们调研发现,一些国家选择财政主导型,是因为有的国家中央银行在性质上是私有的,当然不能拥有国家的外汇储备。而我们不存在这个问题,中国人民银行和财政部一样,都是政府机构,因此讨论财政主导或央行主导的区别不大。
    在接触到这个观点之后,笔者曾咨询了前美国总统顾问John Rutledge和前纽约联储研究员Raymond Stone。两位美国专家含糊地承认了美联储的股份是为私有机构拥有,不过两位也着重强调,通过对联储主席以及几位理事的提名和任命,“美国政府保持对联储的控制”。
    诺贝尔奖得主、著名经济学家弗里德曼在他《货币的祸害》一书中探讨过这个问题。他坦言,关于联邦储备体系究竟是一家政府机构还是一家私人机构,存在非常多的困惑。
    他指出,困惑的出现是因为12家联邦储备银行是联邦特许股份公司,每家银行都有自己的股东、董事和总裁。每家银行的股东都是储备银行所在地区的成员银行,他们有权选举9名董事中的6名。每家成员银行都需要购买等同于其资产和净资产的3%的股票额。“因此,名义上,联邦储备银行由私人拥有。”
    但弗里德曼同时指出,由于联邦储备体系的理事会由7名成员组成,所有这7名成员都需经总统提名,并由参议院同意任命。他将美联储的性质总结为,“联邦储备体系实际上是一个政府体系,但在名义上却将自己笼罩在私人拥有的地区银行的烟幕中。”
    弗里德曼告诉了我们这样的事实,美联储是股份公司,而拥有股份的并不是美国政府,政府只是拥有美联储理事的提名和任命权。其次,我们应该说,“联邦储备体系实际上是一个私人体系,但在名义上却将自己笼罩在政府控制的烟幕中。”

    美联储渊源

    美国成立于1776年,但作为中央银行“楷模”的美联储只是成立于1913年。美国在美联储成立之前的137年间,难道没有中央银行吗?不是,可以说想成立中央银行的人在这137年间从未放弃努力。
    独立战争给美国经济带来了创伤,第一任财政部部长汉密尔顿提出了由国会成立中央银行,该银行为私人拥有,负责发行国家货币来满足经济发展的需要,向美国政府贷款并收取利息,这将为政府融资作出贡献。在巨大的债务压力之下,华盛顿总统于1792年签署了中央银行授权,有效期20年。
    这就是第一合众国银行,总股本1000万美元,私人拥有80%,美国政府拥有20%。在25人组成的董事会中20人由私人股东推举,5人由政府任命。1811年第一合众国银行到期,美国政府否决了授权延期的议案。
    此后,1812年爆发了美国与英国的战争,持续三年的战争增大了美国的财政压力。1816年,第二合众国银行成立,同样得到了20年的营业授权,总股本 3500万美元,仍然是80%由私人占有,20%属于政府。1832年美国总统杰克逊否决了第二合众国银行延期的议案。
    作为1913年成立第三任中央银行,美联储显然有不同之处。首先它没有国家银行那样冠冕堂皇的名字;其次,它的总部设立在政治中心华盛顿,并且拥有12家地区分支机构,政府拥有主席和理事的提名和任命权。
    另外的两个不易观察的区别,一是政府已经不再拥有前两任央行那样20%的股份;二是美联储法案里根本没说授权期限问题,人们不再需要为了授权期限到期而再去争吵。
    我们有必要来描述一下谁拥有美联储的股份。当然在美联储的网站上查不到这个信息。
    尤斯塔斯(EustaceMullins)在他《美联储的秘密》一书中披露:美联储纽约银行在1914年5月19日向货币审计署报备的文件上记录着股份发行总数为203053股,其中花旗银行的前身纽约城市国家银行拥有最多的股份30000股。花旗银行的另一个前身第一国家银行拥有15000股。 1955年,这两家银行合并成花旗银行后,它拥有美联储纽约银行近四分之一的股份。此外,纽约国家商业银行拥有21000股;汉诺威银行拥有10200 股;大通银行拥有6000股;汉华银行拥有6000股。这6家银行共持有40%的美联储纽约银行股份,纽约银行是美联储最重要的分支机构。
    这些股东的名字,都是我们熟知的华尔街巨头。也就是说,国际金融市场的巨头们,实则还是国际金融市场指挥棒美联储的拥有者。

    疑问美联储

    第一,前两个合众国银行存在的时间都极为短暂,缘何美国的中央银行时废时立?回答这个问题,涉及美国的货币发行权问题。
    根据美国宪法第一章第八节,“国会拥有货币的制造和价值规定的权力。”这就是说,美国货币的发行权在美国国会,但中央银行法案却将这一权力赋予了私有的中央银行。
    国会拥有货币发行权,但没有授权国会转让发币权给任何私人银行。这就成为讨论美国私有央行问题的核心。
    被市场称为“美元”的纸片,在本质上只是联邦储备券,它对应的是美国政府对美联储的债务,这是美国货币发行的本质。
    我们惊讶于以上的事实,并有如下诸多的疑问。
    第一,美国宪法规定国会拥有货币发行权,而由私有的美联储来执行货币发行权,是否在本质上符合美国宪法?这个问题的争论曾经导致第一、二合众国被关闭,这意味着这种讨论不是没有价值。
    第二,一家私人机构拥有货币发行权,并且是仅有的拥有了货币发行权,这种垄断性质对金融市场乃至全球金融市场意味着什么?美联储与华尔街巨头之间是怎样的关系?有没有什么幕后不为人知的东西?
    第三,在美元本位之下,美联储不仅是美国的央行,甚至还是全世界的央行,但没有任何国际机构对美联储的行为进行监管,私有本质对美联储在全球金融市场上发挥作用有没有影响?
    在这方面一个有说服力的例子,是美联储停止公布货币供应量M3数据。M3 是美国最广义的货币定义,它代表了美国所发放的所有美元,包括流向国际市场的美元,这个数据是对美联储如何迅速地创造新货币的最好描述。然而,美联储却不痛不痒地草率地停止了公布这个重要数据。

    到2006年,美国联邦政府共欠下8.6万亿美元的天文数字的债务,平均每一个四口之家,要摊上11.2万美元的国债,而且国债总额正以每秒两万美元的速度增长!美国联邦政府对国债利息的支出仅次于健康医疗和国防。

    从1864年开始,银行家们可以世世代代享用国债利息这一美餐。仅仅是由于政府直接发行货币还是政府发行债券而银行发行货币这一点看似不起眼的差别,就造成了人类历史上最大的不公平。人民被迫向银行家间接缴税,为了原本是他们血汗劳动所创造的财富和货币!

    到目前为止,中国是世界上仅存的为数不多的由政府直接发行货币的国家。政府和人民为此而节省下来的巨额利息开支是中国能够高速长期发展不可缺少的重要因素。如果有人提出要学习外国的“先进经验”,人民银行必须用政府的国债作为抵押来发行人民币,中国人民就需要当心了。

    August 21

    真的好困——In The End by Linkin Park

    In The End

    It starts with
    One thing  I don’t know why
    It doesn’t even matter how hard you try
    Keep that in mind  I designed this rhyme
    To explain in due time
    All I know
    time is a valuable thing
    Watch it fly by as the pendulum swings
    Watch it count down to the end of the day
    The clock ticks life away
    It’s so unreal
    Didn’t look out below
    Watch the time go right out the window
    Trying to hold on  but didn’t even know
    Wasted it all just to
    Watch you go
    I kept everything inside and even though I tried  it all fell apart
    What it meant to me  will eventually  be a memory  of a time when I tried so hard
    And got so far
    But in the end
    It doesn't even matter
    I had to fall
    To lose it all
    But in the end
    It doesn't even matter
    One thing  I don’t know why
    It doesn’t even matter how hard you try
    Keep that in mind  I designed this rhyme
    To remind myself how
    I tried so hard
    In spite of the way you were mocking me
    Acting like I was part of your property
    Remembering all the times you fought with me
    I’m surprised it got so far
    Things aren’t the way they were before
    You wouldn’t even recognize me anymore
    Not that you knew me back then
    But it all comes back to me
    In the end
    You kept everything inside and even though I tried  it all fell apart
    What it meant to me  will eventually  be a memory  of a time when I tried so hard
    And got so far
    But in the end
    It doesn’t even matter
    I had to fall
    To lose it all
    But in the end
    It doesn’t even matter
    I've put my trust in you
    Pushed as far as I can go
    For all this
    There’s only one thing you should know
    I've put my trust in you
    Pushed as far as I can go
    For all this
    There’s only one thing you should know
    I tried so hard
    And got so far
    But in the end
    It doesn’t even matter
    I had to fall
    To lose it all
    But in the end
    It doesn’t even matter

    August 18

    感冒的一周

    堕天
    还是感冒了,本以为自己能过一个没有感冒的夏天,结果还是。。。同时这周的后半大都贡献给了睡觉,回来就睡,醒了再睡。大概,这次的感冒是个借口,一个逃避压力的借口。呵呵,下周又要开始,借口难得一次也就足够了,自己可不想总活在借口中。

    近亲结婚
    奇怪为什么会谈到这个话题呢?下午,泡上一杯浓咖啡,边品尝边读一本科学期刊时看到的一则有关此话题的报告。众所周知,很多的遗传病的基因都是隐性的,也就是当一半的染色体是正常的,而在此相同位置的另一半染色体为病变的基因时,总体呈现正常,只有当两个都是病变情况下,才会出现病变,也就是通常的遗传病。人类早在很早的年代中就明白的这个生物学上的规律,所以,极力避免了近亲之间的婚配。

    但是其实大自然是更加睿智的,避免近亲是延续种族健康的方式之一,近亲结婚也是维系种群的另类方式。因为遗传病的隐性特性,所以近亲结婚会导致其出现,但是试想一下,既然会出现两个病变染色体对,那么也会诞生两个绝对健康的染色体对。而且概率也是1/4,而且,带有隐性特征凸现的后代会因为此病而夭折,这个病变的基因便无法遗传下去。逐渐的,种群中病变的基因会减少,种群得病的比例也下降。(以上前提是要多生,并让病变的后代被自然所淘汰)。呵呵,现实中的例子很多,有相当部分的生物选择了这种维系方式,而且也保持了相对的健康种群。

    人类社会制定了自己的道德伦理,也因此虔诚的遵守其中。但是上帝却又给我们开了一次玩笑,一个讽刺的玩笑,自以为是的人类往往会过分相信自己的所谓科学判断,并冠以神的名义。上帝的秘密还有很多,人类永远无法探知所有。

    a95ea09e8ee2ac2bdb0094645de13392

    August 13

    BizTalk Server Tips

    提高 BizTalk 编程能力的 8 点技巧和窍门

    Marty Wasznicky

     and Scott Zimmerman






    more ...


    打印


    E-mail


    添加到收藏夹


    评价


    RSS (Issues)


    Add RSS to Any


    相关信息


    Live Spaces


    Digg This


    BlogThis!


    Slashdot


    del.icio.us


    Technorati


    本文讨论:
    • 多部分消息
    • 直接绑定端口
    • 创建 Web 服务
    • 调试 XSLT

    本文使用了以下技术:
    BizTalk Server 2006,Visual Studio


    目录

    1. 始终使用“多部分消息类型”
    2. 始终尽可能使用“直接绑定端口”设计业务流程
    3. 始终使用单独的内部和外部架构
    4. 永远不要在 WSDL 中直接公开您的内部架构
    5. 始终为 Web 服务优化 BizTalk 注册表
    6. 始终使用相对路径设置程序集密钥文件
    7. 永远不要忽视免费的示例代码
    8. 在 Visual Studio 中调试 XSLT
    总结


    一次,Marty 要与一个大客户进行概念证明,就在要开始前半天,他接到一个需要修复的复杂的 BizTalk® 解决方案。 该解决方案的主要组件是一个业务流程,它集成了几个后端系统,要对每一个后端系统执行多次对外调用。 他看到“业务流程设计器”屏幕上几乎全部由黑色线条构成,将几十个“接收”和“发送”形状连接到 40 多个入站和出站端口 — 这种设计几乎不可能对其进行调试。 他的解决办法: 使用“多部分消息类型”和“直接绑定端口”(下面的技巧 1 和技巧 2)重新开始,沿流程路线执行单元测试。 结果如何? 他成功了!

    Marty 的成功部分归功于 BizTalk Server 的设计 — 它的设计可以应对互连系统编程中固有的特殊难题,在某些情况下甚至不必编写代码。 但是,尽管它有简洁的拖放式流程图,而且代码很少,您也不要高兴过了头 — 事情没这么简单。 BizTalk 是一种使用范围广而且功能强大的产品,熟练掌握它需要几年的时间。 如果您打算成为一名 BizTalk 专家,您会遇到很多需要您基于 Microsoft® .NET Framework 编写代码的情形,以与 BizTalk 中复杂的内置消息处理能力形成补充。

    直到最近,BizTalk 新手们都一直很少有机会利用大师的心得和技巧来加快掌握 BizTalk。 (请参阅侧栏上的“学习 BizTalk Server 2006 编程”以查看相关资源。) 我第一次深入接触 BizTalk 是在参加 Marty 主办的为期一周的 BizTalk 培训活动中的一次课程期间,在这一周的时间里,他不断告诫我们要正确设计系统,并在使用之前在实际负载条件下用 PerfMon 对其进行测试。 通过这次活动,我们汲取了大量技巧,这些技巧可以帮助您成为更高效的开发人员。 本文的目的旨在与大家分享这些有用的技巧,下面转入正题。

    1. 始终使用“多部分消息类型”

    BizTalk 的目的旨在处理消息,顺便说一下,所谓消息并非只是电子邮件。 文档、InfoPath 窗体、大型二进制文件、SQL 记录、平面文件以及任何 XML 文件都可以作为消息来处理,同时您还可以获得异步通信带来的好处。 一旦您熟悉了该工具,您会发现面向消息的编程与面向对象的编程一样酷,都是非常有用的编程范例。

    BizTalk 中的消息是数据,每个消息都必须属于一种选定的消息类型。 BizTalk 中最常见的消息类型是架构,也就是说,此类消息基于一个 .XSD 文件,此文件指定了消息中的记录和字段结构。 请参阅 msdn2.microsoft.com/en-us/library/ms942182.aspx,查看有关 BizTalk 中的架构和映射的详细讨论。

    在用 BizTalk 进行编程的过程中,总有一天您会希望更改某个消息所基于的架构。 但问题是,如果您已经为“发送”或“接收”形状选择了此类消息并将其连接到一个业务流程端口,则在您尝试更改“消息类型”时将收到以下错误:

    Property value is not valid: One or more Send or Receive actions are
     connected to Ports and are using this Message. Please disconnect the
     actions before changing the Message Type.
    

    在按错误消息的建议进行操作之前,让我们先想一想它涉及哪些工作。 首先,您必须检查每个“接收”和“发送”形状,以确定它是否使用了与您要更改的架构关联的 Message 变量(已设置了其“消息类型”)。 目前,BizTalk 中没有可提供此类审核或生成依赖关系映射的功能;实际上,若创建的一个业务流程有太多的“接收”/“发送”形状,以至于需要有这样一种功能,只能说明这一流程的创建没有采用良好的做法。 在前面提到的让人发怵的业务流程中,大多数“接收”和“发送”形状都使用不同的 Message 变量,但它们都指向同一架构定义(都是同一消息类型)!

    第二,一旦找到所有“接收”/“发送”形状,必须删除它们的端口连接。 第三,必须更改 Message 变量,以便将“消息类型”属性设置为新的架构,然后重新将 Message 变量与每个“接收”/“发送”形状关联起来。

    第四(您认为您已经完成了),必须找出与已经从“接收”/“发送”形状断开连接的端口关联的所有“端口类型”,并重新设置其“操作”的“消息类型”属性。 您知道,在您最初将“接收”或“发送”形状与一个端口关联时,BizTalk 会自动将“端口”类型中的“消息类型”属性设置为与此“接收”/“发送”形状的 Message 变量的“消息类型”相符。 在删除“端口”和“接收”/“发送”形状之间的连接时,BizTalk 将丢失该“端口”的“消息类型”。

    幸运的是,有一种更好的方法。 计算机科学领域有一条公理指出,添加一个中间环节可以解决许多问题。 本例再次证明了此言不虚;我们需要做的就是使用一个多部分消息类型来包装底层的架构。 最初的工作量可能会稍大一些,但是灵活性会大大提高,并且从长远看可为您节省时间。 下面介绍如何实现这一点。

    在您右键单击“业务流程视图”选项卡中的“消息”来创建新消息时,有四种消息类型属性可供选择(参见图 1 中的右下角)。 为消息类型选择一种架构是通常的做法,但是在这里我们所使用的技巧是要尝试一种全然不同的做法。 单击 + 号展开“多部分消息类型”,然后选择“创建新的多部分消息类型”。 为您的多部分消息类型命名,然后单击 + 号展开它,以便您可以查看其 MessagePart_1 成员(这是 BizTalk 为新的多部分消息类型的第一部分建议的名称)。 现在,将“标识符”属性从“MessagePart_1”更改为更好识别的值,如“Body”(但是不要使用小写“body”,因为它是保留字)。 不要忘记将“消息正文部分”属性设置为 True(以便其行为与常规的消息一样)。

    图 1 在业务流程视图中设置“消息类型”属性
    图 1 在业务流程视图中设置“消息类型”属性 (单击该图像获得较小视图)

    图 1 在业务流程视图中设置“消息类型”属性
    图 1 在业务流程视图中设置“消息类型”属性 (单击该图像获得较大视图)

    需要做的额外工作到此结束。 最后,将新消息部分(如,Body)的“类型”属性设置为常规的基于架构的消息类型所使用的同样的架构。 现在,您的逻辑端口和“接收”/“发送”形状都在使用您的多部分消息类型,将来您可以轻松地更改底层的架构,而无需断开端口与接收形状的连接。

    Back to top

    2. 始终尽可能使用“直接绑定端口”设计业务流程

    请看一下图 2,该图显示了在业务流程设计器中配置端口时可用的选项。 在使用端口配置向导时,您将从此图的顶部移动到底部。 注意此图中的三个“直接”选项。 虽然 BizTalk UI 提供了“直接”作为端口类型,但是我们这里将使用行话,称它们为“直接绑定”。

    图 2 业务流程设计器端口配置向导中的“端口”选项
    图 2 业务流程设计器端口配置向导中的“端口”选项 (单击该图像获得较小视图)

    图 2 业务流程设计器端口配置向导中的“端口”选项
    图 2 业务流程设计器端口配置向导中的“端口”选项 (单击该图像获得较大视图)

    要理解 BizTalk 中的端口术语,关键要理解逻辑端口(也称为业务流程端口)和物理端口的概念。 一句话说,两者的区别是,在业务流程设计器中创建的是逻辑端口,使用 BizTalk 浏览器或 BizTalk 管理控制台创建的是物理端口。

    开发人员在业务流程设计器中创建“以后指定”端口时,他是在配置一个逻辑端口,将相应的物理端口属性留给 BizTalk 管理员在以后进行配置。 “以后指定”是最常使用的选项,关键原因是为了让管理员能够在生产环境中灵活地配置物理端口。

    使用“立即指定”选项,则开发人员完成所有配置(包括逻辑和物理配置),得到的解决方案是硬绑定的。 除了要进行快速试验以外,不建议使用此选项。

    使用“动态”端口时,物理端口属性的最终配置同样也是由管理员完成的。 但是,在这种情况下,开发人员还可以编写代码,在运行时设置特定出站消息属性。 这对于 SMTP 或 HTTP 非常有用,在这两种情形下,业务流程逻辑包括带有如下语句的“表达式”形状:

    DynamicSendPort(Microsoft.XLANGs.BaseTypes.Address)= 
        “mailto:john@contoso.com”;
    

    虽然图 2 中有许多选项,但此图中显示的仅是业务流程设计器中的选项。 “静态”端口适用于哪些环境? 当您在 BizTalk 浏览器或 BizTalk 管理控制台中创建物理端口时,会遇到这一术语。 如果开发人员在业务流程设计器中创建一个“以后指定”或“动态”端口(逻辑端口),那么管理员在 BizTalk 浏览器或 BizTalk 管理控制台中创建相应的物理端口时,将从图 3 中所示的四个选项中选择。

    学习 BizTalk Server 2006 编程

    如果您刚开始学习 BizTalk 编程,您会发现,如果查看 2005 年 11 月份的《MSDN 杂志》上由 Aaron Skonnard 主持的服务站专栏以及 2005 年 12 月专栏,将对您有很大帮助。 在 BizTalk Server 开发中心,您可以找到数十种免费的网络广播。

    如果您处于中级水平,请阅读由 Mark Beckner 编著,Apress 出版的 《BizTalk 2006 Recipes: A Problem-Solution Approach》;并阅读 2006 年 12 月份的《MSDN 杂志》中的 Alex Starykh dives into adapter programming topics(针对 BizTalk Adapters)。

    如欲获得中级到高级资料,请参阅由 George Dunphy 与 Marty 合著、Apress 出版的《Pro BizTalk 2006》,以及由 Darren Jefford 编著、Wrox 出版的《Professional BizTalk Server 2006》,在您阅读本文时,这两本书应该已经面世了。 不要因为看到标题中的版本号而感到失望;由 Scott Woodgate 编著、Sams 出版的《Microsoft BizTalk Server 2004》也是非常适用的。 这些书中包括几个使用 C# 代码将 BizTalk 带入更高级别的示例。

    为增强您在集成系统理论和设计方面的实力,您需要阅读由 Gregor Hohpe 编著、Addison-Wesley 出版的《企业集成模式》一书。 乍一看,您可能会认为这对您学习 BizTalk 不会有什么帮助,但是,了解一下 BizTalk Server 2006 如何隐式实现这几种模式是很有趣的。 如想了解有关技巧 1 的详细信息,以下由 Kurt Guenther 和 Charles Young 撰写的博客是很好的参考资料:

    对于技巧 4,请查看以下由 Brian Loesgen 和 Kevin Lam 撰写的专家博客:

    如欲了解更多 BizTalk 技巧,请参阅 Alan Smith 撰写的“七个习惯”一文和 Scott Colestock 撰写的有关 BizTalk 命名约定的短文:

    Close [x]

    请记住,“动态”物理端口对应于“动态”逻辑端口(相当简单),但“静态”物理端口对应于“以后指定”逻辑端口。 另外,要注意“要求响应”和“请求响应”这两个术语之间的不匹配。 就这些。

    完成了这些初步准备之后,我们终于可以讨论“直接绑定”端口的优势了。 “直接绑定”端口在将消息从 BizTalk 发送到 BizTalk 方面是很出色的。 顺便说一下,正是由于这一点,BizTalk 没有必要为 Web 端口提供“直接”选项。 Web 端口用于从 BizTalk 到 Web,而不是从 BizTalk 到 BizTalk。

    “直接绑定”端口是自我配置的,不会影响灵活性或性能。 “直接绑定”端口的便捷性在于开发人员和管理员都无需在 BizTalk 浏览器或 BizTalk 管理控制台中创建相应的物理端口。 因此,“直接绑定”端口会形成更独立的业务流程,因而可以更好地重复使用,而且更便于独立地重新部署。

    有以下三种“直接绑定”端口类型: 消息框路由、自我关联,以及业务流程到业务流程(也称为合作伙伴端口)。 这三个单选按钮在业务流程设计器中的实际文本要冗长得多,但是,您只要略加观察,就能轻松地把我们的这些短名称与 UI 上的名称相对应。

    在这三种端口类型中,“消息框”是最常使用的一类。 它允许您的业务流程完全独立于其他业务流程,尽管您可能只是让它与其自身通信。 没错,这确实意味着有可能出现无限循环。 我们马上就会谈到这一问题。

    如果为“消息框路由”配置了一个“激活”属性设置为 True 的“接收”形状,则意味着当消息到达符合给定的订阅筛选器的“消息框”时,将启动业务流程的一个新实例,不管消息来自何处,也不管发送给谁。 这可以帮助您构建一个可重复使用的业务流程,如工具库中的泛型函数。 Marty 使用此技巧构建了一个巧妙的基于消息的异常处理系统,此处暂且不论。

    假设您想用以下两种方法启动您的业务流程: 第一,操作员在某个文件夹中对单向静态 FILE(物理)端口发出“启动”消息;或者,第二,业务流程向其自身发送一个启动消息以运行另一个实例。 您首先想到的可能是使用一个“接听”形状(如,用于业务流程的 OR 运算符),并使它下面有两个“接收”形状(“以后指定”用于 FILE 端口,“直接”用于消息框)。 但“直接绑定消息框”端口的最妙之处恰恰是 — 它们不关心消息的来源。 因此,您只需要一个“接收”形状就可以启动此业务流程!

    “自我关联直接绑定”端口通常在您想要以异步方式将消息从一个业务流程发送到下一个业务流程时使用。 假定您有两个业务流程:A 和 B。只需进入业务流程 B,在参数部分下创建一个逻辑“发送端口”,并将其设置为使用在业务流程 A 中创建的“端口类型”。现在,您通过业务流程 B 中的该端口发送的任何消息都将立即路由到您在业务流程 A 中创建的逻辑“接收”端口。基本上,我们利用 BizTalk 的发布/订阅特性来转发消息,此外还通过隐藏的独特的关联令牌为这些消息加盖印记,因此称为“自我关联”。 在这种情况下,由于您在各业务流程之间共用一种端口类型,因此各业务流程都对其他业务流程有所了解。 您可以将“端口类型”上“操作”的“消息类型”设置为 System.Xml.XmlDocument,从一定程度上减小依赖性。这是使业务流程异步运行,同时使某种 broker 能够接收来自其他业务流程的主动确认或被动确认的一种很好的方法。

    业务流程到业务流程直接绑定(合作伙伴)端口用于以异步方式发送消息。 您将向订阅中添加与使用“消息框直接绑定”端口时相比更宽泛的限制。 在这种情况下,也就是说您将接受来自合作伙伴业务流程的任何消息。 一个业务流程指定“直接绑定”端口,另一个业务流程(合作伙伴)指定自身。 发送方或接收方都可以成为引用“直接绑定”端口的一方。 这里的关键是,您将把两个已知的解决方案连接起来进行通信,而使用“消息框直接绑定”端口时发送方和接收方之间的耦合更松散。

    接下来介绍有意思的部分。 使用“直接绑定”端口(特别是使用“消息框”)时常见的缺陷是会造成无限循环。 假设一个简单的业务流程只包括两个形状,“激活”被设置为 True 的“接收”形状(当然是“直接绑定”)和仅将消息转发给 FILE 端口的“发送”形状。 当此业务流程发出消息后,消息将去往何处? 和其他情况一样,首先进入消息框。 一旦消息达到消息框,BizTalk 就会进行搜索,看有没有匹配的订阅。 此消息如何与最先激活业务流程的消息区分开? 无法区分。因此 BizTalk 会不假思索地触发业务流程的另一个实例来处理它,以此类推,直到耗尽内存。 修复此问题的一种方法是将入站消息复制到一个新构造的出站消息,并更改至少一个提升的属性的值,以便“接收”形状上的订阅筛选器无法与新消息匹配。 运行管理控制台,并转到“组中心”|“新建查询”|“打开查询”。 下一步是打开 BizTalk\SDK\Utilities 文件夹中的 BTSSubscriptionViewer.btq。 您将看到,在您为“接收”形状设置消息类型时,BizTalk 将自动创建一个谓词。 在“业务流程设计器”中,将一个谓词添加到“筛选器表达式”属性中,完整订阅将如下所示:

    BTS.MessageType == “http://MyInternalSchemas.MyProject#MyRootNode”
    AND inbound_message(status) != 1
    

    或者,如果您不愿意像上面所说的那样更改架构以添加自定义字段,还可以向“接收”形状上的订阅筛选器中添加一个子句来测试 BTS.Operation 名称与您的业务流程中的名称不同。

    我们前面说过,BizTalk 的目的旨在处理消息,还记得吗? 嗯,回想一下。 实际上也就是订阅。 在 BizTalk 中,在发送端口或业务流程上对消息所做的操作无非就是订阅。

    Back to top

    3. 始终使用单独的内部和外部架构

    您应始终将接收到的消息转换为您自己的规范架构,不管架构的简单程度如何,也不管它的源是谁。

    对于少量的处理,一旦(更恰当地说是“当”)发送方更改架构时,此做法将使您获得很大程度的灵活性。 您不希望您的业务流程逻辑依赖于由其他人控制的架构中的任何属性或字段。 在发送方更改其架构时,您只需更改您的映射,而不是业务流程。 这同样运用了中间环节的公理。

    通过遵循为映射、业务流程、内部架构和外部架构创建单独的 Visual Studio 项目这一最佳做法,可以更轻松地重新部署您更新的解决方案。 这对于 BizTalk Web 服务发布向导生成的 Web 服务确实至关重要。

    如果您想偷懒,那么不创建自己的带有新字段名称的架构也可以。 只要复制为您提供的入站架构,并将所有字段按照原样从源架构中映射出来即可,但至少要将副本保存到您的内部架构项目中,自己给它取个名称。

    这样做还可以减少您需要的映射数。 假设您需要将三种类型的入站消息映射到三种类型的出站消息(可能不是现在,而是在将来)。 应用此技巧,您可以为每个入站架构创建一个到您的规范架构的映射,然后创建从您的规范架构到每个出站架构的映射。 这样一来只需构建和维护六个映射,而不是九个。

    使用禁忌

    BizTalk Server 2006 是一个大型应用程序,幸运的是,它通常会为完成一些事情提供几种方法。 但是由于各种各样的原因,一些方法存在陷阱,多数有经验的使用者现在已经知道远远避开它们:

    1. 避免使用 BizTalk Server 2006 中的 BizTalk 浏览器。此功能在 BizTalk Server 2004 中至关重要,因此,Microsoft 决定不将它从 BizTalk Server 2006 中去除,但新的应用程序打包功能和经过重新设计的 BizTalk 管理控制台已使其成为多余的。 不幸的是,在某些情况下使用它会造成麻烦。
    2. 在 Visual Studio® 2005 解决方案资源管理器中,永远不要在“项目”一级上单击“部署”。 在解决方案中独立构建项目是可以的,但您只应在“解决方案”一级上单击“部署”。 原因是: Visual Studio 会尝试自动跟踪依赖关系,而单独为 BizTalk 部署程序集可能会导致它无法进行跟踪。
    3. 不要指望不仔细编辑命名空间属性(以确保匹配)就能将架构文件 (.XSD) 从一个项目复制到另一个项目。 记住这一点,不然您肯定会遇到让您大为头疼的问题。
    4. BizTalk 专家从不使用 Quick Promote。 等到您采取必要的步骤来纠正它提供给您的类型时(假如您还记得这样做),您会发现其实您自己本来可以快速显式地创建这些类型。
    5. 不要将映射放入业务流程中,除非您需要将多个传入消息映射到一个消息中,或者您需要以现有消息的经过修改(映射后)的内容为基础生成一条新消息。 为简化部署,最好将您的映射放到“接收”和“发送”端口上。 如果您的业务合作伙伴对其架构进行了修改,或者如果您添加了需要新映射的新合作伙伴,您将不得不同时更新您的架构和业务流程,而这不是您所希望的。

    Close [x]

    Back to top

    4. 永远不要在 WSDL 中直接公开您的内部架构

    也就是说,您永远不应单击 BizTalk Web 服务发布向导中的第一个单选按钮;而应始终单击第二个按钮(请参见图 4)。 第一个单选按钮用于发布业务流程,第二个单选按钮用于纯消息处理解决方案,然而使用第二个选项发布业务流程也不失为一个好主意。

    图 4 发布您的外部构架,而不是业务流程
    图 4 发布您的外部构架,而不是业务流程 (单击该图像获得较小视图)

    图 4 发布您的外部构架,而不是业务流程
    图 4 发布您的外部构架,而不是业务流程 (单击该图像获得较大视图)

    是的,这样一来就更复杂了,您肯定希望我们给出合适的理由。 理由是:接口。 如果您想要更详细的解释,那就是松散耦合! 这样做使您在更改业务流程时具有更大的自由性,无需中断调用方。 您可以将这一点看作是技巧 3 中概念的特殊化。

    接下来我们讨论一下如何实现这一点。 下面是关于此向导要记住的一点: 进入步骤 2 后,您需要右键单击“Web 服务”对话框(请参见图 5)中的几乎每一项。 您将通过这种方式对您创建的 Web 服务及其方法进行命名。

    图 5 在“Web 服务”对话框中编辑您的 WSDL
    图 5 在“Web 服务”对话框中编辑您的 WSDL

    开始在 Web 服务发布向导中执行此步骤之前,您需要在 BizTalk 中编译您的架构项目,以便您能够浏览到程序集。 实际上,正如您将在下面将看到的一样,在运行此向导之前继续部署您的解决方案是很有必要的。 此外,当您将业务流程发布为 Web 服务时,在构建和部署之前,您必须将业务流程端口类型上的“类型修饰符”属性从“内部”更改为“公用”。 如果您在最初创建此端口时没有更改此属性,那就要下相当大的工夫才能找到它(在“业务流程视图”中的“类型”窗格中突出显示此端口类型 — 而不是在显示不同属性集的“端口图面”上单击此端口)。 将架构发布为 Web 服务的另一个好处是您再也不用执行此操作了!

    好了,让我们回到此向导,现在来看看图 5。 您需要右键单击“请求”和“响应”节点以选择 Web 消息所基于的架构。 您发布的业务流程通常会具有用于与 Web 服务的调用方通信的一个逻辑“接收”形状和一个“发送”形状。 这些形状将具有关联的消息,而这些消息将有一个架构类型(不需要多部分消息类型,只是建议采用)。 因此,您需要告知此向导使用您的面向外部的架构(记住技巧 3)。 然后,您将使用“接收”端口中的映射(入站和出站映射)将 Web 服务请求和响应架构转换为您的业务流程所期望的内部架构。 当客户端添加对您的 Web 服务的引用时,他将得到一个代理类,其中包括您的面向外部的架构的类型。 客户端将使用该类型创建并填充一个要发送到您的 Web 服务的请求消息。 此外,他将把来自您的 Web 服务的响应添加到一个对象中,此对象基于您在图 5 中指定的外部响应架构。

    您还要记住在“接收”位置选择“XML 管道”,否则,BizTalk 将不会创建“BTS 消息上下文”属性 — 这些属性中的其中一个是传入 Web 服务消息的“消息类型”。 BizTalk 了解此“消息类型”(因为它曾通过管道中的“XML 反汇编程序”解析此消息类型并提升该属性),并使用该类型执行映射,以将请求转换为业务流程期望的类型。

    真正重要的是,您在此向导中选择的操作名称必须与您在业务流程的逻辑端口中指定的操作的名称完全匹配。 完全接受每个名称的默认值是不可行的,因为业务流程设计器中默认的操作名称为“Operation_1”,而向导中默认的名称为“WebMethod1”(请参见图 5)。 用动词 — 名词格式(如 UpdateInventory)将其设置为具有特定意义的名称是一种不错的做法。

    请记住,各种消息(甚至包括传入 Web 服务请求消息)是基于订阅发送到业务流程的。 当您将一个逻辑端口绑定到一个物理端口时(这是在将“请求响应”端口发布为 Web 服务时的一项要求(即使是通过架构发布),BizTalk 将为您创建一个自动订阅。 您可以从 BizTalk 管理控制台中通过以下方法查看订阅:在查询窗口中选择“Subscriptions”作为值。 订阅与通常为其他逻辑到物理端口创建的非“直接绑定”的 SOAP 略有不同。 BizTalk 为业务流程创建的常规订阅将如下所示:

    http://schemas.microsoft.com/BizTalk/2003/
    system-properties.ReceivePortID == {some Guid}
    AND
    http://schemas.microsoft.com/BizTalk/2003/system-properties.MessageType == 
    http://schemas.someschema#Root
    AND
    http://schemas.microsoft.com/BizTalk/2003/
    system-properties.InboundTransportType != SOAP
    OR
    http://schemas.microsoft.com/BizTalk/2003/
    system-properties.ReceivePortID == {some Guid}
    AND
    http://schemas.microsoft.com/BizTalk/2003/soap-properties.MethodName ==
     {Inbound Operation Name on Logical Port}
    

    您会发现,您键入到向导中用作 MethodName 的名称必须与业务流程中该逻辑端口的“操作”名称相匹配,否则,映射的 Web 请求消息将无法发送到业务流程。

    当您进入向导中的“Web 服务项目”对话框时,请输入您的 Web 服务的 URL,例如: http://localhost/MyBizTalkWebService。 另外,您还可以让 BizTalk 在应用程序中为您创建接收位置。 因为您已部署了应用程序,所以在此您可以从下拉列表中选择它。 要了解有关以上所有内容的更多详细信息,请务必查看 BizTalk 帮助文件中名为“如何使用 BizTalk Web 服务发布向导将架构发布为 Web 服务”一文。

    我记得我们说过 BizTalk 的核心就是订阅,但这并不是我们的最终答案。 通过后两个技巧提示,您会发现它的核心实际上是架构。 每个消息和每个映射都依赖于一个(或两个)架构,所以掌握架构对于熟练使用 BizTalk 至关重要。

    Back to top

    5. 始终为 Web 服务优化 BizTalk 注册表

    如果您的 BizTalk 业务流程被发布为 Web 服务,那么您一定想要调整 BizTalk 使用的一些默认的 ASP.NET 参数。 实际上,这些参数会影响任何使用 CLR 的 BizTalk 项目,包括 XLANG。 BizTalk 会自动将这些建议的值乘以您拥有的 CPU 数。 具体步骤如下:

    1. 在修改注册表前,首先对其进行备份。

    2. 在记事本中创建一个包含以下代码的文件。

    Windows Registry Editor version 5.00
    
    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\BTSSvc$BTSHOST\CLR Hosting]
    “MaxIOThreads”=dword:00000064
    “MaxWorkerThreads”=dword:00000064
    “MinIOThreads”=dword:00000019
    “MinWorkerThreads”=dword:00000019
    

    在以此方式创建了文件之后,您可以在其他运行 BizTalk 的计算机上轻松地重复使用它。 DWORD 值是以十六进制形式表示的(注册表脚本不使用标准的 0x 前缀表示十六进制值)。

    3. 用您的计算机的 BizTalk 主机名称替代字符串“BTSHOST”。 您可以首先运行 RegEdit 来检查主机上的实际密钥名称。

    4. 如果您将文件保存为 .REG 格式,那么双击此文件就能使其在您的 BizTalk 安装上运行。

    5. 运行 RegEdit 并导航至 CLR Hosting 项以验证是否已正确添加了这些值。

    请参阅 msdn2.microsoft.com/en-us/library/aa561380.aspx,以了解有关此优化过程及其他优化过程的更多详细信息;并参阅 msdn2.microsoft.com/en-us/library/aa475435.aspx,以查看有关针对低延迟消息处理的性能优化方面的优秀文章。

    Back to top

    6. 始终使用相对路径设置程序集密钥文件

    此技巧将帮助您从版本控制中找到解决方案并在另一个主机上构建它。 您的团队中的一些开发人员可能会用不同的驱动器号来设置其环境,将来您也可以更改您的驱动器号。 这确实非常简单,但是您可能还想了解这些点以后的情况。

    建议让解决方案的第一个开发人员在 Visual Studio 解决方案文件 (.sln) 所在的文件夹中创建一个强名称密钥文件。 然后,创建该解决方案文件夹的子文件夹,用于按项目类型(如映射、管道、业务流程、内部架构、外部架构,以及您正在编译的任何 .NET 组件)存放每个 Visual Studio 项目。 顺便说一下,不管您曾经多少次听到此建议,都不必将其视为严格的规则。 如果您了解某些项目将来可能要一起修改(如映射及其架构),那么您就应将它们放在同一项目中,以减少必须重新部署的组件的数量。 在开发过程中,我们可以在解决方案中的各项目之间以及在各开发人员之间共享同一密钥文件。 (为运行环境创建安全的密钥文件是另一回事。) 只需将密钥文件与解决方案中的其他项目一起签入到版本控制中即可。 现在指明解决方案中每个程序集的密钥文件的路径。 对于 BizTalk 项目来说指明路径的方法是“..\..\..\Key.snk”,如图 6 中所示。 这一方法之所以可行,是因为 BizTalk 在名为类似 [YourSolution]\[YourProject]\bin\Development 的子文件夹中生成您的二进制文件。 因此,三个父目录跳转使 BizTalk 返回到您的包含密钥文件的解决方案文件夹。

    图 6 为 BizTalk 项目配置程序集密钥文件
    图 6 为 BizTalk 项目配置程序集密钥文件 (单击该图像获得较小视图)

    图 6 为 BizTalk 项目配置程序集密钥文件
    图 6 为 BizTalk 项目配置程序集密钥文件 (单击该图像获得较大视图)

    注意,如果您要向您的解决方案中添加多个 .NET Framework 类库项目,而使用与 BizTalk 项目略有不同的目录结构对这些项目进行编译,那么用于设置密钥文件路径的 Visual Studio UI 一定不允许您输入相对路径。 一种解决方案是将 .csproj(针对 C#)或 .vbproj(针对 Visual Basic®)作为文本文件进行编辑。 搜索您在 Visual Studio 项目属性 UI 中浏览到的密钥文件的名称,然后用一个只包含一级父目录的相对路径(如,..\Key.snk)替换它。 在每次生成后,不要忘记将您的 .NET Framework 程序集添加到 GAC 中。 利用 Visual Studio 中的生成后步骤可以自动实现这一点。 它只需要完整路径和用引号引起来的字符串以及空格,格式如下所示(全部在同一行中):

    “C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe” /i “$(TargetPath)” /F
    

    Back to top

    7. 永远不要忽视免费的示例代码

    下面是一个非常有意义的小技巧。 BizTalk 帮助文件收录了 50 多个示例应用程序和脚本(安装在 SDK\Samples 文件夹中),您可以从中学习,对其进行修改和重新使用。 在以下页上您还可以找到 30 多个有用的 BizTalk 应用程序: msdn2.microsoft.com/en-us/biztalk/aa937647.aspx。 最后,BizTalk 博客作者指南(位于 GotDotNet.com)中涵盖了 400 多篇技术文章,其中包括许多有用的代码段和示例。 我将此博客作者指南的快捷方式保存到我的桌面上,这是在进入新的 BizTalk 领域时我首先会去看的地方之一。

    我们承认,如果您已经知道了这一点,您可能会认为这个技巧提示没什么稀奇。 但考虑到除此之外很难找到专业水准的 BizTalk 示例代码,我们认为需要提醒您还是应该将它放在手边。 问题是,这些示例不光在您开始了解 BizTalk 时非常有用,它们还是可供反复查阅的宝贵参考资料。

    顺便说一下,不要忘记经常回到 MSDN 查看 BizTalk 帮助文件,它是定期更新的。 您可以以 PDF 或压缩的 .chm 格式下载它,也可以在线浏览。

    Back to top

    8. 在 Visual Studio 中调试 XSLT

    这可能是 Visual Studio 中最鲜为人知的功能了,它不需要安装 BizTalk。 XSLT 调试器使您能够在其运行时查看转换的结果、设置断点、检查局部变量和调用堆栈。 您甚至可以从 C# 或 Visual Basic 单步执行您的 XSLT 脚本。

    图 7 显示了一个正在运行的转换示例。 我刚刚创建了一个空白的解决方案,并加载了以下这个将转换为 HTML 格式的很小的 XML 数据文件:

    图 7 Visual Studio 中的 XSLT 调试器
    图 7 Visual Studio 中的 XSLT 调试器 (单击该图像获得较小视图)

    图 7 Visual Studio 中的 XSLT 调试器
    图 7 Visual Studio 中的 XSLT 调试器 (单击该图像获得较大视图)

    <?xml version=”1.0” encoding=”utf-8”?>
    <node attr=”debug” />
    
    然后,我进入 XSLT 文件(您可在图 7 的左窗格中看到)。它将创建一个 Hello World 文档,而如果节点元素有一个 attr 属性等于“debug”,它也会启动调试。

    现在,将光标放在 XSLT 文件中(这一点很重要),将“输入”属性设置为您将要转换的 XML 数据文件的路径。 注意,在“解决方案资源管理器”窗口中右键单击 XSLT 文件名将显示一组不同的属性,这是“文件”属性,不是“文档”属性。 我希望上述过程更加直观,但是现在只要一学就能掌握。 如果说专业级人员与水平一般的人员有何区别的话,那就是探索精神。 您还可以设置“输出”属性,或体验中间窗格中所示的转换过程。

    当 Visual Studio 中的活动文档为 XSLT 文件时,下拉 XML 菜单(位于主菜单栏上)包括 Debug XSLT 命令。 只需单击此命令即可查看转换代码,甚至深入查看子例程。 图 7 显示了程序执行完 xsl:if 测试后“监视”窗口中 @attr 的值。 正如您可从中间窗口的输出看到的那样,测试结果为 true,并且 <h1> 节点为输出。

    Back to top

    总结

    考虑到当前公司正在开发的应用程序数量如此之大,使用较好的工具和技术尽快开发出可行的解决方案至关重要。 BizTalk 将帮助您高效地完成从概念到工作原型的过程,同时我们希望这些技巧提示将在您的工作中为您节省一些时间。

    Back to top


    Marty Wasznicky(MCSE、MCSD、MCDBA、MCTS)是在 Microsoft Connected System 部门中负责 BizTalk Server 的地区项目经理。 他帮助客户和 Microsoft 合作伙伴采用和实施这一领域的 Microsoft 解决方案。 目前,他致力于研究面向软件的体系结构和企业服务总线技术。 他和妻子一起生活在洛杉矶。
    Scott Zimmerman(MCSD、MCTS)是 Microsoft 的一名资深应用程序开发顾问,专门提供 BizTalk 和 .NET 方面的咨询。 他曾两次荣获 Web 服务设计奖,八次在世界飞碟锦标赛中夺冠。 他和妻子 Vera 一起生活在华盛顿特区。

    August 09

    もっと今以上 に私を污して----现在这样的我 不再是单纯的我

    这些日子一直在普通的项目和BizTalk项目之间徘徊,常常写着写着一个项目就会立马切到BizTalk的服务器那边去调整一些配置和部署。再加上晚上会继续BizTalk之旅,相比之前的SAP研习,这次在微软强大的doc帮助,众多开源资料的支持下,进程也是相对比较乐观的。

    唉,同样都是中间件,虽然biztalk的功能,整合都没有SAP来的那么猛,价钱也没有那么玄乎,可是对于开发人员来说就是很人性化,开放,自由是推动软件产业前进的动力,自守一隅终究是会被别人赶上而淘汰的。何况这个追赶的人又是业界巨人呢?

    这些日子,每周基本上工作55小时左右,周一,二,四的晚上会继续,周三会放个小假稍早点回家:)呵呵,觉得挺对不起父母的,家成了睡觉的地方。

    大学的时候,每周日会早早的回到寝室,在阳台上架好椅子,泡上一杯咖啡,趁着午后慵懒的阳光,看会儿杂志,等小胖给我带些好吃的上来。真的很舒服的日子:)

    August 07

    biztalk中使用.net class类型的消息(一)

    一. 概述... 1

    二. 消息的结构... 1

    三. 消息的类型... 2

    1. 平面文件... 2

    2. Xml文档... 2

    3. .net class. 2

    4. 二进制数据... 2

    四. .net class类型的序列化... 2

    五. .net class类型的消息... 3

    1. 类要设置为可序列化... 3

    2. 类中只包含公共属性和字段... 3

    3. 设置名称空间... 3

    4. 设置可分辨字段和升级属性... 3

    4.1. 设置可分辨字段... 3

    4.2. 设置升级属性... 3

    5. 一个.net class消息类型的完整代码... 4

    六. Biztalk如何处理.net class类型的消息... 5

    七. Orchestration中从零开始新建一个xml类型的消息... 5

    1. 在消息构造形状中构造新xml消息... 5

    2. 在消息构造形状中构造新.net class类型消息... 5

    3. 从零开始构造新xml类型消息... 6

    3.1. 设置xml文件属性... 6

    3.2. 写一个从嵌入资源中读取xml文件内容的方法... 6

    3.3. 在消息赋值形状中调用读取xml文件的方法... 7

    一. 概述

    一般来讲,在biztalk项目中使用的消息都是基于xsd的xml消息,因为这是biztalk最擅长处理的消息。Biztalk整个体系架构都是建构在xml基础之上,在biztalk内部用xml来处理消息,在message box的存储形式也是xml。

    但是这并不表示biztalk只能处理xml消息,事实上,biztalk可以处理消息类型可以是平面文件、xml类型、可序列化的.net class或者其他任意的二进制数据流。

    这里要讨论的是在biztalk中,尤其是在orchestration中如何使用.net class类型消息。

    二. 消息的结构

    BizTalk中每条消息都可视为多部分消息,此消息可以由零个或多个部分组成。具有一个或多个部分的消息都具有一个标识为正文部分的部分(但是只能有个一部分标识为正文)。每个部分均由可表示 XML 文档、平面文件、序列化的 .NET 类或其他二进制数据流的二进制数据块组成。

    一般的开发biztalk项目体验中,大多是新建一个消息,然后给这个消息指定一个xsd作为这个消息的类型。感觉上一个消息就只能指定一个xsd类型(也可以指定为一个序列化的.net class类型),跟一个xsd相关。其实这样通过这样方式建立的消息也是多部分消息,只是这个消息只有一个正文部分而已。

    如果要建立真正有多个部分的消息类型,可以在orchestration view面板中的Types窗格中,展开Types,在Multi-part Message Types下新建一个多部分消息类型,在新建的多部分消息类型中可以建立多个部分,每个部分分别指定类型,还要指定其中的一个部分为正文部分。以后新建消息把消息类型指定为这个多部分消息类型,这个新建消息就是一个具有多个部分的消息了。

    注意

    任何消息在biztalk的表现都是一个多部分的消息,不过一般的消息只有一个正文部分。

    三. 消息的类型

    从上面的叙述可以得知,每个消息其实都是多部分消息,一般来讲每个消息至少有一个部分,也可能有多个部分,不管是只有一个部分还是有多个部分,其中必须有一个部分被指定为正文部分,整个消息的类型就由正文部分的消息类型决定。如果正文部分分别为以下情况时,如何确定消息的类型:

    1. 平面文件

    平面文件进入到biztalk都会在接收管道中都会被平面文件拆装器拆解为xml的格式,有一个经过平面文件扩展后的xsd架构跟其对应,所以平面文件可以被认为也是xml的消息类型。参看下面的xml文档部分。

    2. Xml文档

    Xml消息的消息类型由xml消息的命名空间(后接 # 符号)和xml消息根节点的名称组成。比如,一个xml消息的根结点的名称空间是“http://tempuri.org/samples/MessageType”,xml消息的根结点的名称是Message,那么这个消息的类型就是:http://tempuri.org/samples/MessageType#Message

    3. .net class

    .net class类型的消息同样是由名称空间加上根元素名称组成。

    .net class类型的消息的名称空间由class类的System.Xml.Serialization.XmlRootAttribute属性指定,在定义.net class类时可以在类名前加上相关attribute来指定这个类的一些类级别的attribute(请参考第五部分“.net class类型消息”中的详细定义一个.net class的完整代码),System.Xml.Serialization.XmlRootAttribute中用Namespace参数指定此类的名称空间。

    定义.net class的类名就相当于xml类型的根元素。

    “名称空间#类名”就是.net class消息的消息类型,跟一般xml消息一样,.net class消息类型也可以作为订阅消息的条件。

    4. 二进制数据

    二进制数据流的消息类型需要由定制的接收管道把消息类型升级到消息的上下文,一般的二进制数据流的消息类型使用全限定的类型名。

    这种情况这里不加讨论,如有必要,以后用专文来探讨二进制数据流消息的情况。

    四. .net class类型的序列化

    Biztalk中的消息必须是可以序列化的,原因很简单,biztalk中消息不管是从外部进来,还是由orchestration产生的消息,统统都要被保存在Message Box数据库中,要能被保存在数据库中持久保存,消息就必须能被序列化。

    还有一点,在长时间运行的orchestration中,运行的周期可能是一天、几天、十几天,甚至可能几个月。在这么长的时间中,一个orchestration实例由始至终都运行在内存中是及其不明智的做法,将耗费大量的资源。所以biztalk设计了一个dehydrat(分解)和rehydrat(重组)的机制,在orchestration实例空闲的时候,把orchestration实例和相关的状态和消息序列化保存到数据库,一旦有消息激活这个orchestration实例时,再把这个orchestration实例和相关状态消息反序列化到内存继续运行。

    对.net class序列化Dotnet框架支持两种序列化方式,可以把类序列化为xml格式,也可以把类序列化为二进制格式。

    二进制序列化是把对象转换成一串二进制的数据流,二进制序列化保持类型保真度,可以最真实的保存一个对象的全部状态。

    Xml序列化是把对象转换成一个xml文档,XML 序列化仅序列化公共属性和字段,且不保持类型保真度。但对于biztalk应用中使用的.net class一般就是使用了类的公共属性和字段。

    Biztalk内建直接支持.net class序列化,就是说在biztalk中使用.net class的消息不用开发者自己考虑.net class消息如何如何序列化和反序列化。Biztalk内建.net class消息序列化使用的是xml序列化方式。

    二进制序列化方式不是biztalk内建支持的序列化方式,可以选择对.net class消息进行二进制的序列化,但是这需要开发者做更多的工作,需要写代码对消息进行二进制的序列化和反序列化,并定制自己的拆装器和组装器对消息进行序列化和反序列化的工作。

    本文只讨论xml序列化的方式,对于二进制序列化的方式,如有必要以后再用专文讨论。

    五. .net class类型的消息

    Biztalk中使用.net class需要考虑作为消息的特点,跟一般的类有些不同,一般要注意以下几点:

    1. 类要设置为可序列化

    在定义类前加上表示可以序列化的attribute:[Serializable()]

    2. 类中只包含公共属性和字段

    一般类中的公共属性和字段会被转换为xml文档中的元素,私有属性没什么意义,方法对转成xml也没什么意义。

    3. 设置名称空间

    名称空间是构成消息类型的一部分,.net class转成xml也可以带有名称空间,看下面的代码,名称空间由定义类前的“[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://myURL")]”设置,表示这个类转成xml的Target Namespace是"http://myURL"。

    另外类的名称就相当于xml的根元素名称,跟上面的名称空间一起组合成消息的类型。

    如果没有设置名称空间,则此.net class消息的类型就是类名称。

    4. 设置可分辨字段和升级属性

    在.net class类型中同样可以设置可分辨字段和升级字段。

    4.1. 设置可分辨字段

    设置可分辨字段很简单,在需要设置的公共属性或字段前加上“[DistinguishedField]” attribute即可,表示这个公共属性或字段已被设置为可分辨字段。

    4.2. 设置升级属性

    设置升级属性同xsd中设置升级属性类似,首先也先有一个属性架构,然后在需要升级为属性的公共属性或字段前用“Property”attribute指定关联到哪个属性。如下面的代码中的:

    [Property(typeof(netClassMessage_PromoteXSD.PropertyName))]

    public string PropertyName

    这表示要把公共属性PropertyName升级,并关联到属性架构netClassMessage_PromoteXSD中的PropertyName属性。

    5. 一个.net class消息类型的完整代码

     1using System;
     2using Microsoft.XLANGs.BaseTypes;
     3
     4namespace netClassMessage_netClass
     5{
     6 //表示此类是可以序列化的
     7    [Serializable()]
     8 //此属性设置目标名称空间Target Namespace
     9    [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://myURL")]
    10 //类名称相当于XSD中的根元素,上面设定的名称空间加上类名称就组成了消息类型
    11 public class netClass
    12 {
    13 private string _ID;
    14 private string _name;
    15 private string _address;
    16 private string _propertyName;
    17 public netClass()
    18 {
    19            _ID = System.Guid.NewGuid().ToString();
    20        }
    21 //DistinguishedField属性表示这个字段是可分辨字段
    22        [DistinguishedField]
    23 public string ID
    24 {
    25 get
    26 {
    27 return _ID;
    28            }
    29 set
    30 {
    31                _ID = value;
    32            }
    33        }
    34        [DistinguishedField]
    35 public string Name
    36 {
    37 get
    38 {
    39 return _name;
    40            }
    41 set
    42 {
    43                _name = value;
    44            }
    45        }
    46        [DistinguishedField]
    47 public string Address
    48 {
    49 get
    50 {
    51 return _address;
    52            }
    53 set
    54 {
    55                _address = value;
    56            }
    57        }
    58        [DistinguishedField]
    59 //netClassMessage_PromoteXSD.PropertyName是在属性schema中定义的属性,此Property属性
    60 //指示这个字段为promote字段,对应netClassMessage_PromoteXSD.PropertyName
    61        [Property(typeof(netClassMessage_PromoteXSD.PropertyName))]
    62 public string PropertyName
    63 {
    64 get
    65 {
    66 return _propertyName;
    67            }
    68 set
    69 {
    70                _propertyName = value;
    71            }
    72        }
    73    }
    74}

    六. Biztalk如何处理.net class类型的消息

    .net class类型的消息从外部进入biztalk,.net class类型消息在进入到biztalk时的存在形式必定是被序列化后的xml形式(这里只讨论xml序列化的情况)。

    所以,对入站的.net class类型消息需要使用xml拆装器,.net class类型消息序列化后同样有名称空间和根元素,并且也跟一般的xml消息类型一样,名称空间和根元素也决定了这个.net class消息的消息类型。

    同样,.net class消息根一般xml消息一样根据消息类型被路由到订阅此消息的orchestration。

    .net class消息在orchestration中的存在形式还是xml形式,只有在消息构造形状中对.net class消息进行构造或赋值的时候,biztalk引擎会对消息做相关的序列化和反序列化的工作,以便对.net class消息进行相关的处理。在消息构造形状以外,.net class消息的存在形式就是xml。

    七. Orchestration中从零开始新建一个xml类型的消息

    在orchestration,一个消息一旦被构造完成,这个消息就不再被允许有任何改动,就是不能被修改了。如果要修改这个消息,必须重新在消息构造形状中构造一个新消息,然后修改新的消息,新消息一旦出了构造形状就算构造完成。

    构造xml消息和构造.net class类型消息有所不同,下面分别列出

    1. 在消息构造形状中构造新xml消息

    l 通过map映射,map映射把源架构的消息映射到目标架构的消息,在转换的同时把消息值赋给了新的目标架构的消息,构造了一个新的消息。

    l 通过消息赋值语句,赋值语句把同类型的消息赋给一个新的消息,构造了新消息。

    l 通过把XmlDocument赋值给消息,xml消息的本质就是一个xml,所以可以把一个XmlDocument类型的变量直接赋给xml消息,当然,这个XmlDocument要是跟这个消息兼容的,XmlDocument要符合这个xml消息的架构。

    2. 在消息构造形状中构造新.net class类型消息

    只能通过new操作符构造新.net class类型消息,.net class类型消息首先它是一个.net的类,可以通过new操作符来新建一个此类的对象。

    3. 从零开始构造新xml类型消息

    如果一个.net class类型消息从外部进入到orchestration,在orchestration中对这个.net class类型消息进行处理转换,无外乎会有两种情况:一种是把这个消息赋值给同类的或者另一个.net class的消息,然后对新消息进行处理。更多的情况是,要把这个.net class消息转换成一个xml的消息,然后处理这个xml消息。

    对于第一种情况简单,只要用new操作符新建一个.net class类型的消息,然后进行赋值或者修改新消息的属性等等即可进行相关处理。

    但是对于第二种情况就比较麻烦,用map吧,map只支持从xml消息到xml消息的转换,不支持.net class消息的转换。用赋值语句吧,xml类型和.net class类型不是同类型,不能直接赋值。如果xml消息类型可以用new操作符新建一个新消息多好,可是,目前还不行,不能跟一般的.net类一样通过new操作符来新建一个对象。

    但是这里又必须要先新建一个xml类型的消息,有了这个xml消息,才能把.net class类型的消息的相关属性转移到这个xml类型的消息。

    从零新建一个xml类型消息(from scratch)在biztalk中是个比较麻烦的事,上面提到的通过把XmlDocument赋值给xml消息好像是目前的唯一方法。

    这种情况大致需要做以下的事情:

    在orchestration中新建一个XmlDocument类型的变量,比如变量名为xmlDocVar,要构造的xml消息为xmlMsg,然后在消息赋值形状表达式中

    xmlDocVar.LoadXml(“xml字符串”);

    xmlMsg = xmlDocVar;

    其中的“xml字符串”是一个跟xmlMsg消息的架构相容的一个xml样例的文本。赋值以后,就可以对xmlMsg进行各种操作了,把可分辨字段或升级属性修改为需要的值。

    把xml样例文本直接放在硬代码里面不太方便,也不灵活,比较好的做法是把xml文本放在一个xml文件中,从文件中读取xml文本。

    上面的例子可以变成这样:

    xmlDocVar.LoadXml(“xml文件名”);

    xmlMsg = xmlDocVar;

    其中的“xml文件名”是xml样例文件的完整路径,这样如果要修改xml样例文本直接修改这个文件就行了,不用去改硬代码。

    但是这样会给部署带来问题,项目部署以后这个xml文件往哪放,biztalk项目其他的资源都是dll,被部署到GAC中,就这么个xml文件孤零零的要找个地方放,虽说也没什么问题,但总觉得不很舒服,至少这个办法不够优雅。

    其实还有一个更舒服的办法,就是把这个xml文件作为一个嵌入资源,把它嵌入到项目生成的dll中,一起被部署到GAC中,读取的时候也到这个dll中读取。这需要做些额外的编码工作,步骤如下:

    3.1. 设置xml文件属性

    在解决方案资源管理其中,选中这个xml文件,查看它的属性,把“生成操作”这一项,改成“嵌入的资源”,这样这个xml文件就会被嵌入到编后的dll文件中。

    3.2. 写一个从嵌入资源中读取xml文件内容的方法

    在跟这个xml文件同一个项目中,新建一个类,这个类只有一个静态方法,这个方法根据提供的xml文件名,在assembly中找到嵌入的xml文件,返回这个xml文件对应的XmlDocument的对象。

    这个方法的完整代码如下:

     1using System;
     2using System.Collections;
     3using System.IO;
     4using System.Reflection;
     5using System.Xml;
     6
     7namespace netClassMessage_netClass
     8{
     9 public class EmbeddedResourseProcessor
    10 {
    11 public static XmlDocument GetXmlDocResource(string fileName)
    12 {
    13            XmlDocument doc = null;
    14            Type type = MethodBase.GetCurrentMethod().DeclaringType;
    15            Assembly _assembly = Assembly.GetExecutingAssembly();
    16 string _namespace = type.Namespace;
    17
    18 string resourceName =  _namespace + "." + fileName;
    19
    20            Stream stream = _assembly.GetManifestResourceStream(resourceName);
    21            doc = new XmlDocument();
    22            doc.Load(stream);
    23 return doc;
    24        }
    25    }
    26}

    3.3. 在消息赋值形状中调用读取xml文件的方法

    在orchestration的消息赋值形状中,用类似下面的语句给新xml消息赋值:

    XmlMsg = netClassMessage_netClass.EmbeddedResourseProcessor.GetXmlDocResource("xml文件名");

    参考资料:

    l Using .NET Classes for Orchestration Message Types

    l BizTalk messages based on .NET types instead of Xsd schemas

    l Constructing BizTalk 2004 XML Messages (In an Orchestration)

    l Messages from Scratch with Embedded Resources

    l Using a Custom .NET Type for a Message in Orchestrations

    biztalk中使用信封(Envelope)消息

    一. 信封(envelope)的作用

    一般的传送消息就传送一个单个的消息,这个消息架构由一个消息schema定义。但是有时候可能需要同时传送多个消息到同一个接收点,如果一个个的传送就显得效率比较低,biztalk支持信封消息功能。所谓信封消息是将多个消息打包成一个交换(interchange),就是用信封(envelope)将多个消息封装起来,形成一个貌似单个xml消息的功能。

    Biztalk收到信封消息,将信封拆开,分别取出其中的消息正文,然后单独的处理每个消息正文。

    信封消息还可以在信封部分定义升级属性,信封部分的升级属性可以被带入到所有的消息正文的上下文中。

    二. 信封(envelope)的设置

    要使用信封,首先要定义信封的架构schema,并指示哪些部分是属于信封部分,哪些部分是要被装入的消息正文的位置。

    定义信封架构形式上跟定义一般的schema没什么区别,只是需要设定一些特殊的属性。

    要把一个schema设置为信封架构,可以在这个schema的<schema>标签的“Envelope”属性设为“Yes”,表示这个架构是个信封架构。

    <schema>标签下可以包含多个根元素,表示可以有多个信封的架构,但是使用时只能使用其中一种信封架构。一般就定义一个根元素。

    根元素有个“Boby Xpath”属性,用来指示这个信封架构中的哪个位置是消息正文的位置。

    看下面这个信封架构,根元素Envelope的“Boby Xpath”属性设置为“Envelope/Boby”,表示消息正文在Boby元素里面的位置,除此之外,别的部分都属于信封部分。


      “Boby Xpath”属性指定的那个元素里面就是消息正文所在的位置,这个元素其下只能包含一个<any>元素(不能包含其他任何元素),这是个特殊的元素,含义就是消息正文的占位符,可以被任意的或者<any>元素的属性所限定的消息正文所替换。

    <any>元素相关属性说明:

    1. Process Contents

    此属性指示消息正文验证的级别,有四个可能的的值:

    Lax ―― 宽松的验证级别,这种设置,只有在收到的消息正文对应的schema在信封schema中已经被import的情况下才会验证此消息正文,否则不验证。

    Skip ―― 不验证收到的任何消息正文。

    Strict ―― 严格的验证级别,这种设置,所有可能收到的消息正文对应的schema都必须在信封schema中预先导入,对每个消息都要进行验证。

    Default ―― 缺省设置等同于“Strict”

    如果<any>元素的Process Contents设置为“Strict”或者“Default”(缺省设置为Strict),按文档的描述,在消息实例进入管道后,XML拆装器会寻找每个跟对应<any>位置的元素的名称空间相对应的schema验证这个元素,如果在信封schema中不到相应的schema被import,则这个元素会验证失败。但是实际测试中发现<any>元素Process Contents的“Strict”设置并没有起作用,在信封schema中没有import输入的消息实例名称空间对应的schema,消息依然传送成功。原因不明。

    2. Namespace

    表示可以接受的消息正文的名称空间,如果指定了名称空间,则只有属于这个名称空间的消息正文可以被接受,其他的不被接受。如果不设置名称空间,表示接受任何名称空间的消息正文。

    3. Max Occurs、Min Occurs

    表示消息正文可以出现的最小次数和最大次数,正文可以再次重复出现。但是这两个属性好像对<any>元素不起作用。

    在实际测试中,设置<any>元素的这两个属性都为1,这个信封消息应该只能包含一条正文消息,但是测试信封消息中包含两条消息正文,依然被接受,被正常拆封,正常的把两条消息正文路由到订阅的服务。

    三. 信封(envelope)的拆装

    信封的拆装是在pipeline的第二阶段拆装阶段(Disassemble)。

    接收位置的接收pipeline要选XmlReceive(其中包含XML Disassembler),或者自建pipeline并使用XML Disassembler,因为只有XML Disassembler 才具有拆装信封消息的功能。

    看一下XML Disassembler是如何处理信封消息的,消息进入到消息管道,经过第一阶段的解码后到达拆装阶段,XML Disassembler对消息的处理步骤如下:

    1. 删除信封

    首先根据消息类型在已部署的schema查找,看这个消息是否能跟哪个信封架构匹配,如果匹配不到信封架构,则继续匹配一般架构。如果匹配到信封架构,则根据信封架构的定义把所有的消息正文提取出来,去掉信封。

    2. 拆装消息正文和升级属性

    分别处理每一个消息正文,根据每个消息正文的消息类型(名称空间#根元素名)在已部署的schema中匹配,匹配到后,给这个消息建立上下文,先把信封部分升级的属性加入到消息上下文,然后根据消息架构升级这个消息本身的属性。

    每条消息都如此处理,直到都处理完毕。如果一切正常,每个消息都匹配到合适的schema,则biztalk把所有的消息正文作为独立的消息发送到MessageBox等待路由。

    如果匹配消息中出现问题,比如某一条消息没有匹配到schema,那么会有两种情况出现,跟接XML收管道的设置有关。

    XmlReceive管道有个RecoverableInterchangeProcessing属性(在biztalk管理器中,查看相应的接收位置的属性,在接收管道的右边有个省略号按钮,点击可以配置一些接收管道的属性,RecoverableInterchangeProcessing属性就在这里),这个属性缺省为false,这时如果消息匹配中有某一条消息出现没有匹配到schema的情况,则所有的消息正文都不被处理,整个消息被挂起。如果这个属性设置为true,则只有没有匹配到schema的那个消息正文被挂起,其他的消息正文被发送到MessageBox等到路由。

    biztalk的例子

    一. 随机文档的tutorial

    在文档中的位置:Help > Getting Started > BizTalk Server 2006 Tutorials

    这套教程一共分五个教程,从简单到复杂,循序渐进,逐步的把biztalk涉及的技术呈现出来。步骤十分详细,很容易上手,十分适合刚开始学习biztalk的人跟着做,作完后就会对biztalk有个比较完整的认识。建议初学者从这套教程开始。
    • Tutorial 1: Enterprise Application Integration.
    • Tutorial 2: Purchase Order Process.
    • Tutorial 3: Invoice and Payment Process.
    • Tutorial 4: Trading Partner Management.
    • Tutorial 5: Business Activity Monitoring.

    二. 随机文档的sample in the SDK

    在文档中的位置:Help > Development > Samples in the SDK

    SDK中提供了超过30个例子,包含在下面这些类别中,每个类别中可能有几个例子。

    Adapter Samples - Development

    Adapter Samples - Usage

    Admin (BizTalk Server Samples Folder)

    Application Deployment (BizTalk Server Samples Folder)

    Business Activity Monitoring (BizTalk Server Samples Folder)

    Business Rules (BizTalk Server Samples Folder)

    HWS (BizTalk Server Samples Folder)

    Messaging (BizTalk Server Samples Folder)

    Orchestrations (BizTalk Server Samples Folder)

    Pipelines (BizTalk Server Samples Folder)

    SSO (BizTalk Server Samples Folder)

    XML Tools (BizTalk Server Samples Folder)

    三. 随机文档的walkthrough

    文章中就某些特殊的特性给出的一些step by step的例子,叫做演练。

    在文档中的位置:分散在文档的各处,可以用搜索功能搜索“Walkthrough”来找出这些例子。这些例子包括:

    Adapters

    Walkthrough: Creating a BizTalk Application That Uses the MQSeries Adapter

    Walkthrough: Creating a BizTalk Application That Uses the POP3 Adapter

    Walkthrough: Module 1 - Sending and Receiving Messages with the Windows SharePoint Services Adapter

    Walkthrough: Module 2 - Integrating Office with the Windows SharePoint Services Adapter

    Walkthrough: Module 3 - Accessing SharePoint Properties from an Orchestration

    Walkthrough: Using Multiple SQL Adapters in an Orchestration

    Walkthrough: Disassembling Result Sets Using the SQL Adapter

    Walkthrough: Using the SQL Adapter with a Stored Procedure in an Orchestration

    Walkthrough: Using the SQL Adapter with an Updategram in an Orchestration

    Application Deployment

    Walkthrough: Deploying a Basic BizTalk Application

    Business Activity Monitoring (BAM)

    Walkthrough: Consuming BAM Data

    Walkthrough: Creating a BAM Activity with ODBA

    Walkthrough: Deploying the BAM Observation Model

    Walkthrough: Creating a BAM Observation Model with the BAM Add-In for Excel

    Walkthrough: Creating a Tracking Profile

    Pipelines

    Walkthrough: Using XML Envelopes (Basic)

    Walkthrough: Flat File Disassembly Using a Header and Trailer

    Schemas

    Walkthrough: Creating a Flat File Schema From a Document Instance

    四. 随机文档中的Scenarios for Business Solutions

    Biztalk SDK中除了提供上面那些简单例子外,还提供了三个重量级的例子,应该说是三个完整的商业应用解决方案。

    在文档中的位置:Help > Planning and Architecture > Scenarios for Business Solutions

    这三个方案分别是:

    1. Service Oriented Solution面向服务的解决方案

    2. Business Process Management Solution业务流程管理 (BPM)解决方案

    3. Business-to-Business Solution企业对企业(B2B)解决方案

    五. MSDN提供的例子

    微软biztalk产品开发团队应biztalk开发者的要求开发了一些例子,并根据开发者的反馈和要求不断推出新的例子,你也可以写信给他们告诉他们你想要看到什么例子。

    BizTalk Server Code Samples

    网址:(http://msdn2.microsoft.com/en-us/biztalk/aa937647.aspx

    目前已有的例子如下(不断更新中):

    Publishing and Consuming Web Services with SOAP Headers

    BAM and HAT Correlation

    Consuming Web Services with Array Parameters

    Extending the BizTalk Server Administration Console

    Viewing Failed Tracking Data

    Inserting XML Nodes from Business Rules

    Using the Mass Copy Functoid

    Using Role Links

    Split File Pipeline

    Using Enterprise Library 2.0 with BizTalk Server

    Consuming Web Services

    Console Adapter

    Delivery Notification

    Using Long-Running Transactions in Orchestrations

    Using the Looping Functoid

    Mapping to a Repeating Structure

    Parallel Convoy

    Policy Chaining

    Recoverable Interchange Processing Using Pipelines

    Using the Table Looping Functoid

    Using the Value Mapping and Value Mapping (Flattening) Functoids

    Direct Binding to an Orchestration

    Direct Binding to the MessageBox Database in Orchestrations

    Using a Custom .NET Type for a Message in Orchestrations

    Writing Orchestration Information as XML Using the ExplorerOM API

    Correlating Messages with Orchestration Instances

    SSO as Configuration Store

    Atomic Transactions with COM+ Serviced Components in Orchestrations

    Exception Handling in Orchestrations

    Implementing Scatter and Gather Pattern

    Using the SQL Adapter with Atomic Transactions in Orchestrations

    六. CodeProject网站

    CodeProject是一个Visual Studio .NET开发者社区,在这里你可以得到别人优秀的源代码,也可以把你自己的得意文章或源代码跟大家分享。

    在CodeProject有biztalk的目录,在里面有很多优秀的文章和例子。

    网址:http://www.codeproject.com/biztalk/

    目前有的文章和例子有:

    Using Dynamic Maps in BizTalk

    How to invoke a BizTalk Orchestration using Office InfoPath 2003

    How to create a self-routing message using Dynamic Ports in BizTalk Server 2004

    Asynchronous call to web services in Biztalk orchestrations

    Using a SQL Adapter in BizTalk Server 2004

    UnzipDisassembler - A custom pipeline component for BizTalk Server 2004

    How to split an XML message in BizTalk 2004 using Document and Envelope Schemas

    Debatching large messages and extending Flatfile pipeline disassembler component in Biztalk 2006

    A Quick guide to handling exceptions in BizTalk Orchestrations

    HOW TO Auto-generate schemas using Well-formed XML documents and DTD documents in Biztalk

    BizUnit Context Tutorial

    How To Troubleshoot Schemas in BizTalk Server 2006

    Building BizTalk Server 2006 Currency Converter Custom Functoid

    HOW To Compensate a Transaction in a BizTalk Orchestration

    Creating an Automated Purchase Order Workflow using BizTalk Server 2004

    Using the MSI installer wizard for deploying applications created in BizTalk Server 2006

    Keep The Orchestration Simple (KTOS) - A BizTalk Pattern

    Creating Flat File schemas using the BizTalk Server 2006 Flat File Schema Wizard

    Calling a Web Service with Custom Parameters from an Orchestration in BizTalk Server 2004

    Using the %SourceFileName% macro to create a custom send file name in BizTalk 2004

    biztalk项目设置注意事项

    适用版本:biztalk 2006

    适用环境:开发测试环境

    在开发过程中,在开发环境中,一定会是一个对项目不断的修改、编译、部署、测试,查看测试结果,发现有问题,然后回到开发环境再修改、编译、部署、测试的反复过程。所以开发环境的项目设置一定要适合这种反复的重新部署的特点,可以方便的修改,编译,重新部署,修改的内容立即能够生效,然后马上测试。

    下面的一些设置注意事项可以帮助biztalk项目在开发环境中达到以上目的

    一、 设置强名称程序集的密钥文件

    在项目属性页中,在左边的树行结构中选择 “通用属性”-“Assembly”,然后在右面的内容面板中找到“Strong name”-“Assembly Key File”项,在这里点击后面的省略号按钮找到密钥文件(密钥文件怎么生成见biztalk文档)。因为biztalk项目生成的程序集必须安装到GAC中,所以程序集必须是强名称的。

    二、 设置项目的部署属性

    在项目属性页中,在左边的树行结构中选择 “配置属性”-“Deployment”,然后看右面的内容面板中,各个属性的含义:

    Server ―― 把项目部署到哪个服务器,开发环境中,选择本地机器(local)

    Configuration database ―― biztalk配置数据库,选BizTalkMgmtDb

    Application name ―― 这个项目部署到biztalk中所属的应用程序名,所有属于同一应用的项目(一般就是一个解决方案中的项目)都应该部署到一个应用程序中。

    Redeploy ―― 本项目是否可以重新部署。指示如果在GAC中已经有了本项目的程序时是否先删掉已经存在的程序集,然后部署新的程序集。开发环境中选“true”,以便可以反复的重新部署程序集。

    Install to Global Assembly Cache ―― 是否将本项目生成的程序集安装到GAC中,当然要,选true

    Restart Host Instance ―― 是否重启主机实例。这一个选项特别重要,下面详细解释这个选项。

    在dotnet托管环境中,应用程序域是代码隔离的边界,就是说每个应用程序域之间是相互隔离,不能直接通讯,也不会相互干扰的。一般一个应用程序域需要由一个运行库宿主创建,通常是一个exe的文件,这个运行库宿主创建应用程序域,在运行中使用到其他程序集会被加载到这个应用程序域内,用到多少程序集就会加载多少,但是这些被加载的程序集在使用完后不会马上从内存中卸载,必须等整个应用程序域运行完毕后,一起从内存中卸载。

    通常Biztalk有两个主机实例:进程内主机实例BizTalkServerApplication,独立进程主机实例BizTalkServerIsolatedHost。BizTalkServerIsolatedHost主机实例是给web services等进程外的服务使用的。一般biztalk项目生成的程序集都会被部署到BizTalkServerApplication实例中。

    BizTalkServerApplication主机实例就是一个BTSNTSvc.exe运行库宿主,所以一旦有biztalk项目部署运行后,相关的程序集都会运行在BTSNTSvc.exe创建的一个应用程序域内,并且如果BTSNTSvc.exe服务不停这些程序集就不会被卸载。

    Restart Host Instance属性设置为true后,每次重新部署biztalk项目后,biztalk会重新启动BizTalkServerApplication主机实例,原先已经运行的那些程序集也会被卸载。

    刚开始学习biztalk的朋友,大多都会碰到一些问题,就是第一次部署biztalk项目后比较顺利,测试运行,发现问题修改后重新部署就会出现几种问题:

    1、 部署不成功。因为上面提到的那个“Redeploy”属性没有设置为true。

    2、 重新部署后结果还是老样子,好像修改没有起作用。一般都是因为修改前的程序集已经在内存中运行,没被卸载,实际运行的还是老版本的程序集,当然结果也就是老样子。这时重启一下BizTalkServerApplication主机实例即可。或者把上面谈到的Restart Host Instance属性设置为true,让每次重新部署都自动重启一下BizTalkServerApplication主机实例,把原来的程序集从内存中卸载。

    三、 配置管理

    一般biztalk的解决方案都是有几个项目组成,比如biztalk文档中tutoial 1“Enterprise Application Integration”这个例子,就是由两个项目组成:EAIOrchestrations和EAISchemas。大些的项目还可能包括更多的项目,这时可能需要配置一下,哪些项目是需要生成的,哪些是不用生成的;哪些项目是要部署的,哪些项目是不用部署的。

    在解决方案上点击右键,选“配置管理器”,弹出如下窗口:


       在需要生成的项目在“生成”那一列打上勾,在需要部署的项目在“部署”那一列打上勾。这样在点击解决方案右键选“生成解决方案”时,就只有设为生成的项目被编译,在点击解决方案右键选“部署解决方案”时,就只有设置了部署的项目被部署。

    对于非biztalk的项目,上图中的“ClassLibray1”是一般的类库项目,可以被biztalk项目引用。非biztalk的项目不能被设置为可部署。

    四、 biztalk项目的部署

    biztalk项目有的地方可以写代码,代码中可以引用一般托管类的代码,所以biztalk解决方案中一般会包含非biztalk项目的类库项目,这些类库项目中的类被biztalk项目中的代码调用。因为biztalk项目的程序集是强名称的,被部署在GAC中,所以被引用的类库的程序集也必须是强名称的并部署到GAC中。

    非biztalk项目不能跟biztalk项目一样通过简单设置就能被部署到GAC中,但是可以通过一定的方法做到。以下是Snega (水滴石穿)提供的方案

    1、 在类库项目中->属性->生成事件->预生成命令

    PATH = C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin

    GacUtil /u $(TargetName)

    这一设置在生成类库项目前先把原来已经在GAC的本项目的程序集卸载,以便新的程序集装载进GAC。

    2、 在类库项目中->属性->生成事件->生成后命令

    PATH = C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin

    GacUtil /i $(TargetPath)

    这一个设置把生成好的类库程序集装载到GAC中。

    或者:
    在类库项目中->属性->生成事件->生成后命令
    REM 先设置适当的环境变量以启用各种命令,其中就有GACUTIL命令所在的“C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin”路径。
    CALL "%VS80COMNTOOLS%\vsvars32.bat" > NUL
    REM “if”参数表示将程序集安装到全局程序集缓存中。如果全局程序集缓存中已经存在同名的程序集,全局程序集缓存工具将改写该程序集。
    GACUTIL /if "$(TargetPath)" 

    五、 总结

    安装以上所述设置biztalk的项目,修改biztalk项目,重新部署会很方便。

    但是有一点要注意,再重新部署一个解决方案时,这个解决方案在biztalk所在的那个应用不要有挂起的实例,有的话把它终止掉然后再进行重新部署。

    一般在开发环境中进行修改,然后编译解决方案,重新部署解决方案,就可以测试新的修改的效果了。不用手工去做停止应用、删除应用,重启服务等等工作,这些上面的设置都已经给解决了。

    biztalk消息引用和引用计数

    一. 消息引用概述

    Biztalk完全基于消息和消息订阅的机制,由发布服务器发布消息,消息代理根据订阅服务器的订阅条件判断发布的消息是否跟某个或某几个订阅匹配到,如果有匹配到消息代理机会把消息路由到所有的订阅了此消息的服务实例。如果没有匹配到就会抛出一个异常,告知这个消息没有订阅者订阅,无法路由。

    可以看出消息跟订阅消息的服务实例是成对出现的,姑且称之为服务实例消息对。一条消息如果只有一个订阅者,那这个消息跟这个订阅的服务实例就是一对。如果一条消息有多个订阅者订阅,那么这个消息要同时发送给所有的订阅者,就会出现多对服务实例消息对。

    同一个消息在biztalk的messagebox数据库中只保存一个副本,多个服务实例订阅同一消息时,各个实例跟这个消息之间是引用关系,不会各自创立一个消息副本。

    消息保存在messagebox数据库的spool表和parts表中。SPOOL 表的内容是消息的总体性描述和消息的上下文属性,一条消息在此表中为一条记录。PARTS 表存放多部分消息的各个部分,一个部分在此表中占一条记录。哪一个是正文部分由spool表中的uidBodyPartID标识。

    消息进入到biztalk系统后,路由到某个服务实例,就跟这个服务实例有了引用关系,在这个服务实例运行期间消息不能从数据库中删除。一旦这个服务实例运行完毕,这个消息也就不再使用,可以删除。如果有多个实例同时引用这个消息,则必须引用此消息的实例都完成后才能删除消息。

    为了反应消息跟实例之间的引用关系,判断一个消息是否还在被某个实例引用,biztalk有着一套消息引用计数功能。

    Biztalk采用消息引用计数表来记录消息的引用数,分为两种情况:如果消息只被一个订阅服务订阅,采用本地引用计数机制,如果消息被多个订阅服务订阅,采用全局引用计数机制,下面分别分析这两种情况下的消息引用计数功能的实现。

    二. 本地引用计数

    如果消息只有一个服务订阅,消息代理调用bts_FindSubscriptions存储过程时发现一个订阅,这个存储过程返回一条记录。

    这种情况下,消息代理会在本地引用计数表BizTalkServerApplication _MessageRefCountLog中记入实例对消息的引用计数。

    BizTalkServerApplication_MessageRefCountLog表有三个字段:

    uidInstanceID ―― 服务实例的guid

    uidMessageID ―― 消息的guid

    nRefCount ―― 引用计数(值为1,表示引用了1次)

    一旦服务实例运行完成,执行如下两个动作:

    l 把BizTalkServerApplication_MessageRefCountLog相关记录删除

    l 将此消息的guid写入MessageZeroSum表中,MessageZeroSum表中保存不再被引用的消息的guid,表示这些消息没有服务实例引用了,可以删除。MessageBox_Message_Cleanup_BizTalkMsgBoxDb作业最终就是根据这个表来清理无用的消息。

    三. 全局引用计数

    如果消息有多个服务订阅,消息代理调用bts_FindSubscriptions存储过程时发现多个订阅,这个存储过程返回N条记录。

    这种情况下,消息代理会把消息引用计数记入到全局消息引用计数表MessageRefCountLog1或者MessageRefCountLog2中,这两个表结构一样,只是一个表是活动的表,另一个作为备用表。至于当时哪个表处于活动状态有ActiveRefCountLog活动引用计数表的相关字段指示。

    MessageRefCountLog表的结构:

    uidMessageID ―― 消息guid

    uidInstanceID ―― 服务实例guid

    snRefCount ―― 引用计数。此字段可以为正负,正表示被引用,负表示被放弃引用。

       ActiveRefCountLog表的结构:
       fType ―― =1 表示消息引用表
       tnActiveTable ―― 哪个引用计数表为活动,可能的值为1和2。=1表示MessageRefCountLog1当前为活动表;=2 表示MessageRefCountLog2当前为活动表。

    当N个服务订阅了同一个消息,消息代理记入一条引用记录:uidMessageID为这条消息的guid;uidInstanceID为空,因为有多个服务订阅;snRefCount设为N,表示这个消息被引用N次。

    每个服务各自运行,一个服务完成后就会在此表中增加一条记录:uidMessageID为这条消息的guid;uidInstanceID为空;snRefCount设为-1,表示减少一次引用。如果所有服务都完成后,将会增加N条引用计数为-1的记录,正好跟正的N计数对消。

    四. 总结

    Biztalk中消息如果不特别的进行清理的话,将会一直堆积下去,不管这个消息是否已经不再有用。所以一般需要定期对messagebox数据库中的消息进行清理,把一些过期的无用的消息清理掉,以防大量无用的消息占用很多硬盘空间,也给系统的性能带来负面影响。

    Biztalk对消息的引用有完整的记录,可以从这些记录中获知哪些消息已经不再使用,系统可以根据这些信息来清理消息。

    关于清理消息biztalk本身提供了几个相关的作业。MessageBox_Message_ManageRefCountLog_BizTalkMsgBoxDb和MessageBox_Message_Cleanup_BizTalkMsgBoxD,它们就是根据这些引用计数的统计来完成清理消息工作的。关于这两个作业另外写文章介绍。

    biztalk消息以及消息订阅发布路由机制(四)-消息的轮询和执行

    一. 消息的轮询和执行

    1. 轮询机制

    消息路由到MessageBox数据库中,只是在数据库中写入了相关记录,表示哪个消息需要由哪个服务实例去执行,并没有付诸实施,还需要在进程中实实在在的去实例化这个服务对象,运行服务实例对象,并把消息交给这个实例对象处理。

    轮询主机队列是由订阅服务器的那些类先实例化为对象后,由服务实例去查询主机队列中的消息队列,找到是自己订阅的消息就拿过来处理,否则继续轮询下去。

    服务实例轮询的时间间隔和同时运行的线程数由在BizTalkMgmtDb管理数据库中的adm_ServiceClass表中设置,此表中有两个字段:

    MaxReceiveInterval ―― 设置此类服务连续轮询数据库的时间间隔

    MaxDequeueThread ―― 最大出列线程的数目

    adm_ServiceClass表中目前有四条记录,表示有四类可用的订阅服务类别。前面章节已经有介绍,分别是:

    XLANG/s – 业务流程(orchestration)

    Messaging InProcess – 表示一般的发送端口、Solicit- Response发送端口

    MSMQT – MS消息队列

    Messaging Isolated –表示请求/响应(Request-Response)接收端口,目前基本上就是指HTTP和SOAP的Request-Response双向接收端口。

    每个服务相应的MaxReceiveInterval字段表示此类服务轮询主机队列的时间间隔(单位毫秒,默认轮询间隔都是500毫秒),就是说每隔这么多时间就要新开一个线程实例化一个这个服务类,这个实例去查询主机队列。

    MaxDequeueThread字段表示同时处理本类服务的线程数,就是可以同时生成多少个本类服务的实例,去查询主机队列(默认都是5个)。这些实例去查询主机队列时有锁定机制进行保障,保证具体某一个时刻只能有一个实例对主机队列就行操作。

    2. 轮询过程

    2.1. 产生轮询的服务实例

    一类服务的轮询包括两种情况,一种是激活订阅的情况,一种是实例订阅的情况。

    激活订阅的情况,Biztalk先按照adm_ServiceClass表中规定的某一服务类的轮询间隔时间一次性生成MaxDequeueThread字段规定的多少个本类服务实例,就是新建多个线程,每个线程把某个服务类实例化为对象,由这些对象去查询主机队列。 这类实例是用来查询激活订阅的,因为激活订阅需要有新的实例来运行接收消息。

    实例订阅的情况,原先“请求/响应接收端口”服务实例在接收消息发并发布出去后,本身会产生一个对返回消息的订阅,这就是实例订阅的情况。这类服务实例也会对主机队列进行轮询,查看是返回消息是否已经路由过来了。

    2.2. 查询主机队列中的消息
    2.2.1. 激活订阅的实例

    每个新生成的服务实例都是由一个线程实例化并在其中运行,每个线程都有一个线程的guid来标识这个线程,就是说每个服务实例都可以对应到一个由线程guid标识的线程。运行中的服务实例到主机队列中进行查询,查看是否有可以处理的消息,主机队列要符合一个条件:

    l 主机队列中订阅消息的服务类型跟本服务实例类型一致

    运行的服务实例找到符合条件的,转入下一步,处理消息。

    2.2.2. 实例订阅的实例

    实例订阅的时候,同样在线程中运行的服务实例去查询主机队列,同样查看是否有路由到自己这的消息,主机队列要符合两个条件:

    l 主机队列中订阅消息的服务类型跟本服务实例类型一致

    l 主机队列中服务实例uidInstanceID字段值跟本服务实例的uidInstanceID一致。

    如果有符合条件的消息,转入下一步,处理消息。

    2.3. 处理消息

    轮询的服务实例一旦在主机队列中匹配到待处理的消息,开始处理消息,大致过程如下:

    l 把线程的guid写入到实例表的uidProcessID字段,表示这个实例由本线程进行处理。

    l 将实例表的nState字段置为2,表示实例在运行中

    l 根据主机队列表指示的消息guid,到spool表和parts表中获得消息具体内容进行处理

    l 删除主机队列中的本条记录,表示此消息已经开始处理。

    l 在服务实例运行过程中,原先在主机队列表中服务实例跟消息实例是有关联的,在删除主机队列中的本条记录后,服务实例跟正在处理的消息就失去了关联,故此,biztalk在删除主机队列记录的同时,把跟本实例的关联的消息guid记入到InstanceStateMessageReferences_BizTalkServerApplication实例与消息引用表,这个表主要字段:
    uidInstanceID ―― 服务实例的guid
    uidInstanceStateID ―― 含义不明
    uidWorkID ―― 含义不明
    uidMessageID ―― 消息的guid
    uidServiceID ―― 服务guid
    这样能保证服务实例在运行中能够知道跟本身相关联的消息是哪一个。

    2.4. 消息处理完毕后

    服务实例处理一个消息,处理完毕后要做的工作:

    l 如果是“请求/响应接收端口”服务请求部分订阅产生的激活订阅服务实例完成后,服务实例在实例表中不删除,依然保留,以便这个实例继续处理返回的消息。

    l 如果是一般的激活实例或“请求/响应接收端口”服务响应部分订阅产生的实例订阅服务实例完成后,会把这个服务实例的记录从实例表中删除。

    l 删除InstanceStateMessageReferences_BizTalkServerApplication实例与消息引用表中跟此实例相关记录。

    biztalk消息以及消息订阅发布路由机制(三)-消息发布和路由

    一. 消息发布和路由

    消息的发布有几种情况,上面讲述发布服务器时说过的三种发布服务都可以发布消息,他们的发布原理基本一致,这里以适配器发布消息为主进行描述消息发布和路由的过程。

    上面的消息流程章节中描述了消息从接收端口接收进入biztalk后的处理过程,但是消息如何进入到MessageBox,如何路由到订阅此消息的服务的过程还没详细说明,这里将详细描述消息的发布和路由过程。

    消息代理处理整个消息发布和路由的过程。

    消息在经过了接收管道处理后,相关的属性已经升级到消息上下文(使用了默认接收管道XMLReceive或自建的管道中使用了xml拆装器的情况下biztalk会根据schema升级属性,使用默认接收管道PassThruTransmit不会升级属性)。

    消息代理获得消息后,先把消息的属性写入到MessageBox数据库的消息属性表MessageProps表,包括了此消息的系统属性和从消息本身升级的属性。

    MessageProps表的结构如下:

    uidBatchID -- 消息批次id。此字段还不是很清楚,可能是一次可能处理多个消息,同一批进行处理的作为一个批次。

    uidMessageID -- 消息的uid

    uidPropID -- 这个消息的某一个属性,属性都用guid来表示。

    vtPropValue -- 这个属性的值

    1. 调用bts_FindSubscriptions过程

    消息代理调用bts_FindSubscriptions存储过程来查找订阅了消息的相关订阅。这个存储过程把订阅表和各个订阅谓词表定义的订阅跟消息的属性表中的属性比较,找出所有所有符合此消息条件的订阅,返回到一个结果集中。这个结果集中最主要包含字段有:订阅guid(uidSubID)、此订阅所属主机实例名(nvcApplicationName)、消息guid(uidMessageID),服务的guid(uidServiceID)、服务实例的guid(uidInstanceID),结果集表示订阅表中的哪些订阅匹配到了这个消息,每个订阅了此消息的订阅为一条记录。如果一个消息被两个服务订阅了,这个结果集中将会有两条记录。

    消息代理根据这个结果集,对每条记录调用存储过程bts_InsertMessage。以下的步骤,结果集中的每条记录都要执行一遍。

    2. 第一次调用bts_InsertMessage过程

    这次调用bts_InsertMessage过程主要任务是调用int_EvaluateSubscription过程。int_EvaluateSubscription过程根据当前处理的订阅所属的应用主机实例名,再调用对应此主机实例的存储过程进一步处理,调用的存储过程名称是“int_InsertIntoQueue_主机实例名”这样的命名形式,比如服务属于BizTalkServerApplication主机,则调用int_InsertIntoQueue_BizTalkServerApplication。

    存储过程“int_InsertIntoQueue_主机实例名”的作用:

    2.1. 激活订阅时,新建实例guid

    如果是订阅类型是激活订阅,即uidInstanceID为空,说明需要新建一个处理订阅消息的服务实例,这一步骤新建一个guid,作为新建实例的实例guid。

    之后要新建实例记录,即在实例表中插入一条实例记录表示要处理这条消息的实例。

    Instances实例表主要字段:

    主要字段

    含义

    uidAppOwnerID

    所属主机实例的guid

    uidInstanceID

    此服务实例的guid

    uidServiceID

    此服务的guid

    uidClassID

    此服务的类型guid

    uidProcessID

    运行这个实例的线程guid

    nState

    实例状态:
    1-准备运行,已激活但尚未开始运行的服务实例,通常由于资源暂时不可用,例如服务器的处理负载过大
    2-已启动,正在运行的服务实例。
    4-可恢复的挂起,实例已挂起,但可恢复该实例。
    8-已冻结,实例状态保持在 MessageBox 数据库中,并且没有 Windows 服务运行该实例。
    32-不可恢复的挂起,实例已挂起,且不可恢复该实例。可以保存该实例所引用的消息,然后终止该实例。
    64 -- 在断点处
    256-已计划要运行

    2.1.1. 订阅状态为活动时(状态码为1)

    如果订阅的状态是处于正常的活动状态,则在Instances实例表中插入一条记录,只记入四个字段:uidAppOwnerID, uidInstanceID, uidServiceID, uidClassID, nState。uidAppOwnerID为此主机实例的guid,uidInstanceID为新建的服务实例的guid,uidServiceID为订阅消息的服务guid,uidClassID为订阅服务的类型guid,nState实例状态为256,表示已计划要运行。

    2.1.2. 订阅状态为停用时(状态码为2)

    如果订阅的状态是处于停用状态,在插入Instances实例表(插入的状态字段nState为4)的同时还会在InstancesSuspended挂起实例表中都插入一条记录,挂起实例表中除了上面上面提到的四个字段,还包括一些错误代码和错误描述字段,可能是描述挂起原因的一些内容。此时nState实例状态为4,表示这个实例是可恢复的挂起。

    2.1.3. 订阅状态码为8时

    我没看出来这个状态码的含义,有知道的朋友请告知

    如果是实例订阅,由于订阅的主体服务实例已经存在(在实例表中有这个服务的一条记录),不必再新建一个订阅服务的实例。

    2.2. 将消息队列插入到相应的主机队列表

    如果订阅是处于活动状态,这一步骤要将这个订阅内容插入到相应的主机队列表中,主机队列表为“<主机实例名>Q”形式,表示路由到此主机的还未被处理的消息队列。如果相应的主机实例是BizTalkServerApplication,那就将此消息订阅内容插入到BizTalkServerApplicationQ表中。

    主机队列表BizTalkServerApplicationQ主要字段:

    主要字段

    含义

    nID

    自动标识

    uidMessageID

    消息guid

    uidSubscriptionID

    订阅guid

    uidClassID

    订阅此消息的服务类别guid

    uidServiceID

    订阅此消息的服务guid

    uidInstanceID

    订阅此消息的服务实例guid

    uidAppInstanceID

    主机实例guid

    如果订阅处于停用(订阅状态码为2),或者订阅状态码为8(此码含义不清楚)时,订阅内容不被插入到主机队列表中,而是插入到主机队列挂起表中,表示订阅此消息的订阅不处于活动状态,此消息被挂起。挂起表为“<主机实例名>Q_Suspended”形式,此表大部分内容跟主机队列表相同,增加了一些表示为何挂起的字段,比如挂起原因nvcAdditionalInfo字段,挂起是否可恢复nIsResumable字段等。

    3. 其后调用bts_InsertMessage过程

    接下来的过程将把消息的所有内容写入到MessageBox数据库中,一条消息本身内容在数据只有一个副本,所有订阅了此消息的服务都参考引用这一个消息的副本。消息本身是不能修改的,如果哪个服务需要修改消息,必然是需要生成另外一条消息。

    3.1. 写入消息上下文和多部分消息的正文部分

    其后的第一次调用bts_InsertMessage过程将传递消息上下文,然后将该消息上下文以及有关消息的元数据(例如,部分数、正文部分名称和 ID)插入到 SPOOL 表中。SPOOL 表是对一条消息的总体性描述和消息的上下文属性,一条消息在此表中有一条记录。另外,消息正文部分也在这一步使用 int_InsertPart 存储过程插入到 PARTS 表中,一条消息的多部分中只能有一个正文部分。

    SPOOL 表主要字段:

    主要字段

    含义

    uidMessageID

    消息的guid

    UserName

    用户名,运行主机实例的用户

    PublishingServer

    biztalk所在服务器的名称

    OriginatorSID

    创建者的安全id,即启动biztalk服务的帐户

    OriginatorPID

    创建者参与方id,一般是“s-1-5-7”

    nvcMessageType

    消息的类型,由正文部分决定的

    nNumParts

    消息包含的部分数

    uidBodyPartID

    正文部分的guid

    nvcBodyPartName

    正文部分名

    nCounter

    部分计数

    imgContext

    上下文的内容

    MessageParts表是SPOOL消息队列表跟PARTS消息部分表之间的中间关系表,MessageParts. uidMessageID字段跟SPOOL.uidMessageID字段关联,PARTS. uidPartID字段跟MessagePart. uidPartID段关联。

    主要字段

    含义

    uidMessageID

    消息guid

    uidPartID

    消息部分的guid

    nvcPartName

    消息部分名

    nBodyPart

    是否正文
    1 -- 正文
    0 -- 不是正文

       PARTS 表存放多部分消息的各个部分,一个部分在此表中占一条记录。哪一个是正文部分由spool表中的uidBodyPartID标识。

    uidPartID

    消息部分guid

    nPartSize

    部分的尺寸

    imgPart

    部分的数据

    实例表Instances表跟消息队列SPOOL表之间关系,就是哪个服务实例订阅了哪个消息是靠主机队列BizTalkServerApplicationQ表的关联起来,Instances. uidInstanceID字段跟BizTalkServerApplicationQ. uidInstanceID字段相关,BizTalkServerApplicationQ. uidMessageID字段跟SPOOL.uidMessageID字段相关。

    这一步的最后还有做一件事就是把消息代理写入到MessageBox属性表MessageProps中这个批次的所有属性记录都删除,因为它们已经不再有用。

    3.2. 依次写入多部分消息的其他部分

    随后,除了消息正文部分为每个剩余的消息部分调用 bts_InsertMessage 存储过程,把这些消息部分一一写入到PARTS 表中。

    4. 消息发布和路由总结

    一个消息有从适配器进来,到消息代理把消息路由到MessageBox数据口中相应的表中,这个过程就是消息的发布和路由过程。

    路由完毕后,在主机队列表中存在待处理的消息队列,这个表可以简单的理解为哪个消息将要由哪个服务实例处理。

    实例表Instances表存放要处理这些消息的服务实例记录,一个待处理的消息对应一个实例,实例表每条记录可以简单的理解为这个实例是哪个服务类型的服务,服务目前是什么状态。其实Instances表中的实例还需要由具体的服务线程来运行它,这时才是真正的服务实例化,这点下一章“消息的轮询和执行”中会有详细讲解。

    消息的具体内容存放在SPOOL 表和PARTS 表中,Spool表存放消息的总体性描述和消息的上下文属性,PARTS 表存放消息的各个部分。

    August 04

    biztalk消息以及消息订阅发布路由机制(一)-消息概述——转载

    一. 消息概述

    BizTalk Server 基于消息发布/订阅的基本机制,在BizTalk Server内部分为发布服务器和订阅服务器,所谓发布服务器就是产生消息并发布到MessageBox中,所谓订阅服务器就是可以消费消息的服务器,根据订阅的消息的条件,只对自己需要的信息进行处理。

    一般的情况是从外部收到的信息经过接收端口后都会被处理转换包装成biztalk的消息,消息中包含了相关属性(消息上下文),比如接收的端口、接收的适配器信息,还有预设的从消息内部提取出来的可以用来路由消息的特征值(从schema升级的属性)。把然后存放到消息数据库MessageBox中。

    消息代理根据订阅表查找订阅了此消息的服务,并将订阅了此消息的所有订阅分别存到的相应的服务器实例对应的消息队列表中,系统不断的轮询此队列,发现有未处理的消息,就会把消息发送到订阅此消息的服务,同时把此条订阅消息从消息队列表去除。

    订阅消息的服务(这个服务可能是业务流程,也可能是输出端口等等)收到消息后对消息就行处理,处理完后,如果服务是输出端口,此消息就经过适配器发送到系统外部。如果服务是业务流程,可能会产生新的消息,这种情况的处理同从接收端口进来的消息做类似的处理,发送消息到MessageBox,并查找订阅此消息的服务,把消息发送到订阅消息队列中继续流转。

    1. 发布和订阅服务器

    发布服务器指的是可以送出消息发布到MessageBox的服务,包括:

    接收端口 ―― 从外部接收信息,处理后发布到MessageBox

    业务流程 ―― 业务流程启动后可能生成消息发送到发送端口或启动别的业务流程,生成的消息也是发布到MessageBox

    要求/响应(Solicit-Response)发送端口 ―― 即双向的要求/响应发送端口。

    订阅服务器是可以订阅并消费消息的服务,可以作为订阅服务器的服务类型目前有四类:

    XLANG/s – 业务流程(orchestration)

    Messaging InProcess – 表示发送端口,Solicit- Response发送端口

    MSMQT – MS消息队列

    Messaging Isolated – 表示请求/响应(Request-Response)接收端口,目前基本上就是指HTTP和SOAP的Request-Response双向接收端口。

    Biztalk中的发布和订阅都是相对MeassagBox而言的,导致消息进入到MeassagBox的就叫发布,根据条件从MeassagBox中取得消息的叫订阅。

    2. 消息构成

    BizTalk Server 2006 本质上是一个消息处理引擎。每条消息都可视为多部分消息,此消息可以由零个或多个部分组成。具有一个或多个部分的消息都具有一个标识为正文部分的部分(只能有个一部分标识为正文)。每个部分均由可表示 XML 文档、平面文件、序列化的 .NET 类或其他二进制数据流的二进制数据块组成。消息的正文部分的类型决定了整个消息的类型,这个消息类型可用为路由消息的条件。


    2.1. 上下文

    每条消息都附带有一个属性集,称为消息上下文,这些属性的值是从消息本身提取或不来自消息本身但与消息本身相关的值。属性分为两种类型,升级属性和写入属性。这两种属性的区别是升级的属性可以用来作为路由消息的条件,写入的属性不能。

    2.1.1. 升级属性

    要把一个消息架构中的某个元素升级到上下文属性,首先要有一个属性架构来对应各个被升级的属性。这个属性架构是简化的架构,只能包含简单数据类型的元素,每个元素对应一个属性,并分配给这个属性一个GUID,用来标识这个属性。看一下升级属性架构中的一个属性:

    <xs:element name=”Property1” type=”xs:string”>

    <xs:annotation>

    <xs:appinfo>

    <b:fieldInfo propertyGuid=”4bfe2aee-9c25-436f-979d-862ed812a523” />

    </xs:appinfo>

    </xs:annotation>

    </xs:element>

    属性名是Property1,属性GUID是4bfe2aee-9c25-436f-979d-862ed812a523。升级消息架构中的属性,先要在消息架构中指定升级架构,然后把消息架构中的某个元素对应到升级架构中的某个同数据类型的属性。消息架构中的元素被升级后,消息架构会保存此升级属性在架构中的位置信息的xpath,以便可以通过xpath提取元素的值。

    如果接收管道中使用了xml拆装器,则消息经过接收端口的管道时,xml拆装器会自动把入站的消息跟已部署的消息架构匹配,匹配到合适的消息架构后,管道根据消息架构中升级属性的xpath提取相应的值保存到上下文属性,然后消息代理把这些属性的GUID和值保存到BizTalkMsgBoxDb数据库MessageProps 表中,就可以根据订阅的条件对照这些属性来路由消息。

    比如某个服务订阅了消息类型为订单、收货单位为xxxx的消息,这里消息类型和收货单位都是升级到上下文属性的属性,消息代理发现这个条件跟收到的消息一致就会把消息发送到这个订阅的服务。

    升级的属性除了从消息本身升级来的外,还有不是消息本身的信息但跟此消息相关的系统属性,比如接到此消息的端口适配器类型,接收此消息的端口id等等,这些系统属性也都具有自己的guid,会同其他的升级属性一同写入到MessageProps 表中作为路由消息的依据。

    关于详细的消息订阅和消息发布路由的机制下面有专门章节论述。

    2.1.2. 写入属性

    写入属性就是把消息架构中的某个元素设置为可分辨字段(Distinguished),消息架构会保存此写入属性在架构中位置信息的xpath,以便可以通过xpath提取元素的值。

    写入的属性不必有属性架构的支持,也就没有相应的GUID,属性会被提取出来保存到上下文属性中,但是写入的属性不能用来作为路由消息的条件。

    写入属性一般是为了在业务流程中方便的访问消息中的某个元素,可以直接从消息上下文属性获得此属性值,省去开发人员手工解析提取这个元素的值麻烦。

    2.2. 多部分

    biztalk中的消息又叫做多部分消息,意为一个消息可以包含多个部分,每个部分都可能为XML 文档、平面文件、序列化的 .NET 类或其他二进制数据流的二进制数据块。一个消息可以是简单的只包含一个部分的消息,也可以有多个部分,但是其中必须并且只能有一个部分为正文本分,正文部分的类型就是整个消息的消息类型。

    3. 消息流程

    先看一下消息在biztalk中的流转过程的图,下面详细描述一个从接收端口进入到biztalk后一直到消息发送出biztalk的整个过程。


    3.1. 接收端口

    一个接收端口可以包含多个接收位置,每个接收位置就是一个对外接收信息的实际物理接口。接收位置接收到的信息经过处理,如果设计有映射,经过消息映射转化后再由消息代理根据消息订阅情况分发到各个订阅消息的服务。

    接收位置:

    接收位置主要由接收适配器和接收管道组成,这两个组件再终结点管理器的管理下协调工作。

    接收适配器:

    Biztalk作为EAI和B2B的平台软件,需要跟各种系统通讯联系,所以信息接口应该覆盖面尽可能的广,能够接收各种协议的各种类型的信息,biztalk使用适配器来解决这个问题,通过适配器来把多种多样的信息接收进来并转换成biztalk内部使用的xml的消息。

    Biztalk本身包含了许多一般常用的适配器SOAP、http、ftp、Smtp、平面文件、msmq、sql等等,基本能满足大多数需求。如果biztalk本身带的适配器不能满足需求,还可以自己开发需要的适配器,另外有很多第三方的公司也提供各种自己开发的适配器给需要者使用。

    接收适配器读取数据流创建消息(Microsoft.BizTalk.Message.Interop.IbaseMessage 接口的实现)、向该消息添加部分(Microsoft.BizTalk.Message.Interop.IbasePart 接口的实现)、然后将数据流作为该部分内容进行提供。

    接收消息后,适配器将接收位置、适配器类型以及其他内容(与适配器相关)升级到消息的上下文属性中, 以便根据接收位置或适配器类型订阅消息的服务能接收到订阅的消息。

    接收管道:

    从适配器出来的消息在终结点管理器的控制下送到接收管道中进行处理。


    接收管道如上图包含四个阶段的处理,这里我们重点关心的是拆装部分,biztalk提供了两个拆装器:xml拆装器和平面文件拆装器。

    Xml拆装器可以指定消息的架构,xml拆装器就会按照这个消息的架构对消息就行处理,并可以校验消息是否符合架构。同时如果消息架构中有升级属性,这一步会根据升级属性的xpath把属性值从消息中提取出来放到消息的上下文属性中。指定了消息架构的xml拆装器还会把消息的类型升级到消息的上下文属性中,消息的类型为命名空间(后接 # 符号)和根节点的名称组成。比如:http://tempuri.org/samples/MessageType#Message

    平面文件拆装器需要指定架构,并且架构是做过平面文件扩展的,就是架构中包含如果分解平面文件数据到xml的信息,平面文件拆装器根据这些信息解析平面文件,并生成xml。

    Biztalk的默认接收管道PassThruTransmit是个直通的管道,它不处理xml文档,所以如果要接收xml消息并升级属性此管道不适合。

    Biztalk的默认接收管道XMLReceive,这个管道专门用来拆装xml消息,管道中的xml拆装器根据架构的命名空间和根节点名称在已经部署的所有架构逐个进行匹配,一旦匹配成功,就使用这个架构,然后根据schema中升级属性的xpath提取属性值放入上下文。如果一个都没匹配成功,则根据是否路由不可识别消息的设置确定是否继续路由,还是生成错误信息。

    消息代理:

    接收管道出来的消息又回到终结点管理器,如果有映射器就把消息送到映射器就行消息的架构转换,如果没有把消息直接送到消息代理,由消息代理把消息发布到MessageBox中,并处理消息的路由。

    消息的发布和路由在下面章节详述。

    3.2. MessageBox

    Microsoft BizTalk Server 中发布/订阅引擎的核心是 MessageBox 数据库。接收到的消息存放在MessageBox中,各个服务消息订阅也是存放在MessageBox中,发送到订阅服务的消息队列也是在MessageBox中。MessageBox是biztalk的信息核心。

    3.3. 业务流程

    业务流程可以参与消息的处理过程,但业务流程不是处理消息过程的必须过程,一个消息流程完全可以直接从接收端口到MessageBox,然后直接路由到一个输出端口,不需要业务流程的参与。

    业务流程中也有端口概念,是业务流程内部跟外部进行消息交换的接口,业务流程的端口称作逻辑端口,用户从biztalk外部接收数据、发送数据的端口称作物理端口,是不同的概念。

    业务流程可以作为发布服务器也可以作为订阅服务器,作为订阅服务器时可以订阅从物理接收端口进入biztalk的消息,作为发布服务器,业务流程从逻辑输出端口输出的消息也可以被别的订阅服务器订阅。

    业务流程内部的各种功能不在本文的讨论范围,可以自行参考biztalk的随即文档的业务流程相关的部分。

    3.4. 发送端口

    在消息准备从 BizTalk Server 发送时,它将在发送端口中经历一个互补的过程。映射将在发送管道执行前应用于消息,从而,消息在由管道处理并通过适配器发送前转换为特定于客户或应用程序的格式。在发送管道中,属性将从上下文降级到消息中,而非升级到消息上下文中。

    biztalk消息以及消息订阅发布路由机制(二)-消息订阅 (转载)

    一. 消息订阅

    订阅消息的主体叫订阅服务器,订阅服务器是可以订阅并消费消息的服务,可以作为订阅服务器的服务类型目前有四类,在BizTalkMgmtDb管理数据库中的adm_ServiceClass的Name字段列出了所有可以作为订阅服务器的服务类型,包括:

    XLANG/s – 业务流程(orchestration)

    Messaging InProcess – 表示一般的发送端口、Solicit- Response发送端口

    MSMQT – MS消息队列

    Messaging Isolated –表示请求/响应(Request-Response)接收端口,目前基本上就是指HTTP和SOAP的Request-Response双向接收端口。

    每种服务都有自己的id,为16字节GUID的形式(biztalk中对象的标识id都采用GUID的形式,biztalk数据表中大量的使用到这种16字节的统一标识数据,sql server中的uniqueidentifier 数据类型,就是用来存放GUID类型的数据)

    1. 消息订阅主体

    消息订阅最后体现在BizTalkMsgBoxDb数据库的反应订阅主体的Subscription表(表示是哪个服务产生的这个订阅)和反应订阅条件的一组谓词表中(表示这个订阅的具体条件,用来判断哪些消息是符合这个订阅的)。

    先来看一下Subscription表的主要字段含义,这个表指示了订阅消息的具体是哪一个服务:

    nvcName ―― 此订阅的名称

    uidSubID ―― Guid类型,此订阅的uid

    nvcApplicationName ―― 订阅服务器所属主机实例名,路由消息时不同的主机实例将调用不同的存储过程处理。

    uidClassID ―― 产生订阅的服务类型,是adm_ServiceClass 服务表UniqueId字段的外键

    uidServiceID ―― 产生此订阅的具体服务,根据uidClassID服务类型的不同,对应到不同类别的服务.如果uidClassID指示的是XLANG/s,则对应的是业务流程,此字段对应到bts_Orchestration表中的uidGUID字段。为Messaging In-Proc时,表示由发送端口订阅消息,对应到bts_SendPort表中的uidGUID 。MSMQt时有点混乱,但大多数情况下也在bts_SendPort table表中体现。实例订阅时,服务实例是请求/响应端口时的这个字段并不是接收端口的guid也不是接收位置的guid,不清楚这个guid跟什么对应。哪位知道的朋友能不能告知一下。

    uidInstanceID ―― 实例订阅时的订阅消息的服务实例的guid。激活订阅时此字节为空。

    Biztalk中存在两类订阅:激活订阅和实例订阅。激活订阅收到执行订阅的消息后,该消息创建新的订阅服务器实例来处理这个消息,一般的订阅都属于这类订阅。实例订阅将指示执行订阅的消息应路由到已在运行的订阅服务器实例。有一种服务会产生实例订阅的情况即“Messaging Isolated ”,这类服务的典型就是“请求/响应接收端口”,这类服务其实可以产生两个订阅。先是“请求/响应接收端口”的接收部分,这部分相当于消息分布服务器,可以由其他订阅服务器来订阅这个消息,比如一般是业务流程的一个接收形状绑定这个端口,实际上就是订阅了这个端口接收到的消息。这个接收端口服务实例建立后,把收到的消息发送到MessageBox。然后“请求/响应接收端口”的响应部分,这部分相当于订阅服务器,如果这部分绑定到业务流程的一个发送形状,这个接收端口服务实例会生成一个实例订阅,这个字段就用来存放这个接收端口服务实例的guid,表示还是由这个服务实例来处理返回的消息。这样,就完成了一个从接收到响应的一个往返过程。实例订阅是由服务实例生成的订阅,所以在产生实例订阅收到消息被放入到消息队列后,会在订阅表中把这个实例订阅删除。

    还有一种情况会形成实例订阅,orchestration中使用相关集时,一个orchestration实例的一个端口发送消息出去,返回的消息仍然由这个orchestration实例的一个接收形状接收。这里也有一个orchestration实例的订阅发出去的消息的实例订阅。

    uidPortID ―― 订阅服务类型为XLANG/s时,此字段表示业务流程中接收消息的端口形状,对应bts_orchestration_port表中的uidGUID字段。对于 Messaging或MSMQt,这个字段指示使用发送端口的主通道还是辅助通道。先根据uidServiceID在bts_SendPort表中找到相应的端口,然后用bts_SendPort表的nID 跟bts_sendport_transport表的nSendPortID 关联。uidPortID跟bts_sendport_transport表的uidGUID 关联,就能确定使用哪个发送端口的通道。

    fEnabled ―― 此订阅的状态,0 ―― 禁用;1 ―― 活动;2 ―― 停用

    uidPredicateGroupID ―― 订阅谓词组id。

    2. 消息订阅条件(谓词)

    一个订阅的主体存在Subscription表中,相应的订阅条件则分别存在一组谓词表中,不同的类型的条件放在不同的表中,比如等于的条件放在EqualsPredicates中,小于的条件放在LessThenPredicates中,一共有以下这么多的谓词表:

    l BitwiseANDPredicates

    l EqualsPredicates

    l EqualsPredicates2ndPass

    l ExistsPredicates

    l FirstPassPredicates

    l GreaterThanOrEqualsPredicates

    l GreaterThanPredicates

    l LessThenOrEqualsPredicates

    l LessThenPredicates

    l NotEqualsPredicates

    这些表的基本结构都是一样的,都是按照什么属性(属性的GUID)+谓词(等于、大于、小于。。。)+属性的值的形式出现。看一下这些表的数据结构:

    uidPropID ―― 属性的guid。所有属性都有自己的guid,包括类似接收端口、接收适配器类型等系统属性,或者从schema升级的属性。

    vtValue ―― 属性的值

    uidPredicateGroupID ―― 一组谓词的id,一个订阅可以有多个条件谓词,这个字段表示同一组的条件,条件也可分为或条件和与条件,条件的组合通过PredicateGroup表在Subscription表和各个谓词表之间进行组合。

    看一下PredicateGroup表的结构:

    uidPredicateORGroupID -- 订阅谓词,对应到Subscription的uidPredicateGroupID字段表示是与这个订阅相关的条件。此字段相同的记录表示相应的订阅有多组条件用或运算组成。

    uidPredicateANDGroupID -- 订阅谓词与运算一组的谓词id,每个或运算条件都能由多条与运算的条件组成,最终由这个字段跟各个谓词表去关联。

    nNumFirstPassPredicates -- 这个或条件组中包含几个与运算条件。


    这个图中显示了一个发送端口设置筛选条件(就是设置订阅条件)的示例。从上可以看出这个订阅实际上设置了两组或运算的条件,其中第一组内又包含了两个与运算的条件。在PredicateGroup表中的表现就是对应这个订阅的有两条uidPredicateORGroupID相同的记录,表示两组或运算条件,相应的uidPredicateANDGroupID字段对应到EqualsPredicates谓词表中,其中有一个对应两条记录,一个对应一条记录。

    3. 消息订阅过程

    下面的图是涉及到订阅部分数据库表的主要结构和相互关系。各字段的含义上面两节基本都有描述了。


    下面看一下biztalk中两种订阅方式的各自如何产生订阅的:

    3.1. 激活订阅

    一般情况下,业务流程、发送端口和MSMQ这三类服务产生的订阅是激活订阅。这种订阅是被订阅的消息根据订阅条件新建订阅消息的服务主体,即新建一个服务实例,然后由这个服务实例处理订阅的消息,服务实例将消息处理完毕后,这个实例就算完成任务。

    业务流程订阅一般表现形式是业务流程的接收端口跟物理端口绑定。其实它的订阅主体是这个业务流程的这个接收端口。条件是绑定的发送端口发送来的消息。

    发送端口订阅一般可以是发送端口绑定到业务流程的一个发送端口。也可以是发送端口直接订阅由接收位置接收的消息,在发送端口的筛选器中可以根据消息的各种属性(包括系统属性和从schema升级的属性)来定义订阅的条件,比如某个消息的哪个升级属性大于某个值时。

    以业务流程绑定一个物理接收端口为例说明:

    业务流程跟一个物理接收端口绑定后,实际进行的操作是产生一个订阅。就是在Subscription表中生成一条记录表示订阅的主体,然后在一组谓词表中生成相应的订阅条件。

    订阅主体就是这个业务流程的绑定的端口。在Subscription表中生成记录,字段uidClassID是XLANG/s业务流程服务的guid,表示订阅主体的服务类型是业务流程。uidServiceID字段是订阅的具体业务流程的guid(对应bts_Orchestration表)。uidPortID字段是这个业务流程中接收端口的guid(对应bts_orchestration_port表),uidPredicateGroupID字段是订阅谓词组id,表示跟这个订阅相关的谓词表中的记录。

    订阅主体在Subscription表生成记录后,然后把订阅的条件要记入到相应的谓词表中。本例中端口绑定的情况,会产生两个条件,一个是接收端口id等于绑定的那个接收端口,形式为:http://schemas.microsoft.com/BizTalk/2003/system-properties. ReceivePortID == {9DB16A5F-ADD7-4CF2-9B9A-D7924426DD18};另一个是消息类型是业务流程接收端口指定的消息类型,形式为:http://schemas.microsoft.com/BizTalk/2003/system-properties.MessageType == http://EAISchemas.Request#Request

    这两个条件中都含有“system-properties”,表示是系统属性,这两个又都是等于条件,所以都记入EqualsPredicates谓词表中。所有的属性都有guid,系统属性有预设的guid,升级属性前面章节已经讲到,每个升级的属性都会生成一个guid(这就是为什么升级的字段可以用来路由消息,而可分辨字段不可以用来路由消息的原因,可分辨字段没有guid)。所以这两个条件在谓词表中的表现是,两属性guid代表的属性分别等于什么值。

    3.2. 实例订阅

    这种订阅由服务实例产生,并放入到订阅表中。当消息路由到消息队列后,会将订阅表中的实例订阅记录删除。

    一般来讲Messaging Isolated(表示物理请求/响应类型的接收端口)这类服务会用到实例订阅,下面就这个为例说明:

    请求/响应类型的接收端口,一般是由业务流程订阅这个端口的请求部分的消息,经过处理后返回消息,这个端口的的响应部分再订阅这个返回的消息,处理后返回给请求端。

    请求部分的订阅是激活订阅,不再赘述。

    响应部分是实例订阅,是由请求部分收到消息后新建Messaging Isolated服务实例后,这个服务实例在订阅表中建立的一个订阅,这个订阅其他部分跟激活订阅一致,就是在Subscription表中的uidInstanceID字段填入这个服务实例自身的guid,表示这是实例订阅,订阅主体就是这个服务实例。

    当消息路由到这个实例订阅的消息队列后,这个实例订阅的使命就完成了,被从订阅表中删除,这个过程在下面消息的发布和路由中还有叙述。

    4. 端口绑定的本质

    端口绑定本质就是生成订阅,订阅服务器订阅发布服务器的消息,但是不表示这个发布服务器的消息只能给一个订阅服务器消费,一个消息可以同时被多个服务订阅,只要这个消息符合订阅条件,消息代理会把订阅把消息发送到所有订阅这个消息的服务实例。