-
Notifications
You must be signed in to change notification settings - Fork 38
Required or Optional
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.
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.
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.
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:
- The field/property is decorated by System.ComponentModel.DataAnnotations.Required
- The Web API codes explicitly check ActionContext.ModelState.IsValid
And there are 2 ways for checking ModelState.IsValid:
- Examine ModelState.IsValid at the beginning of respective Web API functions.
- 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);
}
}
}