2 votes

Refactoring WCF Service

J'ai récemment dû ajouter une nouvelle fonctionnalité à une application existante que j'ai écrite et, en regardant cette section du code, j'ai réalisé qu'il était peut-être temps de la remanier et de l'améliorer.

Méthode d'indexation originale :

  • IsUserEnrolled <-- Appel WCF
    • Si non inscrit
      • Exécuter des règles si l'utilisateur peut s'inscrire <-- Appel WCF
        • Si l'utilisateur n'est pas valide, redirigez-le vers "Pas d'accès".
        • Si l'utilisateur est valide pour s'inscrire, rediriger vers l'enregistrement.
    • Si l'utilisateur est inscrit
      • Obtenir des articles <-- Appel WCF
      • Afficher la page d'index

Trois appels wcf au service web dorsal

Avec le nouvel ajout, j'avais besoin de nouvelles informations, de nouvelles options pour les utilisateurs.

  • IsUserEnrolled <-- Appel WCF
    • Si non inscrit
      • Exécuter des règles si l'utilisateur peut s'inscrire <-- Appel WCF
        • Si l'utilisateur n'est pas valide, redirigez-le vers "Pas d'accès".
        • Si l'utilisateur est valide pour s'inscrire, rediriger vers l'enregistrement.
    • Si l'utilisateur est inscrit
      • Obtenir des articles <-- Appel WCF
      • Obtenir les options de l'utilisateur <-- Appel WCF
      • Afficher la page d'index

Cette fonctionnalité a entraîné un nouvel appel WCF qui a fait que cette méthode a 4 appels sur le fil. Il doit y avoir un meilleur moyen.

Ma proposition était de regrouper tout cela dans un appel wcf pour rassembler toutes les informations sur l'utilisateur, s'il est inscrit, les éléments, les règles d'exécution si nécessaire, et les options de l'utilisateur.

  • Obtenir des informations sur l'utilisateur (objet résultat pour faire court) <--WCF Call
    • Si non result.IsEnrolled
      • Si la propriété result.RulesResult.UserIsValid est false
        • Rediriger vers No Access
      • Si cette propriété est vraie
        • Rediriger vers le registre
    • Si result.IsEnrolled
      • Remplir le ViewModel avec result.UserOptions et result.Items

Nous avons seulement un appel qui est bon, cependant mes questions

  • Est-ce que le fait d'avoir un seul objet a un sens ?

  • Si IsEnrolled est vrai, le RulesResult sera nul. Le fait d'avoir une propriété nulle a-t-il un sens dans ce cas ? Peut-être faut-il fournir un résultat qui indique également que l'utilisateur est inscrit, au cas où il serait inspecté ultérieurement ?

  • Si IsEnrolled est faux, RulesResult sera rempli (c'est logique) mais les éléments seront nuls (c'est aussi logique) et les options de l'utilisateur seront également nulles. Dans ce cas, est-il plus logique d'avoir une liste vide pour les éléments et les options de l'utilisateur plutôt que null ?

  • Du point de vue de la conception de l'API, la deuxième option est-elle judicieuse ou le résultat est-il trop étroitement lié à l'interface utilisateur ?

Exemple de code pour les deux versions :
Version 1 :

public ActionResult Index()
{

    using (var client =ServiceFactory.CreateChannel())
    {
        var isMemberEnrolled = client.IsMemberEnrolled(User.Identity.Name);

        if (!isMemberEnrolled)
        {
            var accessResult = client.RunRules(User.Identity.Name);

            if (!accessResult.UserIsValid)
            {
                return RedirectToAction("NoAccess");
            }
            return RedirectToAction("Register");
        }

        var userOptions = client.GetUserOptions(User.Identity.Name);

        List<Item> items = client.GetUserItems(User.Identity.Name);

        var viewModel = new ViewModel(userOptions, items);

        return View(viewModel);
    }
}

Version 2 (Refactor) :

public ActionResult Index()
{

    using (var client = ServiceFactory.CreateChannel())
    {
        var userInformation = client.GetUserInformation(User.Identity.Name);

        if (!userInformation.IsMemberEnrolled)
        {
            return RedirectToAction(!userInformation.RulesResult.UserIsValid ? "NoAccess" : "Register");
        }

        var viewModel = new ViewModel(userInformation.UserOptions, userInformation.Items);

        return View(viewModel);
    }
}

2voto

MerickOWA Points 4310

Je pense que pour l'efficacité de l'API, l'option n°2 serait définitivement plus performante.

Pour ce qui est d'avoir des paramètres inutilisés dans un seul objet de résultat, cela pourrait facilement être résolu avec une classe de résultat abstraite, puis en divisant les deux réponses différentes en deux sous-types concrets différents.

  [KnownType( typeof( UserInfoEnrolledResult ) )]
  [KnownType( typeof( UserInfoNotEnrolledResult ) )]
  [DataContract]
  public abstract class UserInfoResult
  {
  }

  [DataContract]
  public class UserInfoEnrolledResult : UserInfoResult
  {
    [DataMember]
    public string UserOptions { get; set; }

    [DataMember]
    public string[] Items { get; set; }
  }

  [DataContract]
  class UserInfoNotEnrolledResult : UserInfoResult
  {
    [DataMember]
    public bool UserIsValid { get; set; }
  }

Alors votre code client deviendrait quelque chose comme...

  using ( var client = ServiceFactory.CreateChannel() )
  {
    var userInformation = client.GetUserInformation( User.Identity.Name );

    if ( userInformation is UserInfoNotEnrolledResult )
    {
      return RedirectToAction( ((UserInfoNotEnrolledResult)userInformation).UserIsValid ? "NoAccess" : "Register" );
    }

    var enrolledUserInformation = (UserInfoEnrolledResult)userInformation;

    var viewModel = new ViewModel( enrolledUserInformation.UserOptions, enrolledUserInformation.Items );

    return View( viewModel );
  }

Cela indique clairement au client que deux réponses différentes sont possibles, et permet de savoir quels paramètres sont utilisés ou nécessaires pour quel type de réponse.

Je pense que c'est une façon parfaitement correcte de procéder. Si vous commencez à rencontrer des cas où vous vous retrouvez à créer de nombreux types de fonctions différentes qui sont toutes des étapes à peu près similaires avec de légères différences comme...

UserInfoResult GetUserInformation( string name );
UserInfoResult GetUserInformationWithoutRuleCheck( string name );
UserInfoResult GetUserInformationWithDoubleSecretChecks( string name );

alors, il pourrait être utile de décomposer ces fonctions plus grandes dans les appels multiples de WCF pour s'assurer que vous n'avez pas une explosion des méthodes d'API.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X