2016-01-02 3 views
1

Используя BizTalk 2013r2 CU1, я создал схему свойств для моего входящего xsd и развернул приложение.BizTalk - не удалось повысить свойства

Когда я получаю образец XML-документа с использованием стандартного конвейера «xml receive», я вижу, что необходимый элемент продвигается в контекст, как ожидалось.

Затем я создал собственный конвейер, который содержит компонент «дизассемблер XML» на этапе «Разборка» и пользовательский компонент на этапе «Проверить». Этот пользовательский компонент должен прочитать продвинутое свойство из контекста. Тем не менее, я обнаружил, что, когда я переключаю приемное местоположение из конвейера «xml receive» на мой собственный конвейер, моя собственность не получает повышение. Я использую следующий код в моем пользовательском компоненте выписать список элементов в контексте сообщения:

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

От выхода в журнале событиях можно увидеть, что некоторые свойства, такие как MessageType были повышены, но мой обычное свойство нет. Опять же, если я изменю местоположение приема обратно на использование стандартного конвейера «xml receive», тогда свойство будет продвигаться из копии того же XML-документа (я проверяю это, останавливая подписной порт отправки и просматривая контекст из консоли администратора).

Я нахожу это очень странным, поскольку тот же компонент «дизассемблер XML» присутствует на одном и том же этапе «Разборка» обоих конвейеров с той же (по умолчанию) конфигурацией. Я начинаю думать, возможно, есть проблема с 2013r2CU1 - кто-нибудь еще столкнулся с тем же?

ответ

7

К моменту демонтажа XML-дизассемблера в вашем настраиваемом конвейере нет гарантии, что ваши свойства были повышены.

Входящее сообщение поступает в конвейер как поток с указателем данных, установленным в начале потока.
Я думаю, что дизассемблер XML не читает поток, он переносит его в некоторый класс оболочки потока, который будет заполнять продвигаемые свойства, когда поток действительно будет прочитан.
Поток должен быть прочитан хотя бы один раз: когда сообщение вставляется в поле сообщения. Таким образом, есть гарантия, что свойства будут повышены, но вы не можете предположить, что это будет сделано до выполнения этапа «Проверка».

Чтобы убедиться, что это действительно проблема, с которой вы сталкиваетесь: проверьте свое сообщение ПОСЛЕ того, как оно было импортировано в окно сообщения.
Если ваше продвинутое свойство есть, то, что я описал, вероятно, происходит именно так.

Решения:

Чтобы сделать свой заказ работы компонента трубопровода, лучшим решением было бы сделать так же, как XML Disassembler: получить входящий поток и завернуть его в поток класс-оболочку, которая может вызвать независимо функциональность тебе нужно.

Сборка Microsoft.BizTalk.Streaming.dll имеет класс оболочки, который может вас заинтересовать: ForwardOnlyEventingReadStream.
В этом классе есть событие AfterLastReadEvent. Вы можете создать EventHandler и подписаться на это событие, чтобы активировать пользовательские функции только после того, как поток был полностью прочитан. Все свойства были повышены.

Ваш пользовательский компонент будет выглядеть так:

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

менее эффективный способ решить проблему будет полностью прочитать поток в пользовательском компоненте на «Validate» стадии и поставить указатель потока обратно к началу потока.

Microsoft имеет некоторые рекомендации для того, когда вы манипулируете поток сообщений в компоненте трубопровода: https://msdn.microsoft.com/en-us/library/aa577699.aspx

Update:

OP должен передать контекст сообщение для обработчика событий. Это возможно с помощью лямбда-выражения:

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

Этот SO вопрос может быть интересен для справки для прохождения дополнительного параметра: Pass parameter to EventHandler

+0

Спасибо за подробный ответ Гэри, я думаю, вы можете быть правы. Моя проблема теперь в том, как подключить это. Насколько я вижу, делегат AfterLastReadEvent не принимает контекст конвейера, доступ к которому я должен иметь. У меня нет большого опыта работы с делегатами - знаете ли вы, возможно ли передать контекст конвейера при возникновении события? –

+0

@RobBowman Да, возможно. Я обновил свой ответ для этого. Я предполагаю, что вы хотите передать контекст сообщения, а не контекст конвейера. –

+0

Спасибо за обновление Гэри. Извините, это заставляет меня так долго, но в настоящее время у меня есть только 20 минут каждое утро, чтобы поработать над этим. Знаете ли вы ссылку на пример использования EventingReadStream? Я не смог его найти. В моем событии «DoSomething» у меня теперь есть код, который выполняет требуемую карту. Моя проблема теперь в том, что я не знаю, как вернуть это значение потоку. Должен ли я передавать поток в качестве параметра ref для события, то любое обновление к нему приведет к его внедрению в BizTalk? –

2

Вы можете делать все, что было запланировано на Validate этап в оркестровке ? Это было бы намного проще.

Если нет, наиболее распространенным решением этой конкретной проблемы является промежуточный компонент трубопровода, который заставляет полностью читать поток, хотя технически вам нужно будет читать только до тех пор, пока не будет удален узел Promoted.

+0

Да, мне, возможно, придется прибегнуть к разрыву потока конвейера, если я не могу заставить его работать с потоком чтения, но у меня нет дано еще :) –

+1

Может быть, просто FYI, но Xml Disassembler по существу использует события для записи самих свойств. Ваша проблема в том, что соответствующее событие не будет срабатывать до тех пор, пока элемент не будет прочитан. Итак, если вы пытаетесь создать модель событий, вы рискуете застревать в том же месте, что и xmldasm. –

Смежные вопросы