Skip to content

Commit 1bf25be

Browse files
committed
Marked core view model properties as not-nullable, required
In a typical use case, all properties will be set to their defaults when a view model is initialized. Given this, the return type of otherwise required properties must be nullable. The mapping service will then immediately populate these, however, and thus we never expect them to _actually_ be null. As such, we can annotate them with the `[NotNull]` attribute to assure callers that, in practice, they're not null, and the `[DisallowNull]` attribute to dissuade callers from setting them to null. In addition, there are no scenarios where we expect most of these values to even have empty values. As such, we can mark them as `[Required]` to help enforce their use. This is critical for binding models, where we want to ensure that the interface isn't simply satisfied, but also that data is populated. For instance, a `ITopicBindingModel` without `Key` or `ContentType` values defined isn't especially useful. Given that, most required properties have been annotated as `[Required, NotNull, DisallowNull]`.
1 parent 745e562 commit 1bf25be

8 files changed

Lines changed: 29 additions & 7 deletions

File tree

OnTopic.Tests/BindingModels/BasicTopicBindingModel.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
| Project Topics Library
55
\=============================================================================================================================*/
66
using System.ComponentModel.DataAnnotations;
7+
using System.Diagnostics.CodeAnalysis;
78
using OnTopic.Models;
89

910
namespace OnTopic.Tests.BindingModels {
@@ -21,14 +22,15 @@ public class BasicTopicBindingModel : ITopicBindingModel {
2122

2223
public BasicTopicBindingModel() { }
2324

24-
public BasicTopicBindingModel(string? key, string? contentType) {
25+
public BasicTopicBindingModel(string key, string contentType) {
2526
Key = key;
2627
ContentType = contentType;
2728
}
2829

30+
[Required, NotNull, DisallowNull]
2931
public string? Key { get; init; }
3032

31-
[Required]
33+
[Required, NotNull, DisallowNull]
3234
public string? ContentType { get; init; }
3335

3436
} //Class

OnTopic.Tests/BindingModels/RecordTopicBindingModel.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
| Project Topics Library
55
\=============================================================================================================================*/
66
using System.ComponentModel.DataAnnotations;
7+
using System.Diagnostics.CodeAnalysis;
78
using OnTopic.Models;
89

910
namespace OnTopic.Tests.BindingModels {
@@ -22,9 +23,10 @@ public class RecordTopicBindingModel : ITopicBindingModel {
2223

2324
public RecordTopicBindingModel() { }
2425

26+
[Required, NotNull, DisallowNull]
2527
public string? Key { get; init; }
2628

27-
[Required]
29+
[Required, NotNull, DisallowNull]
2830
public string? ContentType { get; init; }
2931

3032
} //Class

OnTopic.ViewModels/BindingModels/AssociatedTopicBindingModel.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
| Project Topics Library
55
\=============================================================================================================================*/
66
using System.ComponentModel.DataAnnotations;
7+
using System.Diagnostics.CodeAnalysis;
78
using OnTopic.Mapping.Reverse;
89
using OnTopic.Models;
910

@@ -32,7 +33,7 @@ public record AssociatedTopicBindingModel : IAssociatedTopicBindingModel {
3233
/// <requires description="The value from the getter must not be null." exception="T:System.ArgumentNullException">
3334
/// value is not null
3435
/// </requires>
35-
[Required]
36+
[Required, NotNull, DisallowNull]
3637
public string? UniqueKey { get; init; }
3738

3839
} //Class

OnTopic.ViewModels/NavigationTopicViewModel.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
\=============================================================================================================================*/
66
using System;
77
using System.Collections.ObjectModel;
8+
using System.ComponentModel.DataAnnotations;
9+
using System.Diagnostics.CodeAnalysis;
810
using OnTopic.Models;
911

1012
namespace OnTopic.ViewModels {
@@ -34,6 +36,7 @@ public sealed record NavigationTopicViewModel : INavigationTopicViewModel<Naviga
3436
| TITLE
3537
\-------------------------------------------------------------------------------------------------------------------------*/
3638
/// <inheritdoc cref="TopicViewModel"/>
39+
[Required, NotNull, DisallowNull]
3740
public string? Title { get; init; }
3841

3942
/*==========================================================================================================================
@@ -48,6 +51,7 @@ public sealed record NavigationTopicViewModel : INavigationTopicViewModel<Naviga
4851
| WEB PATH
4952
\-------------------------------------------------------------------------------------------------------------------------*/
5053
/// <inheritdoc cref="WebPath"/>
54+
[Required, NotNull, DisallowNull]
5155
public string? WebPath { get; init; }
5256

5357
/*==========================================================================================================================

OnTopic.ViewModels/TopicViewModel.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
| Project Topics Library
55
\=============================================================================================================================*/
66
using System;
7+
using System.ComponentModel.DataAnnotations;
8+
using System.Diagnostics.CodeAnalysis;
79
using OnTopic.Mapping.Annotations;
810
using OnTopic.Models;
911

@@ -32,24 +34,28 @@ public record TopicViewModel: ITopicViewModel, IKeyedTopicViewModel, IAssociated
3234
| KEY
3335
\-------------------------------------------------------------------------------------------------------------------------*/
3436
/// <inheritdoc />
37+
[Required, NotNull, DisallowNull]
3538
public string? Key { get; init; }
3639

3740
/*==========================================================================================================================
3841
| CONTENT TYPE
3942
\-------------------------------------------------------------------------------------------------------------------------*/
4043
/// <inheritdoc />
44+
[Required, NotNull, DisallowNull]
4145
public string? ContentType { get; init; }
4246

4347
/*==========================================================================================================================
4448
| UNIQUE KEY
4549
\-------------------------------------------------------------------------------------------------------------------------*/
4650
/// <inheritdoc />
51+
[Required, NotNull, DisallowNull]
4752
public string? UniqueKey { get; init; }
4853

4954
/*==========================================================================================================================
5055
| WEB PATH
5156
\-------------------------------------------------------------------------------------------------------------------------*/
5257
/// <inheritdoc />
58+
[Required, NotNull, DisallowNull]
5359
public string? WebPath { get; init; }
5460

5561
/*==========================================================================================================================
@@ -62,6 +68,7 @@ public record TopicViewModel: ITopicViewModel, IKeyedTopicViewModel, IAssociated
6268
| TITLE
6369
\-------------------------------------------------------------------------------------------------------------------------*/
6470
/// <inheritdoc />
71+
[Required, NotNull, DisallowNull]
6572
public string? Title { get; init; }
6673

6774
/*==========================================================================================================================

OnTopic/Models/IAssociatedTopicBindingModel.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
| Project Topics Library
55
\=============================================================================================================================*/
66
using System.ComponentModel.DataAnnotations;
7+
using System.Diagnostics.CodeAnalysis;
78
using OnTopic.Mapping.Reverse;
89

910
namespace OnTopic.Models {
@@ -30,7 +31,7 @@ public interface IAssociatedTopicBindingModel {
3031
/// <requires description="The value from the getter must not be null." exception="T:System.ArgumentNullException">
3132
/// value is not null
3233
/// </requires>
33-
[Required]
34+
[Required, NotNull, DisallowNull]
3435
string? UniqueKey { get; init; }
3536

3637
} //Class

OnTopic/Models/ITopicBindingModel.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
| Project Topics Library
55
\=============================================================================================================================*/
66
using System.ComponentModel.DataAnnotations;
7+
using System.Diagnostics.CodeAnalysis;
78
using OnTopic.Mapping.Reverse;
89
using OnTopic.Metadata;
910

@@ -31,7 +32,7 @@ public interface ITopicBindingModel: IKeyedTopicViewModel {
3132
/// Each topic is associated with a content type. The content type determines which attributes are displayed in the Topics
3233
/// Editor (via the <see cref="ContentTypeDescriptor.AttributeDescriptors"/> property).
3334
/// </remarks>
34-
[Required]
35+
[Required, NotNull, DisallowNull]
3536
string? ContentType { get; init; }
3637

3738
} //Class

OnTopic/Models/ITopicViewModel.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
| Client Ignia, LLC
44
| Project Topics Library
55
\=============================================================================================================================*/
6+
using System;
7+
using System.ComponentModel.DataAnnotations;
8+
using System.Diagnostics.CodeAnalysis;
69
using OnTopic.Mapping;
7-
using OnTopic.Metadata;
810

911
namespace OnTopic.Models {
1012

@@ -45,6 +47,7 @@ public interface ITopicViewModel: IKeyedTopicViewModel, IAssociatedTopicBindingM
4547
/// Gets or sets the topic's <see cref="WebPath"/> attribute, which represents the <see cref="IAssociatedTopicBindingModel
4648
/// .UniqueKey"/> in its URL format.
4749
/// </summary>
50+
[Required, NotNull, DisallowNull]
4851
string? WebPath { get; init; }
4952

5053
/*==========================================================================================================================
@@ -82,6 +85,7 @@ public interface ITopicViewModel: IKeyedTopicViewModel, IAssociatedTopicBindingM
8285
/// restrictions on what characters can be used in the title. For this reason, it provides the default public value for
8386
/// referencing topics.
8487
/// </remarks>
88+
[Required, NotNull, DisallowNull]
8589
string? Title { get; init; }
8690

8791
} //Class

0 commit comments

Comments
 (0)