Eventos
Campeonato mundial de DataViz de Power BI
14 feb, 16 - 31 mar, 16
Con 4 posibilidades de entrar, podrías ganar un paquete de conferencia y convertirlo en el Live Grand Finale en Las Vegas
Saber másEste explorador ya no se admite.
Actualice a Microsoft Edge para aprovechar las características y actualizaciones de seguridad más recientes, y disponer de soporte técnico.
Nota
Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión de .NET 9 de este artículo.
Advertencia
Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulte la directiva de compatibilidad de .NET y .NET Core. Para la versión actual, consulte la versión de .NET 9 de este artículo.
Importante
Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.
Para la versión actual, consulte la versión de .NET 9 de este artículo.
Por Justin Kotalik
En este artículo se explica cómo leer el cuerpo de la solicitud y escribir el cuerpo de respuesta. El código para estas operaciones podría ser necesario al escribir middleware. Fuera de la escritura de middleware, el código personalizado no suele ser necesario porque las operaciones se controlan mediante MVC and Razor Pages.
Hay dos abstracciones para los cuerpos de solicitud y respuesta: Stream y Pipe. En la lectura de solicitudes, HttpRequest.Body es Stream y HttpRequest.BodyReader
es PipeReader. En la escritura de respuestas, HttpResponse.Body es Stream y HttpResponse.BodyWriter
es PipeWriter.
Se recomienda el uso de canalizaciones por encima de las secuencias. Las secuencias pueden ser más fáciles de usar en el caso de algunas operaciones sencillas, pero las canalizaciones son más ventajosas para el rendimiento y son más fáciles de usar en la mayoría de los casos. ASP.NET Core está empezando a usar internamente canalizaciones en lugar de secuencias. Ejemplos:
FormReader
TextReader
TextWriter
HttpResponse.WriteAsync
Las secuencias no se quitan del marco. Se seguirán usando en todo .NET, y además muchos tipos de secuencias no tienen equivalentes de canalización, como FileStreams
y ResponseCompression
.
Imagine que el objetivo es crear un middleware que lee el cuerpo de la solicitud entero como una lista de cadenas, que se divide en nuevas líneas. Una implementación de secuencias sencilla podría parecerse al ejemplo siguiente:
Advertencia
El código siguiente:
private async Task<List<string>> GetListOfStringsFromStream(Stream requestBody)
{
// Build up the request body in a string builder.
StringBuilder builder = new StringBuilder();
// Rent a shared buffer to write the request body into.
byte[] buffer = ArrayPool<byte>.Shared.Rent(4096);
while (true)
{
var bytesRemaining = await requestBody.ReadAsync(buffer, offset: 0, buffer.Length);
if (bytesRemaining == 0)
{
break;
}
// Append the encoded string into the string builder.
var encodedString = Encoding.UTF8.GetString(buffer, 0, bytesRemaining);
builder.Append(encodedString);
}
ArrayPool<byte>.Shared.Return(buffer);
var entireRequestBody = builder.ToString();
// Split on \n in the string.
return new List<string>(entireRequestBody.Split("\n"));
}
Si quiere que los comentarios de código se traduzcan en más idiomas además del inglés, háganoslo saber en este problema de debate de GitHub.
Este código funciona, pero hay algunos problemas:
StringBuilder
, en el ejemplo se crea otra cadena (encodedString
) que se desecha inmediatamente. Este proceso se produce con todos los bytes de la secuencia, por lo que el resultado es la asignación de memoria adicional del tamaño del cuerpo de la solicitud entera.En este ejemplo se corrigen algunos de los problemas anteriores:
Advertencia
El código siguiente:
private async Task<List<string>> GetListOfStringsFromStreamMoreEfficient(Stream requestBody)
{
StringBuilder builder = new StringBuilder();
byte[] buffer = ArrayPool<byte>.Shared.Rent(4096);
List<string> results = new List<string>();
while (true)
{
var bytesRemaining = await requestBody.ReadAsync(buffer, offset: 0, buffer.Length);
if (bytesRemaining == 0)
{
results.Add(builder.ToString());
break;
}
// Instead of adding the entire buffer into the StringBuilder
// only add the remainder after the last \n in the array.
var prevIndex = 0;
int index;
while (true)
{
index = Array.IndexOf(buffer, (byte)'\n', prevIndex);
if (index == -1)
{
break;
}
var encodedString = Encoding.UTF8.GetString(buffer, prevIndex, index - prevIndex);
if (builder.Length > 0)
{
// If there was a remainder in the string buffer, include it in the next string.
results.Add(builder.Append(encodedString).ToString());
builder.Clear();
}
else
{
results.Add(encodedString);
}
// Skip past last \n
prevIndex = index + 1;
}
var remainingString = Encoding.UTF8.GetString(buffer, prevIndex, bytesRemaining - prevIndex);
builder.Append(remainingString);
}
ArrayPool<byte>.Shared.Return(buffer);
return results;
}
Este ejemplo anterior:
StringBuilder
a menos que no haya ningún carácter de nueva línea.Split
en la cadena.Sin embargo, todavía hay algunos problemas:
remainingString
) y agrega al búfer de cadenas, lo que resulta en una asignación adicional.Estos problemas se pueden corregir, pero el código se vuelve cada vez más complicado y las mejoras son pocas. Las canalizaciones ofrecen una manera de resolver estos problemas con una complejidad mínima del código.
En el siguiente ejemplo se describe cómo abordar el mismo escenario usando un objeto PipeReader:
private async Task<List<string>> GetListOfStringFromPipe(PipeReader reader)
{
List<string> results = new List<string>();
while (true)
{
ReadResult readResult = await reader.ReadAsync();
var buffer = readResult.Buffer;
SequencePosition? position = null;
do
{
// Look for a EOL in the buffer
position = buffer.PositionOf((byte)'\n');
if (position != null)
{
var readOnlySequence = buffer.Slice(0, position.Value);
AddStringToList(results, in readOnlySequence);
// Skip the line + the \n character (basically position)
buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
}
}
while (position != null);
if (readResult.IsCompleted && buffer.Length > 0)
{
AddStringToList(results, in buffer);
}
reader.AdvanceTo(buffer.Start, buffer.End);
// At this point, buffer will be updated to point one byte after the last
// \n character.
if (readResult.IsCompleted)
{
break;
}
}
return results;
}
private static void AddStringToList(List<string> results, in ReadOnlySequence<byte> readOnlySequence)
{
// Separate method because Span/ReadOnlySpan cannot be used in async methods
ReadOnlySpan<byte> span = readOnlySequence.IsSingleSegment ? readOnlySequence.First.Span : readOnlySequence.ToArray().AsSpan();
results.Add(Encoding.UTF8.GetString(span));
}
En este ejemplo se solucionan muchos problemas que tenían las implementaciones de secuencias:
PipeReader
controla los bytes que no se han usado.ToArray
y de la memoria que usa la cadena, la creación de cadenas es de libre asignación.Las propiedades Body
, BodyReader
y BodyWriter
están disponibles para HttpRequest
y HttpResponse
. Al establecer Body
en una secuencia diferente, un nuevo conjunto de adaptadores se adaptan automáticamente al tipo del otro. Si establece HttpRequest.Body
en una nueva secuencia, HttpRequest.BodyReader
se establece automáticamente en un nuevo objeto PipeReader
que encapsula a HttpRequest.Body
.
HttpResponse.StartAsync
se usa para indicar que los encabezados no se pueden modificar y para ejecutar devoluciones de llamada OnStarting
. Al usar Kestrel como servidor, si se llama a StartAsync
antes de usar el objeto PipeReader
, se garantiza que la memoria que devuelve GetMemory
pertenezca al objeto interno Pipe de Kestrel en lugar de a un búfer externo.
Comentarios de ASP.NET Core
ASP.NET Core es un proyecto de código abierto. Seleccione un vínculo para proporcionar comentarios:
Eventos
Campeonato mundial de DataViz de Power BI
14 feb, 16 - 31 mar, 16
Con 4 posibilidades de entrar, podrías ganar un paquete de conferencia y convertirlo en el Live Grand Finale en Las Vegas
Saber más