2017-05-28 2 views
1

Je déteste demander - je fais vraiment, mais celui-ci m'a eu pour le moment ..et sortir deux Composing futures actions asynchrones à l'écran

Je suis en train de composer des actions (en jouer Cadre & scala) avec mon guide principal étant this vid. Cependant, il a été fait il y a quelques années, donc certaines fonctionnalités ont été déconseillées depuis lors et j'ai donc dû trouver des solutions de rechange au fur et à mesure. Actuellement, j'essaie de générer deux actions asynchrones dans certaines balises HTML.

I émis avec succès une seule action avec ce contrôleur:

package controllers 

import akka.actor.ActorSystem 
import javax.inject._ 
import play.api.mvc._ 
import services.ServiceClient 
import scala.concurrent.ExecutionContext 

@Singleton 
class AsyncController @Inject() (sc: ServiceClient)(actorSystem: ActorSystem)(implicit exec: ExecutionContext) extends Controller { 

    def index = Action.async { request => 

    val asy1 = sc.makeServiceCall("async1") 

    for { 
     async1Message <- asy1 
    } yield { 
     Ok(views.html.async1.async1(async1Message)) 
    } 
    } 

} 

Si vous vous demandez l'sc.makeServiceCall fait référence à ce fichier:

class ServiceClient @Inject() (ws: WSClient) { 

    def makeServiceCall(serviceName: String): Future[String] = { 
    ws.url(s"http://localhost:9000/mock/$serviceName").get().map(_.body) 
    } 

} 

Alors j'ai suivi la vidéo dans son orientation pour composer deux actions asynchrones avec du HTML. Et c'est là, il devient difficile/intéressant/bouleversant:

package controllers 

import javax.inject.Inject 
import akka.actor.ActorSystem 
import play.api.mvc._ 
import scala.concurrent.{ExecutionContext} 
import Ui.Pagelet 

class AsyncHomeController @Inject() (as1: AsyncController)(as2: Async2Controller)(actorSystem: ActorSystem)(implicit exec: ExecutionContext) extends Controller { 

    def index = Action.async { request => 

    val asy1 = as1.index(request) 
    val asy2 = as2.index(request) 

    for { 
     async1Result <- asy1 
     async2Result <- asy2 

     async1Body <- Pagelet.readBody(async1Result) 
     async2Body <- Pagelet.readBody(async2Result) 

    } yield { 
     Ok(views.html.home2(async1Body, async2Body)) 
    } 
    } 

} 

Alors Async2Controller est très similaire à AsyncController et Pagelet.readBody se réfère à ceci:

package Ui 

import play.api.libs.iteratee.Iteratee 
import play.api.mvc.{Codec, Result} 
import play.twirl.api.Html 
import scala.concurrent._ 

object Pagelet { 

    def readBody(result: Result)(implicit codec: Codec): Future[Html] = { 
    result.body.run(Iteratee.consume()).map(bytes => Html(new String(bytes, codec.charset))) 
    } 

} 

Et c'est où l'erreur est - ce qui est:

terme de valeur

ne fait pas partie de play.api.http.HttpEntity

Je ne trouve pas de documentation indiquant s'il doit être injecté ou aucune indication indiquant qu'il a été déconseillé depuis. Si quelqu'un a une réponse à cette question ou une question de travail s'il vous plaît divulguer. Mille mercis

+0

Il pourrait être un problème avec des versions différentes. La vidéo est assez vieille. – Zernike

+0

Oui @Zemike - Ce n'est pas un problème de compatibilité mais oui la vidéo a quelques années maintenant. C'est pourquoi je suis à la recherche d'une solution alternative moderne. –

Répondre

0

La bibliothèque Iteratee est dépréciée et a été remplacée par akka-stream. Vous devez changer la mise en œuvre de readBody:

def readBody(result: Result)(implicit mat: Materializer, ec: ExecutionContext, codec: Codec): Future[Html] = { 
    result.body.consumeData.map(byteString => Html(codec.decode(byteString)) 
} 

Vous devez également modifier les dépendances du contrôleur pour obtenir un Materializer:

class AsyncHomeController @Inject() (as1: AsyncController, as2: Async2Controller)(actorSystem: ActorSystem)(implicit exec: ExecutionContext, mat: Materializer) 

Edit: code mis à jour

+0

merci - cela semble proche mais j'ai eu cette erreur *** pas assez d'arguments pour la méthode consumeData *** donc je l'ai fait 'def readBody (résultat: Résultat) (mat implicite: Materializer, codec: Codec): Future [Html] = { result.body.consumeData (mat) .map (byteString => Html (codec.decode (byteString))) } 'qui récupère ensuite cette erreur - *** Impossible de trouver un ExecutionContext implicite ***. Bien sûr, si j'ajoute ceci comme implicite, cela crée des problèmes avec l'autre implicite, donc je me bats pour obtenir la bonne combinaison. C'est comme si nous nous rapprochions définitivement. –

+0

Merci pour la mise à jour - presque raté.L'implémenter comme ceci provoque une erreur de *** n'a pas pu trouver de valeur implicite pour le paramètre mat: akka.stream.Materializer *** malgré l'avoir importé. Donc, avec cette technique, je devrais passer 'Materializer' comme paramètre chaque fois que j'appelle la fonction qui ne me semble pas correcte. J'ai cependant obtenu cela pour travailler en créant 'implicit val system = ActorSystem(); implicit mat mat = ActorMaterializer() 'dans le * Object * et en le passant dans la méthode comme précédemment, ie' consumeData (mat) 'mais cela semble aussi verbeux –

+0

En faisant cela, vous créez un' ActorSystem' et un 'Materializer 'mais le jeu en a déjà un. Dans votre contrôleur, vous devez indiquer au jeu d'en injecter un: 'class AsyncHomeController @Inject() (as1: AsyncController, as2: Async2Controller) (actorSystem: ActorSystem) (exec implicite: ExecutionContext, mat: Materializer)' – vdebergue