├── .gitignore ├── LICENSE ├── Microsoft-License.txt ├── Microsoft-Patents.txt ├── Portable.DataAnnotations.Net40 ├── Portable.DataAnnotations.Net40.csproj ├── Properties │ └── AssemblyInfo.cs ├── Resources │ ├── DataAnnotationsResources.Designer.cs │ └── DataAnnotationsResources.resx └── TypeForwards.cs ├── Portable.DataAnnotations.Net40Portable ├── Portable.DataAnnotations.Net40Portable.csproj ├── Properties │ └── AssemblyInfo.cs └── Resources │ ├── DataAnnotationsResources.Designer.cs │ └── DataAnnotationsResources.resx ├── Portable.DataAnnotations.Net45 ├── Portable.DataAnnotations.Net45.csproj ├── Properties │ └── AssemblyInfo.cs └── TypeForwards.cs ├── Portable.DataAnnotations.Net45Portable ├── DataType.cs ├── GlobalSuppressions.cs ├── IValidatableObject.cs ├── LocalizableString.cs ├── Portable.DataAnnotations.Net45Portable.csproj ├── Properties │ └── AssemblyInfo.cs ├── Resources │ ├── DataAnnotationsResources.Designer.cs │ └── DataAnnotationsResources.resx ├── ValidationAttributeStore.cs ├── ValidationAttributes │ ├── AssociationAttribute.cs │ ├── BindableTypeAttribute.cs │ ├── ConcurrencyCheckAttribute.cs │ ├── CreditCardAttribute.cs │ ├── CustomValidationAttribute.cs │ ├── DataTypeAttribute.cs │ ├── DisplayAttribute.cs │ ├── DisplayColumnAttribute.cs │ ├── DisplayFormatAttribute.cs │ ├── EditableAttribute.cs │ ├── EmailAddressAttribute.cs │ ├── EnumDataTypeAttribute.cs │ ├── FilterUIHintAttribute.cs │ ├── KeyAttribute.cs │ ├── MaxLengthAttribute.cs │ ├── MetadataTypeAttribute.cs │ ├── MinLengthAttribute.cs │ ├── PhoneAttribute.cs │ ├── RangeAttribute.cs │ ├── RegularExpressionAttribute.cs │ ├── RequiredAttribute.cs │ ├── Schema │ │ ├── ColumnAttribute.cs │ │ ├── ComplexTypeAttribute.cs │ │ ├── DatabaseGeneratedAttribute.cs │ │ ├── DatabaseGeneratedOption.cs │ │ ├── ForeignKeyAttribute.cs │ │ ├── InversePropertyAttribute.cs │ │ ├── NotMappedAttribute.cs │ │ └── TableAttribute.cs │ ├── StringLengthAttribute.cs │ ├── TimestampAttribute.cs │ ├── UIHintAttribute.cs │ ├── UrlAttribute.cs │ └── ValidationAttribute.cs ├── ValidationContext.cs ├── ValidationException.cs ├── ValidationResult.cs └── Validator.cs ├── Portable.DataAnnotations.WindowsRuntime ├── Portable.DataAnnotations.WindowsRuntime.csproj ├── Properties │ └── AssemblyInfo.cs ├── Resources │ ├── DataAnnotationsResources.Designer.cs │ └── DataAnnotationsResources.resx ├── TypeForwards.cs └── ValidationAttributes │ ├── CreditCardAttribute.cs │ ├── EmailAddressAttribute.cs │ ├── MaxLengthAttribute.cs │ ├── MinLengthAttribute.cs │ ├── PhoneAttribute.cs │ └── UrlAttribute.cs ├── Portable.DataAnnotations.Xamarin ├── Portable.DataAnnotations.Xamarin.csproj ├── Properties │ └── AssemblyInfo.cs └── Resources │ ├── DataAnnotationsResources.Designer.cs │ └── DataAnnotationsResources.resx ├── Portable.DataAnnotations.nuspec ├── Portable.DataAnnotations.sln ├── README.md └── Rybird-32.png /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | 5 | /Portable.DataAnnotations.Net40/obj 6 | /Portable.DataAnnotations.Net40/bin 7 | /Portable.DataAnnotations.Net40/bin 8 | /Portable.DataAnnotations.Net40/bin 9 | /Portable.DataAnnotations.Net40Portable/bin/Release 10 | /Portable.DataAnnotations.Net40Portable/obj 11 | /Portable.DataAnnotations.Net45/bin/Release 12 | /Portable.DataAnnotations.Net45/obj 13 | /Portable.DataAnnotations.Net45Portable/bin 14 | /Portable.DataAnnotations.Net45Portable/obj 15 | /Portable.DataAnnotations.WindowsRuntime/obj 16 | /Portable.DataAnnotations.WindowsRuntime/bin 17 | /Portable.DataAnnotations.Xamarin/obj 18 | /Portable.DataAnnotations.Xamarin/bin 19 | NuGet.Config 20 | NuGet.exe 21 | NuGet.targets 22 | /Portable.DataAnnotations.v12.suo 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ryanhorath 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Microsoft-License.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Microsoft Corporation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net40/Portable.DataAnnotations.Net40.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F061DE0B-67ED-4F7B-BB3F-01A45FCAA266} 8 | Library 9 | Properties 10 | System.ComponentModel.DataAnnotations 11 | Portable.DataAnnotations 12 | v4.0 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | ValidationAttributes\BindableTypeAttribute.cs 46 | 47 | 48 | ValidationAttributes\Schema\ColumnAttribute.cs 49 | 50 | 51 | ValidationAttributes\Schema\ComplexTypeAttribute.cs 52 | 53 | 54 | ValidationAttributes\Schema\ForeignKeyAttribute.cs 55 | 56 | 57 | ValidationAttributes\Schema\InversePropertyAttribute.cs 58 | 59 | 60 | ValidationAttributes\Schema\NotMappedAttribute.cs 61 | 62 | 63 | ValidationAttributes\Schema\TableAttribute.cs 64 | 65 | 66 | ValidationAttributes\CreditCardAttribute.cs 67 | 68 | 69 | ValidationAttributes\EmailAddressAttribute.cs 70 | 71 | 72 | ValidationAttributes\MaxLengthAttribute.cs 73 | 74 | 75 | ValidationAttributes\MinLengthAttribute.cs 76 | 77 | 78 | ValidationAttributes\PhoneAttribute.cs 79 | 80 | 81 | ValidationAttributes\UrlAttribute.cs 82 | 83 | 84 | 85 | True 86 | True 87 | DataAnnotationsResources.resx 88 | 89 | 90 | 91 | 92 | 93 | ResXFileCodeGenerator 94 | DataAnnotationsResources.Designer.cs 95 | 96 | 97 | 98 | 105 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net40/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Portable.DataAnnotations.Net40")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Portable.DataAnnotations.Net40")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9d907d4d-ebe8-4134-b4df-8ae30ef036be")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net40/TypeForwards.cs: -------------------------------------------------------------------------------- 1 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.AssociationAttribute))] 2 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ConcurrencyCheckAttribute))] 3 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.CustomValidationAttribute))] 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DataType))] 5 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DataTypeAttribute))] 6 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DisplayAttribute))] 7 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DisplayColumnAttribute))] 8 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DisplayFormatAttribute))] 9 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.EditableAttribute))] 10 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.EnumDataTypeAttribute))] 11 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.FilterUIHintAttribute))] 12 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.KeyAttribute))] 13 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.RangeAttribute))] 14 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.RegularExpressionAttribute))] 15 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.RequiredAttribute))] 16 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.StringLengthAttribute))] 17 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.TimestampAttribute))] 18 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.UIHintAttribute))] 19 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ValidationAttribute))] 20 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ValidationContext))] 21 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ValidationException))] 22 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ValidationResult))] 23 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.Validator))] 24 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.IValidatableObject))] 25 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.MetadataTypeAttribute))] -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net40Portable/Portable.DataAnnotations.Net40Portable.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 10.0 6 | Debug 7 | AnyCPU 8 | {687A452E-572F-45D6-A295-49177D841590} 9 | Library 10 | Properties 11 | System.ComponentModel.DataAnnotations 12 | Portable.DataAnnotations 13 | en-US 14 | 512 15 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | Profile328 17 | v4.0 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | TRACE;DEBUG;NET40 25 | prompt 26 | 4 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE;NET40 33 | prompt 34 | 4 35 | 36 | 37 | 38 | DataType.cs 39 | 40 | 41 | GlobalSuppressions.cs 42 | 43 | 44 | IValidatableObject.cs 45 | 46 | 47 | LocalizableString.cs 48 | 49 | 50 | ValidationAttributeStore.cs 51 | 52 | 53 | ValidationAttributes\AssociationAttribute.cs 54 | 55 | 56 | ValidationAttributes\ConcurrencyCheckAttribute.cs 57 | 58 | 59 | ValidationAttributes\CustomValidationAttribute.cs 60 | 61 | 62 | ValidationAttributes\DataTypeAttribute.cs 63 | 64 | 65 | ValidationAttributes\DisplayAttribute.cs 66 | 67 | 68 | ValidationAttributes\DisplayColumnAttribute.cs 69 | 70 | 71 | ValidationAttributes\DisplayFormatAttribute.cs 72 | 73 | 74 | ValidationAttributes\EditableAttribute.cs 75 | 76 | 77 | ValidationAttributes\EnumDataTypeAttribute.cs 78 | 79 | 80 | ValidationAttributes\FilterUIHintAttribute.cs 81 | 82 | 83 | ValidationAttributes\KeyAttribute.cs 84 | 85 | 86 | ValidationAttributes\MetadataTypeAttribute.cs 87 | 88 | 89 | ValidationAttributes\RangeAttribute.cs 90 | 91 | 92 | ValidationAttributes\RegularExpressionAttribute.cs 93 | 94 | 95 | ValidationAttributes\RequiredAttribute.cs 96 | 97 | 98 | ValidationAttributes\StringLengthAttribute.cs 99 | 100 | 101 | ValidationAttributes\TimestampAttribute.cs 102 | 103 | 104 | ValidationAttributes\UIHintAttribute.cs 105 | 106 | 107 | ValidationAttributes\ValidationAttribute.cs 108 | 109 | 110 | ValidationContext.cs 111 | 112 | 113 | ValidationException.cs 114 | 115 | 116 | ValidationResult.cs 117 | 118 | 119 | Validator.cs 120 | 121 | 122 | 123 | True 124 | True 125 | DataAnnotationsResources.resx 126 | 127 | 128 | 129 | 130 | ResXFileCodeGenerator 131 | DataAnnotationsResources.Designer.cs 132 | 133 | 134 | 135 | 142 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net40Portable/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("Portable.DataAnnotations.Net40Portable")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("Portable.DataAnnotations.Net40Portable")] 14 | [assembly: AssemblyCopyright("Copyright © 2015")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: NeutralResourcesLanguage("en")] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.0.0")] 30 | [assembly: AssemblyFileVersion("1.0.0.0")] 31 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45/Portable.DataAnnotations.Net45.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {24BB9632-F412-4633-80D5-166A0EE44933} 8 | Library 9 | Properties 10 | System.ComponentModel.DataAnnotations 11 | Portable.DataAnnotations 12 | v4.5 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 55 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Portable.DataAnnotations.Net45")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Portable.DataAnnotations.Net45")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("28b11e2d-fcd9-4ea0-8f38-8ecb8685d5eb")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45/TypeForwards.cs: -------------------------------------------------------------------------------- 1 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.AssociationAttribute))] 2 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ConcurrencyCheckAttribute))] 3 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.CustomValidationAttribute))] 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DataType))] 5 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DataTypeAttribute))] 6 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DisplayAttribute))] 7 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DisplayColumnAttribute))] 8 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DisplayFormatAttribute))] 9 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.EditableAttribute))] 10 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.EnumDataTypeAttribute))] 11 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.FilterUIHintAttribute))] 12 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.KeyAttribute))] 13 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.RangeAttribute))] 14 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.RegularExpressionAttribute))] 15 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.RequiredAttribute))] 16 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.StringLengthAttribute))] 17 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.TimestampAttribute))] 18 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.UIHintAttribute))] 19 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ValidationAttribute))] 20 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ValidationContext))] 21 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ValidationException))] 22 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ValidationResult))] 23 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.Validator))] 24 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.IValidatableObject))] 25 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption))] 26 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedAttribute))] 27 | 28 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.BindableTypeAttribute))] 29 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.CreditCardAttribute))] 30 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.EmailAddressAttribute))] 31 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.MaxLengthAttribute))] 32 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.MetadataTypeAttribute))] 33 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.MinLengthAttribute))] 34 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.PhoneAttribute))] 35 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.UrlAttribute))] 36 | 37 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.ColumnAttribute))] 38 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.ComplexTypeAttribute))] 39 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.ForeignKeyAttribute))] 40 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.InversePropertyAttribute))] 41 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute))] 42 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.TableAttribute))] 43 | 44 | 45 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/DataType.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations 2 | { 3 | /// 4 | /// Enumeration of logical data types that may appear in 5 | /// 6 | public enum DataType 7 | { 8 | /// 9 | /// Custom data type, not one of the static data types we know 10 | /// 11 | Custom, 12 | 13 | /// 14 | /// DateTime data type 15 | /// 16 | DateTime, 17 | 18 | /// 19 | /// Date data type 20 | /// 21 | Date, 22 | 23 | /// 24 | /// Time data type 25 | /// 26 | Time, 27 | 28 | /// 29 | /// Duration data type 30 | /// 31 | Duration, 32 | 33 | /// 34 | /// Phone number data type 35 | /// 36 | PhoneNumber, 37 | 38 | /// 39 | /// Currency data type 40 | /// 41 | Currency, 42 | 43 | /// 44 | /// Plain text data type 45 | /// 46 | Text, 47 | 48 | /// 49 | /// Html data type 50 | /// 51 | Html, 52 | 53 | /// 54 | /// Multiline text data type 55 | /// 56 | MultilineText, 57 | 58 | /// 59 | /// Email address data type 60 | /// 61 | EmailAddress, 62 | 63 | /// 64 | /// Password data type -- do not echo in UI 65 | /// 66 | Password, 67 | 68 | /// 69 | /// URL data type 70 | /// 71 | Url, 72 | 73 | /// 74 | /// URL to an Image -- to be displayed as an image instead of text 75 | /// 76 | ImageUrl, 77 | 78 | ///// 79 | ///// Credit card data type 80 | ///// 81 | //CreditCard, 82 | 83 | ///// 84 | ///// Postal code data type 85 | ///// 86 | //PostalCode, 87 | 88 | ///// 89 | ///// File upload data type 90 | ///// 91 | //Upload 92 | } 93 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // (c) Copyright Microsoft Corporation. 2 | // This source is subject to the Microsoft Public License (Ms-PL). 3 | // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. 4 | // All other rights reserved. 5 | 6 | using System.Diagnostics.CodeAnalysis; 7 | 8 | [assembly: SuppressMessage("General", "SWC1001:XmlDocumentationCommentShouldBeSpelledCorrectly", MessageId = "globalizable", Justification = "Spelled correctly.")] 9 | [assembly: SuppressMessage("General", "SWC1001:XmlDocumentationCommentShouldBeSpelledCorrectly", MessageId = "validators", Justification = "Spelled correctly.")] 10 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/IValidatableObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace System.ComponentModel.DataAnnotations 7 | { 8 | public interface IValidatableObject 9 | { 10 | IEnumerable Validate(ValidationContext validationContext); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/LocalizableString.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Globalization; 3 | using System.Reflection; 4 | 5 | namespace System.ComponentModel.DataAnnotations 6 | { 7 | /// 8 | /// A helper class for providing a localizable string property. 9 | /// This class is currently compiled in both System.Web.dll and System.ComponentModel.DataAnnotations.dll. 10 | /// 11 | internal class LocalizableString 12 | { 13 | #region Member fields 14 | 15 | private string _propertyName; 16 | private string _propertyValue; 17 | private Type _resourceType; 18 | 19 | private Func _cachedResult; 20 | 21 | #endregion 22 | 23 | #region All Constructors 24 | 25 | /// 26 | /// Constructs a localizable string, specifying the property name associated 27 | /// with this item. The value will be used 28 | /// within any exceptions thrown as a result of localization failures. 29 | /// 30 | /// The name of the property being localized. This name 31 | /// will be used within exceptions thrown as a result of localization failures. 32 | public LocalizableString(string propertyName) 33 | { 34 | this._propertyName = propertyName; 35 | } 36 | 37 | #endregion 38 | 39 | #region Properties 40 | 41 | /// 42 | /// Gets or sets the value of this localizable string. This value can be 43 | /// either the literal, non-localized value, or it can be a resource name 44 | /// found on the resource type supplied to . 45 | /// 46 | public string Value 47 | { 48 | get 49 | { 50 | return this._propertyValue; 51 | } 52 | set 53 | { 54 | if (this._propertyValue != value) 55 | { 56 | this.ClearCache(); 57 | this._propertyValue = value; 58 | } 59 | } 60 | } 61 | 62 | /// 63 | /// Gets or sets the resource type to be used for localization. 64 | /// 65 | public Type ResourceType 66 | { 67 | get 68 | { 69 | return this._resourceType; 70 | } 71 | set 72 | { 73 | if (this._resourceType != value) 74 | { 75 | this.ClearCache(); 76 | this._resourceType = value; 77 | } 78 | } 79 | } 80 | 81 | #endregion 82 | 83 | #region Methods 84 | 85 | /// 86 | /// Clears any cached values, forcing to 87 | /// perform evaluation. 88 | /// 89 | private void ClearCache() 90 | { 91 | this._cachedResult = null; 92 | } 93 | 94 | /// 95 | /// Gets the potentially localized value. 96 | /// 97 | /// 98 | /// If has been specified and is not 99 | /// null, then localization will occur and the localized value will be returned. 100 | /// 101 | /// If is null then will be returned 102 | /// as a literal, non-localized string. 103 | /// 104 | /// 105 | /// 106 | /// Thrown if localization fails. This can occur if has been 107 | /// specified, is not null, but the resource could not be 108 | /// accessed. must be a public class, and 109 | /// must be the name of a public static string property that contains a getter. 110 | /// 111 | /// 112 | /// Returns the potentially localized value. 113 | /// 114 | public string GetLocalizableValue() 115 | { 116 | if (this._cachedResult == null) 117 | { 118 | // If the property value is null, then just cache that value 119 | // If the resource type is null, then property value is literal, so cache it 120 | if (this._propertyValue == null || this._resourceType == null) 121 | { 122 | this._cachedResult = () => this._propertyValue; 123 | } 124 | else 125 | { 126 | // Get the property from the resource type for this resource key 127 | PropertyInfo property = this._resourceType.GetProperty(this._propertyValue); 128 | 129 | // We need to detect bad configurations so that we can throw exceptions accordingly 130 | bool badlyConfigured = false; 131 | 132 | // Make sure we found the property and it's the correct type, and that the type itself is public 133 | if (!this._resourceType.IsVisible || property == null || property.PropertyType != typeof(string)) 134 | { 135 | badlyConfigured = true; 136 | } 137 | else 138 | { 139 | // Ensure the getter for the property is available as public static 140 | MethodInfo getter = property.GetGetMethod(); 141 | 142 | if (getter == null || !(getter.IsPublic && getter.IsStatic)) 143 | { 144 | badlyConfigured = true; 145 | } 146 | } 147 | 148 | // If the property is not configured properly, then throw a missing member exception 149 | if (badlyConfigured) 150 | { 151 | string exceptionMessage = String.Format(CultureInfo.CurrentCulture, 152 | DataAnnotationsResources.LocalizableString_LocalizationFailed, 153 | this._propertyName, this._resourceType.FullName, this._propertyValue); 154 | this._cachedResult = () => { throw new InvalidOperationException(exceptionMessage); }; 155 | } 156 | else 157 | { 158 | // We have a valid property, so cache the resource 159 | this._cachedResult = () => (string)property.GetValue(null, null); 160 | } 161 | } 162 | } 163 | 164 | // Return the cached result 165 | return this._cachedResult(); 166 | } 167 | 168 | #endregion 169 | } 170 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/Portable.DataAnnotations.Net45Portable.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 10.0 6 | Debug 7 | AnyCPU 8 | {A438D987-9708-4DF4-AF3F-16C03B83108E} 9 | Library 10 | Properties 11 | System.ComponentModel.DataAnnotations 12 | Portable.DataAnnotations 13 | en-US 14 | 512 15 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | Profile344 17 | v4.0 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | TRACE;DEBUG 25 | prompt 26 | 4 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | True 45 | True 46 | DataAnnotationsResources.resx 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | ResXFileCodeGenerator 91 | DataAnnotationsResources.Designer.cs 92 | 93 | 94 | 95 | 102 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("Portable.DataAnnotations")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("Portable.DataAnnotations")] 14 | [assembly: AssemblyCopyright("Copyright © 2015")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: NeutralResourcesLanguage("en")] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.0.0")] 30 | [assembly: AssemblyFileVersion("1.0.0.0")] 31 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/AssociationAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace System.ComponentModel.DataAnnotations 4 | { 5 | /// 6 | /// Used to mark an Entity member as an association 7 | /// 8 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] 9 | public sealed class AssociationAttribute : Attribute 10 | { 11 | private string name; 12 | private string thisKey; 13 | private string otherKey; 14 | private bool isForeignKey; 15 | 16 | /// 17 | /// Full form of constructor 18 | /// 19 | /// The name of the association. For bi-directional associations, the name must 20 | /// be the same on both sides of the association 21 | /// Comma separated list of the property names of the key values 22 | /// on this side of the association 23 | /// Comma separated list of the property names of the key values 24 | /// on the other side of the association 25 | public AssociationAttribute(string name, string thisKey, string otherKey) 26 | { 27 | this.name = name; 28 | this.thisKey = thisKey; 29 | this.otherKey = otherKey; 30 | } 31 | 32 | /// 33 | /// Gets the name of the association. For bi-directional associations, the name must 34 | /// be the same on both sides of the association 35 | /// 36 | public string Name 37 | { 38 | get { return this.name; } 39 | } 40 | 41 | /// 42 | /// Gets a comma separated list of the property names of the key values 43 | /// on this side of the association 44 | /// 45 | public string ThisKey 46 | { 47 | get 48 | { 49 | return this.thisKey; 50 | } 51 | } 52 | 53 | /// 54 | /// Gets a comma separated list of the property names of the key values 55 | /// on the other side of the association 56 | /// 57 | public string OtherKey 58 | { 59 | get 60 | { 61 | return this.otherKey; 62 | } 63 | } 64 | 65 | /// 66 | /// Gets or sets a value indicating whether this association member represents the foreign key 67 | /// side of an association 68 | /// 69 | public bool IsForeignKey 70 | { 71 | get 72 | { 73 | return this.isForeignKey; 74 | } 75 | set 76 | { 77 | this.isForeignKey = value; 78 | } 79 | } 80 | 81 | /// 82 | /// Gets the collection of individual key members specified in the ThisKey string. 83 | /// 84 | public IEnumerable ThisKeyMembers 85 | { 86 | get 87 | { 88 | return GetKeyMembers(this.ThisKey); 89 | } 90 | } 91 | 92 | /// 93 | /// Gets the collection of individual key members specified in the OtherKey string. 94 | /// 95 | public IEnumerable OtherKeyMembers 96 | { 97 | get 98 | { 99 | return GetKeyMembers(this.OtherKey); 100 | } 101 | } 102 | 103 | /// 104 | /// Parses the comma delimited key specified 105 | /// 106 | /// The key to parse 107 | /// Array of individual key members 108 | private static string[] GetKeyMembers(string key) 109 | { 110 | return key.Replace(" ", string.Empty).Split(','); 111 | } 112 | } 113 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/BindableTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations 2 | { 3 | /// 4 | /// Specifies that a type is considered a bindable type for automatic fields generation by controls like GridView / DetailsView. 5 | /// 6 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Struct, AllowMultiple = false, Inherited = true)] 7 | public sealed class BindableTypeAttribute : Attribute 8 | { 9 | 10 | public BindableTypeAttribute() 11 | { 12 | IsBindable = true; 13 | } 14 | 15 | /// 16 | /// Indicates whether the type should be considered Bindable or not. The default value is true when the attribute is specified. 17 | /// 18 | public bool IsBindable 19 | { 20 | get; 21 | set; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/ConcurrencyCheckAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations 2 | { 3 | /// 4 | /// This attribute is used to mark the members of a Type that participate in 5 | /// optimistic concurrency checks. 6 | /// 7 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] 8 | public sealed class ConcurrencyCheckAttribute : Attribute 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/CreditCardAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations.Resources; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace System.ComponentModel.DataAnnotations 9 | { 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 11 | public sealed class CreditCardAttribute : DataTypeAttribute 12 | { 13 | public CreditCardAttribute() 14 | : base(DataType.Custom) 15 | { 16 | var att = new RangeAttribute(0, 100); 17 | ErrorMessage = DataAnnotationsResources.CreditCardAttribute_Invalid; 18 | } 19 | 20 | internal override bool IsValid(object value) 21 | { 22 | if (value == null) 23 | { 24 | return true; 25 | } 26 | 27 | string ccValue = value as string; 28 | if (ccValue == null) 29 | { 30 | return false; 31 | } 32 | ccValue = ccValue.Replace("-", ""); 33 | ccValue = ccValue.Replace(" ", ""); 34 | 35 | int checksum = 0; 36 | bool evenDigit = false; 37 | 38 | // http://www.beachnet.com/~hstiles/cardtype.html 39 | foreach (char digit in Reverse(ccValue)) 40 | { 41 | if (digit < '0' || digit > '9') 42 | { 43 | return false; 44 | } 45 | 46 | int digitValue = (digit - '0') * (evenDigit ? 2 : 1); 47 | evenDigit = !evenDigit; 48 | 49 | while (digitValue > 0) 50 | { 51 | checksum += digitValue % 10; 52 | digitValue /= 10; 53 | } 54 | } 55 | 56 | return (checksum % 10) == 0; 57 | } 58 | 59 | private static string Reverse(string input) 60 | { 61 | StringBuilder sb = new StringBuilder(input.Length); 62 | for (int i = input.Length - 1; i >= 0; i--) 63 | { 64 | sb.Append(input[i]); 65 | } 66 | return sb.ToString(); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/DataTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Globalization; 4 | 5 | namespace System.ComponentModel.DataAnnotations 6 | { 7 | /// 8 | /// Allows for clarification of the represented by a given 9 | /// property (such as 10 | /// or ) 11 | /// 12 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = false)] 13 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 14 | public class DataTypeAttribute : ValidationAttribute 15 | { 16 | /// 17 | /// Gets the DataType. If it equals DataType.Custom, should also be retrieved. 18 | /// 19 | public DataType DataType { get; private set; } 20 | 21 | /// 22 | /// Gets the string representing a custom data type. Returns a non-null value only if is DataType.Custom. 23 | /// 24 | public string CustomDataType { get; private set; } 25 | 26 | /// 27 | /// Return the name of the data type, either using the enum or string 28 | /// 29 | /// The name of the data type enum 30 | /// is thrown if the current attribute is ill-formed. 31 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This method throws an exception if the properties have not been configured correctly")] 32 | public virtual string GetDataTypeName() 33 | { 34 | this.EnsureValidDataType(); 35 | 36 | if (DataType == DataType.Custom) 37 | { 38 | // If it's a custom type string, use it as the template name 39 | return this.CustomDataType; 40 | } 41 | else 42 | { 43 | // If it's an enum, turn it into a string 44 | // Use the cached array with enum string values instead of ToString() as the latter is too slow 45 | return _dataTypeStrings[(int)DataType]; 46 | } 47 | } 48 | 49 | /// 50 | /// Gets the default display format that gets used along with this DataType. 51 | /// 52 | public DisplayFormatAttribute DisplayFormat { get; protected set; } 53 | 54 | /// 55 | /// Constructor that accepts a data type enumeration 56 | /// 57 | /// The enum value indicating the type to apply. 58 | public DataTypeAttribute(DataType dataType) 59 | { 60 | DataType = dataType; 61 | 62 | // Set some DisplayFormat for a few specific data types 63 | switch (dataType) 64 | { 65 | case DataType.Date: 66 | this.DisplayFormat = new DisplayFormatAttribute(); 67 | this.DisplayFormat.DataFormatString = "{0:d}"; 68 | this.DisplayFormat.ApplyFormatInEditMode = true; 69 | break; 70 | case DataType.Time: 71 | this.DisplayFormat = new DisplayFormatAttribute(); 72 | this.DisplayFormat.DataFormatString = "{0:t}"; 73 | this.DisplayFormat.ApplyFormatInEditMode = true; 74 | break; 75 | case DataType.Currency: 76 | this.DisplayFormat = new DisplayFormatAttribute(); 77 | this.DisplayFormat.DataFormatString = "{0:C}"; 78 | 79 | // Don't set ApplyFormatInEditMode for currencies because the currency 80 | // symbol can't be parsed 81 | break; 82 | } 83 | } 84 | 85 | /// 86 | /// Constructor that accepts the string name of a custom data type 87 | /// 88 | /// The string name of the custom data type. 89 | public DataTypeAttribute(string customDataType) 90 | : this(DataType.Custom) 91 | { 92 | this.CustomDataType = customDataType; 93 | } 94 | 95 | /// 96 | /// Override of 97 | /// 98 | /// This override always returns true. Subclasses should override this to provide the correct result. 99 | /// The value to validate 100 | /// Unconditionally returns true 101 | /// is thrown if the current attribute is ill-formed. 102 | internal override bool IsValid(object value) 103 | { 104 | this.EnsureValidDataType(); 105 | 106 | return true; 107 | } 108 | 109 | /// 110 | /// Throws an exception if this attribute is not correctly formed 111 | /// 112 | /// is thrown if the current attribute is ill-formed. 113 | private void EnsureValidDataType() 114 | { 115 | if (this.DataType == DataType.Custom && String.IsNullOrEmpty(this.CustomDataType)) 116 | { 117 | throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.DataTypeAttribute_EmptyDataTypeString)); 118 | } 119 | } 120 | 121 | private static string[] _dataTypeStrings = Enum.GetNames(typeof(DataType)); 122 | } 123 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/DisplayColumnAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace System.ComponentModel.DataAnnotations 4 | { 5 | /// 6 | /// Sets the display column, the sort column, and the sort order for when a table is used as a parent table in FK relationships. 7 | /// 8 | [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] 9 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 10 | public class DisplayColumnAttribute : Attribute 11 | { 12 | public DisplayColumnAttribute(string displayColumn) 13 | : this(displayColumn, null) 14 | { 15 | } 16 | 17 | public DisplayColumnAttribute(string displayColumn, string sortColumn) 18 | : this(displayColumn, sortColumn, false) 19 | { 20 | } 21 | 22 | public DisplayColumnAttribute(string displayColumn, string sortColumn, bool sortDescending) 23 | { 24 | this.DisplayColumn = displayColumn; 25 | this.SortColumn = sortColumn; 26 | this.SortDescending = sortDescending; 27 | } 28 | 29 | public string DisplayColumn { get; private set; } 30 | 31 | public string SortColumn { get; private set; } 32 | 33 | public bool SortDescending { get; private set; } 34 | } 35 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/DisplayFormatAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace System.ComponentModel.DataAnnotations 4 | { 5 | /// 6 | /// Allows overriding various display-related options for a given field. The options have the same meaning as in BoundField. 7 | /// 8 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] 9 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 10 | public class DisplayFormatAttribute : Attribute 11 | { 12 | /// 13 | /// Gets or sets the format string 14 | /// 15 | public string DataFormatString { get; set; } 16 | 17 | /// 18 | /// Gets or sets the string to display when the value is null 19 | /// 20 | public string NullDisplayText { get; set; } 21 | 22 | /// 23 | /// Gets or sets a value indicating whether empty strings should be set to null 24 | /// 25 | public bool ConvertEmptyStringToNull { get; set; } 26 | 27 | /// 28 | /// Gets or sets a value indicating whether the format string should be used in edit mode 29 | /// 30 | public bool ApplyFormatInEditMode { get; set; } 31 | 32 | #if !SILVERLIGHT 33 | /// 34 | /// Gets or sets a value indicating whether the field should be html encoded 35 | /// 36 | public bool HtmlEncode { get; set; } 37 | #endif 38 | 39 | /// 40 | /// Default constructor 41 | /// 42 | public DisplayFormatAttribute() 43 | { 44 | this.ConvertEmptyStringToNull = true; // default to true to match behavior in related components 45 | 46 | #if !SILVERLIGHT 47 | this.HtmlEncode = true; // default to true to match behavior in related components 48 | #endif 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/EditableAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations 2 | { 3 | /// 4 | /// Indicates whether the consumer of a field or property, such as a client application, 5 | /// should allow editing of the value. 6 | /// 7 | /// 8 | /// This attribute neither enforces nor guarantees editability; the underlying data 9 | /// store might allow changing the data regardless of this attribute. The presence 10 | /// of this attribute signals intent to the consumer of the attribute whethere or not 11 | /// the end user should be allowed to change the value via the client application. 12 | /// 13 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] 14 | public sealed class EditableAttribute : Attribute 15 | { 16 | /// 17 | /// Indicates whether or not the field/property allows editing of the 18 | /// value. 19 | /// 20 | /// 21 | /// When true, the field/property is editable. 22 | /// 23 | /// When false, the field/property is not editable. 24 | /// 25 | /// 26 | public bool AllowEdit { get; private set; } 27 | 28 | /// 29 | /// Indicates whether or not the field/property allows an initial value 30 | /// to be specified. 31 | /// 32 | /// 33 | /// The value of this property defaults to match the 34 | /// property value specified in the constructor. 35 | /// 36 | /// 37 | /// When true, the field/property can have its value set for 38 | /// newly constructed instances, such as during an insert operation. 39 | /// 40 | /// When false, the field/property cannot have its 41 | /// value provided for newly constructed instances, such as during 42 | /// an insert operation. This will often indicate that the value 43 | /// is auto-generated by the persistence store. 44 | /// 45 | /// 46 | public bool AllowInitialValue { get; set; } 47 | 48 | /// 49 | /// Indicate whether or not a field/property is editable. 50 | /// 51 | /// 52 | /// Indicates whether the field/property is editable. The value provided 53 | /// will apply to both and 54 | /// unless the 55 | /// property is explicitly specified. 56 | /// 57 | public EditableAttribute(bool allowEdit) 58 | { 59 | this.AllowEdit = allowEdit; 60 | this.AllowInitialValue = allowEdit; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/EmailAddressAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations 2 | { 3 | using System; 4 | using System.ComponentModel.DataAnnotations.Resources; 5 | using System.Text.RegularExpressions; 6 | 7 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 8 | public sealed class EmailAddressAttribute : DataTypeAttribute 9 | { 10 | 11 | // This attribute provides server-side email validation equivalent to jquery validate, 12 | // and therefore shares the same regular expression. See unit tests for examples. 13 | private static Regex _regex = new Regex(@"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture); 14 | 15 | public EmailAddressAttribute() 16 | : base(DataType.EmailAddress) 17 | { 18 | ErrorMessage = DataAnnotationsResources.EmailAddressAttribute_Invalid; 19 | } 20 | 21 | internal override bool IsValid(object value) 22 | { 23 | if (value == null) 24 | { 25 | return true; 26 | } 27 | 28 | string valueAsString = value as string; 29 | return valueAsString != null && _regex.Match(valueAsString).Length > 0; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/EnumDataTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Globalization; 5 | 6 | namespace System.ComponentModel.DataAnnotations 7 | { 8 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = false)] 9 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 10 | public sealed class EnumDataTypeAttribute : DataTypeAttribute 11 | { 12 | public Type EnumType { get; private set; } 13 | 14 | public EnumDataTypeAttribute(Type enumType) 15 | : base("Enumeration") 16 | { 17 | this.EnumType = enumType; 18 | } 19 | 20 | internal override bool IsValid(object value) 21 | { 22 | if (this.EnumType == null) 23 | { 24 | throw new InvalidOperationException(DataAnnotationsResources.EnumDataTypeAttribute_TypeCannotBeNull); 25 | } 26 | if (!this.EnumType.IsEnum) 27 | { 28 | throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.EnumDataTypeAttribute_TypeNeedsToBeAnEnum, this.EnumType.FullName)); 29 | } 30 | 31 | if (value == null) 32 | { 33 | return true; 34 | } 35 | string stringValue = value as string; 36 | if (stringValue != null && String.IsNullOrEmpty(stringValue)) 37 | { 38 | return true; 39 | } 40 | 41 | Type valueType = value.GetType(); 42 | if (valueType.IsEnum && this.EnumType != valueType) 43 | { 44 | // don't match a different enum that might map to the same underlying integer 45 | // 46 | return false; 47 | } 48 | 49 | if (!valueType.IsValueType && valueType != typeof(string)) 50 | { 51 | // non-value types cannot be converted 52 | return false; 53 | } 54 | 55 | if (valueType == typeof(bool) || 56 | valueType == typeof(float) || 57 | valueType == typeof(double) || 58 | valueType == typeof(decimal) || 59 | valueType == typeof(char)) 60 | { 61 | // non-integral types cannot be converted 62 | return false; 63 | } 64 | 65 | object convertedValue; 66 | if (valueType.IsEnum) 67 | { 68 | Debug.Assert(valueType == value.GetType(), "The valueType should equal the Type of the value"); 69 | convertedValue = value; 70 | } 71 | else 72 | { 73 | try 74 | { 75 | if (stringValue != null) 76 | { 77 | convertedValue = Enum.Parse(this.EnumType, stringValue, false); 78 | } 79 | else 80 | { 81 | convertedValue = Enum.ToObject(this.EnumType, value); 82 | } 83 | } 84 | catch (ArgumentException) 85 | { 86 | // 87 | return false; 88 | } 89 | } 90 | 91 | if (IsEnumTypeInFlagsMode(this.EnumType)) 92 | { 93 | // 94 | 95 | 96 | 97 | string underlying = GetUnderlyingTypeValueString(this.EnumType, convertedValue); 98 | string converted = convertedValue.ToString(); 99 | return !underlying.Equals(converted); 100 | } 101 | else 102 | { 103 | return Enum.IsDefined(this.EnumType, convertedValue); 104 | } 105 | } 106 | 107 | private static bool IsEnumTypeInFlagsMode(Type enumType) 108 | { 109 | return enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Length != 0; 110 | } 111 | 112 | 113 | private static string GetUnderlyingTypeValueString(Type enumType, object enumValue) 114 | { 115 | return Convert.ChangeType(enumValue, Enum.GetUnderlyingType(enumType), CultureInfo.InvariantCulture).ToString(); 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/FilterUIHintAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics.CodeAnalysis; 3 | 4 | namespace System.ComponentModel.DataAnnotations 5 | { 6 | /// 7 | /// An attribute used to specify the filtering behavior for a column. 8 | /// 9 | [SuppressMessage("Microsoft.Design", "CA1019:DefineAccessorsForAttributeArguments", Justification = "ControlParameters is exposed, just with a different type")] 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] 11 | public sealed class FilterUIHintAttribute : Attribute 12 | { 13 | private UIHintAttribute.UIHintImplementation _implementation; 14 | 15 | /// 16 | /// Gets the name of the control that is most appropriate for this associated property or field 17 | /// 18 | public string FilterUIHint 19 | { 20 | get 21 | { 22 | return this._implementation.UIHint; 23 | } 24 | } 25 | 26 | /// 27 | /// Gets the name of the presentation layer that supports the control type in 28 | /// 29 | public string PresentationLayer 30 | { 31 | get 32 | { 33 | return this._implementation.PresentationLayer; 34 | } 35 | } 36 | 37 | /// 38 | /// Gets the name-value pairs used as parameters to the control's constructor 39 | /// 40 | /// is thrown if the current attribute is ill-formed. 41 | public IDictionary ControlParameters 42 | { 43 | get 44 | { 45 | return this._implementation.ControlParameters; 46 | } 47 | } 48 | 49 | /// 50 | /// Constructor that accepts the name of the control, without specifying which presentation layer to use 51 | /// 52 | /// The name of the UI control. 53 | public FilterUIHintAttribute(string filterUIHint) 54 | : this(filterUIHint, null, new object[0]) 55 | { 56 | } 57 | 58 | /// 59 | /// Constructor that accepts both the name of the control as well as the presentation layer 60 | /// 61 | /// The name of the control to use 62 | /// The name of the presentation layer that supports this control 63 | public FilterUIHintAttribute(string filterUIHint, string presentationLayer) 64 | : this(filterUIHint, presentationLayer, new object[0]) 65 | { 66 | } 67 | 68 | /// 69 | /// Full constructor that accepts the name of the control, presentation layer, and optional parameters 70 | /// to use when constructing the control 71 | /// 72 | /// The name of the control 73 | /// The presentation layer 74 | /// The list of parameters for the control 75 | public FilterUIHintAttribute(string filterUIHint, string presentationLayer, params object[] controlParameters) 76 | { 77 | this._implementation = new UIHintAttribute.UIHintImplementation(filterUIHint, presentationLayer, controlParameters); 78 | } 79 | 80 | /// 81 | /// Returns the hash code for this FilterUIHintAttribute. 82 | /// 83 | /// A 32-bit signed integer hash code. 84 | public override int GetHashCode() 85 | { 86 | return this._implementation.GetHashCode(); 87 | } 88 | 89 | /// 90 | /// Determines whether this instance of FilterUIHintAttribute and a specified object, 91 | /// which must also be a FilterUIHintAttribute object, have the same value. 92 | /// 93 | /// An System.Object. 94 | /// true if obj is a FilterUIHintAttribute and its value is the same as this instance; otherwise, false. 95 | public override bool Equals(object obj) 96 | { 97 | var otherAttribute = obj as FilterUIHintAttribute; 98 | if (otherAttribute == null) 99 | { 100 | return false; 101 | } 102 | return this._implementation.Equals(otherAttribute._implementation); 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/KeyAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations 2 | { 3 | /// 4 | /// Used to mark one or more entity properties that provide the entity's unique identity 5 | /// 6 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] 7 | public sealed class KeyAttribute : Attribute 8 | { 9 | } 10 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/MaxLengthAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Globalization; 4 | 5 | namespace System.ComponentModel.DataAnnotations 6 | { 7 | /// 8 | /// Specifies the maximum length of array/string data allowed in a property. 9 | /// 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 11 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 12 | public class MaxLengthAttribute : ValidationAttribute 13 | { 14 | private const int MaxAllowableLength = -1; 15 | 16 | /// 17 | /// Gets the maximum allowable length of the array/string data. 18 | /// 19 | public int Length { get; private set; } 20 | 21 | /// 22 | /// Initializes a new instance of the class. 23 | /// 24 | /// 25 | /// The maximum allowable length of array/string data. 26 | /// Value must be greater than zero. 27 | /// 28 | public MaxLengthAttribute(int length) 29 | : base(() => DefaultErrorMessageString) 30 | { 31 | Length = length; 32 | } 33 | 34 | /// 35 | /// Initializes a new instance of the class. 36 | /// The maximum allowable length supported by the database will be used. 37 | /// 38 | public MaxLengthAttribute() 39 | : base(() => DefaultErrorMessageString) 40 | { 41 | Length = MaxAllowableLength; 42 | } 43 | 44 | private static string DefaultErrorMessageString 45 | { 46 | get { return DataAnnotationsResources.MaxLengthAttribute_ValidationError; } 47 | } 48 | 49 | /// 50 | /// Determines whether a specified object is valid. (Overrides ) 51 | /// 52 | /// 53 | /// This method returns true if the is null. 54 | /// It is assumed the is used if the value may not be null. 55 | /// 56 | /// The object to validate. 57 | /// true if the value is null or less than or equal to the specified maximum length, otherwise false 58 | /// Length is zero or less than negative one. 59 | internal override bool IsValid(object value) 60 | { 61 | // Check the lengths for legality 62 | EnsureLegalLengths(); 63 | 64 | var length = 0; 65 | // Automatically pass if value is null. RequiredAttribute should be used to assert a value is not null. 66 | if (value == null) 67 | { 68 | return true; 69 | } 70 | else 71 | { 72 | var str = value as string; 73 | if (str != null) 74 | { 75 | length = str.Length; 76 | } 77 | else 78 | { 79 | // We expect a cast exception if a non-{string|array} property was passed in. 80 | length = ((Array)value).Length; 81 | } 82 | } 83 | 84 | return MaxAllowableLength == Length || length <= Length; 85 | } 86 | 87 | /// 88 | /// Applies formatting to a specified error message. (Overrides ) 89 | /// 90 | /// The name to include in the formatted string. 91 | /// A localized string to describe the maximum acceptable length. 92 | public override string FormatErrorMessage(string name) 93 | { 94 | // An error occurred, so we know the value is greater than the maximum if it was specified 95 | return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, Length); 96 | } 97 | 98 | /// 99 | /// Checks that Length has a legal value. 100 | /// 101 | /// Length is zero or less than negative one. 102 | private void EnsureLegalLengths() 103 | { 104 | if (Length == 0 || Length < -1) 105 | { 106 | throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.MaxLengthAttribute_InvalidMaxLength)); 107 | } 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/MetadataTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System; 3 | 4 | namespace System.ComponentModel.DataAnnotations 5 | { 6 | /// 7 | /// Used for associating a metadata class with the entity class. 8 | /// 9 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 10 | public sealed class MetadataTypeAttribute : Attribute { 11 | 12 | private Type _metadataClassType; 13 | 14 | public Type MetadataClassType { 15 | get { 16 | if (_metadataClassType == null) { 17 | throw new InvalidOperationException(DataAnnotationsResources.MetadataTypeAttribute_TypeCannotBeNull); 18 | } 19 | 20 | return _metadataClassType; 21 | } 22 | } 23 | 24 | public MetadataTypeAttribute(Type metadataClassType) { 25 | _metadataClassType = metadataClassType; 26 | } 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/MinLengthAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Globalization; 4 | 5 | namespace System.ComponentModel.DataAnnotations 6 | { 7 | /// 8 | /// Specifies the minimum length of array/string data allowed in a property. 9 | /// 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 11 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 12 | public class MinLengthAttribute : ValidationAttribute 13 | { 14 | /// 15 | /// Gets the minimum allowable length of the array/string data. 16 | /// 17 | public int Length { get; private set; } 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// 23 | /// The minimum allowable length of array/string data. 24 | /// Value must be greater than or equal to zero. 25 | /// 26 | public MinLengthAttribute(int length) 27 | : base(DataAnnotationsResources.MinLengthAttribute_ValidationError) 28 | { 29 | Length = length; 30 | } 31 | 32 | protected override ValidationResult IsValid(object value, ValidationContext validationContext) 33 | { 34 | return base.IsValid(value, validationContext); 35 | } 36 | 37 | /// 38 | /// Determines whether a specified object is valid. (Overrides ) 39 | /// 40 | /// 41 | /// This method returns true if the is null. 42 | /// It is assumed the is used if the value may not be null. 43 | /// 44 | /// The object to validate. 45 | /// true if the value is null or greater than or equal to the specified minimum length, otherwise false 46 | /// Length is less than zero. 47 | internal override bool IsValid(object value) 48 | { 49 | // Check the lengths for legality 50 | EnsureLegalLengths(); 51 | 52 | var length = 0; 53 | // Automatically pass if value is null. RequiredAttribute should be used to assert a value is not null. 54 | if (value == null) 55 | { 56 | return true; 57 | } 58 | else 59 | { 60 | var str = value as string; 61 | if (str != null) 62 | { 63 | length = str.Length; 64 | } 65 | else 66 | { 67 | // We expect a cast exception if a non-{string|array} property was passed in. 68 | length = ((Array)value).Length; 69 | } 70 | } 71 | 72 | return length >= Length; 73 | } 74 | 75 | /// 76 | /// Applies formatting to a specified error message. (Overrides ) 77 | /// 78 | /// The name to include in the formatted string. 79 | /// A localized string to describe the minimum acceptable length. 80 | public override string FormatErrorMessage(string name) 81 | { 82 | // An error occurred, so we know the value is less than the minimum 83 | return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, Length); 84 | } 85 | 86 | /// 87 | /// Checks that Length has a legal value. 88 | /// 89 | /// Length is less than zero. 90 | private void EnsureLegalLengths() 91 | { 92 | if (Length < 0) 93 | { 94 | throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.MinLengthAttribute_InvalidMinLength)); 95 | } 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/PhoneAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations 2 | { 3 | using System; 4 | using System.ComponentModel.DataAnnotations.Resources; 5 | using System.Text.RegularExpressions; 6 | 7 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 8 | public sealed class PhoneAttribute : DataTypeAttribute 9 | { 10 | // see unit tests for examples 11 | private static Regex _regex = new Regex(@"^(\+\s?)?((? 0; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/RangeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Globalization; 4 | 5 | namespace System.ComponentModel.DataAnnotations 6 | { 7 | /// 8 | /// Used for specifying a range constraint 9 | /// 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 11 | [SuppressMessage("Microsoft.Design", "CA1019:DefineAccessorsForAttributeArguments", Justification = "We want it to be accessible via method on parent.")] 12 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 13 | public class RangeAttribute : ValidationAttribute 14 | { 15 | /// 16 | /// Gets the minimum value for the range 17 | /// 18 | public object Minimum { get; private set; } 19 | 20 | /// 21 | /// Gets the maximum value for the range 22 | /// 23 | public object Maximum { get; private set; } 24 | 25 | /// 26 | /// Gets the type of the and values (e.g. Int32, Double, or some custom type) 27 | /// 28 | public Type OperandType { get; private set; } 29 | 30 | private Func Conversion { get; set; } 31 | 32 | /// 33 | /// Constructor that takes integer minimum and maximum values 34 | /// 35 | /// The minimum value, inclusive 36 | /// The maximum value, inclusive 37 | public RangeAttribute(int minimum, int maximum) 38 | : this() 39 | { 40 | this.Minimum = minimum; 41 | this.Maximum = maximum; 42 | this.OperandType = typeof(int); 43 | } 44 | 45 | /// 46 | /// Constructor that takes double minimum and maximum values 47 | /// 48 | /// The minimum value, inclusive 49 | /// The maximum value, inclusive 50 | public RangeAttribute(double minimum, double maximum) 51 | : this() 52 | { 53 | this.Minimum = minimum; 54 | this.Maximum = maximum; 55 | this.OperandType = typeof(double); 56 | } 57 | 58 | /// 59 | /// Allows for specifying range for arbitrary types. The minimum and maximum strings will be converted to the target type. 60 | /// 61 | /// The type of the range parameters. Must implement IComparable. 62 | /// The minimum allowable value. 63 | /// The maximum allowable value. 64 | public RangeAttribute(Type type, string minimum, string maximum) 65 | : this() 66 | { 67 | this.OperandType = type; 68 | this.Minimum = minimum; 69 | this.Maximum = maximum; 70 | } 71 | 72 | private RangeAttribute() 73 | : base(() => DataAnnotationsResources.RangeAttribute_ValidationError) 74 | { 75 | } 76 | 77 | private void Initialize(IComparable minimum, IComparable maximum, Func conversion) 78 | { 79 | if (minimum.CompareTo(maximum) > 0) 80 | { 81 | throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.RangeAttribute_MinGreaterThanMax, maximum, minimum)); 82 | } 83 | 84 | this.Minimum = minimum; 85 | this.Maximum = maximum; 86 | this.Conversion = conversion; 87 | } 88 | 89 | /// 90 | /// Returns true if the value falls between min and max, inclusive. 91 | /// 92 | /// The value to test for validity. 93 | /// true means the is valid 94 | /// is thrown if the current attribute is ill-formed. 95 | internal override bool IsValid(object value) 96 | { 97 | // Validate our properties and create the conversion function 98 | this.SetupConversion(); 99 | 100 | // Automatically pass if value is null or empty. RequiredAttribute should be used to assert a value is not empty. 101 | if (value == null) 102 | { 103 | return true; 104 | } 105 | string s = value as string; 106 | if (s != null && String.IsNullOrEmpty(s)) 107 | { 108 | return true; 109 | } 110 | 111 | object convertedValue = null; 112 | 113 | try 114 | { 115 | convertedValue = this.Conversion(value); 116 | } 117 | catch (FormatException) 118 | { 119 | return false; 120 | } 121 | catch (InvalidCastException) 122 | { 123 | return false; 124 | } 125 | catch (NotSupportedException) 126 | { 127 | return false; 128 | } 129 | 130 | IComparable min = (IComparable)this.Minimum; 131 | IComparable max = (IComparable)this.Maximum; 132 | return min.CompareTo(convertedValue) <= 0 && max.CompareTo(convertedValue) >= 0; 133 | } 134 | 135 | /// 136 | /// Override of 137 | /// 138 | /// This override exists to provide a formatted message describing the minimum and maximum values 139 | /// The user-visible name to include in the formatted message. 140 | /// A localized string describing the minimum and maximum values 141 | /// is thrown if the current attribute is ill-formed. 142 | public override string FormatErrorMessage(string name) 143 | { 144 | this.SetupConversion(); 145 | 146 | return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, this.Minimum, this.Maximum); 147 | } 148 | 149 | /// 150 | /// Validates the properties of this attribute and sets up the conversion function. 151 | /// This method throws exceptions if the attribute is not configured properly. 152 | /// If it has once determined it is properly configured, it is a NOP. 153 | /// 154 | private void SetupConversion() 155 | { 156 | if (this.Conversion == null) 157 | { 158 | object minimum = this.Minimum; 159 | object maximum = this.Maximum; 160 | 161 | if (minimum == null || maximum == null) 162 | { 163 | throw new InvalidOperationException(DataAnnotationsResources.RangeAttribute_Must_Set_Min_And_Max); 164 | } 165 | 166 | // Careful here -- OperandType could be int or double if they used the long form of the ctor. 167 | // But the min and max would still be strings. Do use the type of the min/max operands to condition 168 | // the following code. 169 | Type operandType = minimum.GetType(); 170 | 171 | if (operandType == typeof(int)) 172 | { 173 | this.Initialize((int)minimum, (int)maximum, v => Convert.ToInt32(v, CultureInfo.InvariantCulture)); 174 | } 175 | else if (operandType == typeof(double)) 176 | { 177 | this.Initialize((double)minimum, (double)maximum, v => Convert.ToDouble(v, CultureInfo.InvariantCulture)); 178 | } 179 | else 180 | { 181 | Type type = this.OperandType; 182 | if (type == null) 183 | { 184 | throw new InvalidOperationException(DataAnnotationsResources.RangeAttribute_Must_Set_Operand_Type); 185 | } 186 | Type comparableType = typeof(IComparable); 187 | if (!comparableType.IsAssignableFrom(type)) 188 | { 189 | throw new InvalidOperationException( 190 | String.Format( 191 | CultureInfo.CurrentCulture, 192 | DataAnnotationsResources.RangeAttribute_ArbitraryTypeNotIComparable, 193 | type.FullName, 194 | comparableType.FullName)); 195 | } 196 | 197 | Func conversion = value => (value != null && value.GetType() == type) ? value : Convert.ChangeType(value, type, CultureInfo.CurrentCulture); 198 | IComparable min = (IComparable)conversion(minimum); 199 | IComparable max = (IComparable)conversion(maximum); 200 | 201 | this.Initialize(min, max, conversion); 202 | } 203 | } 204 | } 205 | } 206 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/RegularExpressionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Globalization; 4 | using System.Text.RegularExpressions; 5 | 6 | namespace System.ComponentModel.DataAnnotations 7 | { 8 | /// 9 | /// Regular expression validation attribute 10 | /// 11 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 12 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 13 | public class RegularExpressionAttribute : ValidationAttribute 14 | { 15 | /// 16 | /// Gets the regular expression pattern to use 17 | /// 18 | public string Pattern { get; private set; } 19 | 20 | private Regex Regex { get; set; } 21 | 22 | /// 23 | /// Constructor that accepts the regular expression pattern 24 | /// 25 | /// The regular expression to use. It cannot be null. 26 | public RegularExpressionAttribute(string pattern) 27 | : base(() => DataAnnotationsResources.RegexAttribute_ValidationError) 28 | { 29 | this.Pattern = pattern; 30 | } 31 | 32 | /// 33 | /// Override of 34 | /// 35 | /// This override performs the specific regular expression matching of the given 36 | /// The value to test for validity. 37 | /// true if the given value matches the current regular expression pattern 38 | /// is thrown if the current attribute is ill-formed. 39 | /// is thrown if the is not a valid regular expression. 40 | internal override bool IsValid(object value) 41 | { 42 | this.SetupRegex(); 43 | 44 | // Convert the value to a string 45 | string stringValue = Convert.ToString(value, CultureInfo.CurrentCulture); 46 | 47 | // Automatically pass if value is null or empty. RequiredAttribute should be used to assert a value is not empty. 48 | if (String.IsNullOrEmpty(stringValue)) 49 | { 50 | return true; 51 | } 52 | 53 | Match m = this.Regex.Match(stringValue); 54 | 55 | // We are looking for an exact match, not just a search hit. This matches what 56 | // the RegularExpressionValidator control does 57 | return (m.Success && m.Index == 0 && m.Length == stringValue.Length); 58 | } 59 | 60 | /// 61 | /// Override of 62 | /// 63 | /// This override provide a formatted error message describing the pattern 64 | /// The user-visible name to include in the formatted message. 65 | /// The localized message to present to the user 66 | /// is thrown if the current attribute is ill-formed. 67 | /// is thrown if the is not a valid regular expression. 68 | public override string FormatErrorMessage(string name) 69 | { 70 | this.SetupRegex(); 71 | 72 | return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, this.Pattern); 73 | } 74 | 75 | 76 | /// 77 | /// Sets up the property from the property. 78 | /// 79 | /// is thrown if the current cannot be parsed 80 | /// is thrown if the current attribute is ill-formed. 81 | private void SetupRegex() 82 | { 83 | if (this.Regex == null) 84 | { 85 | if (string.IsNullOrEmpty(this.Pattern)) 86 | { 87 | throw new InvalidOperationException(DataAnnotationsResources.RegularExpressionAttribute_Empty_Pattern); 88 | } 89 | this.Regex = new Regex(this.Pattern); 90 | } 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/RequiredAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics.CodeAnalysis; 3 | 4 | namespace System.ComponentModel.DataAnnotations 5 | { 6 | /// 7 | /// Validation attribute to indicate that a property field or parameter is required. 8 | /// 9 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 10 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 11 | public class RequiredAttribute : ValidationAttribute 12 | { 13 | /// 14 | /// Default constructor. 15 | /// 16 | /// This constructor selects a reasonable default error message for 17 | public RequiredAttribute() 18 | : base(() => DataAnnotationsResources.RequiredAttribute_ValidationError) 19 | { 20 | } 21 | 22 | /// 23 | /// Gets or sets a flag indicating whether the attribute should allow empty strings. 24 | /// 25 | public bool AllowEmptyStrings { get; set; } 26 | 27 | /// 28 | /// Override of 29 | /// 30 | /// The value to test 31 | /// false if the is null or an empty string. If 32 | /// then false is returned only if is null. 33 | internal override bool IsValid(object value) 34 | { 35 | if (value == null) 36 | { 37 | return false; 38 | } 39 | 40 | // only check string length if empty strings are not allowed 41 | var stringValue = value as string; 42 | if (stringValue != null && !AllowEmptyStrings) 43 | { 44 | return stringValue.Trim().Length != 0; 45 | } 46 | 47 | return true; 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/Schema/ColumnAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Globalization; 4 | 5 | namespace System.ComponentModel.DataAnnotations.Schema 6 | { 7 | /// 8 | /// Specifies the database column that a property is mapped to. 9 | /// 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] 11 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 12 | public class ColumnAttribute : Attribute 13 | { 14 | private readonly string _name; 15 | private string _typeName; 16 | private int _order = -1; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | public ColumnAttribute() 22 | { 23 | } 24 | 25 | /// 26 | /// Initializes a new instance of the class. 27 | /// 28 | /// The name of the column the property is mapped to. 29 | public ColumnAttribute(string name) 30 | { 31 | if (string.IsNullOrWhiteSpace(name)) 32 | { 33 | throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.ArgumentIsNullOrWhitespace, "name")); 34 | } 35 | 36 | _name = name; 37 | } 38 | 39 | /// 40 | /// The name of the column the property is mapped to. 41 | /// 42 | public string Name 43 | { 44 | get { return _name; } 45 | } 46 | 47 | /// 48 | /// The zero-based order of the column the property is mapped to. 49 | /// 50 | public int Order 51 | { 52 | get { return _order; } 53 | set 54 | { 55 | if (value < 0) 56 | { 57 | throw new ArgumentOutOfRangeException("value"); 58 | } 59 | 60 | _order = value; 61 | } 62 | } 63 | 64 | /// 65 | /// The database provider specific data type of the column the property is mapped to. 66 | /// 67 | public string TypeName 68 | { 69 | get { return _typeName; } 70 | set 71 | { 72 | if (string.IsNullOrWhiteSpace(value)) 73 | { 74 | throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.ArgumentIsNullOrWhitespace, "value")); 75 | } 76 | 77 | _typeName = value; 78 | } 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/Schema/ComplexTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace System.ComponentModel.DataAnnotations.Schema 4 | { 5 | /// 6 | /// Denotes that the class is a complex type. 7 | /// Complex types are non-scalar properties of entity types that enable scalar properties to be organized within entities. 8 | /// Complex types do not have keys and cannot be managed by the Entity Framework apart from the parent object. 9 | /// 10 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 11 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 12 | public class ComplexTypeAttribute : Attribute 13 | { 14 | } 15 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/Schema/DatabaseGeneratedAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace System.ComponentModel.DataAnnotations.Schema 4 | { 5 | /// 6 | /// Specifies how the database generates values for a property. 7 | /// 8 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] 9 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 10 | public class DatabaseGeneratedAttribute : Attribute 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// The pattern used to generate values for the property in the database. 16 | public DatabaseGeneratedAttribute(DatabaseGeneratedOption databaseGeneratedOption) 17 | { 18 | if (!(Enum.IsDefined(typeof(DatabaseGeneratedOption), databaseGeneratedOption))) 19 | { 20 | throw new ArgumentOutOfRangeException("databaseGeneratedOption"); 21 | } 22 | 23 | DatabaseGeneratedOption = databaseGeneratedOption; 24 | } 25 | 26 | /// 27 | /// The pattern used to generate values for the property in the database. 28 | /// 29 | public DatabaseGeneratedOption DatabaseGeneratedOption { get; private set; } 30 | } 31 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/Schema/DatabaseGeneratedOption.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations.Schema 2 | { 3 | /// 4 | /// The pattern used to generate values for a property in the database. 5 | /// 6 | public enum DatabaseGeneratedOption 7 | { 8 | /// 9 | /// The database does not generate values. 10 | /// 11 | None, 12 | 13 | /// 14 | /// The database generates a value when a row is inserted. 15 | /// 16 | Identity, 17 | 18 | /// 19 | /// The database generates a value when a row is inserted or updated. 20 | /// 21 | Computed 22 | } 23 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/Schema/ForeignKeyAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Globalization; 4 | 5 | namespace System.ComponentModel.DataAnnotations.Schema 6 | { 7 | /// 8 | /// Denotes a property used as a foreign key in a relationship. 9 | /// The annotation may be placed on the foreign key property and specify the associated navigation property name, 10 | /// or placed on a navigation property and specify the associated foreign key name. 11 | /// 12 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] 13 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 14 | public class ForeignKeyAttribute : Attribute 15 | { 16 | private readonly string _name; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// 22 | /// If placed on a foreign key property, the name of the associated navigation property. 23 | /// If placed on a navigation property, the name of the associated foreign key(s). 24 | /// If a navigation property has multiple foreign keys, a comma separated list should be supplied. 25 | /// 26 | public ForeignKeyAttribute(string name) 27 | { 28 | if (string.IsNullOrWhiteSpace(name)) 29 | { 30 | throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.ArgumentIsNullOrWhitespace, "name")); 31 | } 32 | 33 | _name = name; 34 | } 35 | 36 | /// 37 | /// If placed on a foreign key property, the name of the associated navigation property. 38 | /// If placed on a navigation property, the name of the associated foreign key(s). 39 | /// 40 | public string Name 41 | { 42 | get { return _name; } 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/Schema/InversePropertyAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Globalization; 4 | 5 | namespace System.ComponentModel.DataAnnotations.Schema { 6 | /// 7 | /// Specifies the inverse of a navigation property that represents the other end of the same relationship. 8 | /// 9 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] 10 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 11 | public class InversePropertyAttribute : Attribute { 12 | private readonly string _property; 13 | 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | /// The navigation property representing the other end of the same relationship. 18 | public InversePropertyAttribute(string property) { 19 | if (string.IsNullOrWhiteSpace(property)) { 20 | throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.ArgumentIsNullOrWhitespace, "property")); 21 | } 22 | _property = property; 23 | } 24 | 25 | /// 26 | /// The navigation property representing the other end of the same relationship. 27 | /// 28 | public string Property { 29 | get { return _property; } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/Schema/NotMappedAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace System.ComponentModel.DataAnnotations.Schema 4 | { 5 | /// 6 | /// Denotes that a property or class should be excluded from database mapping. 7 | /// 8 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Class, AllowMultiple = false)] 9 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 10 | public class NotMappedAttribute : Attribute 11 | { 12 | } 13 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/Schema/TableAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Globalization; 4 | 5 | namespace System.ComponentModel.DataAnnotations.Schema 6 | { 7 | /// 8 | /// Specifies the database table that a class is mapped to. 9 | /// 10 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 11 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 12 | public class TableAttribute : Attribute 13 | { 14 | private readonly string _name; 15 | private string _schema; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The name of the table the class is mapped to. 21 | public TableAttribute(string name) 22 | { 23 | if (string.IsNullOrWhiteSpace(name)) 24 | { 25 | throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.ArgumentIsNullOrWhitespace, "name")); 26 | } 27 | _name = name; 28 | } 29 | 30 | /// 31 | /// The name of the table the class is mapped to. 32 | /// 33 | public string Name 34 | { 35 | get { return _name; } 36 | } 37 | 38 | /// 39 | /// The schema of the table the class is mapped to. 40 | /// 41 | public string Schema 42 | { 43 | get { return _schema; } 44 | set 45 | { 46 | if (string.IsNullOrWhiteSpace(value)) 47 | { 48 | throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.ArgumentIsNullOrWhitespace, "value")); 49 | } 50 | _schema = value; 51 | } 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/StringLengthAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Globalization; 4 | 5 | namespace System.ComponentModel.DataAnnotations 6 | { 7 | /// 8 | /// Validation attribute to assert a string property, field or parameter does not exceed a maximum length 9 | /// 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 11 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 12 | public class StringLengthAttribute : ValidationAttribute 13 | { 14 | /// 15 | /// Gets the maximum acceptable length of the string 16 | /// 17 | public int MaximumLength 18 | { 19 | get; 20 | private set; 21 | } 22 | 23 | /// 24 | /// Gets or sets the minimum acceptable length of the string 25 | /// 26 | public int MinimumLength 27 | { 28 | get; 29 | set; 30 | } 31 | 32 | /// 33 | /// Constructor that accepts the maximum length of the string. 34 | /// 35 | /// The maximum length, inclusive. It may not be negative. 36 | public StringLengthAttribute(int maximumLength) 37 | : base(() => DataAnnotationsResources.StringLengthAttribute_ValidationError) 38 | { 39 | this.MaximumLength = maximumLength; 40 | } 41 | 42 | /// 43 | /// Override of 44 | /// 45 | /// This method returns true if the is null. 46 | /// It is assumed the is used if the value may not be null. 47 | /// The value to test. 48 | /// true if the value is null or less than or equal to the set maximum length 49 | /// is thrown if the current attribute is ill-formed. 50 | internal override bool IsValid(object value) 51 | { 52 | // Check the lengths for legality 53 | this.EnsureLegalLengths(); 54 | 55 | // Automatically pass if value is null. RequiredAttribute should be used to assert a value is not null. 56 | // We expect a cast exception if a non-string was passed in. 57 | int length = value == null ? 0 : ((string)value).Length; 58 | return value == null || (length >= this.MinimumLength && length <= this.MaximumLength); 59 | } 60 | 61 | /// 62 | /// Override of 63 | /// 64 | /// The name to include in the formatted string 65 | /// A localized string to describe the maximum acceptable length 66 | /// is thrown if the current attribute is ill-formed. 67 | public override string FormatErrorMessage(string name) 68 | { 69 | this.EnsureLegalLengths(); 70 | 71 | bool useErrorMessageWithMinimum = this.MinimumLength != 0 && !this.CustomErrorMessageSet; 72 | 73 | string errorMessage = useErrorMessageWithMinimum ? 74 | DataAnnotationsResources.StringLengthAttribute_ValidationErrorIncludingMinimum : this.ErrorMessageString; 75 | 76 | // it's ok to pass in the minLength even for the error message without a {2} param since String.Format will just 77 | // ignore extra arguments 78 | return String.Format(CultureInfo.CurrentCulture, errorMessage, name, this.MaximumLength, this.MinimumLength); 79 | } 80 | 81 | /// 82 | /// Checks that MinimumLength and MaximumLength have legal values. Throws InvalidOperationException if not. 83 | /// 84 | private void EnsureLegalLengths() 85 | { 86 | if (this.MaximumLength < 0) 87 | { 88 | throw new InvalidOperationException(DataAnnotationsResources.StringLengthAttribute_InvalidMaxLength); 89 | } 90 | 91 | if (this.MaximumLength < this.MinimumLength) 92 | { 93 | throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.RangeAttribute_MinGreaterThanMax, this.MaximumLength, this.MinimumLength)); 94 | } 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/TimestampAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations 2 | { 3 | /// 4 | /// This attribute is used to mark a Timestamp member of a Type. 5 | /// 6 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] 7 | public sealed class TimestampAttribute : Attribute 8 | { 9 | } 10 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationAttributes/UrlAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations 2 | { 3 | using System; 4 | using System.ComponentModel.DataAnnotations.Resources; 5 | using System.Text.RegularExpressions; 6 | 7 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 8 | public sealed class UrlAttribute : DataTypeAttribute 9 | { 10 | 11 | // This attribute provides server-side url validation equivalent to jquery validate, 12 | // and therefore shares the same regular expression. See unit tests for examples. 13 | private static Regex _regex = new Regex(@"^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture); 14 | 15 | public UrlAttribute() 16 | : base(DataType.Url) 17 | { 18 | ErrorMessage = DataAnnotationsResources.UrlAttribute_Invalid; 19 | } 20 | 21 | internal override bool IsValid(object value) 22 | { 23 | if (value == null) 24 | { 25 | return true; 26 | } 27 | 28 | string valueAsString = value as string; 29 | return valueAsString != null && _regex.Match(valueAsString).Length > 0; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Globalization; 4 | using System.Reflection; 5 | 6 | namespace System.ComponentModel.DataAnnotations { 7 | /// 8 | /// Describes the context in which a validation is being performed. 9 | /// 10 | /// 11 | /// This class contains information describing the instance on which 12 | /// validation is being performed. 13 | /// 14 | /// It supports so that custom validation 15 | /// code can acquire additional services to help it perform its validation. 16 | /// 17 | /// 18 | /// An property bag is available for additional contextual 19 | /// information about the validation. Values stored in 20 | /// will be available to validation methods that use this 21 | /// 22 | /// 23 | [SuppressMessage("Microsoft.Usage", "CA2302:FlagServiceProviders", Justification = "The actual IServiceProvider implementation lies with the underlying service provider.")] 24 | public sealed class ValidationContext : IServiceProvider 25 | { 26 | #region Member Fields 27 | 28 | private Func _serviceProvider; 29 | private object _objectInstance; 30 | private string _memberName; 31 | private string _displayName; 32 | private Dictionary _items; 33 | 34 | #endregion 35 | 36 | #region Constructors 37 | 38 | /// 39 | /// Construct a for a given object instance being validated. 40 | /// 41 | /// The object instance being validated. It cannot be null. 42 | /// When is null 43 | public ValidationContext(object instance) 44 | : this(instance, null, null) { 45 | } 46 | 47 | /// 48 | /// Construct a for a given object instance and an optional 49 | /// property bag of . 50 | /// 51 | /// The object instance being validated. It cannot be null. 52 | /// Optional set of key/value pairs to make available to consumers via . 53 | /// If null, an empty dictionary will be created. If not null, the set of key/value pairs will be copied into a 54 | /// new dictionary, preventing consumers from modifying the original dictionary. 55 | /// 56 | /// When is null 57 | public ValidationContext(object instance, IDictionary items) 58 | : this(instance, null, items) { 59 | } 60 | 61 | /// 62 | /// Construct a for a given object instance, an optional , and an optional 63 | /// property bag of . 64 | /// 65 | /// The object instance being validated. It cannot be null. 66 | /// 67 | /// Optional to use when is called. 68 | /// If it is null, will always return null. 69 | /// 70 | /// Optional set of key/value pairs to make available to consumers via . 71 | /// If null, an empty dictionary will be created. If not null, the set of key/value pairs will be copied into a 72 | /// new dictionary, preventing consumers from modifying the original dictionary. 73 | /// 74 | /// When is null 75 | public ValidationContext(object instance, IServiceProvider serviceProvider, IDictionary items) { 76 | if (instance == null) { 77 | throw new ArgumentNullException("instance"); 78 | } 79 | 80 | if (serviceProvider != null) { 81 | this.InitializeServiceProvider(serviceType => serviceProvider.GetService(serviceType)); 82 | } 83 | 84 | 85 | if (items != null) { 86 | this._items = new Dictionary(items); 87 | } else { 88 | this._items = new Dictionary(); 89 | } 90 | 91 | this._objectInstance = instance; 92 | } 93 | 94 | #endregion 95 | 96 | #region Properties 97 | 98 | /// 99 | /// Gets the object instance being validated. While it will not be null, the state of the instance is indeterminate 100 | /// as it might only be partially initialized during validation. 101 | /// Consume this instance with caution! 102 | /// 103 | /// 104 | /// During validation, especially property-level validation, the object instance might be in an indeterminate state. 105 | /// For example, the property being validated, as well as other properties on the instance might not have been 106 | /// updated to their new values. 107 | /// 108 | public object ObjectInstance { 109 | get { 110 | return this._objectInstance; 111 | } 112 | } 113 | 114 | /// 115 | /// Gets the type of the object being validated. It will not be null. 116 | /// 117 | public Type ObjectType { 118 | get { 119 | return this.ObjectInstance.GetType(); 120 | } 121 | } 122 | 123 | /// 124 | /// Gets or sets the user-visible name of the type or property being validated. 125 | /// 126 | /// If this name was not explicitly set, this property will consult an associated 127 | /// to see if can use that instead. Lacking that, it returns . The 128 | /// type name will be used if MemberName has not been set. 129 | /// 130 | public string DisplayName { 131 | get { 132 | if (string.IsNullOrEmpty(this._displayName)) { 133 | this._displayName = this.GetDisplayName(); 134 | 135 | if (string.IsNullOrEmpty(this._displayName)) { 136 | this._displayName = this.MemberName; 137 | 138 | if (string.IsNullOrEmpty(this._displayName)) { 139 | this._displayName = this.ObjectType.Name; 140 | } 141 | } 142 | } 143 | return this._displayName; 144 | } 145 | set { 146 | if (string.IsNullOrEmpty(value)) { 147 | throw new ArgumentNullException("value"); 148 | } 149 | this._displayName = value; 150 | } 151 | } 152 | 153 | /// 154 | /// Gets or sets the name of the type or property being validated. 155 | /// 156 | /// This name reflects the API name of the member being validated, not a localized name. It should be set 157 | /// only for property or parameter contexts. 158 | public string MemberName { 159 | get { 160 | return this._memberName; 161 | } 162 | set { 163 | this._memberName = value; 164 | } 165 | } 166 | 167 | /// 168 | /// Gets the dictionary of key/value pairs associated with this context. 169 | /// 170 | /// This property will never be null, but the dictionary may be empty. Changes made 171 | /// to items in this dictionary will never affect the original dictionary specified in the constructor. 172 | public IDictionary Items { 173 | get { 174 | return this._items; 175 | } 176 | } 177 | 178 | #endregion 179 | 180 | #region Methods 181 | 182 | /// 183 | /// Looks up the display name using the DisplayAttribute attached to the respective type or property. 184 | /// 185 | /// A display-friendly name of the member represented by the . 186 | private string GetDisplayName() { 187 | string displayName = null; 188 | ValidationAttributeStore store = ValidationAttributeStore.Instance; 189 | DisplayAttribute displayAttribute = null; 190 | 191 | if (string.IsNullOrEmpty(this._memberName)) { 192 | displayAttribute = store.GetTypeDisplayAttribute(this); 193 | } else if (store.IsPropertyContext(this)) { 194 | displayAttribute = store.GetPropertyDisplayAttribute(this); 195 | } 196 | 197 | if (displayAttribute != null) { 198 | displayName = displayAttribute.GetName(); 199 | } 200 | 201 | return displayName ?? this.MemberName; 202 | } 203 | 204 | /// 205 | /// Initializes the with a service provider that can return 206 | /// service instances by when is called. 207 | /// 208 | /// 209 | /// A that can return service instances given the 210 | /// desired when is called. 211 | /// If it is null, will always return null. 212 | /// 213 | public void InitializeServiceProvider(Func serviceProvider) { 214 | this._serviceProvider = serviceProvider; 215 | } 216 | 217 | #endregion 218 | 219 | #region IServiceProvider Members 220 | 221 | /// 222 | /// See . 223 | /// 224 | /// The type of the service needed. 225 | /// An instance of that service or null if it is not available. 226 | public object GetService(Type serviceType) { 227 | object service = null; 228 | 229 | if (service == null && this._serviceProvider != null) { 230 | service = this._serviceProvider(serviceType); 231 | } 232 | 233 | return service; 234 | } 235 | 236 | #endregion 237 | } 238 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationException.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations 2 | { 3 | /// 4 | /// Exception used for validation using . 5 | /// 6 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "SerializationInfo is internal in Silverlight")] 7 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2240:ImplementISerializableCorrectly", 8 | Justification = "SecurityTransparent types cannot override GetObjectData, and this type does not serialize its instance fields anyway.")] 9 | public class ValidationException : Exception 10 | { 11 | private ValidationResult _validationResult; 12 | 13 | /// 14 | /// Gets the ValidationAttribute instance that triggered this exception. 15 | /// 16 | public ValidationAttribute ValidationAttribute { get; private set; } 17 | 18 | /// 19 | /// Gets the instance that describes the validation error. 20 | /// 21 | /// 22 | /// This property will never be null. 23 | /// 24 | public ValidationResult ValidationResult 25 | { 26 | get 27 | { 28 | if (this._validationResult == null) 29 | { 30 | this._validationResult = new ValidationResult(this.Message); 31 | } 32 | return this._validationResult; 33 | } 34 | } 35 | 36 | /// 37 | /// Gets the value that caused the validating attribute to trigger the exception 38 | /// 39 | public object Value { get; private set; } 40 | 41 | /// 42 | /// Constructor that accepts a structured describing the problem. 43 | /// 44 | /// The value describing the validation error 45 | /// The attribute that triggered this exception 46 | /// The value that caused the validating attribute to trigger the exception 47 | public ValidationException(ValidationResult validationResult, ValidationAttribute validatingAttribute, object value) 48 | : this(validationResult.ErrorMessage, validatingAttribute, value) 49 | { 50 | this._validationResult = validationResult; 51 | } 52 | 53 | /// 54 | /// Constructor that accepts an error message, the failing attribute, and the invalid value. 55 | /// 56 | /// The localized error message 57 | /// The attribute that triggered this exception 58 | /// The value that caused the validating attribute to trigger the exception 59 | public ValidationException(string errorMessage, ValidationAttribute validatingAttribute, object value) 60 | : base(errorMessage) 61 | { 62 | this.Value = value; 63 | this.ValidationAttribute = validatingAttribute; 64 | } 65 | 66 | 67 | // 68 | 69 | /// 70 | /// Default constructor. 71 | /// 72 | /// The long form of this constructor is preferred because it gives better error reporting. 73 | public ValidationException() 74 | : base() 75 | { 76 | } 77 | 78 | /// 79 | /// Constructor that accepts only a localized message 80 | /// 81 | /// The long form of this constructor is preferred because it gives better error reporting. 82 | /// The localized message 83 | public ValidationException(string message) 84 | : base(message) { } 85 | 86 | /// 87 | /// Constructor that accepts a localized message and an inner exception 88 | /// 89 | /// The long form of this constructor is preferred because it gives better error reporting 90 | /// The localized error message 91 | /// inner exception 92 | public ValidationException(string message, Exception innerException) 93 | : base(message, innerException) { } 94 | } 95 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Net45Portable/ValidationResult.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics.CodeAnalysis; 3 | 4 | namespace System.ComponentModel.DataAnnotations 5 | { 6 | /// 7 | /// Container class for the results of a validation request. 8 | /// 9 | /// Use the static to represent successful validation. 10 | /// 11 | /// 12 | /// 13 | public sealed class ValidationResult 14 | { 15 | #region Member Fields 16 | 17 | private IEnumerable _memberNames; 18 | private string _errorMessage; 19 | 20 | /// 21 | /// Gets a that indicates Success. 22 | /// 23 | /// 24 | /// The null value is used to indicate success. Consumers of s 25 | /// should compare the values to rather than checking for null. 26 | /// 27 | [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "We want this to be readonly since we're just returning null")] 28 | public static readonly ValidationResult Success; 29 | 30 | #endregion 31 | 32 | #region All Constructors 33 | 34 | /// 35 | /// Constructor that accepts an error message. This error message would override any error message 36 | /// provided on the . 37 | /// 38 | /// The user-visible error message. If null, 39 | /// will use for its error message. 40 | public ValidationResult(string errorMessage) 41 | : this(errorMessage, null) 42 | { 43 | } 44 | 45 | /// 46 | /// Constructor that accepts an error message as well as a list of member names involved in the validation. 47 | /// This error message would override any error message provided on the . 48 | /// 49 | /// The user-visible error message. If null, 50 | /// will use for its error message. 51 | /// The list of member names affected by this result. 52 | /// This list of member names is meant to be used by presentation layers to indicate which fields are in error. 53 | public ValidationResult(string errorMessage, IEnumerable memberNames) 54 | { 55 | this._errorMessage = errorMessage; 56 | this._memberNames = memberNames ?? new string[0]; 57 | } 58 | 59 | #endregion 60 | 61 | #region Properties 62 | 63 | /// 64 | /// Gets the collection of member names affected by this result. The collection may be empty but will never be null. 65 | /// 66 | public IEnumerable MemberNames 67 | { 68 | get 69 | { 70 | return this._memberNames; 71 | } 72 | } 73 | 74 | /// 75 | /// Gets the error message for this result. It may be null. 76 | /// 77 | public string ErrorMessage 78 | { 79 | get 80 | { 81 | return this._errorMessage; 82 | } 83 | set 84 | { 85 | this._errorMessage = value; 86 | } 87 | } 88 | 89 | #endregion 90 | 91 | #region Methods 92 | 93 | /// 94 | /// Override the string representation of this instance, returning 95 | /// the if not null, otherwise 96 | /// the base result. 97 | /// 98 | /// 99 | /// If the is empty, it will still qualify 100 | /// as being specified, and therefore returned from . 101 | /// 102 | /// The property value if specified, 103 | /// otherwise, the base result. 104 | public override string ToString() 105 | { 106 | return this.ErrorMessage ?? base.ToString(); 107 | } 108 | 109 | #endregion Methods 110 | 111 | } 112 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.WindowsRuntime/Portable.DataAnnotations.WindowsRuntime.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8.0.30703 8 | 2.0 9 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD} 10 | Library 11 | Properties 12 | System.ComponentModel.DataAnnotations 13 | Portable.DataAnnotations 14 | en-US 15 | 8.1 16 | 12 17 | 512 18 | {BC8A1FFA-BEE3-4634-8014-F334798102B3};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE;NETFX_CORE;WINDOWS_APP 26 | prompt 27 | 4 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE;NETFX_CORE;WINDOWS_APP 34 | prompt 35 | 4 36 | 37 | 38 | true 39 | bin\ARM\Debug\ 40 | DEBUG;TRACE;NETFX_CORE;WINDOWS_APP 41 | ;2008 42 | full 43 | ARM 44 | false 45 | prompt 46 | true 47 | 48 | 49 | bin\ARM\Release\ 50 | TRACE;NETFX_CORE;WINDOWS_APP 51 | true 52 | ;2008 53 | pdbonly 54 | ARM 55 | false 56 | prompt 57 | true 58 | 59 | 60 | true 61 | bin\x64\Debug\ 62 | DEBUG;TRACE;NETFX_CORE;WINDOWS_APP 63 | ;2008 64 | full 65 | x64 66 | false 67 | prompt 68 | true 69 | 70 | 71 | bin\x64\Release\ 72 | TRACE;NETFX_CORE;WINDOWS_APP 73 | true 74 | ;2008 75 | pdbonly 76 | x64 77 | false 78 | prompt 79 | true 80 | 81 | 82 | true 83 | bin\x86\Debug\ 84 | DEBUG;TRACE;NETFX_CORE;WINDOWS_APP 85 | ;2008 86 | full 87 | x86 88 | false 89 | prompt 90 | true 91 | 92 | 93 | bin\x86\Release\ 94 | TRACE;NETFX_CORE;WINDOWS_APP 95 | true 96 | ;2008 97 | pdbonly 98 | x86 99 | false 100 | prompt 101 | true 102 | 103 | 104 | 105 | IValidatableObject.cs 106 | 107 | 108 | ValidationAttributes\BindableTypeAttribute.cs 109 | 110 | 111 | ValidationAttributes\MetadataTypeAttribute.cs 112 | 113 | 114 | ValidationAttributes\Schema\ColumnAttribute.cs 115 | 116 | 117 | ValidationAttributes\Schema\ComplexTypeAttribute.cs 118 | 119 | 120 | ValidationAttributes\Schema\ForeignKeyAttribute.cs 121 | 122 | 123 | ValidationAttributes\Schema\InversePropertyAttribute.cs 124 | 125 | 126 | ValidationAttributes\Schema\NotMappedAttribute.cs 127 | 128 | 129 | ValidationAttributes\Schema\TableAttribute.cs 130 | 131 | 132 | 133 | True 134 | True 135 | DataAnnotationsResources.resx 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | ResXFileCodeGenerator 148 | DataAnnotationsResources.Designer.cs 149 | 150 | 151 | 152 | 12.0 153 | 154 | 155 | 162 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.WindowsRuntime/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Portable.DataAnnotations.WindowsRuntime")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Portable.DataAnnotations.WindowsRuntime")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /Portable.DataAnnotations.WindowsRuntime/TypeForwards.cs: -------------------------------------------------------------------------------- 1 |  [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.AssociationAttribute))] 2 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ConcurrencyCheckAttribute))] 3 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.CustomValidationAttribute))] 4 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DataType))] 5 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DataTypeAttribute))] 6 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DisplayAttribute))] 7 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DisplayColumnAttribute))] 8 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.DisplayFormatAttribute))] 9 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.EditableAttribute))] 10 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.EnumDataTypeAttribute))] 11 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.FilterUIHintAttribute))] 12 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.KeyAttribute))] 13 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.RangeAttribute))] 14 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.RegularExpressionAttribute))] 15 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.RequiredAttribute))] 16 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.StringLengthAttribute))] 17 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.TimestampAttribute))] 18 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.UIHintAttribute))] 19 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ValidationAttribute))] 20 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ValidationContext))] 21 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ValidationException))] 22 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.ValidationResult))] 23 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.Validator))] 24 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedAttribute))] 25 | [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption))] 26 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.WindowsRuntime/ValidationAttributes/CreditCardAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations.Resources; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace System.ComponentModel.DataAnnotations 9 | { 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 11 | public sealed class CreditCardAttribute : DataTypeAttribute 12 | { 13 | public CreditCardAttribute() 14 | : base(DataType.Custom) 15 | { 16 | var att = new RangeAttribute(0, 100); 17 | ErrorMessage = DataAnnotationsResources.CreditCardAttribute_Invalid; 18 | } 19 | 20 | protected override ValidationResult IsValid(object value, ValidationContext validationContext) 21 | { 22 | if (value == null) 23 | { 24 | return ValidationResult.Success; 25 | } 26 | 27 | string ccValue = value as string; 28 | if (ccValue == null) 29 | { 30 | return new ValidationResult(ErrorMessage); 31 | } 32 | ccValue = ccValue.Replace("-", ""); 33 | ccValue = ccValue.Replace(" ", ""); 34 | 35 | int checksum = 0; 36 | bool evenDigit = false; 37 | 38 | // http://www.beachnet.com/~hstiles/cardtype.html 39 | foreach (char digit in Reverse(ccValue)) 40 | { 41 | if (digit < '0' || digit > '9') 42 | { 43 | return new ValidationResult(ErrorMessage); 44 | } 45 | 46 | int digitValue = (digit - '0') * (evenDigit ? 2 : 1); 47 | evenDigit = !evenDigit; 48 | 49 | while (digitValue > 0) 50 | { 51 | checksum += digitValue % 10; 52 | digitValue /= 10; 53 | } 54 | } 55 | 56 | return (checksum % 10) == 0 ? ValidationResult.Success : new ValidationResult(ErrorMessage); 57 | } 58 | 59 | private static string Reverse(string input) 60 | { 61 | StringBuilder sb = new StringBuilder(input.Length); 62 | for (int i = input.Length - 1; i >= 0; i--) 63 | { 64 | sb.Append(input[i]); 65 | } 66 | return sb.ToString(); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.WindowsRuntime/ValidationAttributes/EmailAddressAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations 2 | { 3 | using System; 4 | using System.ComponentModel.DataAnnotations.Resources; 5 | using System.Text.RegularExpressions; 6 | 7 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 8 | public sealed class EmailAddressAttribute : DataTypeAttribute 9 | { 10 | 11 | // This attribute provides server-side email validation equivalent to jquery validate, 12 | // and therefore shares the same regular expression. See unit tests for examples. 13 | private static Regex _regex = new Regex(@"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture); 14 | 15 | public EmailAddressAttribute() 16 | : base(DataType.EmailAddress) 17 | { 18 | ErrorMessage = DataAnnotationsResources.EmailAddressAttribute_Invalid; 19 | } 20 | 21 | protected override ValidationResult IsValid(object value, ValidationContext validationContext) 22 | { 23 | if (value == null) 24 | { 25 | return ValidationResult.Success; 26 | } 27 | 28 | string valueAsString = value as string; 29 | return valueAsString != null && _regex.Match(valueAsString).Length > 0 ? ValidationResult.Success : new ValidationResult(ErrorMessage); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.WindowsRuntime/ValidationAttributes/MaxLengthAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Globalization; 4 | 5 | namespace System.ComponentModel.DataAnnotations 6 | { 7 | /// 8 | /// Specifies the maximum length of array/string data allowed in a property. 9 | /// 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 11 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 12 | public class MaxLengthAttribute : ValidationAttribute 13 | { 14 | private const int MaxAllowableLength = -1; 15 | 16 | /// 17 | /// Gets the maximum allowable length of the array/string data. 18 | /// 19 | public int Length { get; private set; } 20 | 21 | /// 22 | /// Initializes a new instance of the class. 23 | /// 24 | /// 25 | /// The maximum allowable length of array/string data. 26 | /// Value must be greater than zero. 27 | /// 28 | public MaxLengthAttribute(int length) 29 | : base(() => DefaultErrorMessageString) 30 | { 31 | Length = length; 32 | } 33 | 34 | /// 35 | /// Initializes a new instance of the class. 36 | /// The maximum allowable length supported by the database will be used. 37 | /// 38 | public MaxLengthAttribute() 39 | : base(() => DefaultErrorMessageString) 40 | { 41 | Length = MaxAllowableLength; 42 | } 43 | 44 | private static string DefaultErrorMessageString 45 | { 46 | get { return DataAnnotationsResources.MaxLengthAttribute_ValidationError; } 47 | } 48 | 49 | /// 50 | /// Determines whether a specified object is valid. (Overrides ) 51 | /// 52 | /// 53 | /// This method returns true if the is null. 54 | /// It is assumed the is used if the value may not be null. 55 | /// 56 | /// The object to validate. 57 | /// true if the value is null or less than or equal to the specified maximum length, otherwise false 58 | /// Length is zero or less than negative one. 59 | protected override ValidationResult IsValid(object value, ValidationContext validationContext) 60 | { 61 | // Check the lengths for legality 62 | EnsureLegalLengths(); 63 | 64 | var length = 0; 65 | // Automatically pass if value is null. RequiredAttribute should be used to assert a value is not null. 66 | if (value == null) 67 | { 68 | return ValidationResult.Success; 69 | } 70 | else 71 | { 72 | var str = value as string; 73 | if (str != null) 74 | { 75 | length = str.Length; 76 | } 77 | else 78 | { 79 | // We expect a cast exception if a non-{string|array} property was passed in. 80 | length = ((Array)value).Length; 81 | } 82 | } 83 | 84 | return MaxAllowableLength == Length || length <= Length ? ValidationResult.Success : new ValidationResult(FormatErrorMessage(validationContext.MemberName)); 85 | } 86 | 87 | /// 88 | /// Applies formatting to a specified error message. (Overrides ) 89 | /// 90 | /// The name to include in the formatted string. 91 | /// A localized string to describe the maximum acceptable length. 92 | public override string FormatErrorMessage(string name) 93 | { 94 | // An error occurred, so we know the value is greater than the maximum if it was specified 95 | return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, Length); 96 | } 97 | 98 | /// 99 | /// Checks that Length has a legal value. 100 | /// 101 | /// Length is zero or less than negative one. 102 | private void EnsureLegalLengths() 103 | { 104 | if (Length == 0 || Length < -1) 105 | { 106 | throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.MaxLengthAttribute_InvalidMaxLength)); 107 | } 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.WindowsRuntime/ValidationAttributes/MinLengthAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Resources; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Globalization; 4 | 5 | namespace System.ComponentModel.DataAnnotations 6 | { 7 | /// 8 | /// Specifies the minimum length of array/string data allowed in a property. 9 | /// 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 11 | [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")] 12 | public class MinLengthAttribute : ValidationAttribute 13 | { 14 | /// 15 | /// Gets the minimum allowable length of the array/string data. 16 | /// 17 | public int Length { get; private set; } 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// 23 | /// The minimum allowable length of array/string data. 24 | /// Value must be greater than or equal to zero. 25 | /// 26 | public MinLengthAttribute(int length) 27 | : base(DataAnnotationsResources.MinLengthAttribute_ValidationError) 28 | { 29 | Length = length; 30 | } 31 | 32 | /// 33 | /// Determines whether a specified object is valid. (Overrides ) 34 | /// 35 | /// 36 | /// This method returns true if the is null. 37 | /// It is assumed the is used if the value may not be null. 38 | /// 39 | /// The object to validate. 40 | /// true if the value is null or greater than or equal to the specified minimum length, otherwise false 41 | /// Length is less than zero. 42 | protected override ValidationResult IsValid(object value, ValidationContext validationContext) 43 | { 44 | // Check the lengths for legality 45 | EnsureLegalLengths(); 46 | 47 | var length = 0; 48 | // Automatically pass if value is null. RequiredAttribute should be used to assert a value is not null. 49 | if (value == null) 50 | { 51 | return ValidationResult.Success; 52 | } 53 | else 54 | { 55 | var str = value as string; 56 | if (str != null) 57 | { 58 | length = str.Length; 59 | } 60 | else 61 | { 62 | // We expect a cast exception if a non-{string|array} property was passed in. 63 | length = ((Array)value).Length; 64 | } 65 | } 66 | 67 | return length >= Length ? ValidationResult.Success : new ValidationResult(FormatErrorMessage(validationContext.MemberName)); 68 | } 69 | 70 | /// 71 | /// Applies formatting to a specified error message. (Overrides ) 72 | /// 73 | /// The name to include in the formatted string. 74 | /// A localized string to describe the minimum acceptable length. 75 | public override string FormatErrorMessage(string name) 76 | { 77 | // An error occurred, so we know the value is less than the minimum 78 | return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, Length); 79 | } 80 | 81 | /// 82 | /// Checks that Length has a legal value. 83 | /// 84 | /// Length is less than zero. 85 | private void EnsureLegalLengths() 86 | { 87 | if (Length < 0) 88 | { 89 | throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.MinLengthAttribute_InvalidMinLength)); 90 | } 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.WindowsRuntime/ValidationAttributes/PhoneAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations 2 | { 3 | using System; 4 | using System.ComponentModel.DataAnnotations.Resources; 5 | using System.Text.RegularExpressions; 6 | 7 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 8 | public sealed class PhoneAttribute : DataTypeAttribute 9 | { 10 | // see unit tests for examples 11 | private static Regex _regex = new Regex(@"^(\+\s?)?((? 0 ? ValidationResult.Success : new ValidationResult(ErrorMessage); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.WindowsRuntime/ValidationAttributes/UrlAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.ComponentModel.DataAnnotations 2 | { 3 | using System; 4 | using System.ComponentModel.DataAnnotations.Resources; 5 | using System.Text.RegularExpressions; 6 | 7 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 8 | public sealed class UrlAttribute : DataTypeAttribute 9 | { 10 | 11 | // This attribute provides server-side url validation equivalent to jquery validate, 12 | // and therefore shares the same regular expression. See unit tests for examples. 13 | private static Regex _regex = new Regex(@"^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture); 14 | 15 | public UrlAttribute() 16 | : base(DataType.Url) 17 | { 18 | ErrorMessage = DataAnnotationsResources.UrlAttribute_Invalid; 19 | } 20 | 21 | protected override ValidationResult IsValid(object value, ValidationContext validationContext) 22 | { 23 | if (value == null) 24 | { 25 | return ValidationResult.Success; 26 | } 27 | 28 | string valueAsString = value as string; 29 | return valueAsString != null && _regex.Match(valueAsString).Length > 0 ? ValidationResult.Success : new ValidationResult(ErrorMessage); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Portable.DataAnnotations.Xamarin/Portable.DataAnnotations.Xamarin.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 10.0 6 | Debug 7 | AnyCPU 8 | {627A52A7-08CB-4366-8F8D-33D9400F638B} 9 | Library 10 | Properties 11 | System.ComponentModel.DataAnnotations 12 | Portable.DataAnnotations 13 | en-US 14 | 512 15 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | Profile24 17 | v4.0 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | IValidatableObject.cs 39 | 40 | 41 | ValidationAttributes\BindableTypeAttribute.cs 42 | 43 | 44 | ValidationAttributes\MetadataTypeAttribute.cs 45 | 46 | 47 | ValidationAttributes\Schema\ColumnAttribute.cs 48 | 49 | 50 | ValidationAttributes\Schema\ComplexTypeAttribute.cs 51 | 52 | 53 | ValidationAttributes\Schema\ForeignKeyAttribute.cs 54 | 55 | 56 | ValidationAttributes\Schema\InversePropertyAttribute.cs 57 | 58 | 59 | ValidationAttributes\Schema\NotMappedAttribute.cs 60 | 61 | 62 | ValidationAttributes\Schema\TableAttribute.cs 63 | 64 | 65 | TypeForwards.cs 66 | 67 | 68 | ValidationAttributes\CreditCardAttribute.cs 69 | 70 | 71 | ValidationAttributes\EmailAddressAttribute.cs 72 | 73 | 74 | ValidationAttributes\MaxLengthAttribute.cs 75 | 76 | 77 | ValidationAttributes\MinLengthAttribute.cs 78 | 79 | 80 | ValidationAttributes\PhoneAttribute.cs 81 | 82 | 83 | ValidationAttributes\UrlAttribute.cs 84 | 85 | 86 | 87 | True 88 | True 89 | DataAnnotationsResources.resx 90 | 91 | 92 | 93 | 94 | ResXFileCodeGenerator 95 | DataAnnotationsResources.Designer.cs 96 | 97 | 98 | 99 | 106 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.Xamarin/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("Portable.DataAnnotations.Xamarin")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("Portable.DataAnnotations.Xamarin")] 14 | [assembly: AssemblyCopyright("Copyright © 2015")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: NeutralResourcesLanguage("en")] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.0.0")] 30 | [assembly: AssemblyFileVersion("1.0.0.0")] 31 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Portable.DataAnnotations 5 | 1.0.0 6 | Portable Data Annotations 7 | Ryan Horath 8 | Rybird Studios 9 | A portable library for the DataAnnotations namespace. 10 | A portable library for the DataAnnotations namespace. Reduced surface area matches the Silverlight SDK version of DataAnnotations, with additions of some classes. 11 | en-US 12 | https://github.com/ryanhorath/PortableDataAnnotations 13 | https://raw.githubusercontent.com/ryanhorath/PortableDataAnnotations/master/Rybird-32.png 14 | https://raw.githubusercontent.com/ryanhorath/PortableDataAnnotations/master/LICENSE 15 | net45 win8 net40 netcore45 sl5 wp8 wpa81 dataannotations data annotations 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | First public release. See website for changes and upgrade notes. 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /Portable.DataAnnotations.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portable.DataAnnotations.WindowsRuntime", "Portable.DataAnnotations.WindowsRuntime\Portable.DataAnnotations.WindowsRuntime.csproj", "{26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4A1B1239-C5A7-4868-87DD-0156E56811FB}" 9 | ProjectSection(SolutionItems) = preProject 10 | Microsoft-License.txt = Microsoft-License.txt 11 | Microsoft-Patents.txt = Microsoft-Patents.txt 12 | Portable.DataAnnotations.nuspec = Portable.DataAnnotations.nuspec 13 | EndProjectSection 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portable.DataAnnotations.Net45Portable", "Portable.DataAnnotations.Net45Portable\Portable.DataAnnotations.Net45Portable.csproj", "{A438D987-9708-4DF4-AF3F-16C03B83108E}" 16 | EndProject 17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portable.DataAnnotations.Net40Portable", "Portable.DataAnnotations.Net40Portable\Portable.DataAnnotations.Net40Portable.csproj", "{687A452E-572F-45D6-A295-49177D841590}" 18 | EndProject 19 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portable.DataAnnotations.Net40", "Portable.DataAnnotations.Net40\Portable.DataAnnotations.Net40.csproj", "{F061DE0B-67ED-4F7B-BB3F-01A45FCAA266}" 20 | EndProject 21 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portable.DataAnnotations.Xamarin", "Portable.DataAnnotations.Xamarin\Portable.DataAnnotations.Xamarin.csproj", "{627A52A7-08CB-4366-8F8D-33D9400F638B}" 22 | EndProject 23 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portable.DataAnnotations.Net45", "Portable.DataAnnotations.Net45\Portable.DataAnnotations.Net45.csproj", "{24BB9632-F412-4633-80D5-166A0EE44933}" 24 | EndProject 25 | Global 26 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 27 | Debug|Any CPU = Debug|Any CPU 28 | Debug|ARM = Debug|ARM 29 | Debug|x64 = Debug|x64 30 | Debug|x86 = Debug|x86 31 | Release|Any CPU = Release|Any CPU 32 | Release|ARM = Release|ARM 33 | Release|x64 = Release|x64 34 | Release|x86 = Release|x86 35 | EndGlobalSection 36 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 37 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Debug|ARM.ActiveCfg = Debug|ARM 40 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Debug|ARM.Build.0 = Debug|ARM 41 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Debug|x64.ActiveCfg = Debug|x64 42 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Debug|x64.Build.0 = Debug|x64 43 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Debug|x86.ActiveCfg = Debug|x86 44 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Debug|x86.Build.0 = Debug|x86 45 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Release|Any CPU.ActiveCfg = Release|Any CPU 46 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Release|Any CPU.Build.0 = Release|Any CPU 47 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Release|ARM.ActiveCfg = Release|ARM 48 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Release|ARM.Build.0 = Release|ARM 49 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Release|x64.ActiveCfg = Release|x64 50 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Release|x64.Build.0 = Release|x64 51 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Release|x86.ActiveCfg = Release|x86 52 | {26C2BB8A-0BCF-41B0-A4AF-5D9A6FF175BD}.Release|x86.Build.0 = Release|x86 53 | {A438D987-9708-4DF4-AF3F-16C03B83108E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 54 | {A438D987-9708-4DF4-AF3F-16C03B83108E}.Debug|Any CPU.Build.0 = Debug|Any CPU 55 | {A438D987-9708-4DF4-AF3F-16C03B83108E}.Debug|ARM.ActiveCfg = Debug|Any CPU 56 | {A438D987-9708-4DF4-AF3F-16C03B83108E}.Debug|x64.ActiveCfg = Debug|Any CPU 57 | {A438D987-9708-4DF4-AF3F-16C03B83108E}.Debug|x86.ActiveCfg = Debug|Any CPU 58 | {A438D987-9708-4DF4-AF3F-16C03B83108E}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {A438D987-9708-4DF4-AF3F-16C03B83108E}.Release|Any CPU.Build.0 = Release|Any CPU 60 | {A438D987-9708-4DF4-AF3F-16C03B83108E}.Release|ARM.ActiveCfg = Release|Any CPU 61 | {A438D987-9708-4DF4-AF3F-16C03B83108E}.Release|x64.ActiveCfg = Release|Any CPU 62 | {A438D987-9708-4DF4-AF3F-16C03B83108E}.Release|x86.ActiveCfg = Release|Any CPU 63 | {687A452E-572F-45D6-A295-49177D841590}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 64 | {687A452E-572F-45D6-A295-49177D841590}.Debug|Any CPU.Build.0 = Debug|Any CPU 65 | {687A452E-572F-45D6-A295-49177D841590}.Debug|ARM.ActiveCfg = Debug|Any CPU 66 | {687A452E-572F-45D6-A295-49177D841590}.Debug|x64.ActiveCfg = Debug|Any CPU 67 | {687A452E-572F-45D6-A295-49177D841590}.Debug|x86.ActiveCfg = Debug|Any CPU 68 | {687A452E-572F-45D6-A295-49177D841590}.Release|Any CPU.ActiveCfg = Release|Any CPU 69 | {687A452E-572F-45D6-A295-49177D841590}.Release|Any CPU.Build.0 = Release|Any CPU 70 | {687A452E-572F-45D6-A295-49177D841590}.Release|ARM.ActiveCfg = Release|Any CPU 71 | {687A452E-572F-45D6-A295-49177D841590}.Release|x64.ActiveCfg = Release|Any CPU 72 | {687A452E-572F-45D6-A295-49177D841590}.Release|x86.ActiveCfg = Release|Any CPU 73 | {F061DE0B-67ED-4F7B-BB3F-01A45FCAA266}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 74 | {F061DE0B-67ED-4F7B-BB3F-01A45FCAA266}.Debug|Any CPU.Build.0 = Debug|Any CPU 75 | {F061DE0B-67ED-4F7B-BB3F-01A45FCAA266}.Debug|ARM.ActiveCfg = Debug|Any CPU 76 | {F061DE0B-67ED-4F7B-BB3F-01A45FCAA266}.Debug|x64.ActiveCfg = Debug|Any CPU 77 | {F061DE0B-67ED-4F7B-BB3F-01A45FCAA266}.Debug|x86.ActiveCfg = Debug|Any CPU 78 | {F061DE0B-67ED-4F7B-BB3F-01A45FCAA266}.Release|Any CPU.ActiveCfg = Release|Any CPU 79 | {F061DE0B-67ED-4F7B-BB3F-01A45FCAA266}.Release|Any CPU.Build.0 = Release|Any CPU 80 | {F061DE0B-67ED-4F7B-BB3F-01A45FCAA266}.Release|ARM.ActiveCfg = Release|Any CPU 81 | {F061DE0B-67ED-4F7B-BB3F-01A45FCAA266}.Release|x64.ActiveCfg = Release|Any CPU 82 | {F061DE0B-67ED-4F7B-BB3F-01A45FCAA266}.Release|x86.ActiveCfg = Release|Any CPU 83 | {627A52A7-08CB-4366-8F8D-33D9400F638B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 84 | {627A52A7-08CB-4366-8F8D-33D9400F638B}.Debug|Any CPU.Build.0 = Debug|Any CPU 85 | {627A52A7-08CB-4366-8F8D-33D9400F638B}.Debug|ARM.ActiveCfg = Debug|Any CPU 86 | {627A52A7-08CB-4366-8F8D-33D9400F638B}.Debug|x64.ActiveCfg = Debug|Any CPU 87 | {627A52A7-08CB-4366-8F8D-33D9400F638B}.Debug|x86.ActiveCfg = Debug|Any CPU 88 | {627A52A7-08CB-4366-8F8D-33D9400F638B}.Release|Any CPU.ActiveCfg = Release|Any CPU 89 | {627A52A7-08CB-4366-8F8D-33D9400F638B}.Release|Any CPU.Build.0 = Release|Any CPU 90 | {627A52A7-08CB-4366-8F8D-33D9400F638B}.Release|ARM.ActiveCfg = Release|Any CPU 91 | {627A52A7-08CB-4366-8F8D-33D9400F638B}.Release|x64.ActiveCfg = Release|Any CPU 92 | {627A52A7-08CB-4366-8F8D-33D9400F638B}.Release|x86.ActiveCfg = Release|Any CPU 93 | {24BB9632-F412-4633-80D5-166A0EE44933}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 94 | {24BB9632-F412-4633-80D5-166A0EE44933}.Debug|Any CPU.Build.0 = Debug|Any CPU 95 | {24BB9632-F412-4633-80D5-166A0EE44933}.Debug|ARM.ActiveCfg = Debug|Any CPU 96 | {24BB9632-F412-4633-80D5-166A0EE44933}.Debug|x64.ActiveCfg = Debug|Any CPU 97 | {24BB9632-F412-4633-80D5-166A0EE44933}.Debug|x86.ActiveCfg = Debug|Any CPU 98 | {24BB9632-F412-4633-80D5-166A0EE44933}.Release|Any CPU.ActiveCfg = Release|Any CPU 99 | {24BB9632-F412-4633-80D5-166A0EE44933}.Release|Any CPU.Build.0 = Release|Any CPU 100 | {24BB9632-F412-4633-80D5-166A0EE44933}.Release|ARM.ActiveCfg = Release|Any CPU 101 | {24BB9632-F412-4633-80D5-166A0EE44933}.Release|x64.ActiveCfg = Release|Any CPU 102 | {24BB9632-F412-4633-80D5-166A0EE44933}.Release|x86.ActiveCfg = Release|Any CPU 103 | EndGlobalSection 104 | GlobalSection(SolutionProperties) = preSolution 105 | HideSolutionNode = FALSE 106 | EndGlobalSection 107 | EndGlobal 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NOTE 2 | This project is no longer actively maintained. The DataAnnotations libraries are included in .NET Core 1.0 and .NET Standard 1.6. Portable projects that previously made use of this library should be re-targeted to .NET Standard 1.6 or higher. 3 | 4 | # Portable Data Annotations 5 | A portable implementation of Data Annotations using the PCL bait and switch technique. 6 | 7 | ## Overview 8 | 9 | DataAnnotations is an excellent library providing validation support in .NET. However, it is not implemented on the Windows Phone platforms (Silverlight and WinRT). When creating a PCL using those platforms, DataAnnotations will be unavailable. 10 | 11 | This library resolves that issue using the [PCL Bait and Switch technique](http://log.paulbetts.org/the-bait-and-switch-pcl-trick/). It features a complete implementation of the DataAnnotations library for the Windows Phones platforms, with bait and switch used for the other platforms. What does this mean? It means that on platforms where DataAnnotations is supported, it will work as expected. But on platforms where it is not supported, it will now be available to you. You can write your PCLs targeting DataAnnotations and know that it will just work on whatever platform you deploy to. 12 | 13 | ## How Does It Work? 14 | 15 | All platforms that support DataAnnotations will use the TypeForwardedToAttribute to forward their implementations to the correct classes at runtime. On other platforms (Windows Phone), a custom implementation matching the same surface area will be used. At compile time, you write your code to the portable API and at runtime it runs on the native API - or on the portable API if no native API is present (again, only on Windows Phone). 16 | 17 | Using this forwarding technique means that Microsoft or 3rd Party APIs that build on DataAnnotations will run correctly. 18 | 19 | ## What is the Surface Area of the API? 20 | 21 | I started by providing the same surface area as the DataAnnotations classes that are available in a normal PCL (without Windows Phone). This is also the same as the Silverlight 5 surface area. Then I added some of the newer classes that are available in the .NET 4.5 API, so that the final surface area is larger than the normal PCL surface area. 22 | 23 | There are only five classes from the .NET 4.5.2 DataAnnotations library that are not present in this library. They are: 24 | 25 | `AssociatedMetadataTypeTypeDescriptionProvider`: Reflection support necessary to make this class work is not present in PCLs. It is not a very useful class anyway. 26 | 27 | `CompareAttribute`: There are non-portable elements in the implementation. I did not want to figure out if/how I can work around those yet. This class may be added in the future. 28 | 29 | `FileExtensionsAttribute`: Same as above. Non-portable elements, may be added in the future. 30 | 31 | `ScaffoldColumnAttribute`: I believe this was just overlooked and I can add this back in the future. 32 | 33 | `ScaffoldTableAttribute`: Same as above - I think I overlooked this and can add it back in the future. 34 | 35 | On many platforms, only a subset of DataAnnotations matching the Silverlight and PCL surface areas is available. For those platforms, I have backported the missing classes to increase the overall surface area of the library. When using those classes, a custom implementation will be used instead of a TypeForwardedToAttribute. This should not matter since these classes were unavailable on those platforms anyway. 36 | 37 | ## Limitations 38 | 39 | The DataType enumeration is already implemented on some platforms, but with less enumeration values than the ones in .NET 4.5.2. Because of that, I have only exposed the smaller surface area to the PCL. The new values supported in .NET 4.5.2 (`CreditCard`, `PostalCode`, `Upload`) are thus not available. This also means that on platforms where `CreditCardAttribute` is not present, and thus implemented in the library, the DataType will report as `Custom` rather than the expected, but unavailable, `CreditCard`. On platforms where it is supported (.NET 4.5+), it will return the correct value `CreditCard`. This inconsistency is unfortunate, but totally acceptable and I advise users not to rely on the value of the DataType property in your own code. 40 | 41 | Also, though I said the library uses TypeForwardedToAttribute in all cases where possible, technically that is not true. In the case of Xamarin Android/iOS/Mac, I chose to use one project for simplicity. The full .NET 4.5 DataAnnotations is available in Mono, but only if you choose a specific platform project, such as an Android project, an iOS project, etc. If you choose a PCL that supports all of them, it reduces the surface area to the normal PCL surface area. In that case, I add back custom versions of the missing classes. The alternative is to create specific projects for each Xamarin platform. I chose not to do this because 1) I do not see a need because Android/iOS/Mac have no built in support for DataAnnotations anyway, and therefore this will cause no loss of functionality, and 2) extra projects means extra maintenance, and in this case also means necessitating a Mac build host for building the iOS and Mac projects. Since there is nothing to gain, I have chosen not to do this. 42 | 43 | ## Unit Testing 44 | 45 | There is a limitation to unit testing that may be difficult to understand if you are not aware. Unit testing frameworks are not aware of the bait and switch technique, and can therefore cause failing tests for unclear reasons. If you are testing a PCL that uses this library and wish to unit test the validation logic, you may run into a (resolvable) issue. If you derive a class in your unit testing project and put a `ValidationAttribute` on it, then run code from your PCL that calls `Validator.Validate()`, it will fail. This is because, not knowing about bait and switch, the unit test runner will load the PCL version of the library for the PCL and the .NET version of the library for the unit test project. Thus, your call to `Validate()` will not find the correct attribute class. The reverse will also cause a problem (calling `Validate()` in the .NET test project on attributes defined in the PCL). The workaround for this is not to test the library in this manner. All the code for validation should be in your PCL and invoked from your test project without needing any references to DataAnnotations in your test project. If you do this, your tests will succeed as expected. I assume you can run into similar problems if your code under test spans multiple projects and platforms. Avoid this scenario where possible. 46 | 47 | Keep in mind as well that if you do unit test the validation in PCLs, you will be unit testing against the PCL implementations, not the implementations actually used at runtime. This implementation is only used by Windows Phone, so your tests are really only valid on that platform. However, you should not need to unit test .NET Framework features anyway, so there is really no need to test that the validation works. 48 | 49 | ## Supported Platforms 50 | 51 | .NET 4.5/4.0, iOS, Android, Windows Store 8.0/8.1, Windows Phone Silverlight 8.1/8.0/7.5, Windows Phone 8.1, Silverlight 5.0, and all portable libraries including those platforms. 52 | -------------------------------------------------------------------------------- /Rybird-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanhorath/PortableDataAnnotations/ffb2aab4330fa26ef8b35ea6324a41d2c47591c5/Rybird-32.png --------------------------------------------------------------------------------