c# - 重构WCF服务

标签 c# .net wcf api api-design

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

原始索引方法:

  • IsUserEnrolled <-- WCF 调用
    • 如果未注册
      • 如果用户可以注册<-- WCF 调用,则运行规则
        • 如果用户无效,则重定向至“无访问权限”
        • 如果用户有效,可以注册重定向以进行注册
    • 如果用户已注册
      • 获取项目<-- WCF 调用
      • 显示索引页

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

对于新添加的内容,我需要一些新信息和一些用户选项。

  • IsUserEnrolled <-- WCF 调用
    • 如果未注册
      • 如果用户可以注册<-- WCF 调用,则运行规则
        • 如果用户无效,则重定向至“无访问权限”
        • 如果用户有效,可以注册重定向以进行注册
    • 如果用户已注册
      • 获取项目<-- WCF 调用
      • 获取用户选项<-- WCF 调用
      • 显示索引页

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

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

  • 获取用户信息(简称结果对象)<--WCF 调用
    • 如果没有结果。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);
    }
}

最佳答案

我认为就 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 方法激增的情况。

关于c# - 重构WCF服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11422279/

相关文章:

c# - 在 .NET 2.0 上消除文本锯齿的更好方法吗?

c# - 排序元组列表时的默认行为是什么?

c# - Azure DevOps Docker 在管道中构建并在版本中推送 Docker

c# - 来自 WCF 服务的方法未显示在客户端应用程序中

.net - 在选中验证复选框的情况下将消息发送到私有(private) MSMQ 队列?

wcf - “System.IO.Compression.GZipStream”无法序列化。考虑用 DataContractAttribute 属性标记它

c# - 查找哪个文本框为空

c# - 如何检查 C# Stream 是否可调整大小?

.net - 如何使用名称作为枚举已经被 vb.net 用作关键字

.net - Prism:EventAggregator 和 MEF - EventAggregator 的 2 个不同实例