如何验证集合的类型?

Posted

技术标签:

【中文标题】如何验证集合的类型?【英文标题】:How to validate type of collections? 【发布时间】:2019-04-22 06:44:14 【问题描述】:

如何验证和捕获 System.Web.Http.ApiController 类的集合类型转换(JSON 字符串数组到 C# 长集合)(如果可能,在模型初始化之前)?

我想验证并捕获 JSON 数组中的任何非数字元素,以作为错误的请求响应返回(可能以某种方式带有数据注释)。

当包含非数字 JSON 元素(要转换为长集合)时,它们无法解析并在模型传递给 ApiController 方法之前被剥离。鉴于以下类,有效输入应仅包含“PerferredNutTypes”和“GeographyIDs”的数值。

public class SquirrelController : ApiController

    [HttpPost]
    [Route("api/squirrels/search")]
    [SwaggerResponse(HttpStatusCode.OK, Type = typeof(SquirrelsResponse))]
    public HttpResponseMessage Squirrels(SquirrelsRequest model)
    
        // model already parsed by the time breakpoint reaches here and non-convertable elements already stripped

        ...
        ...
        ...

        SquirrelsResponse results = Targeting.SearchForSquirrels(model);
        return Request.CreateResponse(HttpStatusCode.OK, results);
    


public class SquirrelsRequest

    public SquirrelsRequest() 

    public List<long> PreferredNutTypes  get; set;  = new List<long>();
    public GeographySearch geographySearch  get; set;  = new GeographySearch();


public class GeographySearch

    public GeographySearch() 

    public BooleanOperator Operator  get; set;  = BooleanOperator.OR;
    public List<long> GeographyIDs  get; set;  = new List<long>();


public enum BooleanOperator

    AND,
    OR

示例:

//"Toronto" sould be an invalid input when converting from JSON string array to c# long collection.

  "PreferredNutTypes": [34,21],
  "GeographySearch": 
    "Operator": 1,
    "GeographyIDs": ["Toronto"]
  ,


// This is what the model currently looks like in public HttpResponseMessage Squirrels(SquirrelsRequest model)
new SquirrelsRequest()

    PreferredNutTypes = new List<long>()  34, 21 ,
    GeographySearch = new GeographySearch()
    
        Operator = 1
        GeographyIDs = new List<long>()
    

期望:

理想情况下捕获任何非数字值并将它们作为错误请求返回。类似于如何验证到如何使用数据注释来验证范围。 可以接受数据注释解决方案。 理想情况下,这是一种比访问 ModelState 和解析错误消息/密钥更清晰的方法。 理想情况下,可以普遍应用于任何集合。

我尝试过的事情:

尝试了自定义数据注释验证器,但只能在解析后访问值。 尝试通过 HttpActionContext 的 ModelState 访问验证错误,但充其量只能获取这些值...
System.Web.Http.Controllers.HttpActionContext actionContext.ModelState.["model.GeographySearch.GeographyIDs[0]"].Errors[0].Exception.Message => "Error converting value \"sonali7678687\" to type 'System.Int64'. Path 'subjectSearch.writingAbout[0]', line 6, position 36."
System.Web.Http.Controllers.HttpActionContext actionContext.ModelState.["model.GeographySearch.GeographyIDs[0]"].Errors[0].Exception.InnerException.Message => "Input string was not in a correct format."

...肯定有更好的验证方式吗?

更新 1: 改写问题以使解释和意图更清楚。

【问题讨论】:

ModelState 错误告诉你想要是无效的(即在你给出的例子中,它告诉你GeographyIDs 的第一个值是无效的)所以它不清楚你在期待什么或想做。 我认为您可以从Request["GeographySearch.GeographyId"] 获取当前值,但如果结果不为空,我将只查看ModelState.Where(m =&gt; m.Errors.Count &gt; 0) 并返回通用Response.StatusCode = 404 以保持简单。跨度> 【参考方案1】:

为什么你的字体很长?另外,你会使用小数吗?如果没有,您需要的是 int.TryParse()。无论您在哪里使用 int.parse(或您的情况下的 long.parse()),都将其替换为 int.TryParse()。 TryParse 返回一个布尔值(True 或 False),让您知道要解析的字符串是否为数字。

示例:

bool isNumber = int.TryParse("Data I'm Trying to parse but it's a string", variableTheResultWillGetStoredToifSuccessful);

这将返回错误,并且我永远不应该使用的超长变量名将保持为空或不变。因此,您可以这样做

if(isNumber == false)
//skip storing the number
else
//keep doing what you're doing;

你也可以这样做,更简洁地重写上面的内容:

if(isNumber)
//keep doing what you're doing

或多或少,这就是它的摘要。 TryParse 将根据解析是否成功返回 true 或 false 而不会导致代码崩溃,然后您可以使用该信息继续您看起来合适的方式。

如果您要使用小数,请使用 double 而不是 int。

【讨论】:

【参考方案2】:

您可以尝试 JSON Schema 验证器,修改您的方法以接收 JSON 正文,先对其进行验证,然后将其转换为模型。

public class SquirrelController : ApiController

    [HttpPost]
    [Route("api/squirrels/search")]
    public SquirrelsResponse Squirrels(PostBody model)
    
        var generator = new JSchemaGenerator();
        var schema = generator.Generate(typeof(SquirrelsRequest));
        var body = JObject.Parse(model.Body);

        bool valid = body.IsValid(schema, out IList<string> messages);
        if (!valid)
        
            // Fail, do something
        

        // Success
    


public class PostBody

    public string Body  get; set; 

获取更多信息...Validating JSON with JSON SchemaJson.NET Schema

【讨论】:

你不能这样验证它,因为如果它是无效的消息将是空的 @Marc 如果你只是像我说的那样接受请求作为字符串,而不是模型,它不会无效。 对不起,我错过了那部分,但后来他改变了 api。客户看到一个字符串而不是一个长列表会感到困惑

以上是关于如何验证集合的类型?的主要内容,如果未能解决你的问题,请参考以下文章

10--最后一个数据类型集合

浮点型+字符(串)类型+时间类型+枚举与集合类型+约束条件

ArrayList集合如何存储基本数据类型

如何使用 ActionResult 发送抽象类型的集合

我们可以在 GAME 中使用 Set 或集合作为返回类型吗?

Spring如何装配各种集合类型的属性