Как эффективно изменить текст в потоке в компоненте конвейера 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 года пост...[/ править]