我最近不得不为我编写的现有应用程序添加一个新功能,并查看这部分代码,意识到可能是重构和改进的时候了。
原始索引方法:
对后端Web服务的三次wcf调用
随着新增加,我需要一些新信息,一些用户选项。
此功能导致新的WCF调用,这使得这一方法通过线路进行了4次调用。必须有更好的方法。
我的建议是将其包装成一个wcf调用,以收集有关用户的所有信息,他们是否已注册,项目,运行规则(如果需要)和用户选项。
我们只有一个好的电话,不过我的问题
结果是否有一个对象有意义?
如果IsEnrolled为true,则RulesResult将为null,在此实例中是否有null属性?也许提供一个结果,也表示用户已注册,因为以后会进行检查?
如果IsEnrolled为false,将填充RulesResult(有意义)但是Items将为null(有意义)用户选项也将为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);
}
}
答案 0 :(得分: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方法。