Play framework 2.0: хранить значения в Http.Context

Я пытаюсь реализовать сеансы «на основе запросов» в scalquery в игровой среде. Я создаю сеанс с помощью scalaquery и пытаюсь сохранить его в текущем контексте http следующим образом:

def withTransaction[A](bp: BodyParser[A])(f: Request[A] => Result): Action[A] = {
   Action(bp) {
     request =>
       val context = Http.Context.current()
       val session = createSession()
       session.conn.setAutoCommit(false)
       context.args.put("scalaquery.session", session)
       try {
         val result = f(request)
         session.conn.commit()
         result
       }
       catch {
         case t: Throwable =>
           session.conn.rollback()
           throw t
       }
       finally {
         session.close()
         context.args.remove("scalaquery.session")
       }
   }
}

затем я оборачиваю свои действия в свои контроллеры, например:

withTransaction(parse.anyContent) {
    Action {
       //code that produces a result here
    }
}

Однако он вылетает в следующей строке:

val context = Http.Context.current() 
[RuntimeException: There is no HTTP Context available from here.] 

Итак, почему контекст недоступен? Этот код вызывается непосредственно фреймворком, поэтому не должен ли контекст устанавливаться к моменту выполнения этого кода? Или я использую неправильный способ доступа к контексту?

РЕДАКТИРОВАТЬ: «Сеанс» имеет тип org.scalaquery.session.Session. Причина, по которой я хочу установить его в HttpContext, заключается в том, чтобы завернутые действия могли получить к нему доступ в режиме «http-scoped», т.е. чтобы каждый запрос хранил свой сеанс отдельно, но все службы, которым нужен сеанс, могут найти его в общедоступном область, которая отделяется для каждого запроса.


person Angel Blanco    schedule 11.08.2012    source источник


Ответы (1)


Я думаю, проблема в том, что вы используете Java API с контроллером Scala. Http.Context устанавливается, только если вы используете контроллер Java. Рассматривали ли вы возможность использования Scala Session API?

Так же еще вопрос, а зачем вам хранить сессию в контексте? Я вижу, вы все равно удалили его в конце. Если вам нужно, чтобы поддействия имели доступ к сеансу, вы можете просто передать его в функцию.

Я просто предполагаю, что session относится к типу Session

def withTransaction[A](bp: BodyParser[A])(f: Session => Request[A] => Result): Action[A] = {
   Action(bp) {
     request =>
       val session = createSession()
       session.conn.setAutoCommit(false)
       try {
         val result = f(session)(request)
         session.conn.commit()
         result
       }
       catch {
         case t: Throwable =>
           session.conn.rollback()
           throw t
       }
       finally {
         session.close()
       }
   }
}

и ваши поддействия будут

withTransaction(parse.anyContent) { session => request =>
    //code that produces a result here
}

вам больше не нужно оборачивать это в Action, так как оно уже обернуто withTransaction

person thatsmydoing    schedule 12.08.2012
comment
Я не могу сохранить его в сеансе, так как сеансы воспроизведения хранят информацию с использованием файлов cookie (максимум 4 КБ), поэтому я не мог хранить там такой объект, как сеанс базы данных. Кроме того, я не хочу передавать сеанс БД в качестве параметра действия, поскольку сами действия контроллера ни для чего напрямую не зависят от сеанса. Мне пришлось бы передать сеанс БД на несколько уровней вниз, чтобы передать его службам, которым он нужен, но мне нужно создать его в самой внешней области, поскольку мне нужно, чтобы все службы низкого уровня использовали один и тот же сеанс, одну и ту же транзакцию, и по запросу. - person Angel Blanco; 12.08.2012
comment
Кстати, вы сказали, что Http.Context устанавливается только в том случае, если вы используете Java API, тогда нет ли чего-то похожего на Http.Context.current() для scala? Я имею в виду, что это должна быть структура данных, которая хранится на сервере и имеет отдельный экземпляр для каждого запроса. Http.Context является одноэлементным, но когда вы вызываете текущий, он дает объект Context, который отличается для каждого запроса. - person Angel Blanco; 12.08.2012
comment
Я бы предложил использовать ThreadLocal, но, видимо, есть проблемы с таким подходом. Кроме того, автор игры фактически предлагает прохождение всех параметры down, если вы используете Scala, так как он имеет неявные значения. Таким образом, это подразумевает добавление (неявный сеанс: org.scalaquery.session.Session) ко всем методам, участвующим в цепочке вызовов базы данных. - person thatsmydoing; 12.08.2012