-
Notifications
You must be signed in to change notification settings - Fork 345
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
CanonicalUrlConflictException
has been removed. - The class
XmlSerializationHint
has been removed. - The class
FhirSerializer
andFhirParser
have been removed. They have been obsolete for quite some time and replaced byFhirXmlParser
andFhirJsonParser
. - 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.IsValidBundleContentType
was 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.Base
andBundle.Base
have been removed. These have disappeared from the FHIR datamodel since DSTU2. - The
Bundle.FindEntry()
extension method usingtype
andid
parameters have been replaced by a function taking afullUrl
for quite a while, and has been removed. -
ElementDefinition.Name
has been renamed toElementDefinition.SliceName
since 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
IssueType
parameter have been removed. -
ValueSet.Define
was renamed toCodeSystem
in DSTU2 and then moved to its own proper resource in STU3. This property has now been removed. -
ResourceIdentity.Endpoint
was renamed toResourceBase
in 2015. This property has now been removed. -
ResourceIdentity.Collection
was using the historical term "collection" for what is now a resource. That was a thing in 2014. - The static
FhirParser
andFhirSerializer
classes have been deprecated since 2017, nowadays we create an instance ofFhir[Xml/Json]Parser
andFhir[Xml/Json]Serializer
and use the method on these instances instead. -
ModelInfo.IsInstanceTypeFor()
will no longer accept variants ofstring
,id
andQuantity
as instances type for these types. - The interface
ITerminologyService
has been changed as well: the methodValidateCode
has 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
,Subsumes
andClosure
), 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
Source
property) - 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.
-
SimpleQuantity
andMoneyQuantity
(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-memorySimpleQuantity
instance would be serialized toObservation.valueQuantity
and then parsed as aQuantity
, not aSimpleQuantity
. - The
ResourceType
member has been removed. This member relied on theResourceType
enumeration, 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
,ElementDefinition
andTiming
types 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
DebugDisplayAttributes
and declare theSerializable
andDataContract
attribute. - The
Meta.profile
property (used in any Resource) has changed type fromcanonical
touri
(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.status
has been renamed toVerificationResult.VerificationResultStatus
.status
is 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
,PrimitiveType
andBackboneType
have been introduced:- All datatypes (and primitives) are now subclasses of
DataType
rather thanElement
. - Choice elements (e.g.
Extension.value[x]
) are now of typeDataType
rather thanElement
(a non-breaking change, sinceDataType
is a direct subclass ofElement
. - The extension method
Value(this ElementDefinition ed, DataType fix=null, DataType pattern=null)
has been updated to takeDataType
as parameters instead ofElement
. - The constructor
Extension(string url, DataType value)
now takes aDataType
instead of anElement
- The extension method
AddExtension(this IExtendable extendable, string uri, DataType value, bool isModifier=false)
now takes aDataType
instead of anElement
. - The extension method
SetExtension(this IExtendable extendable, string uri, DataType value, bool isModifier=false)
now takes aDataType
instead of anElement
. - Type
Primitive
has 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
IBackboneElement
or theNamedBackboneElement
parameter to the[FhirType]
attribute around and they have been removed. The corresponding properties onClassMapping
andPropertyMapping
have also been removed.
- All datatypes (and primitives) are now subclasses of
- The abstract class
PrimitiveType<T>
had no members beyond those inherited fromPrimitiveType
and thus had no real use. It has been removed. - Those primitives that used a .NET
string
orint
implemented an interfaceIStringValue
resp.INullableIntegerValue
instead ofIValue<string>
andINullableValue<int>
- which would have been more consistent with the other primitives. This has been corrected by removingIStringValue
andINullableIntegerValue
. 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-name
extension is available, otherwise the lasts part of the element's path is used. Note: the generated propertyTypeName
has been changed accordingly. - The
ModelInspector
class 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
FhirElementAttribute
will be inspected for FHIR metadata, it is no longer necessary to put aNotMappedAttribute
on all non-fhir properties in a class. - In Elements with a choice of types which included the now-removed SimpleQuantity or MoneyQuantity, the
AllowedTypes
attribute will containQuantity
. - If the type of an element is open (e.g.
Extension.value[x]
),PropertyMapping.FhirType
will 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
IsOpen
attribute is no longer generated and removed fromAllowedTypeAttribute
. We introduced this in 1.8 - but only onExtension.value[x]
to accommodate movingExtension
to common, but this cannot faithfully be generated for other types. It has been removed fromPropertyMapping
as well. - Many metadata attribute may now be specified more than once. This makes sense if you also specify the new
Since
parameter, which is a string containing the semver version of the FHIR version for which you want to get the metadata. -
ClassMapping.IsAbstract
has been removed, useNativeType.IsAbstract
instead. -
ClassMapping.Profile
is no longer supported - its predicted use never materialized and no support for profile-based generated POCOs is present other parts of the API - The
FhirTypeAttribute
now requires a name, default names (derived from the type) are no longer supported. -
ClassMapping.IsBackbone
,ClassMapping.IsNamedBackboneElement
have been removed and replaced by a singleIsNestedType
boolean. The corresponding parameter to the[FhirType]
attribute has also been renamed. This attribute is onlytrue
for types that represent complex nested (backbone)elements in a FHIR resource or datatype. Use the new R5 type hierarchy (specificallyDataType
andBackboneType
) 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
TypeRedirect
on 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
date
type 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 asdate
notdateTime
. You may fix this by explicitly suffixing a partial dateTime with a 'T' (so2015-04T
is adateTime
, and2015-04
is 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 adate
instead of adateTime()
. - As a result,
ITypedElement
will now useHl7.Fhir.ElementModel.Types.PartialDate
for 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
Container
andRootContainer
on theEvaluationContext
have been renamed toResource
andRootResource
respectively, to align with the symbols (%resource
and%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 anITypedElement
primitive to an Any, cast theAny
toICqlConvertible
, 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 theValue
property 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 astring
should have been turned into aFHIR.uri
for 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.TypeInfo
class has been removed and replaced by theHl7.Fhir.Language.TypeSpecifier
class (to align with CQL/ELM terminology). It's functionality has been divided into working with the mapping between C# types and so calledSystem
types (which are inTypeSpecifier
) and working with primitive instance data of theSystem
types (which are subclasses ofHl7.Fhir.ElementModel.Types.Any
and other classes in that namespace. - The
Hl7.Fhir.Support.Model.Primitives.Primitives
class has been removed and its methods moved toHl7.Fhir.Language.TypeSpecifier
. SincePrimitives
was the only class that was present in theHl7.Fhir.Support.Model
namespace, this namespace is now gone, and you will have to update yourusing
statements accordingly. - The
Hl7.Fhir.ElementModel.Types
namespace now includes types representing the CQL/FhirPath primitives (likeString
,Boolean
andDecimal
) Importing both the standardSystem
namespace from .NET and this namespace, will cause references to theSystem
type to become ambiguous. Either explicitly qualify the references, or change the references to the built-in lowercase type keywordsstring
,bool
anddecimal
.
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
HttpClient
instead ofHttpWebRequest/Response
might 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
OnBeforeRequest
andOnAfterResponse
, 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 newHttpClientEventHandler
class which implements HttpMessageHandler, and has public membersOnBeforeRequest
andOnAfterResponse
to make thing a bit easier implementing old behaviour. - Removed public members
LastResponse
andLastRequest
. 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
SearchParams
public membersInclude
andRevInclude
have 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.None
for the default behavior. -
BuildContentType
has been changed fromBuildContentType(ResourceFormat format, bool forBundle)
toBuildContentType(ResourceFormat format, string fhirVersion)
.forBundle
has been removed, since it wasn't used anymore,fhirVersion
has been added to add thefhirversion
to the content type and accept-header.
-
PartialDateTime
(now:DateTime
in 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
Quantity
type defined in CQL, TheHl7.Fhir.ElementModel.Types.Quantity
class 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 finalrequireSnapshot
parameter 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
Settings
andRetrieve
have 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. -
BaseFhirSerializer
has been removed, it provided no public methods anymore - they all have been moved to extension methods. - We had inadvertently introduced a
Hl7.Fhir.Support.Utility
namespace, 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.Types
namespace, 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
LocalTerminologyService
expects now aIAsyncResourceResolver
instead ofIResourceResolver
. When you still work with anIResourceResolver
you can use the extension methodAsAsync()
to convert you resourceresolver to asynchronous resolver.