Skip to content

Attribute validation and Overflow

Ewout Kramer edited this page Mar 4, 2025 · 7 revisions

This table lists how overflow is "encoded" in the POCO model, and which validator will catch the error.

Kind of error How encoded Detected by(1)
Incorrect primitive value Incorrect value is stored in primitive's ObjectValue ValidateObjectValue()
Expected primitive, got object (Dynamic)object is stored in primitive's ObjectValue ValidateObjectValue()
Expected object, got primitive Store in overflow, with correct type "attached" (2) ValidateObject(3)
Expected single, got array Store in overflow, with correct type "attached" (2) ValidateObject(3)
Expected array, got single Store in overflow, with correct type "attached" (2) ValidateObject(3)
Choice where no choice allowed Added as unknown element to overflow See Unknown element below
Invalid choice type Property (type of DataType) is set to the value AllowedTypes attribute
Unknown choice type Property is set to a DynamicDataType value AllowedTypes attribute
Unknown resource type Property is set to a DynamicResource value AllowedTypes attribute (4)
Unknown element Store in overflow, with "no type" attached ValidateObject(3)

(1) The property's getter (except for JsonValue) also detects it, and throws. We still might need an unsafe marker to do this efficiently. The setter needs to detect invalid values to remove any entries from the overflow dictionary when a new value is set.

(2) This probably means the overflow needs to contain tuples or types which allow for a value + expected type.

(3) We need detection in ValidateObject for .NET attribute validation, and this will be used when someone "manually" sets the POCO to incorrect values, but for the parsers this is a bit too late. For them to be able to report errors with locations on the right property, they probably need to report errors themselves, preferably reusing functionality to report the same error and error text as will be reported from ValidateObject. This means that ValidateObject should not report these errors if called from a Parser (otherwise we get duplicate messages), but that is easy, since all validation routines get passed in a ValidationContext, from which it is obvious (or can be made obvious) that we're running in the context of a parser.

(4) Normally, nested resources are marked with [AllowedTypes(typeof(Hl7.Fhir.Model.Resource))], we should make sure that in that case we complain about finding a DynamicResource.

Changing SetValue

SetValue currently looks like this:

 public override Base SetValue(string key, object? value)
    {
      switch (key)
      {
        case "identifier":
          Identifier = (List<Hl7.Fhir.Model.Identifier>?)value!;
          return this;

We can see that calling SetValue to something that requires overflow (= of the incorrect type), will throw an invalid cast exception. This needs to be changed so that IF the type is incorrect, we switch to the overflow. And of course, since we already have the correct type at hand, we could store it in the overflow as well. Also, if we are using pairs in the dictionary, we have to make sure Copy, IsExact, Matches, Compare etc keep on working, cause they currently expect just Base/List in the overflow dictionary. It should also (just like normal setters, see remark (1)), make sure that updating a property to a new value removes/updates the entry in the overflow as well.

Clone this wiki locally