65.9K
CodeProject 正在变化。 阅读更多。
Home

提高 WCF 服务质量(第二部分 - 验证)

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2022 年 2 月 28 日

CPOL

4分钟阅读

viewsIcon

5082

如何向 WCF 服务请求添加验证

引言

我们在上一部分这里讨论了这种重构过程的基础知识。 本部分解释了如何向 WCF 服务添加验证。

Using the Code

要添加验证,让我们向解决方案添加一个名为 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。 这有两个目的。 首先,允许从该基类继承的任何 Validation 类实现它们自己的验证过程(甚至对于 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,为了提高可重用性,所有其他请求对象都从 BaseRequest 派生而来,因此可以将所有请求对象发送到此方法。 因此,为了确保该过程的安全,我们应首先检查类型并将其分配到其原始类型中以检查类型验证,然后访问请求对象的属性。 然后,我们创建两个属性 validationResultmessages,它们与 ValidatonResult 类属性相同,其余操作非常简单。 首先,根据需要检查空值或 null 值,然后根据业务规则检查值。 在此示例中,我们要求年龄大于 10 岁,身高在 100 到 220 厘米之间,体重在 40 到 140 公斤之间。 这些只是非恒定的业务规则,如果不需要,甚至可能不存在。 最后,我们要做的就是创建 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 }
        };
    }
}

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

您可以阅读下一部分(身份验证/授权)这里

历史

  • 2022 年 2 月 28 日:初始版本
© . All rights reserved.