en el gobierno

Servicios para el ciudadano
con Ember, .NET, SignalR y Oracle

Itnig Networking

Barcelona, Catalunya, Nov 5 '15

Joel Alejandro Villarreal Bertoldi

@joelalejandro · github.com/joelalejandro

¿Y éste quién es?

¡Pues, yo!

 

Joel Alejandro
Villarreal Bertoldi

 

Lead Software Developer

Ministerio de Gestión Pública
Gobierno de la Provincia de Córdoba
(desde el año 2010)

 

Also, I love graphic design <3

¿Y de qué va esto?

           +                                          +

Turnero Provincial

Turnero Provincial

Turnero Provincial

Turnero Provincial

Turnero Provincial

Turnero Provincial

Turnero Provincial

Turnero Provincial

Turnero Provincial

Turnero Provincial

Turnero Provincial

Todo muy bonito.

Pero... ¿cómo funciona todo esto?

  • Un ORM custom-made en .NET.
  • Un serializador a medida para las respuestas JSON de la Web API de MVC 5 de .NET.
  • Una extensión a DS.Model para permitir la actualización parcial de modelos vía PATCH.
  • Un mixin para DS.Model, para permitir el clonado de registros.
  • Un Ember.Service personalizado para el control de la mensajería en tiempo real (SignalR).
  • Un Ember.Object para manejar un sintetizador de voz (Microsoft Speech) para el llamador del turnero.

Tabla          >>>>>>

T_TURNOS:
ID_TURNO
FEC_TURNO
FEC_SOLICITADO
ID_MODALIDAD_TURNO
N_USUARIO_CIUDADANO

(...)

Modelo

[ProcedimientoParaTraer
("TURNERO.PKG_API.TURNOS_GET", "i_id_turno", OracleType.Int32)]
public class Turno {
  [Columna(Nombre="ID_TURNO")]
  public int ID { get; set; }
  [Columna(Nombre="FEC_TURNO")]
  public DateTime? FechaTurno { get; set; }
  (...)
}

FW.DAL.ODAC (ORM)

Convierte...

{
  "ID": 1,
  "FirstName": "Joel",
  "LastName": "Villarreal",
  "Gender": {
    "ID": "M",
    "Description": "Male"
  },
  "Siblings": [{
    "ID": 2,
    "FirstName": "Pepe",
    "LastName": "Villarreal",
    "Gender": {
      "ID": "M",
      "Description": "Male"
    }
  }]
}

en esto:

{
  "person": 
  {
    "id": 1,
    "firstName": "Joel",
    "lastName": "Villarreal",
    "gender": "M",
    "siblings": [2],
  }
​}

Cinder

Un serializador JSON para DS.RESTAdapter.

 

Sí, por ahora sólo RESTAdapter,

hasta que migremos todo a Ember 2.x ;)

Convierte...

{
  "ID": 1,
  "FirstName": "Joel",
  "LastName": "Villarreal",
  "Gender": {
    "ID": "M",
    "Description": "Male"
  },
  "Siblings": [{
    "ID": 2,
    "FirstName": "Pepe",
    "LastName": "Villarreal",
    "Gender": {
      "ID": "M",
      "Description": "Male"
    }
  }]
}

en esto:

{
  "person": 
  {
    "id": 1,
    "firstName": "Joel",
    "lastName": "Villarreal",
    "gender": "M",
    "links": {
      "siblings": "/api/p/1/sib"
    }
  }
​}

Convierte...

{
  "ID": 1,
  "FirstName": "Joel",
  "LastName": "Villarreal",
  "Gender": {
    "ID": "M",
    "Description": "Male"
  },
  "Siblings": [{
    "ID": 2,
    "FirstName": "Pepe",
    "LastName": "Villarreal",
    "Gender": {
      "ID": "M",
      "Description": "Male"
    }
  }]
}

en esto:

{
  "people": 
  [{
    "id": 1,
    "firstName": "Joel",
    "lastName": "Villarreal",
    "gender": "M",
    "siblings": [2]
  },{
    "id": 2,
    ...
  }],
  "genders":
  [{
    "id": "M"
  }]
​}

¿Cómo?

config.Filters.Add(new CinderMediaTypeFormatter());

Usando:

[IncludeLink]

[IncludeMeta]

[PluralName]

[Sideload]

C# Model:

using Cinder;
using Newtonsoft.Json;

[IncludeLink("siblings", "/api/p/{ID}/sib")]
[JsonObject(Title="person")]
[PluralName("people")]
public class Person {

  [JsonProperty("id")]
  public int ID { get; set; }

  [JsonProperty("firstName")]
  public string FirstName { get; set; }

  [JsonProperty("gender")]
  [Sideload(typeof(Gender))]
  public string FK_GenderID { get; set; }

  [JsonProperty("siblings")]
  [Sideload(typeof(Person))]
  public List<int> FK_SiblingsPersonID { get; set; }

}
using GobCba.EsCom.WebApi;
using Models;

public class PersonController
  : PersistentApiController<Person> {

}

Web API Endpoint

Patch Persistance

Model.patch() para

Ember Data 1.0.0-beta17.

 

Sí, hasta que migremos todo a Ember 2.x ;)

npm install ember-data-patch-persistance

Instalable vía NPM:

github.com/joelalejandro/ember-data-patch-persistance

Código fuente en:

this.store.find('person', 1).then(function(person) {
  person.set('lastName', 'Villarreal Bertoldi');
  // Aquí está lo mágico...
  person.patch().then(function(patchedPerson) {
    // Yay!
  }).catch(function(error) {
    // Oops :(
  });
});

Modo de uso:

¿Cómo funciona?

Detecta los elementos modificados del modelo y el estado de las relaciones de éste, generando una petición AJAX que sólo contiene lo modificado, a diferencia de .save() con PUT.

Replicable Models

Model.replicate() para

Ember Data ¿1.0.0-beta17...?


(Quizá funciona en otros, no lo hemos probado.)

// car.js

import DS from 'ember-data';
import Replicable from 'turnero/mixins';

export default DS.Model.extend(Replicable, {
  make: DS.belongsTo('carMake'),
  model: DS.belongsTo('carModel'),
  year: DS.attr('number'),
  colour: DS.attr('string', { copy: false }),
  numberOfDoors: DS.attr('number'),
  maxSpeed: DS.attr('number', { copy: false })
});

Modo de uso:

// en-algun/lugar/de-tu-app.js

car.replicate().then(function(newCar) {
  // Copiado!
}).catch(function(error) {
  // Oh :(
});

Modo de uso:

¿Cómo funciona?

Hace un .createRecord() del modelo a copiar, transfiere los valores a la nueva instancia (exceptuando los que indiquen { copy: false }), y ejecuta un .save(), por lo que el modelo se guarda vía POST.

Hub Services

Control de canales de mensajería de SignalR para Ember.


(Cualquier versión que soporte Ember.Controller.)

¿Cómo funciona?

SignalR es un sistema de sockets.

Una aplicación puede suscribirse a un canal. Ese canal intercambia mensajes con el servidor. Se produce un callback en cada intercambio.

// Aquí solo declaramos la existencia del hub.
public class TurneroHub : Hub { }

C#

// hub-turnero.js
export default Hub.extend({
  hubName: 'turnero',
  actions: {
    controllers: ['llamador/pantalla'],
    callback: function() {
      var data = this.parameters;
      var cs = this.controllers;
      var c = cs.llamador_pantalla;
      c.send('llamarTurno', data);
    }
  }
});

JavaScript

El servicio Hub creado para Ember funciona como proxy entre el plugin de jQuery de SignalR y los controladores de una aplicación Ember, permitiendo intercambiar mensajes y callbacks.

Audio Manager

Control de reproducción de audio encolado para Ember.


Cualquier versión que soporte Ember.Object :P

¿Cómo funciona?

Más de una persona puede ser llamada para ser atendida. Cada llamado es notificado vía SignalR. Este manejador nos permite evitar que superponga el audio de cada llamada, encolándolos.

// en-algun-lugar/de-tu-app.js
import AudioManager from 'turnero/utils';
import Ember from 'ember';

// ...
var au = new AudioManager();
var textToRead = datosTurno.titular + ', '
           + 'presentarse en ' 
           + datosTurno.puesto + '.';
au.addSound('/assets/audio/ring1.mp3');
au.addSound('/api/speech?text=' + textToRead);
au.beginPlaylist();

JavaScript

¡Y eso es todo!

En un futuro...

...estos componentes serán publicados en GitHub, como open-source.

¿Preguntas?

¡Gracias!

               en el gobierno

Servicios para el ciudadano
con Ember, .NET, SignalR y Oracle

Itnig Networking

Barcelona, Catalunya, Nov 5 '15

Joel Alejandro Villarreal Bertoldi

@joelalejandro · github.com/joelalejandro

Ember en el gobierno: Servicios para el ciudadano con Ember, .NET, SignalR y Oracle

By Joel Alejandro Villarreal Bertoldi

Ember en el gobierno: Servicios para el ciudadano con Ember, .NET, SignalR y Oracle

Las peripecias y obstáculos experimentados por un equipo de desarrolladores a la hora de implementar un sistema complejo, con requisitos de sincronización en tiempo real, con un stack atípico para Ember en el back-end: .NET, SignalR y Oracle. // Obstacles and challenges experienced by a developer team when implementing a complex system requiring real-time event syncing, with a foreign stack for Ember at the back-end: .NET, SignalR and Oracle.

  • 1,507