Angular Interceptors - Ajax Notifications

Building on our last application about a nifty way of building out your angular routes, we will focus on Interceptors. An interceptor can be used to preprocess/postprocess requests and responses. This is commonly used for authentication, error handling, data manipulation, or global config changes on the request.

The source code for this post is located on Plunker.

To give you an example, many server side systems may provide an access token that is required to be sent with each request. This usually takes the form of either an encrypted token or a cookie. We would then be required to send this information on each request as a header typically. An interceptor would allow us to inject this information for every request so that it globally occurs.

interceptor.png

Another example that is much easier to demonstrate is an ajax loading icon. Every time in angular we make a request to the server, we might want to inform the user the application is doing something. A typical way to show this would be via an ajax loading icon so let’s talk about how we can make a global ajax loading icon that is aware of all ajax events.

The icon

The first thing we need is an icon. For my demo, I’ll just use one from cdnjs:

http://cdnjs.cloudflare.com/ajax/libs/semantic-ui/0.16.1/images/loader-large.gif

Directive

Okay, that’s easy enough, but what now? After thinking about it for a few minutes, I’ve decided to create a directive that will show and/or hide this icon based on some loading condition we will have to figure out. The directive is easy enough:

  .directive('ajaxLoader', ['$rootScope', function($rootScope) {
     return {
        restrict: 'EAC',
        template: '<img src="http://cdnjs.cloudflare.com/ajax/libs/semantic-ui/0.16.1/images/loader-large.gif" ng-show="doingAjax" />',
        link: function(scope, element) {
        }
     }
  }]);

All our directive is doing is creating an image. Also, I know that we will need to hide and show it so I’ve added an ng-show.

It’s use is simple:

<ajaxLoader></ajaxLoader>

Easy enough, but what about the interceptor?

Interception

The interceptor is just a fancy word for another factory that gets called in the request cycle for angular’s $http.

.factory('ajaxInterceptor', function($q, $rootScope) {
return {

  'request': function(config) {
    // do something on success
    $rootScope.$broadcast('ajax', true);
    return config;
  },
 'requestError': function(rejection) {
    // do something on error
    $rootScope.$broadcast('ajax', false);
    if (canRecover(rejection)) {
      return responseOrNewPromise
    }
    return $q.reject(rejection);
  },
  'response': function(response) {
    // do something on success
    $rootScope.$broadcast('ajax', false);
    return response;
  },
 'responseError': function(rejection) {
    // do something on error
    $rootScope.$broadcast('ajax', false);
    if (canRecover(rejection)) {
      return responseOrNewPromise
    }
    return $q.reject(rejection);
  }
};
});

This factory is going to broadcast out a true or false depending on if we are pre-ajax or post-ajax. This is all accomplished via angulars [$scope.$broadcast]. Based on this condition we will show or hide our icon. There are four kinds of interceptors: request, requestError, response and responseError. Wiring it up to fire is easy enough.

In our app.config:

$httpProvider.interceptors.push('ajaxInterceptor');

Now, anytime we perform an ajax request using $http, we will get a broadcast flag sent through the app.

Back to our directive

Our directive is a little lean, I mean it doesn’t do anything right now except show an image. Now we will wire up our directive to listen to the ajax event.

  .directive('ajaxLoader', ['$rootScope', function($rootScope) {
     return {
        restrict: 'EAC',
        template: '<img src="http://cdnjs.cloudflare.com/ajax/libs/semantic-ui/0.16.1/images/loader-large.gif" ng-show="doingAjax" />',
        link: function(scope, element) {
           $rootScope.$on('ajax', function(event, val) {
            scope.doingAjax= val;  
            scope.$apply();
           });

        }
     }
  }]);

Now, we can subscribe via $rootScope.$on to the event and set our scope variable that is being used with ng-show to the state of the ajax condition. It will turn on and off based on what our interceptor is doing in all our ajax calls.

In this way we can intercept all of the ajax calls to our application. This can help us with authentication, error checking and logging, UI events, or just about any application state that is determined by or performed through ajax.

The source code is located on Plunker.

Routing gone wild - Taming those Angular routes

Sometimes in our quest for learning we stumble upon a solution that is plain awesome. Routing in an Angular app can be a bit challenging at times which is why there exists the great ui-router project to support those not so edge cases that are needed. That being said, many times we can get along just fine with the built in route provider that comes with angular, but it can get messy.

Source code for this post is located on plunker.

Let’s talk first about routing in general. Inside an Angular application, your app can push the user to different “pages” to show different information. With modern browsers the URL will even update making it seem like the user is browsing to separate pages when in fact, they are not. Angular supports a client side routing mechanism to allow all of this to happen.

route66.jpg

Let’s go to the documentation and see what it is we need to do to setup this darn route:

.config(function($routeProvider, $locationProvider) {
  $routeProvider
   .when('/Book/:bookId', {
    templateUrl: 'book.html',
    controller: 'BookController',
    resolve: {
      // I will cause a 1 second delay
      delay: function($q, $timeout) {
        var delay = $q.defer();
        $timeout(delay.resolve, 1000);
        return delay.promise;
      }
    }
  })
  .when('/Book/:bookId/ch/:chapterId', {
    templateUrl: 'chapter.html',
    controller: 'ChapterController'
  });
});

That example is taken straight from the documentation. If you notice the routes are being setup to pull some books by id and chapter. The main elements of a route are:

  • Route string with parameters. If you want something with wildcards or with more functionality, review the ui-router module.
  • Template partial that will be injected to the dom. This gets placed in the ng-view.
  • Controller that will be called for the template
  • Resolve object that will be called before the route is fully resolved with the object map being passed to the controller. This allows us to preload data for our controller.

Note: You can’t pass in a factory into the app config. This is an important distinction and is one of the reasons why the solution below works so well. Constants however you can pass into the config provider.

These routes are to be used in conjunction with an ng-view directive and I won’t get into html 5 mode in this post but there are a few other tricks you can do if you want nice human readable linkable url’s. If you think about it, your app may have a bunch of these routes defined for each domain of your app. The documentation is referencing some books, but what if we wanted to add movies, magazines, and other items this could get messy very quickly.

Clean up this routing mess

Here is a nice strategy for cleaning up this potential mess. First, we will move our route definition out of the config and place it with the service that will be resolving the data. We will create a constant that contains the routing information and the resolve will be inside the factory/service. Here is an example of such a service.

We have our standard service, ExampleService that is just performing a simple get of a hand coded json file. For all intents and purposes your service will be doing something similar.

Below the service we have a constant that lists our routing information. We can inject our service into this constant in order to resolve the route information.

angular.module('routerexample.services', [])
  .factory('ExampleService', ['$http', '$q',
    function($http, $q) {
      var getData = function(id) {
        var d = $q.defer();
        $http({
          method: 'get',
          url: 'data.json'
        }).success(function(data) {
          d.resolve(data);
        }).error(function() {
          d.reject();
        })
        return d.promise;
      };

      return {
        getData: getData
      };
    }
  ])
  .constant('exampleRoutes', {
 '/example/id/:id': {
  templateUrl: 'example.html',
  controller: 'ExampleCtrl',
  resolve: {
    exampleData: ['ExampleService', '$route',
      function(ExampleService, $route) {
        return ExampleService.getData($route.current.params.id);
      }
    ]
  }
},
  '/example/name/:name': {
    templateUrl: 'example2.html',
    controller: 'ExampleCtrl',
    resolve: {
      exampleData: ['ExampleService', '$route',
        function(ExampleService, $route) {
          return ExampleService.getData($route.current.params.name);
        }
      ]
    }
  }

});

Now, let’s move on to the app config where we wire it all up. We will loop over our exampleRoutes keys(path) and we will set the $routeProvider.when:

app.config(['$routeProvider', '$locationProvider', 'exampleRoutes',
  function($routeProvider, $locationProvider, exampleRoutes) {

    $routeProvider.otherwise({
      redirectTo: '/'
    });

    angular.forEach(exampleRoutes, function(routeData, path) {
      $routeProvider.when(path, routeData);
    });

    $locationProvider
      .html5Mode(true)
      .hashPrefix('!');
  }
]);

Extending the routes

We have our simple ExampleService but let’s say we are going to add some functionality to our app and want to add a SampleService. It is now a breeze to do:

// This sample service is just a copy of our example service to demonstrate
// the idea.
.factory('SampleService', ['$http', '$q',
        function($http, $q) {
          var getData = function(id) {
            var d = $q.defer();
            $http({
              method: 'get',
              url: 'sampledata.json'
            }).success(function(data) {
              d.resolve(data);
            }).error(function() {
              d.reject();
            })
            return d.promise;
          };

          return {
            getData: getData
          };
        }
      ])
      .constant('sampleRoutes', {
     '/sample/id/:id': {
      templateUrl: 'sample.html',
      controller: 'SampleCtrl',
      resolve: {
        exampleData: ['SampleService', '$route',
          function(SampleService, $route) {
            return SampleService.getData($route.current.params.id);
          }
        ]
      }
    },
      '/example/name/:name': {
        templateUrl: 'sample2.html',
        controller: 'SampleCtrl',
        resolve: {
          exampleData: ['SampleService', '$route',
            function(SampleService, $route) {
              return SampleService.getData($route.current.params.name);
            }
          ]
        }
      }

    });

And now in our config:

app.config(['$routeProvider', '$locationProvider', 'exampleRoutes', 'sampleRoutes',
      function($routeProvider, $locationProvider, exampleRoutes, sampleRoutes) {

        $routeProvider.otherwise({
          redirectTo: '/'
        });

        angular.forEach(exampleRoutes, function(routeData, path) {
          $routeProvider.when(path, routeData);
        });

        angular.forEach(sampleRoutes, function(routeData, path) {
          $routeProvider.when(path, routeData);
        });


        $locationProvider
          .html5Mode(true)
          .hashPrefix('!');
      }
    ]);

You can easily build out your routing to accompany a growing app. A quick note, the extended version of this code is not in the plunker referenced.

Conclusion

Everything is now nice and tidy. This solution for standard angular routes keeps the routing information by the factory that is responsible for resolving any data, and allows us to keep our config lean and organized. You can now easily create routing for each section of your app and when it grows, it will be much easier to maintain and debug.

Full Source code for this post is located on plunker.

ASP.NET MVC and passing objects to the client without ajax

Typically when you use a client library like Knockout or Angular, the application is going to communicate to and from the server to the client. Sometimes you run into a scenario when your app is rather large, it might even be something that is already existing, or refactored from jQuery to some more robust client library that is data centric as opposed to DOM centric. In these cases you evaluate the process, controllers, views, and determine that you do not want to make $http.get or $.get calls to the server but want to pass in the data from the server directly on the view. I run into this case when I have a view that works fine, but then requires some client functionality and I don’t want or have time to refactor it. The view is already strongly typed, has the data it needs, but now I want to do X,Y, and Z in the client so we need a mechanism to provide this data to the client (javascript). Ajax is always an option but if we don’t want to create a WebApi or controller just to get the data, we can serialize it directly on the view.

Before we move on, links to all the source code for this post are included at the bottom.

The reason this can be tricky is that when you use some of these more robust data centric client libraries, they update the DOM based on data changes (either via $scope with Angular or observables with knockout) and especially if your view is already receiving these business objects in one form or another it might be easier to eliminate the need for an ajax call and just directly serialize the server data to the view. Of course this can be done manually, but that leads to issues if you have multiple developers working in the project, so today we will work on a way to help serialize data from the server to the client in order to be used with a client library and not via ajax which is how you’d typically do it. It will be organized and automated. This is a blended approach that may help you on a future project.

In addition to these page specific requirements, this technique can also be used to bootstrap something like an Angular app with some configuration data. You may not want to have to use ajax to get this data, but want to just have it available to the application when it starts.

As a bonus, we will also assume the application is quite large and that it will also be including page specific javascript files. What I mean is that you might have a controller called TestController and correspondingly there might be a View (test.cshtml) file to go along with this controller that needs to have some javascript included automatically, test.js. This is a typical type setup with Knockout in that usually Knockout isn’t geared so well towards single page applications but works well when you have discreet server side pages.

Let’s summarize the requirements

All that text above boils down to:

  • Serialize server side view specific data to javascript in an organized way
  • Provide a way to include javascript files on a per View basis in an organized way

Overview

Because .NET MVC is so modular, this task is much easier than it seems. First, we need to think about how we will organize our files so we can determine how to deal with the second requirement. Second, in order to organize this we just need to determine a structure to hold our serialized data so that it can be used on our view.

File Organization

For all practical purposes and for this project, we will just stick with the standard MVC flow.

controller->View Folder with Same Name->view

For the javascript we will do something similar but the file will reside inside of content/script/page/[controller]/ and the name of the javascript will be view.js. It needs to be something calculable so we can auto include it.

Hopefully this makes sense. We need a way to map our view to a javascript file. I know you might be thinking, but wait I really want to combine all my javascript into one massive file. This is fine, it depends on your requirements, but sometimes when an application is larger, it is much easier to architect and maintain when they are separated out. This might be a little slower, but that tradeoff is something you may have to consider. Okay, so let’s move on.

Javascript Variable Naming

Since one of our goals is to pass server side generated data into our javascript domain, we just need to consider how to do this if we aren’t going to be getting the data via ajax. In my project I created a variable, pageVar that is an object. Also, you can add information to the window (makes it global) and it depends on your project. Today, we will do both.

Forloop HTML Helpers

When I originally researched this I tried a few methods and found that forloop html helpers to be a slick and easy way to implement some of the following code. You can read more about it:

https://bitbucket.org/forloop/forloop-htmlhelpers/wiki/Home

Essentially, this library allows you to add script and script blocks. It is quite powerful, and I’m only going to demonstrate a few little pieces of it.

Custom WebViewPage

The meat of this project boils down to creating our own WebViewPage. This is essentially the base type of each view and besides what I show you today, this can be used to extend this basetype to support many more advanced scenarios. Let’s talk about how we can actually create this.

We need to create an abstract class that inherits from System.Web.Mvc.WebViewPage and override the ExecutePageHierarchy. This will allow us to plugin to the page, include our scripts and script chunks and move on.

The class is actually quite simple. Here it is in its entirety:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
using Forloop.HtmlHelpers;
using Forloop;


namespace Tarea.Infrastructure
{
    public abstract class MyWebViewPage<T> : System.Web.Mvc.WebViewPage<T>
    {
        public Dictionary<string, object> PageVars = new Dictionary<string, object>();

        public override void ExecutePageHierarchy()
        {

            var ViewJs = this.VirtualPath.ToLower().Replace("~/views/", "~/content/script/page/").Replace(".cshtml", ".js");

            if (System.IO.File.Exists(HttpContext.Current.Server.MapPath(ViewJs)))
            {
                Html.BeginScriptContext();
                Html.AddScriptFile(ViewJs);
                Html.EndScriptContext();

            }

            base.ExecutePageHierarchy();

            // if PageVars has values we'll add them to the global scope of the window and pageVar variable to be used.
            if (PageVars.Count > 0)
            {
                Html.BeginScriptContext();
                Html.AddScriptBlock(String.Format("var pageVar ={0};_.merge(window, pageVar);", Json.Encode(PageVars)));
                Html.EndScriptContext();
            }
        }
    }
}

There are two main sections that support our two requirements. First, we will check to see if our current view has a matching javascript file. This is pretty straightforward, if it does, we will add it to our Script Context by doing some name replacements.

Secondly, if you noticed we added a property to our class called PageVars that is a dictionary. This variable will be available to all our views and will allow us to add anything we might need that will get serialized to a javascript variable (pageVar) as well as included to the window scope. You may not want to add it to the window scope, but using jQuery or lodash it is quite easy to do.

Html.BeginScriptContext();
Html.AddScriptBlock(String.Format("var pageVar ={0};_.merge(window, pageVar);", Json.Encode(PageVars)));

I am only showing you two ways to include the data, one is a javascript variable pageVar and the other is a global window variable. The difference being that:

pageVar.something

vs.

something

Some people may not want to pollute the window object, it just depends on what you want.

This will set up our views to allow us to serialize data without ajax to the client. There are a few more parts to hook up.

Connecting to the View

In order to tell MVC that we now have our new and shiney WebViewPage we must make a small change to the web.config file that resides in the view folder.

<pages pageBaseType="Tarea.Infrastructure.MyWebViewPage">

That’s it, now we are good to go with regards to the entire project using our new page.

Inside this same web.config (not the main one, but the one inside the view folder) we probably want to add a couple namespaces just to avoid having to include them on our layout.

<add namespace="Forloop.HtmlHelpers"/>
<add namespace="System.Web.Optimization"/>

Now, on our layout, we just need to add a line to render our scripts:

@Html.RenderScripts(Scripts.Render) 

That’s it, now our script include and the serialize data will be included. The last piece is to add some data to one of our views.

It is quite simple, at the top of any view (say index.cshtml) we can now start adding information to the PageVar dictionary. My example below contains some hard coded data.

PageVars.Add("variable1", "123");
PageVars.Add("variable2", 1); 

But let’s say your view was strongly typed to some object that has a config property or even something in TempData (or ViewBag):

PageVars.Add("todo", TempData["tareas"]);

This Tareas will get serialized to the view and will be available as a javascript pageVar or via window.

Now if you were using knockout you could use it in an observable and do whatever you need to do. With angular, I’d probably create a factory or even a constant and just set it equal to my global object. This way your application doesn’t need to make an ajax call to receive this data.

Examples

I’ve put together some posts about creating a todo list (tarea in spanish) with both knockout and angular. The posts are in Spanish but the source code is updated to include examples of how we could use this technique. You can view the source code for each of the pieces below:

The script.js file has been updated to show an example of getting data from pageVar. This project originally was pulling data via ajax which is viewable in the else part below and the following change (checking to see if pageVar has a key) was made below:

 if ('tareas' in pageVar) {
            self.tareas([]);
            for (var i = 0, l = tareas.length; i < l; i++) {
                var row = tareas[i];
                self.tareas.push(new Tarea(row.Id, row.Nombre, row.Desc, row.Status))
            }
            self.isLoading(false);

        } else {


            services.tareas().then(function (data) {
                self.tareas([]);
                for (var i = 0, l = data.length; i < l; i++) {
                    var row = data[i];
                    self.tareas.push(new Tarea(row.Id, row.Nombre, row.Desc, row.Status))
                }
                self.isLoading(false);
            });
        }

To wrap up, today you’ve seen how to interchange data to/from the serverside to a javascript client by serializing it directly on the view in an organized fashioned as well as auto including view specific javascript files. Helpful techniques when your application grows.

Stack Overflow and the love-hate relationship but mostly love

Anyone that makes a living in the world related to programming or developing some piece of software is aware of Stack Overflow. They may not know that name, but the chances are they’ve run across some answer to something on that site that helped them. I’m no different and Stack Overflow has been a huge asset in both my job life as well as on some of the personal projects but on the other side of the coin, it can create some issues.

For instance, while learning NodeJS, I built an integration from an external (public website) SQL Server database to an accounting system. Delving into the world of callbacks, nested callbacks, and all the nuances of asynchronous programming was both delightful and painful. Stack Overflow was there as my guide.

Over the years, I’ve been able to learn Angular which is a complete shift from jQuery from being DOM centric to following a more MVC-ish Data centric focus. Fighting with all those controllers, directives, routing, templates, and modules put some hair on my chest. Stack Overflow was there as my mentor.

Upgrading .NET webforms to MVC has its own pitfalls and learning curve. Going from the complicated and horrendous page lifecycle to a cleaner MVC approach definitely gave me some headaches, but Stack Overflow was one of my teachers on that school trip.

Recently I’ve been getting contacted via Stackoverflow about job opportunities even though I’m not even looking which is a nice testament to the site (and perhaps my skills). On the other hand, I’ve also been tracked down by users that found me on Linked In (via Stackoverflow) and asked me to review their code, or help them as if I don’t already have a job of my own. If you know me, I always claim to be “anti-social”, but my description really only means that although I’m probably normal interacting with people, I enjoy decompressing by myself. There seems to be a large enough group of people that at least online, don’t really know how to behave, interact with others, don’t think before contacting someone for help, and assume everyone else exists to help them at their whim. Wouldn’t that be nice.

In the scheme of things, I am very happy to help, but you need to ask nicely, have realistic expectations, and communicate in a straightforward enough way that what you are asking makes sense to someone you don’t even know.

Unfortunately that now we have almost instant answers to any technical question possible, our expectations for help and how we might interact with others gets lost in some warped-give-it-to-me-now bubble. The next time you are asking a question on Stackoverflow, adding a comment, answering, downvoting/upvoting or viewing the profile of someone that might have helped you with the intent of contacting them, think before you do it.

That is something Stack Overflow won’t teach you.

To be fair, this post wasn’t really about Stack Overflow, but some of the users.

WebApi, Angular, Ionic framework se enamoraron de móviles

Este post es la primera parte de una serie de como crear una aplicación móvil híbrida.

Los voy a presentar algunas estrategias de como producir una aplicación móvil con nuestro proyecto de Tareas. Va a consistir de algunas herramientas para facilitarlo: WebApi, Angular y el framework de Ionic. Vamos a usar el proyecto de Tareas como base para lanzar esta app móvil. Los invito leer la info sobre la app base:

El producto Final

Como siempre el código fuente esta en http://github.com/sbosell/kpensar-tarea-di

Entonces qué vamos a hacer? Primero, vamos a hablar un poquito sobre Web Api porque es la capa de comunicación entre una app móvil (desconectada) y un bd/sistema. Me imagino que ya saben de servicios web y tal vez de la historia de ASP.NET y como producir un servicio web. Los frameworks que existía en .NET antes como los de generan SOAP son bien difíciles implementar en el lado de cliente.
De hecho, has tratado de construir o consumir un web-servicio de soap sin .NET? Es bien trabajoso y demasiado complicado y por eso y la popularidad de servicios “REST” ahora, .NET lanzó Web Api.

Entonces qué es web api?

ASP.NET Web API es un framework para crear servicios HTTP para cualquier cliente incluyendo browsers y aplicativos móviles. ASP.NET Web API es una plataforma ideal para crear aplicaciones “REST” en el framework .NET. - MSDN.aspx)

Te acuerdas que en nuestra app de Tareas que hicimos métodos de JsonResult para comunicarse con nuestra app? Viven en el controller TareaController. Vamos a cambiar esos para Web Api y vamos a vincularlos con nuestra app nueva de móvil. Cuando terminemos con el proyecto vamos a tener nuestra app original más una app para móviles.

La parte móvil va a consistir de una “SPA - Single Page Application”, que es una aplicación móvil de ajax. Para nuestro proyecto va a ser html puro pero con el framework de ionic. Se puede lanzar con phonegap para una experiencia “híbrida/nativa”.

Donde empezamos?

Primero, quiero integrar la “Stater App” de ionic con Tabs. Se puede encontrar aquí. De hecho, puedes bajarlo y lanzarlo para ver que hace.

Ionic Tabs

Nosotros queremos integrar las tareas con esta app ionic. Entonces, voy a crear otro proyecto solamente para móvil. Podemos crearlo dentro de nuestra Tarea Web pero tal vez en el futuro vayamos a integrarlo con un app android/iphone/etc, seria mejor separarlo.

Ya tenemos nuestra ionic starter app en un proyecto pero no esta vinculado con nada de tareas. Puedes correrlo para ver los “friends” (nombre de su app). Para aclarar, ahora tengo 2 proyectos web.

  1. Tarea - Tiene nuestra página web original.
  2. Tarea.MobileApp - Lo que acabamos de hacer lo que es un clon del starter de Ionic.

Tarea.MobileApp nos va a servir como una app a parte que podemos lanzar en un android, iphone, etc o podria ser una app html. Será bastante básico y cumplirá con los requisitos de listar, detalle, agregar y eliminar una tarea.

Vamos a dejar el front end ahora para ver la parte de servidor porque sin los métodos web api, nuestra app no podrá hacer mucho. Volveremos a esta parte en el siguiente post. Por ahora, acuerdate que tenemos que tener una capa para que algo desconectado pueda comunicarse con nuestro sistema.

Web Api

Para que Web Api sea disponible el en proyecto vamos a agregar el nuget Microsoft.Web.Api también necesitaremos Microsoft.AspNet.WebApi.Cors. En un rato voy a explicar un poquito sobre CORS.

Después de agregar WebApi podemos crear nuestro controller para enviar los datos. Podemos usar los JsonResult métodos del TareaController pero para mi es importante separar el API de la parte del sitio que retorna HTML (vistas). Por eso, vamos a mover los JSONRESULT métodos al web api.

Los controllers de MVC son optimizado para crear un documento de HTML por Views, PartialViews, y HTML Helpers. Ese proceso no tiene mucho sentido cuando hablemos de un api que solamente va a volver entities, dto’s, modelos, etc.

En nuestro caso vamos a devolverHttpResponseMessage que es un wrapper del dato de lo que vamos a devolver también nos permite devolver otro códigos como 400 o 500 si queremos. De hecho con web api, se puede enviar los datos directamente sin HttpResponseMessage pero como mencioné, si queremos enviar otro código como 401, es necesario que utilicemos esa clase para devolver los datos. Si deseas, cambia cada HttpResponseMessage para un tipo como Tarea o List<Tarea> y funciona igual.

Vamos a ver el controller web api:

public class TareaDataController : ApiController
{
    public readonly ITareaServicio _tareaServicio;

    public TareaDataController(ITareaServicio tareaServicio)
    {
        _tareaServicio = tareaServicio;
    }


    [HttpGet]
    public HttpResponseMessage Listar()
    {
        var tareas = _tareaServicio.Listar();

        return Request.CreateResponse(tareas);

    }

    [HttpGet]
    public HttpResponseMessage Obtener(int id)
    {
        var tarea = _tareaServicio.Obtener(id);
        return Request.CreateResponse(tarea);
    }

    [HttpPost]
    public HttpResponseMessage Guardar(Tarea.Modelos.Tarea Tarea)
    {
        if (ModelState.IsValid)
        {
            _tareaServicio.Agregar(Tarea);
            return Request.CreateResponse(Tarea);
        }
        else
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest, ModelState);
        }

    }
    [HttpPost]
    public HttpResponseMessage Eliminar(Tarea.Modelos.Tarea Tarea)
    {
        _tareaServicio.Eliminar(Tarea);
        return Request.CreateResponse(200);
    }
}

Si notas, esta capa es muy sencilla. Con nuestro inyección de dependencia del ITareaServicio es muy fácil crear una capa de api para ajax o movil. Antes de que lancemos vamos a crear una ruta para que corra nuestro api:

 configuration.Routes.MapHttpRoute("API Default", "api/{controller}/{action}/{id}",
        new { id = RouteParameter.Optional });

Vamos a poner un prefijo de api` en la ruta para separarlo de la aplicación web. Ahora, con PostMan (una extensión de chrome), probaremos el api:

Perfecto, el webapi devuelve datos y ahora podemos seguir con la parte front end. Pero espera, vamos a chocarnos con un problema si tratamos de llamar este web api de una aplicación web externa (por lo menos con un browser) vamos a tener problemas con CORS:

Cross-origin resource sharing (CORS) es un mecanismo que permite recursos (e.g. fonts, JavaScript, etc.) de una página web ser pedidos por otro dominio fuera del dominio esta los recursos.

Todo eso significa que para un browser recibir algo (imagen, json, xml, html), la página que hace el pedido debería estar en el mismo dominio. No esta claro? Lanza tu proyecto ahora vas a notar que tienes dos proyectos web con dominios diferentes:

Entonces para el cliente de proyecto móvil (browser) recibir datos del proyecto web (web api), tenemos que configurarlo aceptar el pedido con CORS.

Bueno, es fácil implementar aunque vas a querer especificar un dominio en lugar de “*” en la configuración de web api:

class WebApiConfig
{
    public static void Register(HttpConfiguration configuration)
    {
        var cors = new EnableCorsAttribute("*", "*", "*");  // habilitar CORS en todos dominios, no es un buen idea hacer * pero podemos cambiarlo mas tarde despues de probar
        configuration.EnableCors(cors);

        configuration.Routes.MapHttpRoute("API Default", "api/{controller}/{action}/{id}",
            new { id = RouteParameter.Optional });
    }
}

Ahora podemos llamar y comunicar entre los dos proyectos. También, podemos apuntar el browser al http://localhost:52643/api/tareadata/listar y vas a ver una lista de datos json.

Web Api completo. Te toca front end.

Voy a concluir este post con que tenemos una capa lista para un front end. La capa que hicimos es super sencilla y vuelva los datos del bd. Fue súper sencillo porque solamente tuvimos que agregar un controller web api, definir la ruta, y con DI todo trabaja juntos. El siguiente post vamos a implementar el framework Ionic lo que consiste de una aplicación web con angular, html, javascript y se ve como una app nativo. El video al principio es la meta final de este series.