Skip to content

Required or Optional

fonlow edited this page Jun 5, 2017 · 2 revisions

By default, all fields/properties in the client data models generated are optional, except some fields/properties decorated by DataMember(IsRequired =true) or System.ComponentModel.DataAnnotations.Required. Another exception is struct.

For example,

        [DataMember(IsRequired =true)]//MVC and Web API does not care
        [System.ComponentModel.DataAnnotations.Required](System.ComponentModel.DataAnnotations.Required)//MVC and Web API care about only this
        public string Name { get; set; }

will be translated to client C# codes:

        [System.ComponentModel.DataAnnotations.RequiredAttribute()](System.ComponentModel.DataAnnotations.RequiredAttribute())
        public string Name
        {
            get
            {
                return _Name;
            }
            set
            {
                _Name = value;
            }
        }

or client TypeScript codes:

        Name: string;

All public fields in a struct will be required in TypeScript interfaces generated. And in C# codes generated, only public fields are supported, and the types of fields are expected to be primitive types or value types. WebApiClientGen presumes that you follow the general guidelines of choosing between class and struct.

Client side validation

With TypeScript

A decent TypeScript editor will give you some warning if you don't assign a required field during design time. Please note, javascript runtime does not check this kind of data constraints.

With C#

WPF client program may honor RequiredAttribute, and validate at runtime.

Remarks:

Client side validation against required fields/properties is more of UX concern rather than data integrity concern. To ensure data integrity, the validation should be done at the service side as well.

Service side validation against required fields/properties

ASP.NET MVC and Web API do not check DataContractAttribute and DataMemberAttribute, while WebApiClientGen uses these attributes for the opt-in approach of cherry-picking, and Newtonsoft JSON does handle these attributes well.

Either DataMember(IsRequired =true) or System.ComponentModel.DataAnnotations.Required at the service side will result in a client field required. However, whether the validation at the service side will be triggered depends on 2 conditions:

  1. The field/property is decorated by System.ComponentModel.DataAnnotations.Required
  2. The Web API codes explicitly check ActionContext.ModelState.IsValid

And there are 2 ways for checking ModelState.IsValid:

  1. Examine ModelState.IsValid at the beginning of respective Web API functions.
  2. Create a custom action filter attribute and apply it to some API functions, or globally, as shown below.
    public class ValidateModelAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if (!actionContext.ModelState.IsValid)
            {
                var errors = actionContext.ModelState.Values.SelectMany(v => v.Errors);
                var errorMessages = errors.Select(d => d.Exception==null ? d.ErrorMessage : d.Exception.ToString());
                Trace.TraceError($"Validation error, Controller: {actionContext.ControllerContext.ControllerDescriptor.ControllerName}  Action: {actionContext.ActionDescriptor.ActionName}  {String.Join(Environment.NewLine, errorMessages)}");
                actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
            }
        }
    }
Clone this wiki locally