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); } }
/// <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> /// Serialize the reply /// </summary> public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result) { try { // Outbound control var format = WebContentFormat.Raw; Message request = OperationContext.Current.RequestContext.RequestMessage; HttpRequestMessageProperty httpRequest = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name]; string accepts = httpRequest.Headers[HttpRequestHeader.Accept], contentType = httpRequest.Headers[HttpRequestHeader.ContentType], formatParm = httpRequest.QueryString; Message reply = null; // Result is serializable if (result?.GetType().GetCustomAttribute <XmlTypeAttribute>() != null || result?.GetType().GetCustomAttribute <JsonObjectAttribute>() != null) { XmlSerializer xsz = s_serializers[result.GetType()]; MemoryStream ms = new MemoryStream(); xsz.Serialize(ms, result); format = WebContentFormat.Xml; contentType = "application/xml+fhir"; ms.Seek(0, SeekOrigin.Begin); // The request was in JSON or the accept is JSON if (accepts?.StartsWith("application/json+fhir") == true || contentType?.StartsWith("application/json+fhir") == true || formatParm.Contains("_format=json")) { // Parse XML object Object fhirObject = null; using (StreamReader sr = new StreamReader(ms)) { String fhirContent = sr.ReadToEnd(); var parser = new FhirXmlParser(); parser.Settings.AllowUnrecognizedEnums = true; fhirObject = parser.Parse <Resource>(fhirContent); } // Now we serialize to JSON byte[] body = FhirSerializer.SerializeResourceToJsonBytes(fhirObject as Hl7.Fhir.Model.Resource); // Prepare reply for the WCF pipeline format = WebContentFormat.Raw; contentType = "application/json+fhir"; reply = Message.CreateMessage(messageVersion, this.m_operationDescription?.Messages[1]?.Action, new RawBodyWriter(body)); } // The request was in XML and/or the accept is JSON else { reply = Message.CreateMessage(messageVersion, this.m_operationDescription?.Messages[1]?.Action, XmlDictionaryReader.Create(ms)); } } else if (result is XmlSchema) { MemoryStream ms = new MemoryStream(); (result as XmlSchema).Write(ms); ms.Seek(0, SeekOrigin.Begin); format = WebContentFormat.Xml; contentType = "text/xml"; reply = Message.CreateMessage(messageVersion, this.m_operationDescription.Messages[1].Action, XmlDictionaryReader.Create(ms)); } else if (result is Stream) // TODO: This is messy, clean it up { reply = Message.CreateMessage(messageVersion, this.m_operationDescription.Messages[1].Action, new RawBodyWriter(result as Stream)); } reply.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(format)); WebOperationContext.Current.OutgoingResponse.ContentType = contentType; WebOperationContext.Current.OutgoingResponse.Headers.Add("X-PoweredBy", String.Format("{0} v{1} ({2})", Assembly.GetEntryAssembly().GetName().Name, Assembly.GetEntryAssembly().GetName().Version, Assembly.GetEntryAssembly().GetCustomAttribute <AssemblyInformationalVersionAttribute>()?.InformationalVersion)); WebOperationContext.Current.OutgoingResponse.Headers.Add("X-GeneratedOn", DateTime.Now.ToString("o")); return(reply); } catch (Exception e) { this.m_traceSource.TraceEvent(TraceEventType.Error, e.HResult, e.ToString()); throw; } }