2016-01-02 1 views
1

En utilisant BizTalk 2013r2 CU1, j'ai créé un schéma de propriété pour ma xsd entrante et déployé l'application. Lorsque je reçois un exemple de document XML à l'aide d'un pipeline standard "réception xml", je peux voir que l'élément requis est promu dans le contexte comme prévu. J'ai ensuite créé un pipeline personnalisé qui contient le composant "XML Disassembler" dans l'étape "Disassemble" et un composant personnalisé dans l'étape "Validate". Ce composant personnalisé doit lire la propriété promue à partir du contexte. Cependant, je trouve que lorsque je passe l'emplacement de réception du pipeline "xml receive" à mon pipeline personnalisé, ma propriété n'est pas promue. J'utilise le code suivant dans mon composant personnalisé pour écrire une liste d'éléments dans le contexte du message:BizTalk - Echec de la promotion des propriétés

for (int x = 0; x < contextList.CountProperties; x++) 
     { 
      contextList.ReadAt(x, out name, out nspace); 
      string value = contextList.Read(name, nspace).ToString(); 
      contextItems += "Name: " + name + " - " + "Namespace: " + nspace + " - " + value + "\r\n"; 
      if (name == _ContextPropertyName && nspace == _ContextPropertyNamespace) 
       promotedPropFound = true; 

     } 
     Helpers.EventLogHelper eventHelper = new EventLogHelper(); 
     eventHelper.LogEvent(string.Format("Context items:{0}", contextItems)); 

     if (promotedPropFound == false) 
      throw new Exception(string.Format("Unable to find promoted property with name[{0}] and namespace [{1}]", _ContextPropertyName, _ContextPropertyNamespace)); 

De la sortie dans le journal des événements, je peux voir que certaines propriétés telles que MessageType ont été promus mais mon propriété personnalisée n'a pas. Encore une fois, si je change l'emplacement de réception pour utiliser un pipeline standard «xml receive», la propriété sera promue à partir d'une copie du même document xml (je vérifie cela en arrêtant le port d'envoi d'abonnement et en visualisant le contexte de la console d'administration).

Je trouve cela très étrange puisque le même composant "désassembleur XML" est présent dans le même étage "Désassembler" des deux pipelines, avec la même configuration (par défaut). Je commence à penser qu'il y a peut-être un problème avec 2013r2CU1 - quelqu'un d'autre a-t-il rencontré la même chose?

Répondre

7

Au moment où le désassembleur XML a été exécuté dans votre pipeline personnalisé, il n'existe aucune garantie que vos propriétés ont été promues.

Le message entrant arrive dans le pipeline sous la forme d'un flux avec le pointeur de données défini au début du flux.
Je pense que le désassembleur XML ne lit pas le flux, il l'enveloppe dans une classe de wrapper de flux qui remplira les propriétés promues lorsque le flux sera lu.
Le flux devra être lu au moins une fois: lorsque le message sera inséré dans la boîte de message. Il y a donc une garantie que les propriétés seront promues, mais vous ne pouvez pas supposer que cela sera fait avant l'exécution de la phase "Valider". Pour vous assurer que c'est vraiment le problème que vous rencontrez: vérifiez votre message APRÈS qu'il a été importé dans la boîte de message.
Si votre propriété promue est là, ce que j'ai décrit est probablement ce qui se passe.

Solutions:

Pour faire votre travail de composant de pipeline personnalisé, la meilleure solution serait de faire comme le désassembleur XML: obtenir le flux entrant et l'envelopper dans une classe enveloppe de flux qui peut déclencher toutes les fonctionnalités que vous avez besoin.

L'assembly Microsoft.BizTalk.Streaming.dll a une classe wrapper qui pourrait vous intéresser: ForwardOnlyEventingReadStream.
Cette classe a un événement AfterLastReadEvent. Vous pouvez créer un EventHandler et le faire souscrire à cet événement pour déclencher votre fonctionnalité personnalisée uniquement après la lecture complète du flux. Toutes les propriétés ont été promues.

Votre composant personnalisé ressemblerait à ce que:

public IBaseMessage Execute(IPipelineContext context, IBaseMessage message) 
{ 
    Stream stream = message.BodyPart.GetOriginalDataStream(); 
    CForwardOnlyEventingReadStream eventingReadStream = new CForwardOnlyEventingReadStream(stream); 
    eventingReadStream.AfterLastReadEvent += new AfterLastReadEventHandler(DoSomething); 

    message.BodyPart.Data = eventingReadStream; 
    return message; 
} 

private static void DoSomething(object src, EventArgs args) 
{ 
} 

Une façon moins efficace pour résoudre votre problème serait de lire le flux entièrement dans votre composant personnalisé à l'étape « Valider » et placez le pointeur de flux de retour au début du flux.

Microsoft a quelques directives pour quand vous manipuler le flux de messages dans le composant de pipeline: https://msdn.microsoft.com/en-us/library/aa577699.aspx

Mise à jour:

OP doit passer le contexte de message au gestionnaire d'événements. Il est possible en utilisant une expression lambda:

public IBaseMessage Execute(IPipelineContext context, IBaseMessage message) 
{ 
    Stream stream = message.BodyPart.GetOriginalDataStream(); 
    CForwardOnlyEventingReadStream eventingReadStream = new CForwardOnlyEventingReadStream(stream); 
    eventingReadStream.AfterLastReadEvent += new AfterLastReadEventHandler((src, args) => DoSomething(src, args, message.Context)); 

    message.BodyPart.Data = eventingReadStream; 
    return message; 
} 

private static void DoSomething(object src, EventArgs args, IBaseMessageContext messageContext) 
{ 
} 

Cette question SO peut être intéressante pour référence pour passer le paramètre supplémentaire: Pass parameter to EventHandler

+0

Merci pour votre réponse détaillée Gary, je pense que vous avez peut-être raison. Mon problème maintenant est de savoir comment câbler ça. Autant que je puisse voir, le délégué AfterLastReadEvent n'accepte pas le contexte de pipeline - auquel je dois pouvoir accéder. Je n'ai pas beaucoup d'expérience avec les délégués - savez-vous s'il est possible de passer le contexte du pipeline lorsque l'événement est soulevé? –

+0

@RobBowman Oui c'est possible. J'ai mis à jour ma réponse pour cela. Je suppose que vous voulez passer le contexte du message plutôt que le contexte du pipeline. –

+0

Merci pour la mise à jour Gary. Désolé, cela me prend tellement de temps mais actuellement je n'ai que 20 minutes chaque matin pour travailler dessus. Connaissez-vous un lien vers un exemple d'utilisation d'un EventingReadStream? Je n'ai pas réussi à en trouver un. Dans mon événement "DoSomething" j'ai maintenant le code qui exécute la carte requise. Mon problème maintenant est que je ne sais pas comment l'assigner au flux. Devrais-je transmettre le flux en tant que paramètre ref à l'événement, alors toute mise à jour le fera entrer dans BizTalk? –

2

Pouvez-vous faire ce que vous aviez prévu pour la validation étape dans un Orchestration ? Ce serait beaucoup plus facile. Si ce n'est pas le cas, la solution la plus commune à ce problème spécifique est un composant de pipeline intermédiaire qui force une lecture complète sur le flux, bien que techniquement, il suffise de lire jusqu'à ce que le nœud Promoted soit atteint.

+0

Oui, je devrais avoir recours à casser le courant du pipeline si je ne peux pas le faire fonctionner avec le flux de lecture d'événement mais je n'ai pas donné encore :) –

+1

Peut-être juste FYI, mais le désassembleur Xml utilise essentiellement des événements pour écrire les propriétés lui-même. Votre problème est que l'événement pertinent ne se déclenchera pas tant que l'élément n'aura pas été lu. Donc, si vous essayez un modèle d'événement, vous risquez de rester coincé au même endroit que xmldasm. –