2
votes

I have a an Ember Cli project that runs on the localhost:4200 and an asp.net webapi project that runs on localhost:56967. Both projects run fine seperatly: I can start up my Ember app and test several routes, looks fine and I can visit my api (for example: api/products) and i see my response.

The problem I'm having is hooking the two things up with each other.

Adapter

 export default DS.RESTAdapter.extend({
      host: 'http://localhost:56967',
      namespace: 'api'
 });

I first ran into some Cors-problems, but i fixed the contentSecurityPolicy in my Ember app and enabled Cors on my Api.

When I go to the products route I can see the request to the Api gets accepted and the Api replies the Json answer. However, I'm failing to serialize the model so I can use it in my Ember App.

This is my response from the Api

  [{"ProductId":1,"Name":"Product 1","Description":"Category 1"},{"ProductId":2,"Name":"Product 2","Description":"Category 2"},{"ProductId":3,"Name":"Product 3","Description":"Category 3"}] 

Ember model for a product

export default DS.Model.extend({
    name : DS.attr('string'),
    description: DS.attr('string')
});

Asp.net model for a product:

public class Product
{
    public int ProductId { get; set; }
    [Required]
    public string Name { get; set; }
    public string Description { get; set; }
}

I know I have to serialize the Api response to make it "readable" Json for my Ember App. The question now: is it better to change the formatting on the Api? Or make a good serializer? How would I go about making the serializer? It's hard to find some decent tutorials. I tried this but that's not working:

 export default DS.RESTSerializer.extend({
      primaryKey: 'productId'
  });

This is the error i'm getting:

  Error while processing route: products No model was found for '0' Error: No model was found for '0'

EDIT After trying the suggested serializer and some ASP.NET serializers as well I still couldn't get it to work. Today I found this project : http://jsonapi.codeplex.com/. It's a Nuget Package that helps the output of your ASP.NET API to be complient with the json.api standard. I got this working with my Ember-data in no time. Just add the correct header in your rest adapter that it looks like this:

 import DS from 'ember-data';

 export default DS.RESTAdapter.extend({
       host: 'http://localhost:57014',
       namespace: 'api',
       headers:{
          "Accept": "application/vnd.api+json"
        }
 });

And in your Asp.net model just add

[JsonObject(Title="product")]
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }

}

It will pluralize your output to this:

{
"products": [
    {
        "id": "1",
        "name": "Product 1",
        "description": "Category 1"
    },
    {
        "id": "2",
        "name": "Product 2",
        "description": "Category 2"
    },
    {
        "id": "3",
        "name": "Product 3",
        "description": "Category 3"
    }
]
}

It's still in Alpha state but looks promising. A small note on the pluralization: it just adds the -s to your model name, something to keep in mind.

1
Do you mind going into more detail about how you got JSONAPI working with ember js? Did you use the ember-json-api (github.com/kurko/ember-json-api)? I've been trying to get this to work for days and any help would be much appreciated!oalbrecht

1 Answers

6
votes

The main issue is that Asp Web API returns the following response:

[
  {
    "ProductId":1,
    "Name":"Product 1",
    "Description":"Category 1"
  }
]

But Ember Data expects the server to respond with the following format instead:

{
  "products": [
    {
      "productId": 1,
      "name": "Product 1",
      "description": "Category 1"
    }
  ]
}

You could update the response from the Web API server to be in the format that Ember expects, but it's easier to create a Serializer in Ember to map the data from Asp Web API into Ember's format.

I wrote a detailed blog post that explains how to create an Ember Serializer to perform this mapping.

Be sure to read the blog post to understand what is going on in the Serializer. But as a reference, here is what I believe your serializer should look like:

App.ProductSerializer = DS.RESTSerializer.extend({
  primaryKey: 'productId',

  extract: function(store, primaryType, payload, id, requestType) {
    if (payload.length) {
      for (var i = 0; i < payload.length; i++) {
        this.mapRecord(payload[i]); 
      }
    } else {
      this.mapRecord(payload);
    }

    payloadWithRoot = {};
    payloadWithRoot[primaryType.typeKey] = payload;

    this._super(store, primaryType, payloadWithRoot, id, requestType)
  },

  mapRecord: function(record) {
    for (var property in record) {
      var value = record[property];
      record[property.camelize()] = value;
      delete record[property];
      return record;
    }
  },

  serializeIntoHash: function(hash, type, record, options) {
    var recordJSON = record.toJSON();
    for (var property in recordJSON) {
      var value = recordJSON[property];
      hash[property.capitalize()] = value
    }
  }
});