/// <summary> /// Try to deserialize the full resource represented by the specified <see cref="ArtifactSummary"/>. /// </summary> /// <param name="info">An <see cref="ArtifactSummary"/> instance.</param> /// <typeparam name="T">The expected resource type.</typeparam> /// <returns>A new instance of type <typeparamref name="T"/>, or <c>null</c>.</returns> private static T getResourceFromScannedSource <T>(ArtifactSummary info) where T : Resource { // File path of the containing resource file (could be a Bundle) var path = info.Origin; using (var navStream = DefaultNavigatorStreamFactory.Create(path)) { // TODO: Handle exceptions & null return values // e.g. file may have been deleted/renamed since last scan // Advance stream to the target resource (e.g. specific Bundle entry) if (navStream != null && navStream.Seek(info.Position)) { // Create navigator for the target resource var nav = navStream.Current; if (nav != null) { // Parse target resource from navigator var parser = new BaseFhirParser(); var result = parser.Parse <T>(nav); if (result != null) { // Add origin annotation result.SetOrigin(info.Origin); return(result); } } } return(null); } }
public void TestLoadResourceFromZipStream() { // Harvest summaries and load artifact straight from core ZIP archive // Use XmlNavigatorStream to navigate resources stored inside a zip file // ZipDeflateStream does not support seeking (forward-only stream) // Therefore this only works for the XmlNavigatorStream, as the ctor does NOT (need to) call Reset() // JsonNavigatorStream cannot support zip streams; ctor needs to call Reset after scanning resourceType ArtifactSummary corePatientSummary; var corePatientUrl = ModelInfo.CanonicalUriForFhirCoreType(FHIRDefinedType.Patient); string zipEntryName = "profiles-resources.xml"; // Generate summaries from core ZIP resource definitions (extract in memory) using (var archive = ZipFile.Open(ZipSource.SpecificationZipFileName, ZipArchiveMode.Read)) { var entry = archive.Entries.FirstOrDefault(e => e.Name == zipEntryName); Assert.IsNotNull(entry); using (var entryStream = entry.Open()) using (var navStream = new XmlNavigatorStream(entryStream)) { var summaries = ArtifactSummaryGenerator.Default.Generate(navStream); Assert.IsNotNull(summaries); corePatientSummary = summaries.FindConformanceResources(corePatientUrl).FirstOrDefault(); } } Assert.IsNotNull(corePatientSummary); Assert.AreEqual(ResourceType.StructureDefinition, corePatientSummary.ResourceType); Assert.AreEqual(corePatientUrl, corePatientSummary.GetConformanceCanonicalUrl()); // Load core Patient resource from ZIP (extract in memory) using (var archive = ZipFile.Open(ZipSource.SpecificationZipFileName, ZipArchiveMode.Read)) { var entry = archive.Entries.FirstOrDefault(e => e.Name == zipEntryName); using (var entryStream = entry.Open()) using (var navStream = new XmlNavigatorStream(entryStream)) { var nav = navStream.Current; if (nav != null) { // Parse target resource from navigator var parser = new BaseFhirParser(); var corePatient = parser.Parse <StructureDefinition>(nav); Assert.IsNotNull(corePatient); Assert.AreEqual(corePatientUrl, corePatient.Url); } } } }
/// <summary>Returns <c>null</c> if the specified <paramref name="summary"/> equals <c>null</c>.</summary> T loadResourceInternal <T>(ArtifactSummary summary) where T : Resource { if (summary == null) { return(null); } // File path of the containing resource file (could be a Bundle) var origin = summary.Origin; if (string.IsNullOrEmpty(origin)) { throw Error.Argument($"Cannot load resource from summary. The {nameof(ArtifactSummary.Origin)} information is empty or missing."); } var pos = summary.Position; if (string.IsNullOrEmpty(pos)) { throw Error.Argument($"Cannot load resource from summary. The {nameof(ArtifactSummary.Position)} information is empty or missing."); } T result = null; using (var navStream = DefaultNavigatorStreamFactory.Create(origin)) { // Handle exceptions & null return values? // e.g. file may have been deleted/renamed since last scan // Advance stream to the target resource (e.g. specific Bundle entry) if (navStream != null && navStream.Seek(pos)) { // Create navigator for the target resource var nav = navStream.Current; if (nav != null) { // Parse target resource from navigator var parser = new BaseFhirParser(); result = parser.Parse <T>(nav); // Add origin annotation result?.SetOrigin(origin); } } } return(result); }
public FhirClient(HttpClient httpClient, ResourceFormat format) { HttpClient = httpClient; _format = format; if (format == ResourceFormat.Json) { var jsonSerializer = new FhirJsonSerializer(); _serializer = jsonSerializer; _serialize = (resource, summary) => jsonSerializer.SerializeToString(resource, summary); var jsonParser = new FhirJsonParser(); _parser = jsonParser; _deserialize = jsonParser.Parse <Resource>; _contentType = ContentType.JSON_CONTENT_HEADER; } else if (format == ResourceFormat.Xml) { var xmlSerializer = new FhirXmlSerializer(); _serializer = xmlSerializer; _serialize = (resource, summary) => xmlSerializer.SerializeToString(resource, summary); var xmlParser = new FhirXmlParser(); _parser = xmlParser; _deserialize = xmlParser.Parse <Resource>; _contentType = ContentType.XML_CONTENT_HEADER; } else { throw new InvalidOperationException("Unsupported format."); } _mediaType = MediaTypeWithQualityHeaderValue.Parse(_contentType); SetupAuthenticationAsync(TestApplications.ServiceClient).GetAwaiter().GetResult(); }
private async Task <HttpResponseMessage> Upsert(string resourceType, HttpStatusCode statusCode) { try { string raw = await Request.Content.ReadAsStringAsync(); BaseFhirParser parser = null; if (IsContentTypeJSON) { parser = jsonparser; } else if (IsContentTypeXML) { parser = xmlparser; } else { throw new Exception("Invalid Content-Type must be application/fhir+json or application/fhir+xml"); } var reader = IsContentTypeJSON ? FhirJsonParser.CreateFhirReader(raw) : FhirXmlParser.CreateFhirReader(raw, false); var p = (Resource)parser.Parse(reader, FhirHelper.ResourceTypeFromString(resourceType)); ResourceType rt; Enum.TryParse(resourceType, out rt); if (p.ResourceType != rt) { OperationOutcome oo = new OperationOutcome(); oo.Issue = new System.Collections.Generic.List <OperationOutcome.IssueComponent>(); OperationOutcome.IssueComponent ic = new OperationOutcome.IssueComponent(); ic.Severity = OperationOutcome.IssueSeverity.Error; ic.Code = OperationOutcome.IssueType.Exception; ic.Diagnostics = "Resource provide is not of type " + resourceType; oo.Issue.Add(ic); var respconf = this.Request.CreateResponse(HttpStatusCode.BadRequest); respconf.Content = new StringContent(SerializeResponse(oo), Encoding.UTF8, CurrentAcceptType); return(respconf); } //Store resource regardless of type p = await ProcessSingleResource(p, resourceType, IsMatchVersionId); var response = this.Request.CreateResponse(statusCode); response.Headers.Add("Location", Request.RequestUri.AbsoluteUri + "/" + p.Id); response.Headers.Add("ETag", "W/\"" + p.Meta.VersionId + "\""); //Extract and Save each Resource in bundle if it's a batch type if (p.ResourceType == ResourceType.Bundle && ((Bundle)p).Type == Bundle.BundleType.Batch) { Bundle source = (Bundle)p; Bundle results = new Bundle(); results.Id = Guid.NewGuid().ToString(); results.Type = Bundle.BundleType.Searchset; results.Total = source.Entry.Count(); results.Link = new System.Collections.Generic.List <Bundle.LinkComponent>(); results.Link.Add(new Bundle.LinkComponent() { Url = Request.RequestUri.AbsoluteUri, Relation = "original" }); results.Entry = new System.Collections.Generic.List <Bundle.EntryComponent>(); foreach (Bundle.EntryComponent ec in source.Entry) { var rslt = await ProcessSingleResource(ec.Resource, Enum.GetName(typeof(Hl7.Fhir.Model.ResourceType), ec.Resource.ResourceType)); results.Entry.Add(new Bundle.EntryComponent() { Resource = rslt }); } } return(response); } catch (Exception e) { OperationOutcome oo = new OperationOutcome(); oo.Issue = new System.Collections.Generic.List <OperationOutcome.IssueComponent>(); OperationOutcome.IssueComponent ic = new OperationOutcome.IssueComponent(); ic.Severity = OperationOutcome.IssueSeverity.Error; ic.Code = OperationOutcome.IssueType.Exception; ic.Diagnostics = e.Message; oo.Issue.Add(ic); var response = this.Request.CreateResponse(HttpStatusCode.BadRequest); response.Content = new StringContent(SerializeResponse(oo), Encoding.UTF8, CurrentAcceptType); return(response); } }
private async Task <HttpResponseMessage> Upsert(string resourceType, string headerid = null) { try { string raw = await Request.Content.ReadAsStringAsync(); BaseFhirParser parser = null; if (IsContentTypeJSON) { parser = jsonparser; } else if (IsContentTypeXML) { parser = xmlparser; } else { throw new Exception("Invalid Content-Type must be application/fhir+json or application/fhir+xml"); } var reader = IsContentTypeJSON ? FhirJsonParser.CreateFhirReader(raw) : FhirXmlParser.CreateFhirReader(raw, false); var p = (Resource)parser.Parse(reader, FhirHelper.ResourceTypeFromString(resourceType)); if (p.ResourceType != FhirHelper.GetResourceType(FhirHelper.ValidateResourceType(resourceType))) { OperationOutcome oo = new OperationOutcome(); oo.Issue = new System.Collections.Generic.List <OperationOutcome.IssueComponent>(); OperationOutcome.IssueComponent ic = new OperationOutcome.IssueComponent(); ic.Severity = OperationOutcome.IssueSeverity.Error; ic.Code = OperationOutcome.IssueType.Exception; ic.Diagnostics = "Resource provided is not of type " + resourceType; oo.Issue.Add(ic); var respconf = this.Request.CreateResponse(HttpStatusCode.BadRequest); respconf.Content = new StringContent(SerializeResponse(oo), Encoding.UTF8); respconf.Content.Headers.LastModified = DateTimeOffset.Now; respconf.Headers.TryAddWithoutValidation("Accept", CurrentAcceptType); respconf.Content.Headers.TryAddWithoutValidation("Content-Type", IsAccceptTypeJSON ? FHIRCONTENTTYPEJSON : FHIRCONTENTTYPEXML); return(respconf); } if (String.IsNullOrEmpty(p.Id) && headerid != null) { p.Id = headerid; } //Store resource regardless of type var dbresp = await ProcessSingleResource(p, resourceType, IsMatchVersionId); p = dbresp.Resource; var response = this.Request.CreateResponse(dbresp.Response == 1 ? HttpStatusCode.Created : HttpStatusCode.OK); response.Content = new StringContent("", Encoding.UTF8); response.Content.Headers.LastModified = p.Meta.LastUpdated; response.Headers.Add("Location", Request.RequestUri.AbsoluteUri + (headerid == null ? "/" + p.Id :"")); response.Headers.Add("ETag", "W/\"" + p.Meta.VersionId + "\""); //Extract and Save each Resource in bundle if it's a batch type if (p.ResourceType == ResourceType.Bundle && (((Bundle)p).Type == Bundle.BundleType.Batch || ((Bundle)p).Type == Bundle.BundleType.Message)) { Bundle source = (Bundle)p; /*Bundle results = new Bundle(); * results.Id = Guid.NewGuid().ToString(); * results.Type = Bundle.BundleType.Searchset; * results.Total = source.Entry.Count(); * results.Link = new System.Collections.Generic.List<Bundle.LinkComponent>(); * results.Link.Add(new Bundle.LinkComponent() { Url = Request.RequestUri.AbsoluteUri, Relation = "original" }); * results.Entry = new System.Collections.Generic.List<Bundle.EntryComponent>();*/ foreach (Bundle.EntryComponent ec in source.Entry) { var rslt = await ProcessSingleResource(ec.Resource, Enum.GetName(typeof(Hl7.Fhir.Model.ResourceType), ec.Resource.ResourceType)); //results.Entry.Add(new Bundle.EntryComponent() { Resource = rslt.Resource, FullUrl = FhirHelper.GetFullURL(Request, rslt.Resource) }); } } return(response); } catch (Exception e) { OperationOutcome oo = new OperationOutcome(); oo.Issue = new System.Collections.Generic.List <OperationOutcome.IssueComponent>(); OperationOutcome.IssueComponent ic = new OperationOutcome.IssueComponent(); ic.Severity = OperationOutcome.IssueSeverity.Error; ic.Code = OperationOutcome.IssueType.Exception; ic.Diagnostics = e.Message; oo.Issue.Add(ic); var response = this.Request.CreateResponse(HttpStatusCode.BadRequest); response.Headers.TryAddWithoutValidation("Accept", CurrentAcceptType); response.Content = new StringContent(SerializeResponse(oo), Encoding.UTF8); response.Content.Headers.TryAddWithoutValidation("Content-Type", IsAccceptTypeJSON ? FHIRCONTENTTYPEJSON : FHIRCONTENTTYPEXML); response.Content.Headers.LastModified = DateTimeOffset.Now; return(response); } }