tag route net for data asp all c# asp.net-core .net-core

c# - route - Seguridad de AsyncLocal en ASP.NET Core



tag helpers asp net core (1)

Solo busco el código fuente de la clase ExecutionContext para CoreClr: https://github.com/dotnet/coreclr/blob/775003a4c72f0acc37eab84628fcef541533ba4e/src/mscorlib/src/System/Threading/ExecutionContext.cs

De acuerdo con mi comprensión del código, los valores locales asíncronos son campos / variables de cada instancia de ExecutionContext. No se basan en ThreadLocal ni en ningún almacén de datos persistente específico de subprocesos.

Para verificar esto, en mis pruebas con subprocesos del grupo de subprocesos, no se puede acceder a una instancia en un valor local asincrónico cuando se reutiliza el mismo subproceso del grupo de subprocesos, y se llama al destructor de la instancia "izquierda" para limpiarse en el siguiente ciclo del GC, lo que significa la instancia se GCed como se esperaba.

Para .NET Core, AsyncLocal es el reemplazo de CallContext . Sin embargo, no está claro qué tan "seguro" es usar en ASP.NET Core.

En ASP.NET 4 (MVC 5) y versiones anteriores, el modelo de agilidad de hilos de ASP.NET hizo CallContext inestable . Por lo tanto, en ASP.NET, la única forma segura de lograr el comportamiento de un contexto lógico por solicitud, era usar HttpContext.Current.Items. Bajo las cubiertas, HttpContext.Current.Items se implementa con CallContext , pero se hace de una manera que es segura para ASP.NET.

Por el contrario, en el contexto de OWIN / Katana Web API, el modelo de agilidad de hilos no fue un problema. Pude usar CallContext de manera segura, después de cuidadosas consideraciones sobre cómo deshacerme de él correctamente .

Pero ahora estoy tratando con ASP.NET Core. Me gustaría utilizar el siguiente middleware:

public class MultiTenancyMiddleware { private readonly RequestDelegate next; static int random; private static AsyncLocal<string> tenant = new AsyncLocal<string>(); //This is the new form of "CallContext". public static AsyncLocal<string> Tenant { get { return tenant; } private set { tenant = value; } } //This is the new verion of [ThreadStatic]. public static ThreadLocal<string> LocalTenant; public MultiTenancyMiddleware(RequestDelegate next) { this.next = next; } public async Task Invoke(HttpContext context) { //Just some garbage test value... Tenant.Value = context.Request.Path + random++; await next.Invoke(context); //using (LocalTenant = new AsyncLocal<string>()) { // Tenant.Value = context.Request.Path + random++; // await next.Invoke(context); //} } }

Hasta ahora, el código anterior parece estar funcionando bien. Pero hay al menos una bandera roja. En el pasado, era fundamental garantizar que CallContext se tratara como un recurso que debe liberarse después de cada invocación.

Ahora veo que no hay una forma evidente de "limpiar" AsyncLocal .

ThreadLocal<T> código, comentado, que muestra cómo funciona ThreadLocal<T> . Es IDisposable , por lo que tiene un mecanismo obvio de limpieza. Por el contrario, AsyncLocal no es IDisposable . Esto es desconcertante.

¿Esto es porque AsyncLocal todavía no está en la condición de candidato de lanzamiento? ¿O es esto porque realmente ya no es necesario realizar la limpieza?

E incluso si AsyncLocal se está utilizando correctamente en mi ejemplo anterior, ¿hay algún tipo de problemas de "agilidad de hilos" de la vieja escuela en ASP.NET Core que vayan a hacer que este middleware sea inviable?

Nota especial

Para quienes no estén familiarizados con los problemas que tiene CallContext dentro de las aplicaciones ASP.NET, en esta publicación de SO, Jon Skeet hace referencia a una discusión en profundidad sobre el problema (que a su vez hace referencia a los comentarios de Scott Hanselman ). Este "problema" no es un error, es solo una circunstancia que debe ser considerada cuidadosamente.

Además, personalmente puedo dar fe de este comportamiento desafortunado. Cuando construyo aplicaciones ASP.NET, normalmente incluyo pruebas de carga como parte de mi infraestructura de prueba de automatización. Es durante las pruebas de carga que presencio que CallContext vuelve inestable (donde quizás 2% a 4% de las solicitudes muestran que CallContext está dañado. También he visto casos donde un GET Web API tiene un comportamiento CallContext estable, pero las operaciones POST son todas inestables. La única forma de lograr la estabilidad total es confiar en HttpContext.Current.Items.

Sin embargo, en el caso de ASP.NET Core, no puedo confiar en HttpContext.Items ... no existe ese punto de acceso estático. Tampoco soy capaz de crear pruebas de carga para las aplicaciones .NET Core con las que estoy retocando, que es en parte la razón por la que no he respondido esta pregunta por mi cuenta. :)

De nuevo: comprendan que la "inestabilidad" y el "problema" que estoy discutiendo no son un error en absoluto. CallContext no es de alguna manera defectuoso. El problema es simplemente una consecuencia del modelo de envío de subprocesos empleado por ASP.NET. La solución es simplemente saber que existe el problema, y ​​codificar en consecuencia (por ejemplo, usar HttpContext.Current.Items lugar de CallContext , cuando se encuentra dentro de una aplicación ASP.NET).

Mi objetivo con esta pregunta es comprender cómo se aplica (o no) esta dinámica en ASP.NET Core, de modo que no construya accidentalmente código inestable cuando se utiliza la nueva construcción AsyncLocal .