Абстрагирование запроса и сеанса HttpContext - безопасность потока - PullRequest
1 голос
/ 01 декабря 2010

В моем приложении ASP.NET есть следующие сборки:

Веб-сайт - это веб-сайт ASP.NET ClassLib - это просто библиотека классов, которая содержит всю бизнес-логику

Class Lib должен взаимодействовать с объектами HttpContext Session и Request. Это обновление кода из старого приложения ASP, где я собрал весь VBScript, содержащий логику, и поместил его в VB.NET. У нас просто не было времени переписать.

Вместо того, чтобы ClassLib напрямую взаимодействовал с HttpContext, который, как я думал, был ПЛОХОЙ, а также мешал нам проводить модульное тестирование, я ввел следующий уровень абстракции:

Public Class Request
 Private Shared _requestWrapper as IRequestWrapper
     Public Shared ReadOnly Property RequestWrapper()
        Get
            If _requestWrapper Is Nothing Then
                Throw New Exception("_requestWrapper is null.  Make sure InitRequest() is called with valid parameters")
            End If
            Return _requestWrapper
        End Get
    End Property


    Public Shared Sub InitRequest(ByRef requestWrapper As IRequestWrapper)
        _requestWrapper = requestWrapper
    End Sub

     Public Shared Function GetVal(ByVal key As String) As Object
        Return RequestWrapper.GetVal(key)
    End Function

и т.д.

Это означает, что в модульных тестах я могу предоставить свой собственный объект MockRequest в этот класс Request, который является простой коллекцией NameValue. Затем код в ClassLib и на Веб-сайте просто использует класс Request и не является мудрым, поскольку он не исходит из HttpContext, а скорее является этим ложным классом.

Когда дело доходит до реальной сделки, у меня просто есть следующий (C #) класс:

public class RealRequest : IRequestWrapper
    {
        public void Initialize(HttpContext context)
        {
        }

        #region Implementation of IRequestWrapper

        public object GetVal(string index)
        {
            return HttpContext.Current.Request[index];
        }

и т.д.

Это инициализируется в Session_Start файла global.asax на Сайте следующим образом:

 protected void Session_Start(object sender, EventArgs e)
    {


        IRequestWrapper requestWrapper = new RealRequest();
        WebSession.Request.InitRequest(ref requestWrapper);
    }

Я думаю, что это похоже на шаблон Static Gateway.

Теперь мне известны синглтоны и статические переменные в многопоточной среде, такой как ASP.NET, но это немного отличается. Когда он переходит к RequestWrapper.GetVal (), он на самом деле идет к HttpContext для этого запущенного потока - и извлекает значение из этого.

Конечно, любые параллельные тесты, которые мы проводим с несколькими пользователями, подключающимися к одному и тому же серверу, никогда не обнаруживали какого-либо странного поведения.

Я просто хочу заверить, что это звуковой дизайн, и если нет, то почему?

Спасибо Дункан

1 Ответ

1 голос
/ 01 декабря 2010

Это нормально. У нас очень похожий случай в наших приложениях, который использует HttpContext, если он существует, или поддельные реализации в противном случае.

Единственное, на что следует обратить внимание, - это очень специфический случай, когда HttpContext.Current вернет значение, но HttpContext.Current.Request сгенерирует исключение при запуске события Application_Start. В фреймворковом коде вы действительно не знаете (или не хотите знать), что вызвало вызов.

Обходной путь для HttpContext.HideRequestResponse, являющегося внутренним? Определить, действительно ли доступен HttpContext.Request?

...