重构WCF服务

问题描述 投票:0回答:1

我最近不得不向我编写的现有应用程序添加一个新功能,并查看这部分代码,意识到可能是时候重构和改进了。

原始索引方法:

  • 用户是否已注册 <-- WCF Call
    • 如果没有注册
      • 如果用户可以注册,则运行规则 <-- WCF Call
        • 如果用户无效,则重定向至无访问权限
        • 如果用户有效注册重定向到注册
    • 如果用户已注册
      • 获取物品<-- WCF Call
      • 显示索引页

对后端 Web 服务的三个 wcf 调用

随着新的添加,我需要一些新信息、一些用户选项。

  • 用户是否已注册 <-- WCF Call
    • 如果没有注册
      • 如果用户可以注册,则运行规则 <-- WCF Call
        • 如果用户无效,则重定向至无访问权限
        • 如果用户有效注册重定向到注册
    • 如果用户已注册
      • 获取物品<-- WCF Call
      • 获取用户选项 <-- WCF Call
      • 显示索引页

此功能导致了一个新的 WCF 调用,这使得该方法通过网络进行了 4 次调用。 必须有更好的方法。

我的建议是将其包装到一个 wcf 调用中,以收集有关用户的所有信息,例如他们是否注册、项目、运行规则(如果需要)以及用户选项。

  • 获取用户信息(简称结果对象)<--WCF Call
    • 如果没有结果。IsEnrolled
      • 如果 result.RulesResult.UserIsValid 属性为 false
        • 重定向至无访问权限
      • 如果该属性为真
        • 重定向至注册
    • 如果结果.IsEnrolled
      • 使用 result.UserOptions 和 result.Items 填充 ViewModel

我们只有一个很好的电话,但是我的问题

  • 因此拥有一个对象有意义吗?

  • 如果 IsEnrolled 为 true,则 RulesResult 将为 null,在这种情况下拥有 null 属性是否有意义? 也许提供一个结果,也表明用户已注册,以防稍后检查?

  • 如果 IsEnrolled 为 false,则将填充 RulesResult(有意义),但是 Items 将为 null(有点有意义)用户选项也将为 null 在这种情况下,项目和用户选项的空列表是否比空列表更有意义?

  • 从 api 设计的角度来看,第二个选项是否有意义,或者结果与 UI 密切相关?

两个版本的代码示例:
版本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);
    }
}

版本 2(重构):

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);
    }
}
c# .net wcf api-design
1个回答
2
投票

我认为就 API 效率而言,选项 #2 肯定会表现更好。

就将未使用的参数全部放在一个结果对象中而言,可以使用抽象结果类轻松解决这个问题,然后将两个不同的响应划分为两个不同的具体子类型。

  [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; }
  }

然后你的客户端代码会变成类似...

  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 );
  }

这使客户端清楚地知道可能有两种不同的响应,并清楚地表明哪种响应使用或需要哪些参数。

我认为这是一个非常好的方法。 如果您开始遇到案例,发现自己创建了许多不同类型的函数,这些函数的步骤大致相似,但略有不同,例如......

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

那么,将这些较大的函数分解为多个 WCF 调用可能是值得的,以确保 API 方法不会激增。

© www.soinside.com 2019 - 2024. All rights reserved.