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