-
Notifications
You must be signed in to change notification settings - Fork 354
Breaking changes in 2.0
Starting from version 2.0 of the SDK we will gradually be moving classes from the assemblies that are specific to a FHIR version to a common, not FHIR version related assembly. Although we try to retain the existing public interfaces, it does mean these classes are moved between assemblies (not namespaces!). This will be irrelevant to most, but if you have created aliases referring to specific assemblies (as you might do if you need to support multiple versions of FHIR by loading the different FHIR-specific assemblies in your application concurrently), you will of course be hit by these changes.
-
PartialDateTime.FromDateTime(DateTime)has been removed. Replace with a call toFromDateTimeOffset(). - The functions in namespace
Hl7.Fhir.XPath(Hl7.Fhir.Specificaion assembly) have been dropped. They have been in disuse since DSTU1 and have not been maintained since. - The class
CanonicalUrlConflictExceptionhas been removed. - The class
XmlSerializationHinthas been removed. - The class
FhirSerializerandFhirParserhave been removed. They have been obsolete for quite some time and replaced byFhirXmlParserandFhirJsonParser. - The interface
IElementNavigator(and all its implementations and referring methods) have been removed. All of these have been obsoleted for quite a while. -
Base.UserData(this property appears in all FHIR POCO's) has been removed. It has been replaced by the IAnnotated/IAnnotatable/Annotations() approach from .NET since 2016. -
ContentType.IsValidBundleContentTypewas used to recognize the old DSTU1 "atom" bundle type. It was time for it to go. - All "DSTU1/2 backwards compatibility members". We retained some of the DSTU1/DSTU2 members in StructureDefinition/ElementDefinition just so you would get an Obsolete message on how to upgrade. These have now been removed.
- We removed the FhirPath extension methods on
Base(Select(),Scalar(),Predicate(),IsBoolean()) that did not take an EvaluationContext parameter. These have been replaced since 2016/2017. -
Bundle.EntryComponent.BaseandBundle.Basehave been removed. These have disappeared from the FHIR datamodel since DSTU2. - The
Bundle.FindEntry()extension method usingtypeandidparameters have been replaced by a function taking afullUrlfor quite a while, and has been removed. -
ElementDefinition.Namehas been renamed toElementDefinition.SliceNamesince DSTU2, and has been removed. -
ModelInfo.GetFhirTypeForType(),GetTypeForResourceName()and `GetResourceNameForType() have been obsoleted in 2016 and are now gone. - The OperationOutcome.ForException() and ForMessage() overloads that did not take an
IssueTypeparameter have been removed. -
ValueSet.Definewas renamed toCodeSystemin DSTU2 and then moved to its own proper resource in STU3. This property has now been removed. -
ResourceIdentity.Endpointwas renamed toResourceBasein 2015. This property has now been removed. -
ResourceIdentity.Collectionwas using the historical term "collection" for what is now a resource. That was a thing in 2014. - The static
FhirParserandFhirSerializerclasses have been deprecated since 2017, nowadays we create an instance ofFhir[Xml/Json]ParserandFhir[Xml/Json]Serializerand use the method on these instances instead. -
ModelInfo.IsInstanceTypeFor()will no longer accept variants ofstring,idandQuantityas instances type for these types. - The interface
ITerminologyServicehas been changed as well: the methodValidateCodehas been made obsolete and has been replaced by the async methodValueSetValidateCode. Futhermore the interface has been expanded with extra async methods (ValueSetValidateCode,CodeSystemValidateCode,Expand,Lookup,Translate,SubsumesandClosure), which should be implemented when you are implementing this interface.
We have started to add async support to the resolvers for the conformance resources (i.e. DirectorySource), which are the most critical I/O parts of the SDK:
- DirectorySource, ZipSource, WebResolver (though these are not yet completely fully async internally)
- SnapshotSource (which also meant removing its
Sourceproperty) - MultiResolver, CachedResolver
Based on this new functionality, we have changed the implementation of the SnapshotGenerator and ValueSetExpander to be asynchronous. For backwards compatibility, all of these components still support the existing sync functionality, although it is marked as [Obsolete]
The async functionality is based on an async version of the IResourceResolver interface, called IAsyncResourceResolver. Existing resolvers may chose to implement one or both of these. There is no expectation that a an async resolver will also implement sync behaviour, although the resolvers provided by the API will support both.
All components in the API that depend on resolvers will eventually accept both interfaces as a dependency. We introduced the (empty) base interface ISyncOrAsyncResolver for dependencies in, so on constructors and settable properties on setting objects (e.g. ValueSetExpanderSettings). In contrast, when these dependencies are exposed as properties (out), we include both an sync and async version of the property, where the sync version will return null if an (exclusively) async resolver was provided as an in dependency. This design ensures existing code will continue to compile.
-
SimpleQuantityandMoneyQuantity(R4+) have been removed from the POCO model. These types were actually just profiles on types and were a constant source of confusion and bugs. E.g. since these types are profiles, they are not represented in the suffix of the name of an element with a choice type (e.g.Observation.value[x]), hence when round-tripping data, an in-memorySimpleQuantityinstance would be serialized toObservation.valueQuantityand then parsed as aQuantity, not aSimpleQuantity. - The
ResourceTypemember has been removed. This member relied on theResourceTypeenumeration, which cannot be customized by the user with new resource types. You can use the new extension methodbool TryDeriveResourceType(this Resource r, out ResourceType rt)instead. - The R4
Dosage,ElementDefinitionandTimingtypes no longer derive fromBackboneElement, but fromBackboneType(as in R5). - We cleaned out numerous spurious interface declarations on subclasses when those were already declared on the base classes. This should not be breaking changes, but might be visible in some very specialized reflection scenarios.
- All primitive datatype POCO's were made consistent again: all of them now have
DebugDisplayAttributesand declare theSerializableandDataContractattribute. - The
Meta.profileproperty (used in any Resource) has changed type fromcanonicaltouri(in R4). This is done to be able to reuse the Meta type across the different versions of FHIR. This change is only visible in the POCO class and has no influence on the serialization or the type metadata, which will reflect the correct type for each FHIR version. -
VerificationResult.statushas been renamed toVerificationResult.VerificationResultStatus.statusis the official name assigned by the committee, but it's not very unique (which is painful, since this is the name of a C#enum) and also not CLS-compliant (since it uses a lower-case letter). - To align the POCOs across all version with the normative R5 type model, the classes
DataType,PrimitiveTypeandBackboneTypehave been introduced:- All datatypes (and primitives) are now subclasses of
DataTyperather thanElement. - Choice elements (e.g.
Extension.value[x]) are now of typeDataTyperather thanElement(a non-breaking change, sinceDataTypeis a direct subclass ofElement. - The extension method
Value(this ElementDefinition ed, DataType fix=null, DataType pattern=null)has been updated to takeDataTypeas parameters instead ofElement. - The constructor
Extension(string url, DataType value)now takes aDataTypeinstead of anElement - The extension method
AddExtension(this IExtendable extendable, string uri, DataType value, bool isModifier=false)now takes aDataTypeinstead of anElement. - The extension method
SetExtension(this IExtendable extendable, string uri, DataType value, bool isModifier=false)now takes aDataTypeinstead of anElement. - Type
Primitivehas been renamed toPrimitiveType. - Since datatypes with modifier extensions and complex components can now be distinguished based on their inheritance hierarchy, it is no longer necessary to keep the
IBackboneElementor theNamedBackboneElementparameter to the[FhirType]attribute around and they have been removed. The corresponding properties onClassMappingandPropertyMappinghave also been removed.
- All datatypes (and primitives) are now subclasses of
- The abstract class
PrimitiveType<T>had no members beyond those inherited fromPrimitiveTypeand thus had no real use. It has been removed. - Those primitives that used a .NET
stringorintimplemented an interfaceIStringValueresp.INullableIntegerValueinstead ofIValue<string>andINullableValue<int>- which would have been more consistent with the other primitives. This has been corrected by removingIStringValueandINullableIntegerValue. One can simply match onIValue<T>orINullableValue<T>instead. - The POCO classes representing resources no longer contain functionality for working with constraints. This means static members representing the ConstraintComponents like:
public static ElementDefinition.ConstraintComponent Patient_PAT_1 = new ElementDefinition.ConstraintComponent()
and the associated functions such as AddDefaultConstraints() and ValidateInvariants() have been removed. These validation functions were incomplete and full validation cannot reliably be done based on the information available in the POCO model. Instead, use the Hl7.Fhir.Validation.Validator class instead. See the examples at https://github.com/FirelyTeam/Furore.Fhir.ValidationDemo on how to work with these classes.
- The type name for nested types (like the Patient.contact backbone component) has been made unique: the name of the resource is now used as a prefix, separated by '#'. The name is generated from the
http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-nameextension is available, otherwise the lasts part of the element's path is used. Note: the generated propertyTypeNamehas been changed accordingly. - The
ModelInspectorclass has been rewritten: the constructor now requires a fhirVersion to use when inspecting the generated classes. Also, the interface has been simplified. Existing functions for getting mappings specifically for resource names have been removed and integrated in two generic functions for retrieving mappings (by name and by type). - Only the properties marked with
FhirElementAttributewill be inspected for FHIR metadata, it is no longer necessary to put aNotMappedAttributeon all non-fhir properties in a class. - In Elements with a choice of types which included the now-removed SimpleQuantity or MoneyQuantity, the
AllowedTypesattribute will containQuantity. - If the type of an element is open (e.g.
Extension.value[x]),PropertyMapping.FhirTypewill now only contain the typeDataType(instead of all allowed types for an open element). - Since the FHIR spec has no formal notion of "open" elements (you cannot derive this faithfully from the StructureDefinition), the
IsOpenattribute is no longer generated and removed fromAllowedTypeAttribute. We introduced this in 1.8 - but only onExtension.value[x]to accommodate movingExtensionto common, but this cannot faithfully be generated for other types. It has been removed fromPropertyMappingas well. - Many metadata attribute may now be specified more than once. This makes sense if you also specify the new
Sinceparameter, which is a string containing the semver version of the FHIR version for which you want to get the metadata. -
ClassMapping.IsAbstracthas been removed, useNativeType.IsAbstractinstead. -
ClassMapping.Profileis no longer supported - its predicted use never materialized and no support for profile-based generated POCOs is present other parts of the API - The
FhirTypeAttributenow requires a name, default names (derived from the type) are no longer supported. -
ClassMapping.IsBackbone,ClassMapping.IsNamedBackboneElementhave been removed and replaced by a singleIsNestedTypeboolean. The corresponding parameter to the[FhirType]attribute has also been renamed. This attribute is onlytruefor types that represent complex nested (backbone)elements in a FHIR resource or datatype. Use the new R5 type hierarchy (specificallyDataTypeandBackboneType) to identify extensible datatypes. -
ClassMapping.FindMappedElementByName()did not only lookup elements by their actual name but also by the name of the XML element (which may be suffixed for choice types). This secondary function lead to confusion and frankly was a design mistake in the first place. It has been removed, just like the supporting methodsPropertyMapping.MatchesSuffixedName()andPropertyMapping.GetChoiceSuffixFromName(). - The argument
TypeRedirecton the[FhirElement]attribute has been promoted to a separate[DeclaredType]attribute. This makes it easier to generate properties in common datatypes for which the FHIR-type of an element has changed from version to version.
The FhirPath engine is upgraded to support FhirPath normative. The normative version of FP includes some incompatibilities, which include:
- A new
datetype has been introduced, and the literals have been enhanced to make the distinction clear. In many cases this causes partial date literals (without a time) to be interpreted asdatenotdateTime. You may fix this by explicitly suffixing a partial dateTime with a 'T' (so2015-04Tis adateTime, and2015-04is adate). - Using double quotes for identifiers has been obsoleted and replaced by single backticks. Though the engine will accept both you should replace your FP statements accordingly.
- The
today()functions now returns adateinstead of adateTime(). - As a result,
ITypedElementwill now useHl7.Fhir.ElementModel.Types.PartialDatefor FHIR primitive 'date' instead ofHl7.Fhir.ElementModel.Types.PartialDateTime. - Equality, equivalence and ordering for (partial) datetimes has been tweaked to better deal with difference in precision (see http://hl7.org/fhirpath/#datetime-equality)
- The
ofType()function no longer takes a string, but expects a type-name literal, e.g.ofType('Quantity')becomesofType(Quantity). Since namespaces for types were introduced, this would more explicitly now be written asofType(FHIR.Quantity). - The new FP engine fixes a bug which allowed you to compare booleans to string constants, this is no longer allowed.
- The properties
ContainerandRootContaineron theEvaluationContexthave been renamed toResourceandRootResourcerespectively, to align with the symbols (%resourceand%rootResource) used within FhirPath. - The extension functions on ITypedElement for conversion (like ToDecimal, ToStringRepresentation) have been moved to the ICqlConvertible interface and are now explicitly implemented by the new system types deriving from
Any. If you'd like to call them, useAny.Convert(ite.Value)to convert the value of anITypedElementprimitive to an Any, cast theAnytoICqlConvertible, then call the conversion functions via that interface.
This list is by no means exhaustive - though most changes are subtle enough that the new normative engine will still be able to execute the pre-normative FhirPath statements from older FHIR specifications.
The refresh of the FhirPath engine and work on mapping functionality has made it clear that parts of the API depend too much on hard-wired knowledge of the FHIR types. Although this seems natural for a FHIR API, the mapping engine and FhirPath are actually model-agnostic, so we have started to locate these dependencies. This will cause a few breaking changes:
-
ElementNode.ForPrimitive()is now more strict: it will only accept values that can be represented as a primitive value in theValueproperty ofITypedElement. -
ElementModel.Add()allows adding a child to a node, without specifying the actual type of the child, since this can be derived from the type information present in the StructureDefinition. This was even true for choice types, where we would try to derive the desired FHIR type from the .NET primitive value passed in as the value for the child. Not only was this ambiguous (there's no way to derive that astringshould have been turned into aFHIR.urifor example), but also tied the implementation of ElementNode to FHIR - this would work incorrectly for non-FHIR models. Therefore, this functionality has been removed and you will now get an exception IF the element has a choice of types and you have not indicated the actual type to theAdd(). - The
Hl7.Fhir.FhirPath.TypeInfoclass has been removed and replaced by theHl7.Fhir.Language.TypeSpecifierclass (to align with CQL/ELM terminology). It's functionality has been divided into working with the mapping between C# types and so calledSystemtypes (which are inTypeSpecifier) and working with primitive instance data of theSystemtypes (which are subclasses ofHl7.Fhir.ElementModel.Types.Anyand other classes in that namespace. - The
Hl7.Fhir.Support.Model.Primitives.Primitivesclass has been removed and its methods moved toHl7.Fhir.Language.TypeSpecifier. SincePrimitiveswas the only class that was present in theHl7.Fhir.Support.Modelnamespace, this namespace is now gone, and you will have to update yourusingstatements accordingly. - The
Hl7.Fhir.ElementModel.Typesnamespace now includes types representing the CQL/FhirPath primitives (likeString,BooleanandDecimal) Importing both the standardSystemnamespace from .NET and this namespace, will cause references to theSystemtype to become ambiguous. Either explicitly qualify the references, or change the references to the built-in lowercase type keywordsstring,boolanddecimal.
The previous FHIR client was still using Microsoft's HttpWebRequest and HttpWebResponse as a mechanism. It now has had been upgraded and uses Microsoft's newer HttpClient. Note: The older client based on HttpWebRequest is still available, but is now called LegacyFhirClient and marked as obsolete. However, it is strongly recommended to use the new FhirClient implementation.
- The use of
HttpClientinstead ofHttpWebRequest/Responsemight slightly change the client behaviour slightly. - Added new optional parameter
FhirClientSettings. This replaces the public membersPreferredFormat,VerifyFhirVersion,ReturnFullResource,TimeOut,andUseFormatParame, which are now marked as obsolete. - Removed public members
OnBeforeRequestandOnAfterResponse, this are replaced by the optional parametermessageHandler. This option allows for more flexibility by letting the user add a custom "HttpMessageHandler" to the FHIR Client. We have added a newHttpClientEventHandlerclass which implements HttpMessageHandler, and has public membersOnBeforeRequestandOnAfterResponseto make thing a bit easier implementing old behaviour. - Removed public members
LastResponseandLastRequest. These members were obsolete in the previous version of the client since the values were already disposed by the time they arrived at the client. So no point having them around. - In
SearchParamspublic membersIncludeandRevIncludehave been changed fromList<string>toList<(string, IncludeModifier)>to be able to add modifiers, such as "iterate" to the include and reverse include search parameters while using search on theFhirClient. If you don't want to add any modifiers, useIncludeModifier.Nonefor the default behavior. -
BuildContentTypehas been changed fromBuildContentType(ResourceFormat format, bool forBundle)toBuildContentType(ResourceFormat format, string fhirVersion).forBundlehas been removed, since it wasn't used anymore,fhirVersionhas been added to add thefhirversionto the content type and accept-header.
-
PartialDateTime(now:DateTimein the Hl7.Fhir.ElementModel.Types namespace) no longer has aToUniversalTime()method, since there is no reasonable default behaviour for this function when the partial does not have a timezone offset specified. Instead, useToDateTimeOffset(), which will enable the caller to pass in a default offset to use for the conversion. Then call ToUniversalTime(). - To stay aligned with the
Quantitytype defined in CQL, TheHl7.Fhir.ElementModel.Types.Quantityclass no longer allows you to have a system other than UCUM. - For
FindStructureDefinition(this IResourceResolver resolver, string uri)andFindExtensionDefinition(this IResourceResolver resolver, string uri)the finalrequireSnapshotparameter has been removed. It promoted behaviour where an application would conclude a structuredefinition was not resolvable, even if it was just missing snapshot. The developer should explicitly check for the presence of a snapshot and report back to the user if a snapshot is missing while required for further processing. - The extension method
IsValidTypeProfile(this IResourceResolver resolver, string type, StructureDefinition profile)has been removed. This method was mistakenly marked as public in a previous version. - Properties
SettingsandRetrievehave been removed theCache<T>class: this suggested these properties could be modified, while in fact internally changes to these properties would not have any effect. -
BaseFhirSerializerhas been removed, it provided no public methods anymore - they all have been moved to extension methods. - We had inadvertently introduced a
Hl7.Fhir.Support.Utilitynamespace, which should have beenHl7.Fhir.Utility. The classes in this namespace (which were luckily just a few minor ones amongst which AnnotationList) have been moved. - The functions
ToPartialDateTime()on the POCO's Date.cs, Instant.cs and FhirDateTime.cs returned types from theHl7.Fhir.ElementModel.Typesnamespace, which blended the POCO/non-POCO (ITypedElement) worlds. To avoid this confusion and keep the interfaces consistent, these functions have been removed from these classes. - The constructor of
LocalTerminologyServiceexpects now aIAsyncResourceResolverinstead ofIResourceResolver. When you still work with anIResourceResolveryou can use the extension methodAsAsync()to convert you resourceresolver to asynchronous resolver.