c# что - Безопасность AsyncLocal в ядре ASP.NET




уроки книга (2)

Для .NET Core AsyncLocal заменяет CallContext . Однако неясно, как «безопасно» использовать его в ASP.NET Core.

В ASP.NET 4 (MVC 5) и более ранних CallContext модель CallContext ASP.NET сделала CallContext неустойчивой . Таким образом, в ASP.NET единственным безопасным способом достижения поведения логического контекста для каждого запроса было использование HttpContext.Current.Items. Под обложками HttpContext.Current.Items реализуется с помощью CallContext , но это делается безопасным способом для ASP.NET.

Напротив, в контексте Web-API OWIN / Katana модель гибкости потоков не была проблемой. Я смог безопасно использовать CallContext после тщательного изучения того, как правильно его утилизировать .

Но теперь я имею дело с ASP.NET Core. Я хотел бы использовать следующее промежуточное ПО:

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);
        //}
    }
}

Пока что этот код работает нормально. Но есть хотя бы один красный флаг. Раньше было важно обеспечить, чтобы CallContext обрабатывался как ресурс, который должен быть освобожден после каждого вызова.

Теперь я вижу, что нет никакого очевидного способа «очистить» AsyncLocal .

Я включил код, закомментировал, показывая, как работает ThreadLocal<T> . Это IDisposable , и поэтому он имеет очевидный механизм очистки. Напротив, AsyncLocal не является IDisposable . Это раздражает.

Это потому, что AsyncLocal еще не находится в состоянии кандидата-кандидата? Или это потому, что действительно больше не нужно выполнять очистку?

И даже если AsyncLocal используется должным образом в моем примере выше, существуют ли какие-либо проблемы «гибкости потоков» старой школы в ASP.NET Core, которые собираются сделать это промежуточное программное обеспечение неработоспособным?

Специальное примечание

Для тех, кто не знаком с проблемами, которые CallContext имеет в приложениях ASP.NET, в этой статье SO Jon Skeet ссылается на углубленное обсуждение проблемы (которая, в свою очередь, ссылается на комментарий Скотта Гензельмана ). Эта «проблема» не является ошибкой - это просто обстоятельство, которое необходимо тщательно учитывать.

Более того, я лично могу подтвердить это неудачное поведение. Когда я создаю приложения ASP.NET, я обычно включаю тесты нагрузки как часть моей инфраструктуры тестирования автоматизации. Во время нагрузочных тестов я могу наблюдать, что CallContext становится нестабильным (где, возможно, от 2% до 4% запросов показывают повреждение CallContext . Я также видел случаи, когда веб-API GET имеет стабильное поведение CallContext , но операции POST нестабильны. Единственный способ добиться полной стабильности - полагаться на HttpContext.Current.Items.

Однако в случае ASP.NET Core я не могу полагаться на HttpContext.Items ... нет такой точки статического доступа. Я также пока не могу создавать тесты нагрузки для приложений .NET Core, с которыми я занимаюсь, отчасти поэтому я не ответил на этот вопрос сам. :)

Опять же: Пожалуйста, поймите, что «нестабильность» и «проблема», которые я обсуждаю, не являются ошибкой. CallContext не является чем-то испорченным. Проблема просто является следствием модели отправки потоков, используемой ASP.NET. Решение состоит в том, чтобы знать, что проблема существует, и соответствующим образом кодировать (например, использовать HttpContext.Current.Items вместо CallContext , когда внутри приложения ASP.NET).

Моя цель с этим вопросом состоит в том, чтобы понять, как эта динамика применяется (или нет) в ASP.NET Core, так что я случайно не создаю нестабильный код при использовании новой конструкции AsyncLocal .


Answers

Я просто изучаю исходный код класса ExecutionContext для CoreClr: https://github.com/dotnet/coreclr/blob/775003a4c72f0acc37eab84628fcef541533ba4e/src/mscorlib/src/System/Threading/ExecutionContext.cs

Основываясь на моем понимании кода, асинхронные локальные значения являются полями / переменными каждого экземпляра ExecutionContext. Они не основаны на ThreadLocal или каком-либо конкретном хранилище данных.

Чтобы убедиться в этом, в моем тестировании с потоками пулов потоков экземпляр, оставшийся в локальном значении асинхронного доступа, недоступен, когда один и тот же поток потока потоков повторно используется, а деструктор «левого» экземпляра для очистки сам вызван в следующий цикл GC, что означает экземпляр GCed, как и ожидалось.


ASP.NET CORE с использованием .NET Core - все зависимости автономны, могут использовать большинство пакетов nuget, не могут использовать специальные пакеты для Windows, могут выполняться на windows, linux, Mac

ASP.NET CORE с использованием .NET Framework - большинство зависимостей автономны, выполняются только в окнах, будут иметь доступ к конкретным пакетам для Windows, требуется версия .net framework, которая настроена на компьютере





c# asp.net-core .net-core