HL7 FHIR serialisation to json in asp.net web api
Asked Answered
O

1

5

I'm using the HL7.Fhir nuget package 0.9.3 created by Ewout Kramer.

I am tying it up with ASP.NET Web API, but unfortunately the built in JSON serialization isn't generating the JSON correctly. It contains lots of this:

"<IdentifierElement>k__BackingField"

As suggested by the framework, this code works...

public HttpResponseMessage GetConformance()
    {
        var conformance = new Conformance();
        var json = FhirSerializer.SerializeResourceToJson(conformance);
        return new HttpResponseMessage{Content = new StringContent(json)};
    }

but this will become quite repetitive and isn't following the "by convention" json/xml serialization methods of Web API.

Are there any other FHIR objects packages available or should I just write my own?

Opponent answered 14/1, 2014 at 15:52 Comment(0)
A
10

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.

Ablepsia answered 15/1, 2014 at 12:9 Comment(3)
Thanks Ewout. I'm still using the stable 0.9.3 nuget packages, so missing a few things, but this is really helpful. You posted the XML snippet in the 3rd code block, instead of the JSON one, but I get the idea. Thanks :)Opponent
@Ewout, you can add the [HttpOptions ...] attribute to the Metadata method. You don't need to add extra methods.Cherian
@Ewout You created the custom class JsonFhirFormatter. But how to attach this formatter to controller's method (ie Metadata()).Spindell

© 2022 - 2024 — McMap. All rights reserved.