提高WCF服务质量(第2部分——验证)

目录

介绍

使用代码


介绍

我们在前面的部分中讨论了这个重构过程的基础知识。这部分解释了我如何将验证添加到WCF服务。

使用代码

要添加验证,让我们添加一个名为WCFService.Utils的新类库项目到解决方案,然后添加一个名为Validation的文件夹到项目。

然后,在继续之前,让我们回到WCFService.Shared项目并在Objects文件夹下添加一个名为ValidationResult的类,如下所示:

public class ValidationResult
{
    public bool IsValidated { get; set; }
    public List<string> Messages { get; set; }
}

其中IsValidated属性将保存验证结果,Messages属性将保存验证错误消息(如果有)。

现在返回到WCFService.Utils项目,添加一个名为IBaseValidator的接口和一个名为BaseValidator的类,该类继承了Validation文件夹下的IBaseValidator

public interface IBaseValidator
{
    ValidationResult Validate(BaseRequest request);
}
public class BaseValidator : IBaseValidator
{
    public virtual ValidationResult Validate(BaseRequest request)
    {
        bool validationResult = false;
        List<string> messages = new List<string>();
        if (string.IsNullOrWhiteSpace(request.Username))
        {
            validationResult = false;
            messages.Add("Empty username.");
        }
        if (string.IsNullOrWhiteSpace(request.Password))
        {
            validationResult = false;
            messages.Add("Empty password");
        }
        return new ValidationResult
        {
            IsValidated = validationResult,
            Messages = messages
        };
    }
}

关于BaseValidator类,我想注意几点。首先,由于我们将使用身份验证,并且将从BaseRequest类中继承每个请求对象,因此每个传入的请求都将保留UsernamePassword值。由于这些字段是身份验证所必需的,因此应验证每个请求是否存在其属性。这就是我们将这些验证放在基类中的原因。还要标记该Validate函数被标记为virtual。这有两个目的。首先,允许从该基类继承的任何验证类实现它们自己的验证过程(甚至对于UsernamePassword属性)并统一所有派生验证类的实现。

然后,我们通过在每个服务库下的Validators文件夹下创建验证器,开始为所需的每个请求实现验证器。让我们创建并检查我们的第一个验证器,它将验证玩家创建过程的请求。

internal class CreatePlayerValidator : BaseValidator
{
    public override ValidationResult Validate(BaseRequest req)
    {
        ValidationResult result = base.Validate(req);
        if (!result.IsValidated)
            return result;
        else
        {
            bool validationResult = true;
            List<string> messages = new List<string>();
            CreatePlayerRequest request = req as CreatePlayerRequest;
            if (request == null)
                return new ValidationResult
                {
                    IsValidated = false,
                    Messages = new List<string> { "Can not convert request object 
                                                   or request object null" }
                };
            if (string.IsNullOrWhiteSpace(request.Name))
            {
                validationResult = false;
                messages.Add("Name attribute can not be null when creating a player");
            }
            if (request.DateOfBirth.AddYears(10) > DateTime.Now)
            {
                validationResult = false;
                messages.Add("A player must be at least 10 years old to be registered");
            }
            if (request.Height.HasValue && request.Height.Value < 100)
            {
                validationResult = false;
                messages.Add("A player must be at least 10 cm tall to be registered");
            }
            if (request.Height.HasValue && request.Height.Value > 220)
            {
                validationResult = false;
                messages.Add("A player must be most 220 cm tall to be registered");
            }
            if (request.Weight.HasValue && request.Weight.Value < 40)
            {
                validationResult = false;
                messages.Add("A player must be at least 40 kg to be registered");
            }
            if (request.Weight.HasValue && request.Weight.Value > 140)
            {
                validationResult = false;
                messages.Add("A player must be most 140 kg tall to be registered");
            }
            return new ValidationResult
            {
                IsValidated = validationResult,
                Messages = messages
            };
        }
    }
}

请注意,我们已将此CreatePlayerValidator类的访问修饰符从public更改为internal。由于我们将仅在当前程序集中使用此类,因此这是最适合设置的访问修饰符。另外,标记我们正在覆盖从基类继承的Validate方法,但仍然不想丢失在基类中完成的验证过程。为了保持基础验证,我们首先从基类运行验证过程,如果基础验证失败,则返回而不进一步执行。尽管这不是强制性的(开发人员可以选择一次返回所有验证结果),但这是一种设计选择。如果我们继续进行基本验证过程,下一步是通过使用恢复原始请求as关键词。由于我们已将输入参数定义为BaseRequest, 以增加可重用性,所有其他请求对象都是从其中派生的,因此可以将所有请求对象发送到此方法。所以为了保证这个过程的安全,我们应该首先检查类型并将其分配给它的原始类型以检查类型验证,然后访问请求对象的属性。然后我们创建两个属性validationResultmessages,它们与ValidatonResult类属性相同,其余的本身就很简单。首先,如有必要则检查是否为空或null,然后根据业务规则检查值。在这个例子中,我们要求年龄超过10岁,身高在100220厘米之间,体重在40140公斤之间。这些只是业务规则,它们不是一成不变的,如果不需要,甚至可能不存在。最后,我们所要做的就是创建一个ValidationResult类型的返回对象并设置我们从规则检查中收集的值。

如有必要,相同的规则适用于所有请求对象。

internal class GetClubPlayersValidator : BaseValidator
{
    public override ValidationResult Validate(BaseRequest req)
    {
        ValidationResult result = base.Validate(req);
        if (!result.IsValidated)
            return result;
        else
        {
            bool validationResult = true;
            List<string> messages = new List<string>();
            GetClubPlayersRequest request = req as GetClubPlayersRequest;
            if (request == null)
                return new ValidationResult
                {
                    IsValidated = false,
                    Messages = new List<string> { "Can not convert request object 
                                                   or request object null" }
                };
            if (string.IsNullOrWhiteSpace(request.Club))
            {
                validationResult = false;
                messages.Add("Club name attribute can not be null 
                              when searching for club players");
            }
            return new ValidationResult
            {
                IsValidated = validationResult,
                Messages = messages
            };
        }
    }
}
internal class GetPlayerByIdValidator : BaseValidator
{
    public override ValidationResult Validate(BaseRequest req)
    {
        ValidationResult result = base.Validate(req);
        if (!result.IsValidated)
            return result;
        else
        {
            bool validationResult = true;
            List<string> messages = new List<string>();
            GetPlayerByIdRequest request = req as GetPlayerByIdRequest;
            if (request == null)
                return new ValidationResult
                {
                    IsValidated = false,
                    Messages = new List<string> { "Can not convert request object 
                                                   or request object null" }
                };
            if (request.PlayerId < 1)
            {
                validationResult = false;
                messages.Add("Player identifier should be a positive integer");
            }
            return new ValidationResult
            {
                IsValidated = validationResult,
                Messages = messages
            };
        }
    }
}

在创建必要的验证类之后,我们应该更新我们的服务方法以包含验证过程。但在继续之前,如果您还没有注意到,请快速提醒一下,我们还没有创建一个名为GetAllPlayersValidator的验证器类以验证GetAllPlayers方法。由于该方法只需要一个BaseRequest类型的输入对象,因此BaseValidator类足以验证该方法的传入请求。

这些更改将使我们的服务方法如下所示:

public CreatePlayerResponse CreatePlayer(CreatePlayerRequest request)
{
    try
    {
        CreatePlayerValidator validator = new CreatePlayerValidator();
        ValidationResult valResult = validator.Validate(request);
        if (!valResult.IsValidated)
            return new CreatePlayerResponse
            {
                IsException = false,
                IsSuccess = false,
                Messages = valResult.Messages.ToArray()
            };
        return new CreatePlayerResponse
        {
            PlayerId = PlayerRepository.CreateNewPlayer(request.Name, 
                       request.DateOfBirth, request.Height, request.Weight, request.Club),
            IsException = false,
            IsSuccess = true,
            Messages = new string[] { "Operation successful" }
        };
    }
    catch (Exception ex)
    {
        return new CreatePlayerResponse
        {
            IsException = true,
            IsSuccess = false,
            Messages = new string[] { ex.Message }
        };
    }
}
public GetAllPlayersResponse GetAllPlayers(BaseRequest request)
{
    try
    {
        BaseValidator validator = new BaseValidator();
        ValidationResult valResult = validator.Validate(request);
        if (!valResult.IsValidated)
            return new GetAllPlayersResponse
            {
                IsException = false,
                IsSuccess = false,
                Messages = valResult.Messages.ToArray()
            };
        return new GetAllPlayersResponse
        {
            PlayerList = PlayerRepository.GetAllPlayers(),
            IsException = false,
            IsSuccess = true,
            Messages = new string[] { "Operation successful" }
        };
    }
    catch (Exception ex)
    {
        return new GetAllPlayersResponse
        {
            IsException = true,
            IsSuccess = false,
            Messages = new string[] { ex.Message }
        };
    }
}
public GetClubPlayersResponse GetClubPlayers(GetClubPlayersRequest request)
{
    try
    {
        GetClubPlayersValidator validator = new GetClubPlayersValidator();
        ValidationResult valResult = validator.Validate(request);
        if (!valResult.IsValidated)
            return new GetClubPlayersResponse
            {
                IsException = false,
                IsSuccess = false,
                Messages = valResult.Messages.ToArray()
            };
        return new GetClubPlayersResponse
        {
            PlayerList = PlayerRepository.GetClubPlayers(request.Club),
            IsException = false,
            IsSuccess = true,
            Messages = new string[] { "Operation successful" }
        };
    }
    catch (Exception ex)
    {
        return new GetClubPlayersResponse
        {
            IsException = true,
            IsSuccess = false,
            Messages = new string[] { ex.Message }
        };
    }
}
public GetPlayerByIdResponse GetPlayerById(GetPlayerByIdRequest request)
{
    try
    {
        GetPlayerByIdValidator validator = new GetPlayerByIdValidator();
        ValidationResult valResult = validator.Validate(request);
        if (!valResult.IsValidated)
            return new GetPlayerByIdResponse
            {
                IsException = false,
                IsSuccess = false,
                Messages = valResult.Messages.ToArray()
            };
        return new GetPlayerByIdResponse
        {
            Player = PlayerRepository.GetPlayerById(request.PlayerId),
            IsException = false,
            IsSuccess = true,
            Messages = new string[] { "Operation successful" }
        };
    }
    catch (Exception ex)
    {
        return new GetPlayerByIdResponse
        {
            IsException = true,
            IsSuccess = false,
            Messages = new string[] { ex.Message }
        };
    }
}

这是我们系列的第二部分,解释了将验证过程添加到我们的服务请求中。

您可以在此处阅读下一部分(身份验证/授权)。

https://www.codeproject.com/Articles/5325807/Improving-WCF-Service-Quality-Part-2-Validation

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值