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?
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.
Related
I got redirected from here: https://github.com/aspnet/AspNetCore/issues/11963
I'm in the process of converting a solution over from .Net 4.6 and i'm looking at metadata.
In the old solution I had a custom implementation of the data annotations metadata provider which I had extended like this ....
public class ApiMetadataProvider : DataAnnotationsModelMetadataProvider, IDisposable
{
public IResourceProvider ResourceProvider { get; }
public ICoreDataContext CoreDb { get; }
public ApiMetadataProvider(IResourceProvider resourceProvider, ICoreDataContext core)
{
ResourceProvider = resourceProvider;
CoreDb = core;
}
protected override ModelMetadata CreateMetadata(
IEnumerable<Attribute> attributes,
Type containerType,
Func<object> modelAccessor,
Type modelType,
string propertyName)
{
ModelMetadata modelMetadata = base.CreateMetadata(
attributes,
containerType,
modelAccessor,
modelType,
propertyName);
Type serverType = (modelType == typeof(string))
? typeof(string)
: modelType.ImplementsGenericInterface(typeof(IEnumerable<>)) ?? modelType;
if (serverType.IsGenericType && serverType.Name.StartsWith("Nullable") && typeof(Nullable<>).MakeGenericType(serverType.GenericTypeArguments) == serverType) { serverType = serverType.GenericTypeArguments[0]; }
modelMetadata.AdditionalValues.Add("ServerType", serverType.AssemblyQualifiedName);
SetTemplateHint(modelMetadata);
SetCustomAttributes(attributes, modelMetadata, modelType, propertyName);
SetResourceStrings(modelMetadata);
return modelMetadata;
}
....
}
... the key thing here is that I pull the base copy of the model meta for the given type and then manipulate it in my own custom ways (some of which is shown in the sample above).
I cut the rest out because there's quite a bit of it.
The net result is that from my own base generic controller I had an action that looked like this ...
protected MetadataContainer GetMetadataForType(Type type)
{
return new MetadataContainer(MetaProvider.GetMetadataForType(null, type));
}
Controllers would then often make decisions based on this.
I am looking to reproduce this behaviour, the key thing being the ability to get a customised version of the "final meta" from the stack (I gather from this: https://github.com/aspnet/Mvc/issues/2522 ... that meta is now a "chain of providers" in some fashion).
So I have a couple of questions ....
How can i add or remove / update custom "properties" / attributes in the meta information for a given type?
How can I get an instance of the meta that the stack sees as being the "final result" after all providers have been executed?
The existing solution often handed this meta information to client JS code to allow for "dynamic component construction" in the browser, is this a scenario that has any form of best practice that I can gather more advice from (perhaps you guys have a blog post or something to get me started)?
The answer was simple in the end ...
Don't bother doing any of this, build a cache of the reflection derived information and in the controller just serve it up.
This basically just means this is simple reflection code to extract the relevant type info wanted.
I have an existing controller where [FromBody] is working as expect in HttpPost methods. When writing tests, I found it necessary to use a customer serializer in order to avoid a circular reference due to the parent object having a child that references the parent. The serializer uses these settings:
JsonSerializerSettings Settings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Auto,
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
ObjectCreationHandling = ObjectCreationHandling.Auto
};
The problem is that [FromBody] is unable to parse the object produced by that serializer (it throws a Newtonsoft.Json.JsonSerializationException). However, if I change [FromBody] to be dynamic, e.g.
public IActionResult Update([FromBody]dynamic json)
{
var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<MyType>(json);
...
}
then I'm able to parse the object without a problem. This is confusing me, and I am wondering if I can override what WebApi does for [FromBody] so that I can get the correct object without having to make every method accept a dynamic parameter?
Here is something I did in my WebAPI. I had a Team entity which has many Player entities. Each Player entity had a reference to a Team entity. When I retrieve a Player it will have a Team, and Team will have all players and each player again will have have a team in it.
To Handle this, I had to change the approach of exposing data and using the data. I created Models for each entities and exposed the model objects. Model objects are flat objects. In case of Player model, it has a TeamID and Team Name rather than using a whole Team object.
I used a Model-Factory to create Models out of Entities and Entities out of Models. In WebAPI controller, used something like below
[ModelValidator]
public IHttpActionResult Post([FromBody] DoctorModel doctorModel)
{
try
{
var doctorEntity = ModelFactory.Create(doctorModel);
doctorEntity.UserId = Userid;
var doctor = UnitOfWork.Doctors.Add(doctorEntity);
var doctorModelNew = ModelFactory.Create(doctor);
return Ok(doctorModelNew);
}
catch (Exception ex)
{
//Logging
#if DEBUG
return InternalServerError(ex);
#endif
return InternalServerError();
}
}
I am developing an ASP.NET application that uses ODataApiController. The application shows users a grid by querying data and showing it in a table. I would like the ability to export to a number of different formats, including CSV and a custom XML format. Ideally, I would just take the same OData query the grid uses, set the Accepts header, and get back CSV or XML.
I've created MediaTypeFormatters to do what I need, but they only work with "regular" ApiController, not ODataApiController. Looking at the code in github, I see that OData has it's own MediaTypeFormatter scheme to handle various cases, and built in XML and JSON formatters. But I can't see how to hook into this to provide custom formats. I've attempted inheriting ODataMediaTypeFormatter, but a breakpoint set on it never hits.
I am only really interested in output formats here. How can I extend OdataApi to output different formats?
You can use MediaTypeFormatter on OData queries as well. Just add a new class to your project that inherit MediaTypeFormatter. Then add this to your WebApiConfig file on Register:
config.Formatters.Add(new JSONPFormatter(new QueryStringMapping("$format","jsonp","application/javascript")));
If you then query your entity with the $format=jsonp it will return the entity as JSONP. You can also request it with the contenttype application/javascript to get a JSONP return.
Here is a full example for a MediaFormatter for JSONP return. You could easily change it for your need:
using MyProject.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.ServiceModel.Syndication;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
using Newtonsoft.Json;
namespace SMSIdent.Modules.Formatter
{
/// <summary>
/// Adds a $format=jsop to all odata query
/// </summary>
public class JSONPFormatter : MediaTypeFormatter
{
private readonly string jsMIME = "application/javascript";
public JSONPFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue(jsMIME));
}
public JSONPFormatter(MediaTypeMapping mediaTypeMapping) : this()
{
MediaTypeMappings.Add(mediaTypeMapping);
}
//THis checks if you can POST or PUT to this media-formater
public override bool CanReadType(Type type)
{
return false;
}
//this checks if you can GET this media. You can exclude or include your Resources by checking for their types
public override bool CanWriteType(Type type)
{
return true;
}
//This actually takes the data and writes it to the response
public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
{
//you can cast your entity
//MyType entity=(MyType) value;
var callback=HttpContext.Current.Request.Params["callback"];
return Task.Factory.StartNew(() =>
{
using (StreamWriter sw = new StreamWriter(writeStream))
{
if (string.IsNullOrEmpty(callback))
{
callback = "values";
}
sw.Write(callback + "(" + JsonConvert.SerializeObject(value, Newtonsoft.Json.Formatting.None,
new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
}) + ")");
}
});
}
}
}
Note: I'am using Web API 2. I don't know exactly if it also works in Web Api 1.
I am working on a legacy system that has been using .Net remoting for its communication.Now I want to write new client and server side web-api code to do the same thing.
Here's a sample code that I am dealing with :
public SearchResult Search(Condition condition,Sort sort,PageInfo pageInfo)
{
......
}
I would like to be able to have a web-api action with the same signature that gets its value form Uri , thus :
[HttpGet()]
public SearchResult Search([FromUri]Condition condition,[FromUri]Sort sort,[FromUri]PageInfo pageInfo)
{
......
}
Here are my questions :
Is it possible to have such an action in a web-api ?
If yes, How can I pass these parameters using HttpClient ?
You can setup your Route attribute to accept as many parameters as you like.
[Route("/api/search/{condition}/{sort}/{pageInfo}")]
[HttpGet]
public HttpResponseMessage Search( string condition, string sort, string pageInfo) {
...
}
This would mean that your url changes from
/Search?condition=test&sort=first&pageInfo=5
to
/Search/test/first/5
Alternatively, bundle the Condition, Sort and PageInfo objects into single Json class, and pass this object to your route:
[Route("/api/search/{SortParams}")]
[HttpGet]
public HttpResponseMessage Search( object sortParams) {
// deserialize sortParams into C# object structure
}
Have a look at this question : C# .net how to deserialize complex object of JSON
I have an n-tier application, whereas the core web service is built with Web API. many of the web service's methods are set as HTTPGET and accept a DTO object as parameter. my client app, built with MVC 5 is using HttpClient to call this API.
so it seems that by using client.PostAsJsonAsync() I can pass an object, whereas client.GetAsync() doesn't allow me to do that. this forces me to explicitly specify the properties of DTO in the URL, which works, but seem a bit redundant.
Can somebody explain why this is not possible through a GET call and suggest a better practice?
Why does passing data in the URI seem redundant? The HTTP spec says that GET methods are not to use content sent in the body. This is primarily to facilitate caches being able to cache responses based only on the URI, method and headers. Requiring caches to parse the body of a message to identify a resource would be very inefficient.
Here is an basic extension method that will do the grunt work for you,
public static class UriExtensions
{
public static Uri AddToQuery<T>(this Uri requestUri,T dto)
{
Type t = typeof (T);
var properties = t.GetProperties();
var dictionary = properties.ToDictionary(info => info.Name,
info => info.GetValue(dto, null).ToString());
var formContent = new FormUrlEncodedContent(dictionary);
var uriBuilder = new UriBuilder(requestUri) {Query = formContent.ReadAsStringAsync().Result};
return uriBuilder.Uri;
}
}
and assuming you have a DTO like this,
public class Foo
{
public string Bar { get; set; }
public int Baz { get; set; }
}
you can use it like this.
[Fact]
public void Foo()
{
var foo = new Foo()
{
Bar = "hello world",
Baz = 10
};
var uri = new Uri("http://example.org/blah");
var uri2 = uri.AddToQuery(foo);
Assert.Equal("http://example.org/blah?Bar=hello+world&Baz=10", uri2.AbsoluteUri);
}