/// <inheritdoc/>
        public async Task PrepareRequestAsync(FhirTransactionContext context, CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(context, nameof(context));

            DicomDataset dataset = context.ChangeFeedEntry.Metadata;

            if (dataset == null)
            {
                return;
            }

            if (!dataset.TryGetSingleValue(DicomTag.PatientID, out string patientId))
            {
                throw new MissingRequiredDicomTagException(nameof(DicomTag.PatientID));
            }

            var patientIdentifier = new Identifier(string.Empty, patientId);

            FhirTransactionRequestMode requestMode = FhirTransactionRequestMode.None;

            Patient existingPatient = await _fhirService.RetrievePatientAsync(patientIdentifier, cancellationToken);

            Patient patient = (Patient)existingPatient?.DeepCopy();

            if (existingPatient == null)
            {
                patient = new Patient();

                patient.Identifier.Add(patientIdentifier);

                requestMode = FhirTransactionRequestMode.Create;
            }

            _patientSynchronizer.Synchronize(dataset, patient);

            if (requestMode == FhirTransactionRequestMode.None &&
                !existingPatient.IsExactly(patient))
            {
                requestMode = FhirTransactionRequestMode.Update;
            }

            Bundle.RequestComponent request = requestMode switch
            {
                FhirTransactionRequestMode.Create => GenerateCreateRequest(patientIdentifier),
                FhirTransactionRequestMode.Update => GenerateUpdateRequest(patient),
                _ => null
            };

            IResourceId resourceId = requestMode switch
            {
                FhirTransactionRequestMode.Create => new ClientResourceId(),
                _ => existingPatient.ToServerResourceId(),
            };

            context.Request.Patient = new FhirTransactionRequestEntry(
                requestMode,
                request,
                resourceId,
                patient);
        }
Example #2
0
        /// <summary>
        /// Deserialize JSON into a FHIR Bundle#Request
        /// </summary>
        public static void DeserializeJson(this Bundle.RequestComponent current, ref Utf8JsonReader reader, JsonSerializerOptions options)
        {
            string propertyName;

            while (reader.Read())
            {
                if (reader.TokenType == JsonTokenType.EndObject)
                {
                    return;
                }

                if (reader.TokenType == JsonTokenType.PropertyName)
                {
                    propertyName = reader.GetString();
                    if (Hl7.Fhir.Serialization.FhirSerializerOptions.Debug)
                    {
                        Console.WriteLine($"Bundle.RequestComponent >>> Bundle#Request.{propertyName}, depth: {reader.CurrentDepth}, pos: {reader.BytesConsumed}");
                    }
                    reader.Read();
                    current.DeserializeJsonProperty(ref reader, options, propertyName);
                }
            }

            throw new JsonException($"Bundle.RequestComponent: invalid state! depth: {reader.CurrentDepth}, pos: {reader.BytesConsumed}");
        }
        public async Task <IEnumerable <FhirTransactionRequestEntry> > BuildAsync(FhirTransactionContext context, CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(context, nameof(context));
            EnsureArg.IsNotNull(context.ChangeFeedEntry, nameof(context.ChangeFeedEntry));

            Identifier         identifier           = IdentifierUtility.CreateIdentifier(context.ChangeFeedEntry.StudyInstanceUid);
            List <Observation> matchingObservations = (await _fhirService.RetrieveObservationsAsync(identifier, cancellationToken)).ToList();

            // terminate early if no observation found
            if (matchingObservations.Count == 0)
            {
                return(null);
            }

            var requests = new List <FhirTransactionRequestEntry>();

            foreach (Observation observation in matchingObservations)
            {
                Bundle.RequestComponent request = new Bundle.RequestComponent()
                {
                    Method = Bundle.HTTPVerb.DELETE,
                    Url    = $"{ResourceType.Observation.GetLiteral()}/{observation.Id}"
                };

                requests.Add(new FhirTransactionRequestEntry(
                                 FhirTransactionRequestMode.Delete,
                                 request,
                                 observation.ToServerResourceId(),
                                 observation));
            }

            return(requests);
        }
Example #4
0
 public IRequestMeta Set(Bundle.RequestComponent RequestComponent)
 {
     this.PyroRequestUri = IPyroRequestUriFactory.CreateFhirRequestUri();
     CreateAndParsePyroRequestUri(ConstructAbsoluteRequestUrl(RequestComponent.Url, this.PyroRequestUri.PrimaryRootUrlStore.Url));
     this.RequestHeader          = IRequestHeaderFactory.CreateRequestHeader().Parse(RequestComponent);
     this.SearchParameterGeneric = ISearchParameterGenericFactory.CreateDtoSearchParameterGeneric().Parse(this.PyroRequestUri.FhirRequestUri.Query);
     return(this);
 }
        /// <inheritdoc/>
        public async Task <FhirTransactionRequestEntry> BuildAsync(FhirTransactionContext context, CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(context, nameof(context));
            EnsureArg.IsNotNull(context.ChangeFeedEntry, nameof(context.ChangeFeedEntry));
            EnsureArg.IsNotNull(context.Request, nameof(context.Request));

            IResourceId patientId = context.Request.Patient.ResourceId;

            ChangeFeedEntry changeFeedEntry = context.ChangeFeedEntry;

            Identifier imagingStudyIdentifier = ImagingStudyIdentifierUtility.CreateIdentifier(changeFeedEntry.StudyInstanceUid);

            ImagingStudy existingImagingStudy = await _fhirService.RetrieveImagingStudyAsync(imagingStudyIdentifier, cancellationToken);

            ImagingStudy imagingStudy = (ImagingStudy)existingImagingStudy?.DeepCopy();

            FhirTransactionRequestMode requestMode = FhirTransactionRequestMode.None;

            if (existingImagingStudy == null)
            {
                imagingStudy = new ImagingStudy()
                {
                    Status  = ImagingStudy.ImagingStudyStatus.Available,
                    Subject = patientId.ToResourceReference(),
                };

                imagingStudy.Identifier.Add(imagingStudyIdentifier);
                requestMode = FhirTransactionRequestMode.Create;
            }

            SynchronizeImagingStudyProperties(context, imagingStudy);

            if (requestMode != FhirTransactionRequestMode.Create &&
                !existingImagingStudy.IsExactly(imagingStudy))
            {
                requestMode = FhirTransactionRequestMode.Update;
            }

            Bundle.RequestComponent request = requestMode switch
            {
                FhirTransactionRequestMode.Create => ImagingStudyPipelineHelper.GenerateCreateRequest(imagingStudyIdentifier),
                FhirTransactionRequestMode.Update => ImagingStudyPipelineHelper.GenerateUpdateRequest(imagingStudy),
                _ => null,
            };

            IResourceId resourceId = requestMode switch
            {
                FhirTransactionRequestMode.Create => new ClientResourceId(),
                _ => existingImagingStudy.ToServerResourceId(),
            };

            return(new FhirTransactionRequestEntry(
                       requestMode,
                       request,
                       resourceId,
                       imagingStudy));
        }
        public FhirTransactionRequestEntry(
            FhirTransactionRequestMode requestMode,
            Bundle.RequestComponent request,
            IResourceId resourceId,
            Resource resource)
        {
            EnsureArg.EnumIsDefined(requestMode, nameof(requestMode));

            RequestMode = requestMode;
            Request     = request;
            ResourceId  = resourceId;
            Resource    = resource;
        }
Example #7
0
        private Bundle.RequestComponent GenerateRequestComponentForEntry(Bundle.EntryComponent Entry)
        {
            var RequestComponent = new Bundle.RequestComponent();

            if (!string.IsNullOrWhiteSpace(Entry.Resource.Id))
            {
                //Perform a PUT (Update)
                RequestComponent.Method = Bundle.HTTPVerb.PUT;
                RequestComponent.Url    = $"{Entry.Resource.TypeName}/{Entry.Resource.Id}";
            }
            else
            {
                //Perform a POST (Create)
                RequestComponent.Method = Bundle.HTTPVerb.POST;
                RequestComponent.Url    = $"{Entry.Resource.TypeName}";
            }
            return(RequestComponent);
        }
Example #8
0
        public IRequestHeader Parse(Bundle.RequestComponent RequestComponent)
        {
            if (!string.IsNullOrWhiteSpace(RequestComponent.IfNoneExist))
            {
                this.IfNoneExist = RequestComponent.IfNoneExist;
            }

            if (RequestComponent.IfModifiedSince.HasValue)
            {
                var DateTime = new FhirDateTime(RequestComponent.IfModifiedSince.Value);
                this.IfModifiedSince = DateTime.Value;
            }

            if (!string.IsNullOrWhiteSpace(RequestComponent.IfNoneMatch))
            {
                this.IfNoneMatch = ParseVersionHeader(RequestComponent.IfNoneMatch);
            }

            if (!string.IsNullOrWhiteSpace(RequestComponent.IfMatch))
            {
                this.IfMatch = ParseVersionHeader(RequestComponent.IfMatch);
            }
            return(this);
        }
        public Stream TerminzBatch()
        {
            string rv = string.Empty;

            string responseType = GetResponseType();
            string fhirVersion  = GetFhirVersion();

            // get Bundle from the Request Stream

            string       reqBody   = string.Empty;
            UTF8Encoding enc       = new UTF8Encoding();
            Stream       reqStream = OperationContext.Current.RequestContext.RequestMessage.GetBody <Stream>();

            using (StreamReader reader = new StreamReader(reqStream, enc))
            {
                reqBody = reader.ReadToEnd();
            }

            string reqType = WebOperationContext.Current.IncomingRequest.ContentType.ToLower();

            Resource fhirResource;

            if (reqType.Contains("json"))
            {
                FhirJsonParser fjp = new FhirJsonParser();
                fhirResource = fjp.Parse <Resource>(reqBody);
            }
            else
            {
                FhirXmlParser fxp = new FhirXmlParser();
                fhirResource = fxp.Parse <Resource>(reqBody);
            }

            if (fhirResource.ResourceType == ResourceType.Bundle)
            {
                Bundle fb = (Bundle)fhirResource;
                if (fb.Type == Bundle.BundleType.Batch)
                {
                    Bundle responseBundle = new Bundle();

                    responseBundle.Id   = Guid.NewGuid().ToString();
                    responseBundle.Type = Bundle.BundleType.BatchResponse;

                    foreach (Bundle.EntryComponent comp in fb.Entry)
                    {
                        Bundle.RequestComponent rc = comp.Request;

                        if (rc.Method == Bundle.HTTPVerb.GET)
                        {
                            if (rc.Url.IndexOf("$validate-code") > 0)
                            {
                                // extract and parse query string to get parameters
                                int    qsPos       = rc.Url.IndexOf('?');
                                string querystring = (qsPos < rc.Url.Length - 1) ? rc.Url.Substring(qsPos + 1) : String.Empty;
                                qParam = System.Web.HttpUtility.ParseQueryString(querystring);
                                // extract resource (CodeSystem or ValueSet) ID
                                string resourceID   = string.Empty;
                                string resourceName = resourceID.IndexOf("/ValueSet/") > 0 ? "ValueSet" : "CodeSystem";
                                try
                                {
                                    resourceID = rc.Url.Remove(qsPos);
                                    int resNamePos = resourceID.IndexOf("/" + resourceName + "/");
                                    resourceID = resourceID.Substring(resNamePos + 9).Replace("/", "").Replace("$validate-code", "");
                                }
                                catch { }
                                ServiceInterface appSi = new ServiceInterface();
                                responseBundle.AddResourceEntry(appSi.GetFhirResource(resourceName, resourceID, "$validate-code", qParam, fhirVersion), string.Empty);
                            }
                            else
                            {
                                responseBundle.AddResourceEntry(OperationOutcome.ForMessage("Unrecognised Operation in Request..." + rc.Url, OperationOutcome.IssueType.Unknown), string.Empty);
                            }
                        }
                        else if (rc.Method == Bundle.HTTPVerb.POST)
                        {
                            if (rc.Url.IndexOf("$translate") > 0 && comp.Resource.ResourceType == ResourceType.Parameters)
                            {
                                // extract ConceptMap ID
                                string cmID = string.Empty;
                                try
                                {
                                    cmID = rc.Url.Replace("ConceptMap/", "").Replace("$translate", "").Replace("/", "");
                                }
                                catch { }
                                // get parameters
                                Parameters fParam = (Parameters)comp.Resource;
                                SetQueryParameters(fParam);
                                ServiceInterface appSi = new ServiceInterface();
                                responseBundle.AddResourceEntry(appSi.GetFhirResource("ConceptMap", cmID, "$translate", qParam, fhirVersion), string.Empty);
                            }
                            else
                            {
                                responseBundle.AddResourceEntry(OperationOutcome.ForMessage("Unrecognised Operation in Request..." + rc.Url, OperationOutcome.IssueType.Unknown), string.Empty);
                            }
                        }
                        else
                        {
                            responseBundle.AddResourceEntry(OperationOutcome.ForMessage("Method Not Supported in Batch Mode '" + rc.Method.ToString() + "'", OperationOutcome.IssueType.NotSupported), string.Empty);
                        }
                    }

                    fhirResource = responseBundle;
                }
                else
                {
                    fhirResource = OperationOutcome.ForMessage("No module could be found to handle the bundle type '" + fb.TypeName + "'", OperationOutcome.IssueType.NotFound);
                }
            }
            else
            {
                fhirResource = OperationOutcome.ForMessage("No module could be found to handle the request '" + fhirResource.ResourceType.ToString() + "'", OperationOutcome.IssueType.NotFound);
            }

            if (fhirResource.ResourceType == ResourceType.OperationOutcome)
            {
                AddNarrativeToOperationOutcome(fhirResource);
                OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
                response.StatusCode = HttpStatusCode.BadRequest;
                // if wish for more granular response codes, need Issue Type
                //OperationOutcome oo = (OperationOutcome)fhirResource;
                //OperationOutcome.IssueType opOutcome = (OperationOutcome.IssueType)oo.Issue[0].Code;
            }

            // convert to stream to remove leading XML elements and json quotes
            rv = SerializeResponse(fhirResource, responseType, SummaryType.False);
            return(new System.IO.MemoryStream(UTF8Encoding.Default.GetBytes(rv)));
        }
Example #10
0
        public async Task PrepareRequestAsync(FhirTransactionContext context, CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(context, nameof(context));

            string queryParameter = $"name={FhirTransactionConstants.EndpointName}&connection-type={FhirTransactionConstants.EndpointConnectionTypeSystem}|{FhirTransactionConstants.EndpointConnectionTypeCode}";

            Endpoint endpoint = await _fhirService.RetrieveEndpointAsync(queryParameter, cancellationToken);

            FhirTransactionRequestMode requestMode = FhirTransactionRequestMode.None;

            if (endpoint == null)
            {
                endpoint = new Endpoint()
                {
                    Name           = FhirTransactionConstants.EndpointName,
                    Status         = Endpoint.EndpointStatus.Active,
                    ConnectionType = new Coding()
                    {
                        System = FhirTransactionConstants.EndpointConnectionTypeSystem,
                        Code   = FhirTransactionConstants.EndpointConnectionTypeCode,
                    },
                    Address     = _dicomWebEndpoint,
                    PayloadType = new List <CodeableConcept>
                    {
                        new CodeableConcept(string.Empty, string.Empty, FhirTransactionConstants.EndpointPayloadTypeText),
                    },
                    PayloadMimeType = new string[]
                    {
                        FhirTransactionConstants.DicomMimeType,
                    },
                };

                requestMode = FhirTransactionRequestMode.Create;
            }
            else
            {
                // Make sure the address matches.
                if (!string.Equals(endpoint.Address, _dicomWebEndpoint, StringComparison.Ordinal))
                {
                    // We have found an endpoint with matching name and connection-type but the address does not match.
                    throw new FhirResourceValidationException(DicomCastCoreResource.MismatchEndpointAddress);
                }
            }

            Bundle.RequestComponent request = requestMode switch
            {
                FhirTransactionRequestMode.Create => new Bundle.RequestComponent()
                {
                    Method      = Bundle.HTTPVerb.POST,
                    IfNoneExist = queryParameter,
                    Url         = ResourceType.Endpoint.GetLiteral(),
                },
                _ => null,
            };

            IResourceId resourceId = requestMode switch
            {
                FhirTransactionRequestMode.Create => new ClientResourceId(),
                _ => endpoint.ToServerResourceId(),
            };

            context.Request.Endpoint = new FhirTransactionRequestEntry(
                requestMode,
                request,
                resourceId,
                endpoint);
        }
Example #11
0
        /// <summary>
        /// Deserialize JSON into a FHIR Bundle#Request
        /// </summary>
        public static void DeserializeJsonProperty(this Bundle.RequestComponent current, ref Utf8JsonReader reader, JsonSerializerOptions options, string propertyName)
        {
            switch (propertyName)
            {
            case "method":
                if (reader.TokenType == JsonTokenType.Null)
                {
                    current.MethodElement = new Code <Hl7.Fhir.Model.Bundle.HTTPVerb>();
                    reader.Skip();
                }
                else
                {
                    current.MethodElement = new Code <Hl7.Fhir.Model.Bundle.HTTPVerb>(Hl7.Fhir.Utility.EnumUtility.ParseLiteral <Hl7.Fhir.Model.Bundle.HTTPVerb>(reader.GetString()));
                }
                break;

            case "_method":
                if (current.MethodElement == null)
                {
                    current.MethodElement = new Code <Hl7.Fhir.Model.Bundle.HTTPVerb>();
                }
                ((Hl7.Fhir.Model.Element)current.MethodElement).DeserializeJson(ref reader, options);
                break;

            case "url":
                if (reader.TokenType == JsonTokenType.Null)
                {
                    current.UrlElement = new FhirUri();
                    reader.Skip();
                }
                else
                {
                    current.UrlElement = new FhirUri(reader.GetString());
                }
                break;

            case "_url":
                if (current.UrlElement == null)
                {
                    current.UrlElement = new FhirUri();
                }
                ((Hl7.Fhir.Model.Element)current.UrlElement).DeserializeJson(ref reader, options);
                break;

            case "ifNoneMatch":
                if (reader.TokenType == JsonTokenType.Null)
                {
                    current.IfNoneMatchElement = new FhirString();
                    reader.Skip();
                }
                else
                {
                    current.IfNoneMatchElement = new FhirString(reader.GetString());
                }
                break;

            case "_ifNoneMatch":
                if (current.IfNoneMatchElement == null)
                {
                    current.IfNoneMatchElement = new FhirString();
                }
                ((Hl7.Fhir.Model.Element)current.IfNoneMatchElement).DeserializeJson(ref reader, options);
                break;

            case "ifModifiedSince":
                if (reader.TokenType == JsonTokenType.Null)
                {
                    current.IfModifiedSinceElement = new Instant();
                    reader.Skip();
                }
                else
                {
                    current.IfModifiedSinceElement = new Instant(DateTimeOffset.Parse(reader.GetString()));
                }
                break;

            case "_ifModifiedSince":
                if (current.IfModifiedSinceElement == null)
                {
                    current.IfModifiedSinceElement = new Instant();
                }
                ((Hl7.Fhir.Model.Element)current.IfModifiedSinceElement).DeserializeJson(ref reader, options);
                break;

            case "ifMatch":
                if (reader.TokenType == JsonTokenType.Null)
                {
                    current.IfMatchElement = new FhirString();
                    reader.Skip();
                }
                else
                {
                    current.IfMatchElement = new FhirString(reader.GetString());
                }
                break;

            case "_ifMatch":
                if (current.IfMatchElement == null)
                {
                    current.IfMatchElement = new FhirString();
                }
                ((Hl7.Fhir.Model.Element)current.IfMatchElement).DeserializeJson(ref reader, options);
                break;

            case "ifNoneExist":
                if (reader.TokenType == JsonTokenType.Null)
                {
                    current.IfNoneExistElement = new FhirString();
                    reader.Skip();
                }
                else
                {
                    current.IfNoneExistElement = new FhirString(reader.GetString());
                }
                break;

            case "_ifNoneExist":
                if (current.IfNoneExistElement == null)
                {
                    current.IfNoneExistElement = new FhirString();
                }
                ((Hl7.Fhir.Model.Element)current.IfNoneExistElement).DeserializeJson(ref reader, options);
                break;

            // Complex: request, Export: RequestComponent, Base: BackboneElement
            default:
                ((Hl7.Fhir.Model.BackboneElement)current).DeserializeJsonProperty(ref reader, options, propertyName);
                break;
            }
        }
Example #12
0
        /// <summary>
        /// Serialize a FHIR Bundle#Request into JSON
        /// </summary>
        public static void SerializeJson(this Bundle.RequestComponent current, Utf8JsonWriter writer, JsonSerializerOptions options, bool includeStartObject = true)
        {
            if (includeStartObject)
            {
                writer.WriteStartObject();
            }
            // Component: Bundle#Request, Export: RequestComponent, Base: BackboneElement (BackboneElement)
            ((Hl7.Fhir.Model.BackboneElement)current).SerializeJson(writer, options, false);

            writer.WriteString("method", Hl7.Fhir.Utility.EnumUtility.GetLiteral(current.MethodElement.Value));

            writer.WriteString("url", current.UrlElement.Value);

            if (current.IfNoneMatchElement != null)
            {
                if (!string.IsNullOrEmpty(current.IfNoneMatchElement.Value))
                {
                    writer.WriteString("ifNoneMatch", current.IfNoneMatchElement.Value);
                }
                if (current.IfNoneMatchElement.HasExtensions() || (!string.IsNullOrEmpty(current.IfNoneMatchElement.ElementId)))
                {
                    JsonStreamUtilities.SerializeExtensionList(writer, options, "_ifNoneMatch", false, current.IfNoneMatchElement.Extension, current.IfNoneMatchElement.ElementId);
                }
            }

            if (current.IfModifiedSinceElement != null)
            {
                if (current.IfModifiedSinceElement.Value != null)
                {
                    writer.WriteString("ifModifiedSince", ((DateTimeOffset)current.IfModifiedSinceElement.Value).ToString("yyyy-MM-dd'T'HH:mm:ss.FFFFFFFK", System.Globalization.CultureInfo.InvariantCulture));
                }
                if (current.IfModifiedSinceElement.HasExtensions() || (!string.IsNullOrEmpty(current.IfModifiedSinceElement.ElementId)))
                {
                    JsonStreamUtilities.SerializeExtensionList(writer, options, "_ifModifiedSince", false, current.IfModifiedSinceElement.Extension, current.IfModifiedSinceElement.ElementId);
                }
            }

            if (current.IfMatchElement != null)
            {
                if (!string.IsNullOrEmpty(current.IfMatchElement.Value))
                {
                    writer.WriteString("ifMatch", current.IfMatchElement.Value);
                }
                if (current.IfMatchElement.HasExtensions() || (!string.IsNullOrEmpty(current.IfMatchElement.ElementId)))
                {
                    JsonStreamUtilities.SerializeExtensionList(writer, options, "_ifMatch", false, current.IfMatchElement.Extension, current.IfMatchElement.ElementId);
                }
            }

            if (current.IfNoneExistElement != null)
            {
                if (!string.IsNullOrEmpty(current.IfNoneExistElement.Value))
                {
                    writer.WriteString("ifNoneExist", current.IfNoneExistElement.Value);
                }
                if (current.IfNoneExistElement.HasExtensions() || (!string.IsNullOrEmpty(current.IfNoneExistElement.ElementId)))
                {
                    JsonStreamUtilities.SerializeExtensionList(writer, options, "_ifNoneExist", false, current.IfNoneExistElement.Extension, current.IfNoneExistElement.ElementId);
                }
            }

            if (includeStartObject)
            {
                writer.WriteEndObject();
            }
        }