public Hl7.Fhir.ElementModel.ITypedElement Resolver(string url) { CustomResolveElementNavigator ResolveElementNavigator = new CustomResolveElementNavigator(); #pragma warning disable IDE0059 // Unnecessary assignment of a value if (IFhirUriFactory.TryParse(url, Common.Enums.FhirVersion.R4, out IFhirUri? fhirUri, out string ErrorMessage)) #pragma warning restore IDE0059 // Unnecessary assignment of a value { if (fhirUri is object && !string.IsNullOrWhiteSpace(fhirUri.ResourseName)) { ResolveElementNavigator.Name = fhirUri.ResourseName; //This type property is the key property to set for resolve() as it needs to match the comparison //for example 'AuditEvent.agent.who.where(resolve() is Patient)' Patient is Patient //PyroElementNavigator.Type = PyroRequestUri.FhirRequestUri.ResourseName; ResolveElementNavigator.InstanceType = fhirUri.ResourseName; ResolveElementNavigator.Value = fhirUri.ResourseName; ResolveElementNavigator.Location = url; return(ResolveElementNavigator); } } #pragma warning disable CS8603 // Possible null reference return. return(null); #pragma warning restore CS8603 // Possible null reference return. }
public override void ParseValue(string Values) { this.IsValid = true; this.ValueList = new List <SearchQueryReferenceValue>(); foreach (string Value in Values.Split(OrDelimiter)) { if (this.Modifier.HasValue && this.Modifier == SearchModifierCode.Missing) { bool?IsMissing = SearchQueryReferenceValue.ParseModifierEqualToMissing(Value); if (IsMissing.HasValue) { this.ValueList.Add(new SearchQueryReferenceValue(IsMissing.Value, null)); } else { this.InvalidMessage = $"Found the {SearchModifierCode.Missing.GetCode()} Modifier yet is value was expected to be true or false yet found '{Value}'. "; this.IsValid = false; break; } } else if (!this.IsChained) // If IsChained then there is no value to check { SearchQueryReferenceValue?SearchQueryReferenceValue = null; if (!Value.Contains('/') && !string.IsNullOrWhiteSpace(Value.Trim()) && this.TargetResourceTypeList.Count() == 1) { //If only one allowed Resource type then use this so the reference is just a resource Id '10' and we add on the appropriate ResourceName i.e 'Patient/10' string ParseValue = $"{this.TargetResourceTypeList.ToArray()[0].ResourceTypeId.GetCode()}/{Value.Trim()}"; if (IFhirUriFactory.TryParse(ParseValue, this.FhirVersionId, out IFhirUri? FhirUri, out string ErrorMessage)) { SearchQueryReferenceValue = new SearchQueryReferenceValue(false, FhirUri); } else { this.InvalidMessage = $"The resource reference was {Value} and the only allowed resource type was appended to give {ParseValue} however parsing of this as a FHIR reference failed with the error: {ErrorMessage}"; this.IsValid = false; break; } } else if (IFhirUriFactory.TryParse(Value.Trim(), this.FhirVersionId, out IFhirUri? FhirUri, out string ErrorMessage)) { if (string.IsNullOrWhiteSpace(FhirUri !.ResourseName)) { //After parsing the search parameter of type reference if there is no Resource Type for the reference //e.g no Patient is the example 'Patient/123456' string RefResources = string.Empty; this.TargetResourceTypeList.ToList().ForEach(v => RefResources += ", " + v.ResourceTypeId.GetCode()); string ResourceName = this.ResourceContext.GetCode(); string Message = string.Empty; Message = $"The search parameter: {this.Name} is ambiguous. "; Message += $"Additional information: "; Message += $"The search parameter: {this.Name} can reference the following resource types ({RefResources.TrimStart(',').Trim()}). "; Message += $"To correct this you must prefix the search parameter with a Type modifier, for example: {this.Name}={this.TargetResourceTypeList.ToArray()[0].ResourceTypeId.GetCode()}/{FhirUri.ResourceId}"; Message += $"or: {this.Name}:{this.TargetResourceTypeList.ToArray()[0].ResourceTypeId.GetCode()}={FhirUri.ResourceId} "; Message += $"If the: {this.TargetResourceTypeList.ToArray()[0].ResourceTypeId.GetCode()} resource was the intended reference for the search parameter: {this.Name}."; this.IsValid = false; break; } //Most likely an absolute or relative so just parse it SearchQueryReferenceValue = new SearchQueryReferenceValue(false, FhirUri); } else { this.InvalidMessage = $"Unable to parse the reference search parameter of: '{Value}'. {ErrorMessage}"; this.IsValid = false; break; } if (SearchQueryReferenceValue is object && SearchQueryReferenceValue.FhirUri is object) { //Check the Resource type we resolved to is allowed for the search parameter if (!string.IsNullOrWhiteSpace(SearchQueryReferenceValue.FhirUri.ResourseName) && !this.TargetResourceTypeList.Any(x => x.ResourceTypeId.GetCode() == SearchQueryReferenceValue.FhirUri.ResourseName)) { this.InvalidMessage = $"The resource name used in the reference search parameter is not allowed for this search parameter type against this resource type."; this.IsValid = false; break; } else { this.ValueList.Add(SearchQueryReferenceValue); } } else { throw new ArgumentNullException($"Internal Server Error: Either {nameof(SearchQueryReferenceValue)} or {nameof(SearchQueryReferenceValue.FhirUri)} was found to be null"); } } } if (ValueList.Count > 1) { this.HasLogicalOrProperties = true; } if (this.ValueList.Count == 0) { if (!this.IsChained) { this.InvalidMessage = $"Unable to parse any values into a {this.GetType().Name} from the string: {Values}."; this.IsValid = false; } } }
public bool IsValid(FhirBaseApiQuery fhirApiQuery, out Common.FhirTools.FhirResource?OperationOutCome) { OperationOutCome = null; if (!IFhirUriFactory.TryParse(fhirApiQuery.RequestUri.OriginalString, fhirApiQuery.FhirVersion, out IFhirUri? FhirUri, out string ErrorMessage)) { OperationOutCome = IOperationOutcomeSupport.GetError(fhirApiQuery.FhirVersion, new string[] { ErrorMessage }); return(false); } if (FhirUri is null) { throw new ArgumentNullException(nameof(FhirUri)); } if (fhirApiQuery is FhirApiResourceQuery fhirApiResourceQuery) { if (string.IsNullOrWhiteSpace(fhirApiResourceQuery.ResourceName)) { string message = $"An empty resource name found in the request URL for a {nameof(fhirApiResourceQuery)} request. " + $"All {nameof(fhirApiResourceQuery)} requests must have a resource name. The full URL was: {FhirUri.OriginalString}"; throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message); } } if (fhirApiQuery is FhirApiResourceInstanceQuery fhirApiResourceInstanceQuery) { if (string.IsNullOrWhiteSpace(fhirApiResourceInstanceQuery.ResourceId)) { string message = $"An empty {nameof(fhirApiResourceInstanceQuery.ResourceId)} found in the {nameof(fhirApiResourceInstanceQuery)} object instance for the request. " + $"All {nameof(fhirApiResourceInstanceQuery)} requests must have a populated {nameof(fhirApiResourceInstanceQuery.ResourceId)}."; throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message); } if (string.IsNullOrWhiteSpace(FhirUri.ResourceId)) { string message = $"An empty resource id found in the request URL for a {nameof(fhirApiResourceInstanceQuery)} request. " + $"All {nameof(fhirApiResourceInstanceQuery)} requests must have a resource id. The full URL was: {FhirUri.OriginalString}"; throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message); } } if (fhirApiQuery is FhirApiResourceInstanceHistoryInstanceQuery fhirApiResourceInstanceHistoryInstanceQuery) { if (fhirApiResourceInstanceHistoryInstanceQuery.VersionId == 0) { string message = $"A {nameof(fhirApiResourceInstanceHistoryInstanceQuery.VersionId)} must begin at one for this server. The request had a {nameof(fhirApiResourceInstanceHistoryInstanceQuery.VersionId)} equal to {fhirApiResourceInstanceHistoryInstanceQuery.VersionId.ToString()}. " + $"All {nameof(fhirApiResourceInstanceHistoryInstanceQuery.VersionId)} requests must be numeric and begin from one within this server."; OperationOutCome = IOperationOutcomeSupport.GetError(fhirApiResourceInstanceHistoryInstanceQuery.FhirVersion, new string[] { message }); return(false); } if (string.IsNullOrWhiteSpace(FhirUri.VersionId)) { string message = $"An empty {nameof(FhirUri.VersionId)} found in the request URL for a {nameof(fhirApiResourceInstanceHistoryInstanceQuery)} request. " + $"All {nameof(fhirApiResourceInstanceHistoryInstanceQuery)} requests must have a {nameof(FhirUri.VersionId)}. The full URL was: {FhirUri.OriginalString}"; throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message); } } if (fhirApiQuery is CreateQuery createQuery) { //Check the Method is set correctly if (createQuery.Method != HttpVerb.POST) { string message = $"The {nameof(createQuery)} did not have a Method of: {HttpVerb.POST.GetCode()}. The Method found was: {createQuery.Method.GetCode()}. All CreateQueries must be of Method: {HttpVerb.POST.GetCode()}"; throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message); } //Check we have a FHIR Resource if (createQuery.FhirResource is null) { string message = $"A {HttpVerb.POST.GetCode()} request must have a FHIR resource provided in the body of the request."; OperationOutCome = IOperationOutcomeSupport.GetError(fhirApiQuery.FhirVersion, new string[] { message }); return(false); } //Check the FHIR Resource's name equals the FHIR URL endpoint string ResourceName = IFhirResourceNameSupport.GetName(createQuery.FhirResource); if (!ResourceName.Equals(FhirUri.ResourseName, StringComparison.CurrentCulture)) { string message = $"The resource provided in the body of the request does not match the resource type stated in the URL. The resource in the body was of type '{ResourceName}' and the URL stated the type '{FhirUri.ResourseName}'. The full URL was: {FhirUri.OriginalString}"; OperationOutCome = IOperationOutcomeSupport.GetError(createQuery.FhirResource.FhirVersion, new string[] { message }); return(false); } //Check the FHIR Resource's name equals the query property ResourceName (should never fail but worth checking) if (!ResourceName.Equals(createQuery.ResourceName, StringComparison.CurrentCulture)) { string message = $"The resource provided in the body of the request does not match the resource type found on the {nameof(createQuery)}. The resource in the body was of type: {ResourceName} and the {nameof(createQuery)} stated the type: {createQuery.ResourceName}. The full URL was: {FhirUri.OriginalString}"; throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message); } //Check that the Create resource has no resourceId string?ResourceResourceId = IFhirResourceIdSupport.GetResourceId(createQuery.FhirResource); if (!string.IsNullOrWhiteSpace(ResourceResourceId)) { string message = $"The Create ({createQuery.Method.GetCode()}) interaction creates a new resource in a server-assigned location with a server assigned resource id. If the client wishes to have control over the id of a newly submitted resource, it should use the update ({HttpVerb.PUT.GetCode()}) interaction instead. The resource provide was found to contain the id: {ResourceResourceId}"; OperationOutCome = IOperationOutcomeSupport.GetError(createQuery.FhirResource.FhirVersion, new string[] { message }); return(false); } } if (fhirApiQuery is UpdateQuery updateQuery) { //Check the Method is set correctly if (updateQuery.Method != HttpVerb.PUT) { string message = $"The {nameof(updateQuery)} did not have a Method of: {HttpVerb.PUT.GetCode()}. The Method found was: {updateQuery.Method.GetCode()}. All CreateQueries must be of Method: {HttpVerb.PUT.GetCode()}"; throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message); } //Check we have a FHIR Resource if (updateQuery.FhirResource is null) { string message = $"A {HttpVerb.PUT.GetCode()} request must have a FHIR resource provided in the body of the request."; OperationOutCome = IOperationOutcomeSupport.GetError(fhirApiQuery.FhirVersion, new string[] { message }); return(false); } //Check the FHIR Resource's name equals the FHIR URL endpoint string ResourceName = IFhirResourceNameSupport.GetName(updateQuery.FhirResource); if (!ResourceName.Equals(FhirUri.ResourseName, StringComparison.CurrentCulture)) { string message = $"The resource provided in the body of the request does not match the resource type stated in the URL. The resource in the body was of type '{ResourceName}' and the URL stated the type '{FhirUri.ResourseName}'. The full URL was: {FhirUri.OriginalString}"; OperationOutCome = IOperationOutcomeSupport.GetError(updateQuery.FhirResource.FhirVersion, new string[] { message }); return(false); } //Check the FHIR Resource's name equals the query property ResourceName (should never fail but worth checking) if (!ResourceName.Equals(updateQuery.ResourceName, StringComparison.CurrentCulture)) { string message = $"The resource provided in the body of the request does not match the resource type found on the {nameof(updateQuery)}. The resource in the body was of type: {ResourceName} and the {nameof(updateQuery)} stated the type: {updateQuery.ResourceName}. The full URL was: {FhirUri.OriginalString}"; throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message); } string?ResourceResourceId = IFhirResourceIdSupport.GetResourceId(updateQuery.FhirResource); //Check resource has a resource id if (string.IsNullOrWhiteSpace(ResourceResourceId)) { string message = $"There was no resource id found in the resource of the request. " + $"An update ({updateQuery.Method.GetCode()}) request must contain a resource with a resource id in the body of the request."; OperationOutCome = IOperationOutcomeSupport.GetError(updateQuery.FhirResource.FhirVersion, new string[] { message }); return(false); } //Check the URL has a resource id equals the resource's id if (!ResourceResourceId.Equals(FhirUri.ResourceId, StringComparison.CurrentCulture)) { string message = $"The resource id found in the resource of the request does not match the resource id stated in the request URL. " + $"The resource id in the body was: '{ResourceResourceId}' and in the URL it was: '{FhirUri.ResourceId}'. The full URL was: {FhirUri.OriginalString}"; OperationOutCome = IOperationOutcomeSupport.GetError(updateQuery.FhirResource.FhirVersion, new string[] { message }); return(false); } //Check the UpdateQuery ResourceId property matches the URL and Resource (this should never fail) if (!updateQuery.ResourceId.Equals(FhirUri.ResourceId, StringComparison.CurrentCulture) && !updateQuery.ResourceId.Equals(ResourceResourceId, StringComparison.CurrentCulture)) { string message = $"The resource id found in the body of the request does not match the resource id stated in the request URL. " + $"The resource id in the body was: '{ResourceResourceId}' and in the URL it was: '{FhirUri.ResourceId}'. The full URL was: {FhirUri.OriginalString}"; OperationOutCome = IOperationOutcomeSupport.GetError(updateQuery.FhirResource.FhirVersion, new string[] { message }); return(false); } } //if (fhirApiQuery is ReadQuery readQuery) //{ //} //if (fhirApiQuery is VReadQuery vReadQuery) //{ //} //if (fhirApiQuery is DeleteQuery DeleteQuery) //{ //} return(true); }