private HttpWebRequest prepareRequest(string method, Uri uri, object data, IEnumerable <Tag> tags, bool expectBundleResponse) { byte[] body = null; Uri api = uri; if (UseFormatParam) { api = api.AddParam(HttpUtil.RESTPARAM_FORMAT, ContentType.BuildFormatParam(PreferredFormat)); } var req = initializeRequest(api, method); if (!UseFormatParam) { req.Accept = ContentType.BuildContentType(PreferredFormat, forBundle: expectBundleResponse); } if (data is Binary) { var bin = (Binary)data; body = bin.Content; req.ContentType = bin.ContentType; } else if (data is Resource) { body = PreferredFormat == ResourceFormat.Xml ? FhirSerializer.SerializeResourceToXmlBytes((Resource)data) : FhirSerializer.SerializeResourceToJsonBytes((Resource)data); req.ContentType = ContentType.BuildContentType(PreferredFormat, false); } else if (data is Bundle) { body = PreferredFormat == ResourceFormat.Xml ? FhirSerializer.SerializeBundleToXmlBytes((Bundle)data) : FhirSerializer.SerializeBundleToJsonBytes((Bundle)data); req.ContentType = ContentType.BuildContentType(PreferredFormat, true); } else if (data is TagList) { body = PreferredFormat == ResourceFormat.Xml ? FhirSerializer.SerializeTagListToXmlBytes((TagList)data) : FhirSerializer.SerializeTagListToJsonBytes((TagList)data); req.ContentType = ContentType.BuildContentType(PreferredFormat, false); } if (tags != null) { req.Headers[HttpUtil.CATEGORY] = HttpUtil.BuildCategoryHeader(tags); } if (body != null) { writeBody(req, body); } return(req); }
/// <summary> /// Update (or create) a resource at a given endpoint /// </summary> /// <param name="entry">A ResourceEntry containing the resource to update</param> /// <param name="versionAware">Whether or not version aware update is used.</param> /// <typeparam name="TResource">The type of resource that is being updated</typeparam> /// <returns>The resource as updated on the server. Throws an exception when the update failed, /// in particular may throw an exception when the server returns a 409 when a conflict is detected /// while using version-aware updates or 412 if the server requires version-aware updates.</returns> public ResourceEntry <TResource> Update <TResource>(ResourceEntry <TResource> entry, bool versionAware = false) where TResource : Resource, new() { if (entry == null) { throw new ArgumentNullException("entry"); } if (entry.Resource == null) { throw new ArgumentException("Entry does not contain a Resource to update", "entry"); } if (entry.Id == null) { throw new ArgumentException("Entry needs a non-null entry.id to send the update to", "entry"); } if (versionAware && entry.SelfLink == null) { throw new ArgumentException("When requesting version-aware updates, Entry.SelfLink may not be null.", "entry"); } string contentType = null; byte[] data = null; if (entry.Resource is Binary) { var bin = entry.Resource as Binary; data = bin.Content; contentType = bin.ContentType; } else { data = PreferredFormat == ContentType.ResourceFormat.Xml ? FhirSerializer.SerializeResourceToXmlBytes(entry.Resource) : FhirSerializer.SerializeResourceToJsonBytes(entry.Resource); contentType = ContentType.BuildContentType(PreferredFormat, false); } var req = createRequest(entry.Id, false); req.Method = "PUT"; req.ContentType = contentType; prepareRequest(req, data, entry.Tags); // If a version id is given, post the data to a version-specific url if (versionAware) { req.Headers[HttpRequestHeader.ContentLocation] = entry.SelfLink.ToString(); } return(doRequest(req, new HttpStatusCode[] { HttpStatusCode.Created, HttpStatusCode.OK }, () => resourceEntryFromResponse <TResource>())); }
/// <summary> /// Validates whether the contents of the resource would be acceptable as an update /// </summary> /// <param name="entry">The entry containing the updated Resource to validate</param> /// <returns>null if validation succeeded, otherwise returns OperationOutcome detailing the validation errors. /// If the server returned an error, but did not return an OperationOutcome resource, an exception will be /// thrown.</returns> public OperationOutcome Validate <TResource>(ResourceEntry <TResource> entry) where TResource : Resource, new() { if (entry == null) { throw new ArgumentNullException("entry"); } if (entry.Resource == null) { throw new ArgumentException("Entry does not contain a Resource to validate", "entry"); } if (entry.Id == null) { throw new ArgumentException("Entry needs a non-null entry.id to use for validation", "entry"); } string contentType = ContentType.BuildContentType(PreferredFormat, false); byte[] data = PreferredFormat == ContentType.ResourceFormat.Xml ? FhirSerializer.SerializeResourceToXmlBytes(entry.Resource) : FhirSerializer.SerializeResourceToJsonBytes(entry.Resource); var rl = new ResourceLocation(entry.Id); rl.Operation = ResourceLocation.RESTOPER_VALIDATE; var req = createRequest(rl.ToUri(), false); req.Method = "POST"; req.ContentType = contentType; prepareRequest(req, data, entry.Tags); try { doRequest(req, HttpStatusCode.OK, () => true); return(null); } catch (FhirOperationException foe) { if (foe.Outcome != null) { return(foe.Outcome); } else { throw foe; } } }
public void AvoidBOMUse() { Bundle b = new Bundle(); var data = FhirSerializer.SerializeBundleToJsonBytes(b); Assert.IsFalse(data[0] == Encoding.UTF8.GetPreamble()[0]); data = FhirSerializer.SerializeBundleToXmlBytes(b); Assert.IsFalse(data[0] == Encoding.UTF8.GetPreamble()[0]); Patient p = new Patient(); data = FhirSerializer.SerializeResourceToJsonBytes(p); Assert.IsFalse(data[0] == Encoding.UTF8.GetPreamble()[0]); data = FhirSerializer.SerializeResourceToXmlBytes(p); Assert.IsFalse(data[0] == Encoding.UTF8.GetPreamble()[0]); }
public static HttpResponseMessage ToHttpResponseMessage(this OperationOutcome outcome, ResourceFormat target, HttpRequestMessage request) { byte[] data = null; if (target == ResourceFormat.Xml) { data = FhirSerializer.SerializeResourceToXmlBytes((OperationOutcome)outcome); } else if (target == ResourceFormat.Json) { data = FhirSerializer.SerializeResourceToJsonBytes((OperationOutcome)outcome); } HttpResponseMessage response = new HttpResponseMessage(); //setResponseHeaders(response, target); response.Content = new ByteArrayContent(data); setContentHeaders(response, target); return(response); }
public void SetBody(Resource resource, ResourceFormat format) { if (resource == null) { throw Error.ArgumentNull("resource"); } if (resource is Binary) { var bin = (Binary)resource; _body = bin.Content; _contentType = bin.ContentType; } else { _body = format == ResourceFormat.Xml ? FhirSerializer.SerializeResourceToXmlBytes(resource, summary: false) : FhirSerializer.SerializeResourceToJsonBytes(resource, summary: false); _contentType = ContentType.BuildContentType(format, forBundle: false); } }
public void SerializationDoesNotEmitXmlHeader() { Bundle b = createTestBundle(); var actual = FhirSerializer.SerializeBundleToXml(b); Assert.IsFalse(actual.StartsWith("<?xml")); var data = FhirSerializer.SerializeBundleToXmlBytes(b); actual = System.Text.Encoding.UTF8.GetString(data); Assert.IsFalse(actual.StartsWith("<?xml")); Patient p = new Patient(); actual = FhirSerializer.SerializeResourceToXml(p); Assert.IsFalse(actual.StartsWith("<?xml")); data = FhirSerializer.SerializeResourceToXmlBytes(p); actual = System.Text.Encoding.UTF8.GetString(data); Assert.IsFalse(actual.StartsWith("<?xml")); }
/// <summary> /// Create a resource /// </summary> /// <param name="collectionEndpoint">Endpoint where the resource is sent to be created</param> /// <param name="resource">The resource instance to create</param> /// <param name="tags">Optional. List of Tags to add to the created instance.</param> /// <returns>The resource as created on the server, or an exception if the create failed.</returns> /// <typeparam name="TResource">The type of resource to create</typeparam> /// <remarks><para>The returned resource need not be the same as the resources passed as a parameter, /// since the server may have updated or changed part of the data because of business rules.</para> /// </remarks> public ResourceEntry <TResource> Create <TResource>(Uri collectionEndpoint, TResource resource, IEnumerable <Tag> tags = null) where TResource : Resource, new() { if (collectionEndpoint == null) { throw new ArgumentNullException("collectionEndpoint"); } if (resource == null) { throw new ArgumentNullException("resource"); } string contentType = null; byte[] data = null; if (resource is Binary) { var bin = resource as Binary; data = bin.Content; contentType = bin.ContentType; } else { data = PreferredFormat == ContentType.ResourceFormat.Xml ? FhirSerializer.SerializeResourceToXmlBytes(resource) : FhirSerializer.SerializeResourceToJsonBytes(resource); contentType = ContentType.BuildContentType(PreferredFormat, false); } var req = createRequest(collectionEndpoint, false); req.Method = "POST"; req.ContentType = contentType; prepareRequest(req, data, tags); return(doRequest(req, HttpStatusCode.Created, () => resourceEntryFromResponse <TResource>())); }
/// <summary> /// Deserialize the request /// </summary> public void DeserializeRequest(Message request, object[] parameters) { try { HttpRequestMessageProperty httpRequest = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name]; string contentType = httpRequest.Headers[HttpRequestHeader.ContentType]; UriTemplateMatch templateMatch = (UriTemplateMatch)request.Properties.SingleOrDefault(o => o.Value is UriTemplateMatch).Value; // Not found if (templateMatch == null) { throw new WebFaultException(HttpStatusCode.NotFound); } for (int pNumber = 0; pNumber < parameters.Length; pNumber++) { var parm = this.m_operationDescription.Messages[0].Body.Parts[pNumber]; // Simple parameter if (templateMatch.BoundVariables.AllKeys.Any(o => o.ToString().ToLower() == parm.Name.ToLower())) { var rawData = templateMatch.BoundVariables[parm.Name]; parameters[pNumber] = Convert.ChangeType(rawData, parm.Type); } // Use XML Serializer else if (contentType?.StartsWith("application/xml+fhir") == true) { var messageFormatProperty = (WebBodyFormatMessageProperty)request.Properties[WebBodyFormatMessageProperty.Name]; XmlDictionaryReader rawReader = request.GetReaderAtBodyContents(); switch (messageFormatProperty.Format) { case WebContentFormat.Raw: { rawReader.ReadStartElement("Binary"); byte[] rawBody = rawReader.ReadContentAsBase64(); using (MemoryStream ms = new MemoryStream(rawBody)) { using (XmlReader bodyReader = XmlReader.Create(ms)) { while (bodyReader.NodeType != XmlNodeType.Element) { bodyReader.Read(); } Type eType = s_knownTypes.FirstOrDefault(o => o.GetCustomAttribute <XmlRootAttribute>()?.ElementName == bodyReader.LocalName && o.GetCustomAttribute <XmlRootAttribute>()?.Namespace == bodyReader.NamespaceURI); XmlSerializer xsz = s_serializers[eType]; parameters[pNumber] = xsz.Deserialize(bodyReader); } } } break; case WebContentFormat.Xml: { using (rawReader) { rawReader.MoveToStartElement(); Type eType = s_knownTypes.FirstOrDefault(o => o.GetCustomAttribute <XmlRootAttribute>()?.ElementName == rawReader.LocalName && o.GetCustomAttribute <XmlRootAttribute>()?.Namespace == rawReader.NamespaceURI); this.m_traceSource.TraceEvent(TraceEventType.Information, 0, "Contract: {0}", typeof(IFhirServiceContract).Name); this.m_traceSource.TraceEvent(TraceEventType.Information, 0, "Attempting to deserialize type: {0}", eType?.Name); XmlSerializer xsz = s_serializers[eType]; parameters[pNumber] = xsz.Deserialize(rawReader); } } break; } } // Use JSON Serializer else if (contentType?.StartsWith("application/json+fhir") == true) { // Read the binary contents form the WCF pipeline XmlDictionaryReader bodyReader = request.GetReaderAtBodyContents(); bodyReader.ReadStartElement("Binary"); byte[] rawBody = bodyReader.ReadContentAsBase64(); // Now read the JSON data Object fhirObject = null; using (MemoryStream mstream = new MemoryStream(rawBody)) using (StreamReader sr = new StreamReader(mstream)) { string fhirContent = sr.ReadToEnd(); fhirObject = FhirParser.ParseFromJson(fhirContent); } // Now we want to serialize the FHIR MODEL object and re-parse as our own API bundle object MemoryStream ms = new MemoryStream(FhirSerializer.SerializeResourceToXmlBytes(fhirObject as Hl7.Fhir.Model.Resource)); XmlSerializer xsz = s_serializers[fhirObject?.GetType()]; parameters[0] = xsz.Deserialize(ms); } else if (contentType != null)// TODO: Binaries { throw new InvalidOperationException("Invalid request format"); } } } catch (Exception e) { this.m_traceSource.TraceEvent(TraceEventType.Error, e.HResult, e.ToString()); throw; } }