Как эффективно изменить текст в потоке в компоненте конвейера BizTalk? - PullRequest
6 голосов
/ 07 января 2011

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

Какой самый эффективный способ сделать это, не прерывая поток? Я хочу использовать это в пользовательском компоненте конвейера для 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 ]

4 голосов
/ 20 января 2011

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

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

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

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

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

Следующий фрагмент должен быть каноническим исходным кодом для метода 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 классе.

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

2 голосов
/ 07 января 2011

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

0 голосов
/ 19 июля 2013

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

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

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

...