Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integrating ASP.NET Webforms, WebAPI and AngularJS

I'm trying to get my first ASP.NET Webforms and AngularJS app up and running, but I'm struggling...

I created a blank, new ASP.NET 4.5.1 webforms app, and included WebAPI into the mix. I created a sample page for my list of customers, and a standard, EF6-based WebAPI CustomerController : ApiController with all the usual CRUD methods. I tested that WebAPI using Fiddler and low and behold - I get my 8 customers back from my database.

Getting this into AngularJS however has been a bit of a unsuccessful and highly frustrating experience ....

I included AngularJS from NuGet and that seems to have worked - no errors shown or anything, a pile of angular*.js files dumped into my Scripts folder.

I created a basic CustomerList.aspx page based on a master page which includes the <html lang="en" ng-app="TestAngular"> tag.

In order to get the data from the WebAPI service, I created my Angular module, and created a model inside the $scope, and created a service to fetch the data from the WebAPI:

Inside app.js:

var testModule = angular.module('TestAngular', [ ]);

testModule.controller('clientController', function ($scope, clientService) {
    $scope.model = [];
    clientService.getAllClients(function(results) {
        $scope.model.clients = results;
    });

    $scope.model.clientCount = $scope.model.clients.count;
});

testModule.factory('clientService', function ($http) {
    var srv = {};
    srv._baseUrl = 'http://localhost:56313';

    // Public API
    return {
        getAllClients: function(callback) {
            return $http.get(srv._baseUrl + '/api/Customer').success(callback);
        }
    };
});

From what limited Javascript understanding I have, this should define a clientService (the testModule.factory() call) that calls my WebAPI URL, gets the JSON back, and the callback function then stuffs those customers retrieved into the $scope.model.clients property, and the $scope.model.clientCount should also be calculated.

My ASPX page looks something like this:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="CustomerList.aspx.cs" Inherits="TestAngular.CustomerList" MasterPageFile="~/Site.Master"  %>

<asp:Content runat="server" ID="content" ContentPlaceHolderID="MainContent">
    <h2>My customers</h2>

    <div class="panel panel-default" data-ng-controller="clientController">
        We have a total of {{ model.clientCount }} clients in our database table ...

        <div class="list-group" data-ng-repeat="client in model.clients">
            <div class="list-group-item">
                <span>{{ client.Name }}</span><br/>
                <span>{{ client.Name2 }}</span><br/>
            </div>     
        </div>
    </div>
</asp:Content>

So the <div> with the data-ng-controller should "connect" that DIV with the AngularJS controller, should load the customers from the WebAPI call, and contain them in the model, which would then be rendered to the ASPX page using the data binding syntax ({{ client.Name }} etc.)

Trouble is: the call to the WebAPI happens and the correct 8 customers are returned, however, when I debug into the Javascript code, the clientCount is always undefined and the ASPX page only shows two empty rows which probably would correspond to customers that have been retrieved - but why only 2, not 8 ??

I'm totally lost and stuck - can anyone spot what I'm doing wrong, what I'm missing here??

like image 922
marc_s Avatar asked Oct 19 '22 16:10

marc_s


1 Answers

You are definately on the right track. At the moment, the problem is down to the clientService getAllClients method.

You should return the promise and then the data will chain through to the controller:

getAllClients: function(callback) {
    return $http.get(srv._baseUrl + '/api/Customer').success(callback);
}

You may also want to take a look at the count line:

$scope.model.clientCount = $scope.model.clients.count;

Before the promise is resolved (and the callback is invoked), $scope.model.clients will be undefined. So, I'd expect this line to fail. Also, to get the count of an array, you need length.

You should set the clientCount inside of the callback:

clientService.getAllClients(function(results) {
    $scope.model.clients = results;
    $scope.model.clientCount = $scope.model.clients.length;
});

Edit:

Typically, it is favoured to use the promise returned by $http. So, the controller would slightly change to:

clientService.getAllClients().then(function(response) {
    $scope.model.clients = response.results;
    $scope.model.clientCount = response.results.length;
});

And then the service would change to:

getAllClients: function() {
    return $http.get(srv._baseUrl + '/api/Customer');
}

Angular uses promises from $q instead of callbacks (for most apis). They make chaining and exception handling much easier.

Also, since, in this case, you know you are handling a promise from $http, you can use the success method in the controller as well:

clientService.getAllClients().success(function(results) {
    $scope.model.clients = results;
    $scope.model.clientCount = results.length;
});

success unwraps the response and sends only the body through to the callback.

like image 140
Davin Tryon Avatar answered Oct 27 '22 11:10

Davin Tryon