9
votes

Comment passer des messages de validation de couche de service à l'appelant?

J'ai fait beaucoup de recherche, y compris ici, et je ne peux pas sembler trouver une direction claire. J'ai actuellement une application ASP.NET MVC3, avec une couche de service qui repose sur le dessus d'un référentiel.

dans ma couche de service, j'ai des fonctions telles que: xxx

J'ai vu que des gens disent que la validation des paramètres n'est pas très exceptionnelle et que, donc, jeter une exception n'est pas très appropriée. Je n'aime pas non plus l'idée de passer dans un paramètre Out, telle qu'une chaîne, et vérifier une valeur vide. J'ai envisagé de mettre en œuvre une classe de validationndiction et en faisant une propriété de toute classe de service donnée (il contiendrait un iSvalid booléen et une liste de messages d'erreur, et pourrait être vérifié après une fonction de fonction donnée dans la couche de service pour voir comment les choses sont allées). Je pourrais vérifier l'état validationdiction après avoir exécuté une fonction donnée: xxx

La chose que je n'aime pas à ce sujet est que je devrais le mettre à jour pour chaque appel de la fonction de couche de service , pour éviter d'avoir conserver des valeurs anciennes (si j'ai choisi de ne pas l'utiliser pour de nombreuses fonctions ou la plupart des fonctions, on s'attendrait toujours à ce qu'elle ait une valeur significative ou nulle après avoir exécuté une fonction donnée). Une autre chose que j'ai envisagée est en train de passer dans le validationdictionnaire pour chaque appel de fonction qui pourrait avoir des informations de validation détaillées, mais je suis revenu à l'aide d'un paramètre OUT ...

Faites-vous des recommandations? Je ne peux pas sembler trouver un moyen propre de faire cela. Parfois, le retour de NULL pour une fonction est suffisamment d'informations, mais parfois, j'aimerais que des informations plus de validation sont passées à l'appelant. Tout conseil serait apprécié!

Modifier pour clarifier: Ma couche de service n'est pas consciente qu'il s'agit d'une application MVC qui la consomme. La couche de service comporte simplement certaines fonctions publiques telles que CreateBatchFile () ou AdddeBebest (). Le retour de NULL est parfois suffisant pour le consommateur (dans ce cas un contrôleur, mais pourrait être autre chose) à savoir ce qui s'est passé, et parfois, le consommateur voudrait peut-être plus d'informations sur la couche de service (peut-être passer à modélisation si le consommateur est un contrôleur). Comment puis-je bouillir à partir de la couche de service elle-même?


0 commentaires

4 Réponses :


1
votes

J'ai utilisé un système où il faisait passer une éventail de messages (ou collection de classes), chaque élément avait des codes, des descriptions, des messages conviviaux. Nous voulions simplement vérifier si quelque chose était là. Cela a fonctionné super entre l'interface utilisateur et un autre calque "Service", toutes les exceptions ont été gentiment attrapées, ils ont été traduits dans ces règles de validation ... juste une idée


0 commentaires

1
votes

Utilisez des objets ViewModel qui sont passés entre les vues et les méthodes d'action du contrôleur. Les objets ViewModel peuvent gérer la validation par un Validate (validationdictiondiction de validationddiction) méthode.

Le contrôleur devra appeler la méthode de validation sur l'objet ViewModel avant d'appeler n'importe quelle méthode dans la couche de service. Cela ne devrait être nécessaire que pour les actions de post HTTP.

Vos vues devront alors afficher des messages de validation.

Cette solution nécessite que les objets de mention de vie soient passés entre l'action du contrôleur et la vue, mais de nos jours, principalement géré par la modélisation En MVC.

Vos actions de votre contrôleur (http Post) ressembleront à ceci: xxx

Votre méthode de validation dans votre viewModel ressemblera à ceci: < / p> xxx


6 commentaires

Hmmm ... je pense que je parle d'un niveau inférieur. Nous supposerons que l'utilisateur a appuyé sur un bouton et que la validation de la vue Mododel est sortie sans attelage. Mon contrôleur appellera ensuite une fonction dans la couche de service et cette fonction peut échouer pour une variété de raisons (ou peut-être que la validation des images de vue était plus généreuse que le service n'exige réellement que lorsque le service valide les paramètres de lui-même, il échoue) . Comment puis-je transmettre ces informations à partir de la couche de service à la suite du contrôleur, pour arriver au point où je pourrais afficher avec ViewModel ou ModelState?


Je m'assure que toutes les logiques de validation existent dans la viewModel. Pourquoi voulez-vous que la logique de validation soit diffusée partout? La validation d'entrée appartient au module d'interface utilisateur. Si quelque chose ne va pas dans la couche de service, vous devez lancer une exception, pour fournir une journalisation avec de meilleurs messages d'erreur. Votre application MVC peut ensuite rediriger vers des pages d'erreur amies en fonction du code d'exception / http.


Disons que je suis dans la couche de service et validant que la date passée dans CareeBebreQuest (...) n'est pas plus de trois jours à l'avenir. Il semble que je devais valider cela ici dans la couche de service, en plus de, où je l'ai validé plus haut dans la chaîne. Serais-tu d'accord avec ça? Si oui, pensez-vous que je devrais réellement effectuer une validation dans ma couche de service, mais je viens de jeter des exceptions lorsque la validation échoue? Ou devrais-je ne pas valider cette date dans ma couche de service (je serais nerveux de s'appuyer sur le consommateur de service)? Merci...


Je pense que vous devriez effectuer votre validation de l'interface utilisateur (comme la date de crédibleBebreQuest) dans un niveau supérieur à la couche de service. Si vous n'écrivez pas vous-même la couche ci-dessus et ne faites pas confiance à ce calque, je pense que votre couche de service devrait lancer une exception. La couche de service est-elle une couche de service Web que l'application MVC utilise-t-elle? Dans ce cas, la couche WebService sur la couche de service doit effectuer la validation d'entrée et lancer des exceptions en conséquence avec des codes HTTP appropriés et des messages.


Intéressant. Nope, pas de service Web à ce stade. Donc, vous disiez essentiellement que quelque chose d'invalide qui entre dans la couche de service est digne d'exception (sonne raisonnable, mais je veux juste être clair)? Le consommateur d'essayer de ne pas lancer d'exceptions en validant les données avant son entrée, mais si le consommateur est irresponsable, la couche de service jette une exception en dernier recours. Est-ce que ça sonne exactement? Il est attrayant dans sa propreté.


Exactement! :-) Et parce que l'appelant et la couche de service réside dans la même application, une exception ne sera levée que lorsque vous avez un bogue dans votre logique de validation dans l'appelant.



10
votes

C'est ce que je fais. Avoir une classe pour votre validation et, au lieu de passer des paramètres, passez un modèle de vue. Donc, dans votre cas, quelque chose comme ça, où ValidationResult est juste un simple nom de classe W / Nom et ErrormSage Propriétés: xxx

}

puis crée une méthode d'extension de contrôleur pour copier ces Résultats de la validation à l'état modèle. xxx

puis dans votre contrôleur fait quelque chose comme xxx

alors dans votre vue que vous pouvez Afficher des erreurs comme la normale. xxx


10 commentaires

Ma couche de service n'est pas consciente qu'il s'agit d'une application MVC qui la consomme. Il possède simplement certaines fonctions publiques telles que CreateBatchfile ou AdddeBeQuest. Le retour de NULL est parfois suffisant pour que le contrôleur sache ce qui s'est passé et que le contrôleur souhaite parfois plus d'informations auprès de la couche de service (peut-être de transmettre le modèle de modélisation et de ne pas). Comment la bulle est-elle de la couche de service elle-même?


@JOSH - La couche de service dans cet exemple n'a aucune dépendance sur MVC, seule la classe ValidationResult, qui n'est qu'une classe normale que j'ai créée. Vous pouvez faire la même chose en passant dans la modélisation, mais je pense que le retour d'un iNeumable est une meilleure façon, car il serait plus facile de tester.


Où puis-je retourner cet itenhabilable ? Je comprends que la validation devrait être effectuée à un niveau avant d'arriver à l'appel de la fonction de service, mais que se passe-t-il si des erreurs se produisent dans cette fonction réelle dans la couche de service (par exemple dans SVC.CreateBatchFile ())? Devrais-je adopter une iTenumerable vide à la fonction de service comme un paramètre OUT, puis vérifiez-le après avoir appelé ma fonction de service? Ex: svc.createbatchfile (hors validationResults)? Merci


@JOSH - Vous pouvez retourner les validationsRésultats des fonctions de service, pas besoin de paramètres. Ensuite, l'extension du contrôleur (le modèle ModelState.addModelerors) s'occupera de l'ajouter à l'état modèle s'il y avait des erreurs.


Dans mon cas, j'ai des articles comme ChargePaymentCardCard (), qui renvoie une distribution de paiement ou CreateUser, qui renvoie l'utilisateur. Si je retourne les validationsRésultats, il semble que je perds ma capacité à renvoyer l'élément pertinent à la fonction ...?


Dans le code de la réponse ci-dessus, la validation est effectuée à partir du contrôleur (par appel à DEBITREQUESTVALIDADOR) et non dans la couche de service. Il n'est donc nécessaire de renvoyer les validationsRésultats des méthodes de couche de service.


Si vous devez exécuter la validation dans la couche de service, enveloppez la modélisation de l'installation dans une interface et fournissez une implémentation par défaut (avec une modélisation). Envoyez l'interface à chaque méthode de service (l'interface est utilisée, sans dépendance sur MVC dans la couche de service). Comme il s'agit d'un type de référence, il fonctionnera comme paramètre d'entrée et de sortie, c'est-à-dire qu'il peut être modifié par la couche de service en ajoutant des erreurs. De cette façon, la couche de service peut toujours retourner un autre objet tel que PaymentTransaction.


@Marcus - merci pour vos commentaires. Ne pas continuer à battre un cheval mort, mais si je faisais de la validation de la couche de service dans certaines circonstances, il serait-il préférable de transmettre ce dictionnaire dans le constructeur de service et qu'il est accessible via une propriété de la classe de services? Ensuite, je n'aurais pas besoin d'instancier et de le transmettre pour chaque appel de fonction. Ou est-il préférable de le transmettre dans la fonction elle-même?


@JOSH - Si vous utilisez un conteneur IOC, vous aurez du mal à le transmettre dans le constructeur, vous voudrez probablement probablement le transmettre dans la fonction. Bien que je pense toujours que le retour de la liste des résultats de validation serait un test d'unité plus facile sage.


Il est possible de transmettre le dictionnaire du constructeur de service, mais il faut que le service soit "nouveau" pour chaque demande Web. Ceci est possible de faire avec un conteneur COI et le mode de vie du service doit être réglé sur "transitoire" ou "par demande web". Le mode de vie du dictionnaire doit être réglé sur transitoire, vous aurez besoin d'une nouvelle instance vide pour chaque demande Web. Si vous devez effectuer la validation dans la couche de service, j'aurais utilisé la propriété ModelState du contrôleur et l'avez transmise à chaque appel à la couche de service.



1
votes

Si vous venez de faire la validation de Mododel, flueuretvalidation forte> est une excellente bibliothèque.

Si vous souhaitez inclure la validation des affaires en tant que rétroaction à l'utilisateur, vous pouvez utiliser le motif de l'adaptateur, Ça va vous donner ce que vous voulez. P>

Créer une interface (iDalidationDictionary ou quelque chose de similaire). Cette interface définirait une méthode Adderror et serait transmise à votre service afin d'ajouter des messages d'erreur. P> xxx pré>

Créer un modèle de modèle pour votre application MVC. P>

public ActionResult Test(ViewModel viewModel)
{
    var modelStateAdapter = new ModelStateAdapter(ModelState);
    _serviceName.CreateDebitRequest(viewModel.UserId, viewModel.CardId, ... , modelStateAdapter);

    if(ModelState.IsValid)
        return View("Success")

    return View(viewModel);
}


0 commentaires