6

I am toying around with AngularJS and ASP.Net's Web API working together. I have a TestController in the API that's as simple as it gets:

public class TestController : ApiController {
    [HttpGet]
    public String Ping() {
        return "Pong";
    }
}

In Chrome I can go to http://localhost/api/Test/Ping and fiddler shows a simple "Pong" result and the browser shows:

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Pong</string>

Back in Angular JS, I setup a factory to call the Ping function:

app.factory('API', ['$resource', function ($resource) {
    return {
        Ping: function () {
            var result = $resource('api/Test/Ping', {}, { get: { method: 'GET' }, isArray: false });
            return result.get();
        }
    };
}]);

And a super simple controller:

app.controller('MyCtrl', [ '$scope', 'API', function ($scope, API) {
    $scope.CallTest = function () {
        API.Ping().$promise.then(function (response) {
            alert(response);
        });
    }
}]);

When I click the button that CallTest is bound to, it makes the call, the API returns Pong like it should but the return object is not exactly what I would expect. Response is an odd object:

{
    0: """,
    1: "P",
    2: "o",
    3: "n",
    4: "g",
    5: """,
    $promise: {...},
    $resolved: true
}

I don't receive any errors and everything syntactically is working fine. I was however hoping that response would be a string, especially since I set isArray to false in my API factory. I believe that angular has to return a "Resource" that has a $promise and $resolved on it so I now understand it may not work that way. Other than making a trivial wrapper in the WebAPI to return a string as a parameter on a Model, are there options available client side so that response could contain a normal string instead of this pseudo array? Like maybe response.data or something?

EDIT: When I request from the browser, the Accept header contains:

text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

Which results in the XML result above. When Angular requests the same url, the Accept header contains:

application/json, text/plain, */*

Which results in the content of the response simply being "Pong"

4
  • Why aren't you just using JSON.net in your web api and returning json or a JObject to angular? Commented Sep 10, 2014 at 17:17
  • @Owen I could wrap it in JSON, XML, SOAP, anything, but a simple string should be the easiest thing to parse correctly. Commented Sep 10, 2014 at 17:21
  • From what I've found, dumping a literal into $resource turns that literal into a string array. I had this happen when passing a value to $resource to use as a parameter. If the value was not an assigned variable, the string was broken into an array. Assigning a variable with the value of the literal was the quickest way around this for me. Getting data back from my Web API, I only pass JObjects. Commented Sep 10, 2014 at 18:39
  • Here is where I posted on the gitHub commit that I discovered this. github.com/angular/angular.js/commit/… Commented Sep 10, 2014 at 18:42

2 Answers 2

10

As described in the docs, $resource is a factory which creates a resource object that lets you interact with RESTful server-side data sources.

In your case, you are not trying to interact with a proper RESTful data source, thus the behaviour seems strange.

Until you have a proper RESTful data source and while you just want to hit an API endpoint and retrieve a simple response (such as a string), you should be using the $http service:

$http.get('api/Test/Ping').success(function (data) {...})...

E.g.:

app.factory('API', ['$http', function ($http) {
    return {
        Ping: function () {
            return $http.get('api/Test/Ping');
        }
    };
}]);

app.controller('MyCtrl', ['$scope', 'API', function ($scope, API) {
    $scope.CallTest = function () {
        API.Ping().success(function (data) {
            alert(data);
        });
    };
}]);
Sign up to request clarification or add additional context in comments.

1 Comment

Good point. Ever since I started using $resource, I completely tune out the $http. This is a situation where it would be warranted.
0

As described in the Angular repository here, String literals are converted to objects when shallowClearAndCopy iterates over keys. In my case, passing a string literal to $resource caused the literal to become an array of characters. The first way I was able to get around this was to assign the literal to a variable and pass the variable through.

api.Trip.get(data.token) - Incorrect
api.Trip.get({token: data.token}) - Correct.

Seeing as you're coming from the Web API, this would most likely require your response being sent as a JObject or JToken. My Web API returns JObject using Newtonsoft's JSON.net library, and Angular hasn't skipped a beat yet.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.