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





0/5 (0投票)
如何向 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
类继承每个请求对象,因此每个传入的请求都将包含 Username
和 Password
值。 由于这些字段是身份验证所必需的,因此应验证每个请求是否存在这些属性。 这就是我们将这些验证放在基类中的原因。 另请注意,Validate
函数被标记为 virtual
。 这有两个目的。 首先,允许从该基类继承的任何 Validation 类实现它们自己的验证过程(甚至对于 Username
和 Password
属性),并统一所有派生验证类的实现。
然后,我们开始为每个服务库下的 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
派生而来,因此可以将所有请求对象发送到此方法。 因此,为了确保该过程的安全,我们应首先检查类型并将其分配到其原始类型中以检查类型验证,然后访问请求对象的属性。 然后,我们创建两个属性 validationResult
和 messages
,它们与 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 日:初始版本