Digamos que tienes un web service, sí, un web service. Y este, acaba de recibir una petición, si tu web service desea sobrevivir, lo que tendrá que hacer es hacer uso de algún Thread dentro de su Thread Pool. Mientras el procesamiento de cada petición no le tome demasiado a un Thread, podría no haber problema.
Pero en el caso contrario podriamos no solo dejar varias solicitudes en espera, sino también afectar el rendimiento de las demás tareas.
Antes de continuar, recordemos que la creación de un Thread es costosa en términos de memoria (1MB) y tiempo(500ms). Hay escenarios que lo justifican, pero aquellos dónde un Thread se queda bloqueado por esperar el resultado de alguna operación, simplemente no.
Lo bueno de este asunto es que desde .NET 4.5 y C# 5, la programación asíncrona nos permite fácilmente lidear con esta clase de situaciones, un claro ejemplo sería la forma en que HttpClient trabaja, pero igual nos podemos encontrar con casos que no estan listos para esto, por eso ahora veremos como trabajar asíncronamente con Enterprise Library.
En el siguiente código podemos apreciar un controllador que devuelve una lista de elementos.
Lo bueno de este asunto es que desde .NET 4.5 y C# 5, la programación asíncrona nos permite fácilmente lidear con esta clase de situaciones, un claro ejemplo sería la forma en que HttpClient trabaja, pero igual nos podemos encontrar con casos que no estan listos para esto, por eso ahora veremos como trabajar asíncronamente con Enterprise Library.
En el siguiente código podemos apreciar un controllador que devuelve una lista de elementos.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using AEL.Api.Entities;
using AEL.Api.Repositories;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web.Http;
namespace AEL.Api.Controllers
{
public class EntitiesController : ApiController
{
public List<MyEntity> Get()
{
var repository = new MyEntityRepository();
return repository.GetAllEntities();
}
public void Put(MyEntity myEntity)
{
var repository = new MyEntityRepository();
repository.Update(myEntity);
}
}
}
Y en este otro, un método que logra establecer una conexión a una base de datos para recuperar algunos resultados.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using AEL.Api.Entities;
using Microsoft.Practices.EnterpriseLibrary.Data;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Threading.Tasks;
namespace AEL.Api.Repositories
{
public class MyEntityRepository
{
public List<MyEntity> GetAllEntitiesAsync()
{
var database = DatabaseFactory.CreateDatabase();
var entities = new List<MyEntity>();
using (var reader = database.ExecuteReader("[dbo].[myTable_sel]"))
{
var a = reader.GetOrdinal("Id");
var b = reader.GetOrdinal("Names");
var c = reader.GetOrdinal("Address");
var d = reader.GetOrdinal("Email");
var e = reader.GetOrdinal("Code");
var f = reader.GetOrdinal("Lat");
var g = reader.GetOrdinal("Lng");
while (reader.Read())
{
entities.Add(new MyEntity
{
Id = reader.GetInt32(a),
Names = reader.GetString(b),
Address = reader.GetString(c),
Email = reader.GetString(d),
Code = reader.GetString(e),
Lat = reader.GetDouble(f),
Lng = reader.GetDouble(g)
});
}
}
return entities;
}
public void Update(MyEntity myEntity)
{
var database = DatabaseFactory.CreateDatabase();
using(var connection = database.CreateConnection())
database.ExecuteNonQuery("[dbo].[myTable_upd]", myEntity.Code, myEntity.Email);
}
}
}
Si una solicitud llega a nuestro servicio y nuestro Thread queda bloqueado por esperar el resultado de una gran consulta o la ejecución de una operación larga, la inmediata próxima solicitud exigirá que se tenga que usar otro Thread o se tenga que crear uno nuevo. Para este sencillo e hipotético ejemplo tendremos que realizar las siguientes modificaciones.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using AEL.Api.Entities;
using AEL.Api.Repositories;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web.Http;
namespace AEL.Api.Controllers
{
public class EntitiesController : ApiController
{
public async Task<List<MyEntity>> Get()
{
var repository = new MyEntityRepository();
return await repository.GetAllEntitiesAsync();
}
public async Task Put(MyEntity myEntity)
{
var repository = new MyEntityRepository();
await repository.UpdateAsync(myEntity);
}
}
}
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using AEL.Api.Entities;
using Microsoft.Practices.EnterpriseLibrary.Data;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Threading.Tasks;
namespace AEL.Api.Repositories
{
public class MyEntityRepository
{
public Task<List<MyEntity>> GetAllEntitiesAsync()
{
var taskCompletionSource = new TaskCompletionSource<List<MyEntity>>();
var database = DatabaseFactory.CreateDatabase();
database.BeginExecuteReader("[dbo].[myTable_sel]", (asyncResult) =>
{
try
{
var entities = new List<MyEntity>();
var db = (Database)asyncResult.AsyncState;
using (var reader = db.EndExecuteReader(asyncResult))
{
var a = reader.GetOrdinal("Id");
var b = reader.GetOrdinal("Names");
var c = reader.GetOrdinal("Address");
var d = reader.GetOrdinal("Email");
var e = reader.GetOrdinal("Code");
var f = reader.GetOrdinal("Lat");
var g = reader.GetOrdinal("Lng");
while (reader.Read())
{
entities.Add(new MyEntity
{
Id = reader.GetInt32(a),
Names = reader.GetString(b),
Address = reader.GetString(c),
Email = reader.GetString(d),
Code = reader.GetString(e),
Lat = reader.GetDouble(f),
Lng = reader.GetDouble(g)
});
}
}
taskCompletionSource.TrySetResult(entities);
}
catch (Exception ex)
{
taskCompletionSource.TrySetException(ex);
}
}, database);
return taskCompletionSource.Task;
}
public Task UpdateAsync(MyEntity myEntity)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
var database = DatabaseFactory.CreateDatabase();
var connection = database.CreateConnection();
database.BeginExecuteNonQuery("[dbo].[myTable_upd]", (asyncResult) =>
{
try
{
dynamic states = asyncResult.AsyncState;
var db = (Database)states.database;
var cn = (DbConnection)states.connection;
db.EndExecuteNonQuery(asyncResult);
cn.Close();
taskCompletionSource.TrySetResult(true);
}
catch (Exception ex)
{
taskCompletionSource.TrySetException(ex);
}
}, new { database, connection }, myEntity.Code, myEntity.Email);
return taskCompletionSource.Task;
}
}
}
No hay comentarios.:
Publicar un comentario