HL7 FHIR serialisation to json in asp.net web api

吃可爱长大的小学妹 提交于 2019-11-30 21:08:29

Although the newer version of the HL7.Fhir NuGet package (currently in beta) will carry additional [DataContract] and [DataMember] attributes, and thus prevent these kind of errors, the standard .NET DataContract serializer will not be able to serialize in-memory POCO's to the correct FHIR XML and Json representation. The FHIR serialization has specific rules about how both XML and json are used, which is hard, if not impossible, to configure using the (limited) possibilities of the DataContract serializer.

However, it's also not necessary to invoke the FhirSerializer for each call as you showed in your codesnippet (in fact, that would be an WebApi anti-pattern). For example, our FHIR server (at http://spark.furore.com/fhir) is based on WebApi and uses a custom MediaTypeFormatter to handle this. To get a taste of what that looks like, we have created two formatters, one for json and one for xml:

public class JsonFhirFormatter : MediaTypeFormatter
{
        public JsonFhirFormatter() : base()
        {
            foreach (var mediaType in ContentType.JSON_CONTENT_HEADERS)
                SupportedMediaTypes.Add(new MediaTypeHeaderValue(mediaType));
        }
}

This tells the framework this formatter will take any of the formats in ContentType.JSON_CONTENT_HEADERS (which are application/json and some common variants) and is able to parse and read FHIR ModelTypes:

public override bool CanReadType(Type type)
{
    return type == typeof(ResourceEntry) || type == typeof(Bundle) || (type == typeof(TagList));
}

public override bool CanWriteType(Type type)
{
    return type == typeof(ResourceEntry) || type == typeof(Bundle) || (type == typeof(TagList)) || type == typeof(OperationOutcome);
}

Finally, you have to override the ReadFromStreamAsync and WriteToStreamAsync methods:

public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
{
    // Some code left out...
    XmlWriter writer = new XmlTextWriter(writeStream, Encoding.UTF8);

    if (type == typeof(ResourceEntry))
    {
        ResourceEntry entry = (ResourceEntry)value;
        FhirSerializer.SerializeResource(entry.Resource, writer);

        content.Headers.SetFhirTags(entry.Tags);
    }

Now, once you've done that, your Controller can simply do:

[HttpGet, Route("metadata")]
public ResourceEntry Metadata()
{
   return service.Conformance();
}

[HttpOptions, Route("")]
public ResourceEntry Options()
{
   return service.Conformance();
}

Note that our server does not use Resources as parameters and return values in the controller. Resources won't allow you to capture important metadata (like the id, version-id, last modified date etc). By using ResourceEntry in my controller, this data can be passed around with the resource data and the WebApi framework can bind this metadata to the appropriate HTTP headers.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!