Как эффективно изменить текст в потоке в компоненте конвейера BizTalk?

У меня есть поток, который содержит текст, теперь я хочу редактировать некоторый текст (заменить некоторые значения) в этом потоке.

Каков наиболее эффективный способ сделать это, не прерывая поток? Я хочу использовать это в пользовательском компоненте конвейера для BizTalk,

public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg)
{
    string msg = "";
    using (VirtualStream virtualStream = new VirtualStream(pInMsg.BodyPart.GetOriginalDataStream()))
    {
        using(StreamReader sr = new StreamReader(VirtualStream))
        {
            msg = sr.ReadToEnd();
        }

        // modify string here
        msg = msg.replace("\r\n","");

        while (msg.Contains(" <"))
           msg = msg.Replace(" <", "<");

        VirtualStream outStream = new VirtualStream();
        StreamWriter sw = new StreamWriter(outStream, Encoding.Default);
        sw.Write(msg);
        sw.Flush();
        outStream.Seek(0, SeekOrigin.Begin);

        pInMsg.BodyPart.Data = outStream;
        pContext.ResourceTracker.AddResource(outStream);
    }

    return pInMsg;
}

Это код, но, как вы можете видеть, я нарушаю поток, когда я делаю sr.ReadToEnd(),

Есть ли лучший способ сделать это?

3 ответа

Тот факт, что вы используете классы Stream в вашем конвейерном компоненте, не делает его потоковым конвейерным компонентом как таковым, как вам интуитивно интересно.

Наиболее подходящий способ - разделить ответственность на две составляющие:

  • Сначала вы создаете клиента System.IO.Stream класс - это класс, который оборачивает исходный входящий поток и предоставляет потоковый интерфейс. В этом классе вы эффективно обрабатываете байты, когда они читаются вызывающим кодом. Этот класс не должен зависеть от BizTalk, и вы должны иметь возможность создать образец программы модульного тестирования для этого класса вне BizTalk.

Для первого случая я рекомендую вам перейти к одной из нескольких статей с примерами исходного кода.

  • Во-вторых, сам компонент конвейера, единственной обязанностью которого является замена входящего потока экземпляром вашего пользовательского потока. Это идиоматический паттерн, который вы найдете в хороших конвейерных компонентах. В частности, во время выполнения метода Executeне следует читать исходный входящий поток. Чтение произойдет - автоматически - само по себе, когда агент обмена сообщениями вступит во владение.

Следующий фрагмент должен быть каноническим исходным кодом для Executeметод, за исключением дополнительного кода для обработки ошибок, конечно:

IBaseMessage IComponent.Execute(IPipelineContext pContext, IBaseMessage pInMsg)
{
   // assign a new CustomStream to the incoming message

    System.IO.Stream stream = pInMsg.BodyPart.GetOriginalDataStream();
    System.IO.Stream customStream = new CustomStream(stream);

    // return the message for downstream pipeline components (further down in the pipeline)

    pInMsg.BodyPart.Data = customStream;
    pContext.ResourceTracker.AddResource(customStream);

    return pInMsg;
}

Увидеть? Нет чтения вообще в предыдущем методе. Вся обработка должна происходить во время (повторяющихся) вызовов Read метод в вашем обычае Stream учебный класс.

Как я уже писал в своем ответе на следующий вопрос, я настоятельно рекомендую вам ознакомиться с целой серией публикаций, которые сделал Ник Барден о разработке компонентов потокового конвейера.

Для простого случая недоступного для чтения потока, доступного только для чтения, вы можете создать поток-обертку, который заменяет данные на лету, как это необходимо в Stream.Read (и, возможно, Stream.ReadByte) метод. Однако они работают с необработанными байтами, поэтому вам, возможно, придется учитывать и кодировку потока.

Я думаю, что путь будет состоять в том, чтобы сохранить готовый и обрабатывающий буфер, затем вы, когда вы получаете новый контент, записанный в ваш поток, сохраняете его в ожидающем буфере, пока не узнаете, что больше нечего заменить. После замены или принятия решения, что ничто не заменит, переместите эти данные из ожидающего в готовый буфер. Метод read должен только читать из готового буфера, запись должна только записывать в буфер обработки, а сброс сбрасывает все ожидающие выполнения.

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

[править] извините, ответил 2 года пост...[/ править]

Другие вопросы по тегам