ABP框架系列之五十二:(Validating-Data-Transfer-Objects-驗證資料傳輸物件)

weixin_33896726發表於2018-01-16

Introduction to validation

Inputs of an application should be validated first. This input can be sent by user or another application. In a web application, validation is usually implemented twice: in client and in the server. Client-side validation is implemented mostly for user experience. It's better to check a form first in the client and show invalid fields to the user. But, server-side validation is more critical and unavoidable.

應用程式的輸入應該首先驗證。此輸入可以由使用者或其他應用程式傳送。在Web應用程式中,驗證通常實現兩次:客戶端和伺服器端。客戶端驗證主要用於使用者體驗。最好在客戶端檢查表單,並向使用者顯示無效欄位。但是,伺服器端驗證更為關鍵和不可避免。

Server side validation is generally implemented in application services or controllers (in general, all services get data from presentation layer). An application service method should first check (validate) input and then use it. ASP.NET Boilerplate provides a good infrastructure to automatically validate all inputs of an application for;

伺服器端驗證通常在應用程式服務或控制器中實現(一般來說,所有服務都從表示層獲取資料)。應用程式服務方法應該首先檢查(驗證)輸入然後使用它。ASP.NET樣板提供良好的基礎設施來自動驗證所有輸入的應用;

See Disabling Validation section to disable validation if needed.

如果需要,請檢視禁用驗證部分禁用驗證。

Using data annotations(使用資料註釋

ASP.NET Boilerplate supports data annotation attributes. Assume that we're developing a Task application service that is used to create a task and gets an input as shown below:

ASP.NET樣板支援資料註解屬性。假設我們正在開發一個任務應用程式服務,該服務用於建立任務並獲取如下所示的輸入:

public class CreateTaskInput
{
    public int? AssignedPersonId { get; set; }

    [Required]
    public string Description { get; set; }
}

Here, Description property is marked as Required. AssignedPersonId is optional. There are also many attributes (like MaxLength, MinLength, RegularExpression...) in System.ComponentModel.DataAnnotationsnamespace. See Task application service implementation:

這裡,Description屬性被標記為所需。assignedpersonid是可選的。也有許多屬性(如MaxLength,minLength,正規表示式在System.ComponentModel.DataAnnotationsnamespace…)。檢視任務應用程式服務實現:

public class TaskAppService : ITaskAppService
{
    private readonly ITaskRepository _taskRepository;
    private readonly IPersonRepository _personRepository;

    public TaskAppService(ITaskRepository taskRepository, IPersonRepository personRepository)
    {
        _taskRepository = taskRepository;
        _personRepository = personRepository;
    }

    public void CreateTask(CreateTaskInput input)
    {
        var task = new Task { Description = input.Description };

        if (input.AssignedPersonId.HasValue)
        {
            task.AssignedPerson = _personRepository.Load(input.AssignedPersonId.Value);
        }

        _taskRepository.Insert(task);
    }
}

As you see, no validation code is written since ASP.NET Boilerplate does it automatically. ASP.NET Boilerplate also checks if input is null and throws AbpValidationException if so. So, you don't have to write null-check code (guard clause). It also throws AbpValidationException if any of the input properties are invalid.

正如你看到的,沒有驗證碼可寫,因為ASP.NET樣板是自動寫入的。ASP.NET樣板檢查是否輸入是無效的,如果無效則丟擲abpvalidationexception。因此,您不必編寫null檢查碼(保護子句)。如果任何輸入屬性無效它會丟擲abpvalidationexception。

This machanism is similar to ASP.NET MVC's validation but notice that an application service class is not derived from Controller, it's a plain class and can work even out of a web application.

這種機制是類似ASP.NET MVC的驗證而注意到應用服務類不是來自控制器,它是一個普通班,甚至可以從一個Web應用程式的工作

Custom Validation(自定義驗證

If data annotations are not sufficient for your case, you can implement ICustomValidate interface as shown below:

如果資料註釋不夠滿足你的情況,你可以實現icustomvalidate 介面如下圖所示:

public class CreateTaskInput : ICustomValidate
{
    public int? AssignedPersonId { get; set; }

    public bool SendEmailToAssignedPerson { get; set; }

    [Required]
    public string Description { get; set; }

    public void AddValidationErrors(CustomValidatationContext context)
    {
        if (SendEmailToAssignedPerson && (!AssignedPersonId.HasValue || AssignedPersonId.Value <= 0))
        {
            context.Results.Add(new ValidationResult("AssignedPersonId must be set if SendEmailToAssignedPerson is true!"));
        }
    }
}

ICustomValidate interface declares AddValidationErrors method to be implemented. We must add ValidationResult objects to context.Results list if there are validation errors. You can also use context.IocResolver toresolve dependencies if needed in validation progress. 

icustomvalidate 介面揭露 addvalidationerrors方法被執行。我們必須在上下文中加上ValidationResult物件。如果驗證錯誤。你也可以使用context.iocresolver 如果在驗證中需要。

In addition to ICustomValidate, ABP also supports .NET's standard IValidatableObject interface. You can also implement it to perform additional custom validations. If you implement both interfaces, both of them will be called.

除了icustomvalidate,ABP也支援.NET的標準ivalidatableobject介面。您也可以執行它執行其他自定義驗證。如果實現這兩個介面,它們都將被呼叫。

Disabling Validation(禁用驗證

For automatically validated classes (see Introduction section), you can use these attributes to control validation:

對於自動驗證類(參見導言部分),您可以使用這些屬性來控制驗證:

  • DisableValidation attribute can be used for classes, methods or properties of DTOs to disable validation.
  • disablevalidation屬性可以用於類、方法或屬性的DTOS禁用驗證。
  • EnableValidation attribute can only be used to enable validation for a method, if it's disabled for the containing class.
  • enablevalidation屬性只能用於使一個方法驗證,如果該類被禁用。

Normalization(標準化

We may need to perform an extra operation to arrange DTO parameters after validation. ASP.NET Boilerplate defines IShouldNormalize interface that has Normalize method for that. If you implement this interface, Normalize method is called just after validation (and just before method call). Assume that our DTO gets a Sorting direction. If it's not supplied, we want to set a default sorting:

我們可能需要執行額外的操作安排DTO引數後驗證。ASP.NET的模板定義ishouldnormalize介面,有規範的方法。如果實現此介面,則在驗證之後(呼叫方法呼叫之前)呼叫標準化方法。假設我們的DTO獲取排序方向。如果沒有提供,我們要設定預設排序:

public class GetTasksInput : IShouldNormalize
{
    public string Sorting { get; set; }

    public void Normalize()
    {
        if (string.IsNullOrWhiteSpace(Sorting))
        {
            Sorting = "Name ASC";
        }
    }
}

相關文章