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



0 Answers

Question

Для .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 .






Related