diff --git a/src/vanilla/ClientModelExtensions.cs b/src/vanilla/ClientModelExtensions.cs
index f23645aa0b2..5a95da0793c 100644
--- a/src/vanilla/ClientModelExtensions.cs
+++ b/src/vanilla/ClientModelExtensions.cs
@@ -317,9 +317,10 @@ public static string CheckNull(string valueReference, string executionBlock)
/// The type to validate
/// A scope provider for generating variable names as necessary
/// A reference to the value being validated
+ /// Indicates whether the parameter or property is expressed as a nullable type or not
/// Constraints
/// The code to validate the reference of the given type
- public static string ValidateType(this IModelType type, IChild scope, string valueReference,
+ public static string ValidateType(this IModelType type, IChild scope, string valueReference, bool isNullable,
Dictionary constraints)
{
if (scope == null)
@@ -346,7 +347,7 @@ public static string ValidateType(this IModelType type, IChild scope, string val
if (sequence != null && sequence.ShouldValidateChain())
{
var elementVar = scope.GetUniqueName("element");
- var innerValidation = sequence.ElementType.ValidateType(scope, elementVar, null);
+ var innerValidation = sequence.ElementType.ValidateType(scope, elementVar, false, null);
if (!string.IsNullOrEmpty(innerValidation))
{
sb.AppendLine("foreach (var {0} in {1})", elementVar, valueReference)
@@ -358,7 +359,7 @@ public static string ValidateType(this IModelType type, IChild scope, string val
else if (dictionary != null && dictionary.ShouldValidateChain())
{
var valueVar = scope.GetUniqueName("valueElement");
- var innerValidation = dictionary.ValueType.ValidateType(scope, valueVar, null);
+ var innerValidation = dictionary.ValueType.ValidateType(scope, valueVar, false, null);
if (!string.IsNullOrEmpty(innerValidation))
{
sb.AppendLine("foreach (var {0} in {1}.Values)", valueVar, valueReference)
@@ -370,7 +371,7 @@ public static string ValidateType(this IModelType type, IChild scope, string val
if (sb.ToString().Trim().Length > 0)
{
- if (type.IsValueType())
+ if (type.IsValueType() && !isNullable)
{
return sb.ToString();
}
diff --git a/src/vanilla/Templates/Rest/Client/MethodBodyTemplateRestCall.cshtml b/src/vanilla/Templates/Rest/Client/MethodBodyTemplateRestCall.cshtml
index d85576fb636..44de231c677 100644
--- a/src/vanilla/Templates/Rest/Client/MethodBodyTemplateRestCall.cshtml
+++ b/src/vanilla/Templates/Rest/Client/MethodBodyTemplateRestCall.cshtml
@@ -20,7 +20,7 @@
}
if(parameter.CanBeValidated && (Model.HttpMethod != HttpMethod.Patch || parameter.Location != ParameterLocation.Body))
{
-@:@(parameter.ModelType.ValidateType(Model, parameter.Name, parameter.Constraints))
+@:@(parameter.ModelType.ValidateType(Model, parameter.Name, parameter.IsNullable(), parameter.Constraints))
}
}
diff --git a/src/vanilla/Templates/Rest/Common/ModelTemplate.cshtml b/src/vanilla/Templates/Rest/Common/ModelTemplate.cshtml
index 04bba639f81..597fc287a33 100644
--- a/src/vanilla/Templates/Rest/Common/ModelTemplate.cshtml
+++ b/src/vanilla/Templates/Rest/Common/ModelTemplate.cshtml
@@ -205,7 +205,7 @@ foreach (PropertyCs property in Model.InstanceProperties.Where(p => p.IsRequired
foreach (var property in Model.InstanceProperties.Where(p => p.Constraints.Any() || !(p.ModelType is PrimaryType)))
{
anythingToValidate = true;
- @:@property.ModelType.ValidateType(Model, $"this.{property.Name}", property.Constraints)
+ @:@property.ModelType.ValidateType(Model, $"this.{property.Name}", property.IsNullable(), property.Constraints)
}
if (!anythingToValidate)
{
diff --git a/src/vanilla/Templates/Rest/Server/ServiceMethodTemplate.cshtml b/src/vanilla/Templates/Rest/Server/ServiceMethodTemplate.cshtml
index 785d8f9ced6..fcc7494d338 100644
--- a/src/vanilla/Templates/Rest/Server/ServiceMethodTemplate.cshtml
+++ b/src/vanilla/Templates/Rest/Server/ServiceMethodTemplate.cshtml
@@ -54,7 +54,7 @@
}
if (parameter.CanBeValidated && (Model.HttpMethod != HttpMethod.Patch || parameter.Location != ParameterLocation.Body))
{
- @:@(parameter.ModelType.ValidateType(Model, parameter.Name, parameter.Constraints))
+ @:@(parameter.ModelType.ValidateType(Model, parameter.Name, parameter.IsNullable(), parameter.Constraints))
}
}
@if (Model.HttpMethod == HttpMethod.Get)
diff --git a/test/Resource/Bug885/Bug885.json b/test/Resource/Bug885/Bug885.json
new file mode 100644
index 00000000000..fee6d2ece7e
--- /dev/null
+++ b/test/Resource/Bug885/Bug885.json
@@ -0,0 +1,40 @@
+{
+ "swagger": "2.0",
+ "info": {
+ "version": "1.0.0",
+ "title": "Simple API",
+ "termsOfService": "http://helloreverb.com/terms/",
+ "contact": {
+ "email": "apiteam@swagger.io"
+ },
+ "license": {
+ "name": "Apache 2.0",
+ "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
+ }
+ },
+ "host": "test.swagger.io",
+ "basePath": "/v2",
+ "schemes": [
+ "http"
+ ],
+ "paths": {},
+ "definitions": {
+ "DateAfterModification": {
+ "properties": {
+ "daysAfterModificationGreaterThan": {
+ "type": "number",
+ "multipleOf": 1.0,
+ "minimum": 0,
+ "description": "Value indicating the age in days after last modification"
+ },
+ "daysAfterLastAccessTimeGreaterThan": {
+ "type": "number",
+ "multipleOf": 1.0,
+ "minimum": 0,
+ "description": "Value indicating the age in days after last blob access. This property can only be used in conjuction with last access time tracking policy"
+ }
+ },
+ "description": "Object to define the number of days after object last modification Or last access. Properties daysAfterModificationGreaterThan and daysAfterLastAccessTimeGreaterThan are mutually exclusive"
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Resource/Bug885/ISimpleAPI.cs b/test/Resource/Bug885/ISimpleAPI.cs
new file mode 100644
index 00000000000..1a90d9cf090
--- /dev/null
+++ b/test/Resource/Bug885/ISimpleAPI.cs
@@ -0,0 +1,33 @@
+//
+// Code generated by Microsoft (R) AutoRest Code Generator.
+// Changes may cause incorrect behavior and will be lost if the code is
+// regenerated.
+//
+
+namespace Bug885
+{
+ using Models;
+ using Newtonsoft.Json;
+
+ ///
+ ///
+ public partial interface ISimpleAPI : System.IDisposable
+ {
+ ///
+ /// The base URI of the service.
+ ///
+ System.Uri BaseUri { get; set; }
+
+ ///
+ /// Gets or sets json serialization settings.
+ ///
+ JsonSerializerSettings SerializationSettings { get; }
+
+ ///
+ /// Gets or sets json deserialization settings.
+ ///
+ JsonSerializerSettings DeserializationSettings { get; }
+
+
+ }
+}
diff --git a/test/Resource/Bug885/Models/DateAfterModification.cs b/test/Resource/Bug885/Models/DateAfterModification.cs
new file mode 100644
index 00000000000..c70f4f19a34
--- /dev/null
+++ b/test/Resource/Bug885/Models/DateAfterModification.cs
@@ -0,0 +1,95 @@
+//
+// Code generated by Microsoft (R) AutoRest Code Generator.
+// Changes may cause incorrect behavior and will be lost if the code is
+// regenerated.
+//
+
+namespace Bug885.Models
+{
+ using Microsoft.Rest;
+ using Newtonsoft.Json;
+ using System.Linq;
+
+ ///
+ /// Object to define the number of days after object last modification Or
+ /// last access. Properties daysAfterModificationGreaterThan and
+ /// daysAfterLastAccessTimeGreaterThan are mutually exclusive
+ ///
+ public partial class DateAfterModification
+ {
+ ///
+ /// Initializes a new instance of the DateAfterModification class.
+ ///
+ public DateAfterModification()
+ {
+ CustomInit();
+ }
+
+ ///
+ /// Initializes a new instance of the DateAfterModification class.
+ ///
+ /// Value indicating the
+ /// age in days after last modification
+ /// Value indicating
+ /// the age in days after last blob access. This property can only be
+ /// used in conjuction with last access time tracking policy
+ public DateAfterModification(double? daysAfterModificationGreaterThan = default(double?), double? daysAfterLastAccessTimeGreaterThan = default(double?))
+ {
+ DaysAfterModificationGreaterThan = daysAfterModificationGreaterThan;
+ DaysAfterLastAccessTimeGreaterThan = daysAfterLastAccessTimeGreaterThan;
+ CustomInit();
+ }
+
+ ///
+ /// An initialization method that performs custom operations like setting defaults
+ ///
+ partial void CustomInit();
+
+ ///
+ /// Gets or sets value indicating the age in days after last
+ /// modification
+ ///
+ [JsonProperty(PropertyName = "daysAfterModificationGreaterThan")]
+ public double? DaysAfterModificationGreaterThan { get; set; }
+
+ ///
+ /// Gets or sets value indicating the age in days after last blob
+ /// access. This property can only be used in conjuction with last
+ /// access time tracking policy
+ ///
+ [JsonProperty(PropertyName = "daysAfterLastAccessTimeGreaterThan")]
+ public double? DaysAfterLastAccessTimeGreaterThan { get; set; }
+
+ ///
+ /// Validate the object.
+ ///
+ ///
+ /// Thrown if validation fails
+ ///
+ public virtual void Validate()
+ {
+ if (DaysAfterModificationGreaterThan != null)
+ {
+ if (DaysAfterModificationGreaterThan < 0)
+ {
+ throw new ValidationException(ValidationRules.InclusiveMinimum, "DaysAfterModificationGreaterThan", 0);
+ }
+ if (DaysAfterModificationGreaterThan % 1 != 0)
+ {
+ throw new ValidationException(ValidationRules.MultipleOf, "DaysAfterModificationGreaterThan", 1);
+ }
+ }
+ if (DaysAfterLastAccessTimeGreaterThan != null)
+ {
+ if (DaysAfterLastAccessTimeGreaterThan < 0)
+ {
+ throw new ValidationException(ValidationRules.InclusiveMinimum, "DaysAfterLastAccessTimeGreaterThan", 0);
+ }
+ if (DaysAfterLastAccessTimeGreaterThan % 1 != 0)
+ {
+ throw new ValidationException(ValidationRules.MultipleOf, "DaysAfterLastAccessTimeGreaterThan", 1);
+ }
+ }
+ }
+ }
+}
diff --git a/test/Resource/Bug885/SimpleAPI.cs b/test/Resource/Bug885/SimpleAPI.cs
new file mode 100644
index 00000000000..a41b6176151
--- /dev/null
+++ b/test/Resource/Bug885/SimpleAPI.cs
@@ -0,0 +1,156 @@
+//
+// Code generated by Microsoft (R) AutoRest Code Generator.
+// Changes may cause incorrect behavior and will be lost if the code is
+// regenerated.
+//
+
+namespace Bug885
+{
+ using Microsoft.Rest;
+ using Microsoft.Rest.Serialization;
+ using Models;
+ using Newtonsoft.Json;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Net;
+ using System.Net.Http;
+
+ public partial class SimpleAPI : ServiceClient, ISimpleAPI
+ {
+ ///
+ /// The base URI of the service.
+ ///
+ public System.Uri BaseUri { get; set; }
+
+ ///
+ /// Gets or sets json serialization settings.
+ ///
+ public JsonSerializerSettings SerializationSettings { get; private set; }
+
+ ///
+ /// Gets or sets json deserialization settings.
+ ///
+ public JsonSerializerSettings DeserializationSettings { get; private set; }
+
+ ///
+ /// Initializes a new instance of the SimpleAPI class.
+ ///
+ ///
+ /// HttpClient to be used
+ ///
+ ///
+ /// True: will dispose the provided httpClient on calling SimpleAPI.Dispose(). False: will not dispose provided httpClient
+ public SimpleAPI(HttpClient httpClient, bool disposeHttpClient) : base(httpClient, disposeHttpClient)
+ {
+ Initialize();
+ }
+
+ ///
+ /// Initializes a new instance of the SimpleAPI class.
+ ///
+ ///
+ /// Optional. The delegating handlers to add to the http client pipeline.
+ ///
+ public SimpleAPI(params DelegatingHandler[] handlers) : base(handlers)
+ {
+ Initialize();
+ }
+
+ ///
+ /// Initializes a new instance of the SimpleAPI class.
+ ///
+ ///
+ /// Optional. The http client handler used to handle http transport.
+ ///
+ ///
+ /// Optional. The delegating handlers to add to the http client pipeline.
+ ///
+ public SimpleAPI(HttpClientHandler rootHandler, params DelegatingHandler[] handlers) : base(rootHandler, handlers)
+ {
+ Initialize();
+ }
+
+ ///
+ /// Initializes a new instance of the SimpleAPI class.
+ ///
+ ///
+ /// Optional. The base URI of the service.
+ ///
+ ///
+ /// Optional. The delegating handlers to add to the http client pipeline.
+ ///
+ ///
+ /// Thrown when a required parameter is null
+ ///
+ public SimpleAPI(System.Uri baseUri, params DelegatingHandler[] handlers) : this(handlers)
+ {
+ if (baseUri == null)
+ {
+ throw new System.ArgumentNullException("baseUri");
+ }
+ BaseUri = baseUri;
+ }
+
+ ///
+ /// Initializes a new instance of the SimpleAPI class.
+ ///
+ ///
+ /// Optional. The base URI of the service.
+ ///
+ ///
+ /// Optional. The http client handler used to handle http transport.
+ ///
+ ///
+ /// Optional. The delegating handlers to add to the http client pipeline.
+ ///
+ ///
+ /// Thrown when a required parameter is null
+ ///
+ public SimpleAPI(System.Uri baseUri, HttpClientHandler rootHandler, params DelegatingHandler[] handlers) : this(rootHandler, handlers)
+ {
+ if (baseUri == null)
+ {
+ throw new System.ArgumentNullException("baseUri");
+ }
+ BaseUri = baseUri;
+ }
+
+ ///
+ /// An optional partial-method to perform custom initialization.
+ ///
+ partial void CustomInitialize();
+ ///
+ /// Initializes client properties.
+ ///
+ private void Initialize()
+ {
+ BaseUri = new System.Uri("http://test.swagger.io/v2");
+ SerializationSettings = new JsonSerializerSettings
+ {
+ Formatting = Newtonsoft.Json.Formatting.Indented,
+ DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat,
+ DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc,
+ NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
+ ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize,
+ ContractResolver = new ReadOnlyJsonContractResolver(),
+ Converters = new List
+ {
+ new Iso8601TimeSpanConverter()
+ }
+ };
+ DeserializationSettings = new JsonSerializerSettings
+ {
+ DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat,
+ DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc,
+ NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
+ ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize,
+ ContractResolver = new ReadOnlyJsonContractResolver(),
+ Converters = new List
+ {
+ new Iso8601TimeSpanConverter()
+ }
+ };
+ CustomInitialize();
+ }
+ }
+}
diff --git a/test/unit/Bug885.cs b/test/unit/Bug885.cs
new file mode 100644
index 00000000000..61fe923856c
--- /dev/null
+++ b/test/unit/Bug885.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+using System.Threading.Tasks;
+using Bug885.Models;
+using Xunit;
+
+namespace AutoRest.CSharp.Unit.Tests
+{
+ public class Bug885
+ {
+ ///
+ /// https://github.com/Azure/autorest.csharp/issues/885
+ /// Validate optional properties successfully.
+ ///
+ [Fact]
+ public async Task ValidateOptionalProperties()
+ {
+ var dateAfterModification = new DateAfterModification();
+ dateAfterModification.Validate();
+ }
+ }
+}
\ No newline at end of file