Error: Validation failed for one or more entities

Si tienes este error al guardar una entidad en Entity FrameworkValidation failed for one or more entities. See ‘EntityValidationErrors’ property for more details“, es posible que te vuelvas loco buscando entre las propiedades de la excepción, cuál es el verdadero problema.

Para ello podemos utilizar el inspector rápido de Visual Studio (Shift + F9) y poner lo siguiente:

((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors

Así veremos el detalle del error que estamos viendo, como podemos ver en la imágen:

excepcion-entity-validation-errors

 

Convertir encriptación en PHP 3DES en C#

Recientemente ha avisado que el sistema de pago por TPV virtual de Redsys se va a actualizar. En esta actualización se van a incorporar medidas de cifrado más potentes que la firma actual que se tiene implementado. Para ello los bancos han enviado cierta documentación (un poco tarde…) para hacer esta migración, puesto que el 23/11/2015 se supone que dejará de funcionar el sistema de encriptación actual.

Realizando la migración en mi empresa me he encontrado con un escollo que me ha costado un poco de solventar, y por lo que veo a muchos más desarrolladores de .NET les ha sucedido lo mismo. El problema está en el cifrado triple DES.

Este es el código de ejemplo que te facilitan en Redsys para realizar este cifrado.

function encrypt_3DES($message, $key){
// Se establece un IV por defecto
$bytes = array(0,0,0,0,0,0,0,0); //byte [] IV = {0, 0, 0, 0, 0, 0, 0, 0}
$iv = implode(array_map("chr", $bytes)); //PHP 4 = 4.0.2


// Se cifra
$ciphertext = mcrypt_encrypt(MCRYPT_3DES, $key, $message, MCRYPT_MODE_CBC, $iv); //PHP 4 >= 4.0.2
return $ciphertext;
}


$key = $this->decodeBase64($key);
$ciphertext = $this->encrypt_3DES($message, $key);

La variable $message sería el texto a encryptar (en el caso de Redsys el número de pedido). La variable $key es la clave de encriptación de Redsys que previamente la decodificamos en Base64.
Al final obtenemos un resultado ($ciphertext) que es un array de bytes.

Ahora viene cuando hacemos lo mismo en .NET C#.


///
/// Uso de la encriptación TripleDES con IV todo 0 -> byte [] IV = {0, 0, 0, 0, 0, 0, 0, 0}
/// Esta encriptación se usa así para los TPV's de Redsys
///


///Texto a encriptar ///Clave de la encriptación en un array de Bytes ///
public static byte[] EncriptarTripleDES_IV_0(string texto, byte[] key)
{
using (TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider())
{
byte[] iv_0 = { 0, 0, 0, 0, 0, 0, 0, 0 };  //same IV that Redsys
byte[] toEncryptArray = Encoding.ASCII.GetBytes(texto);
tdes.IV = iv_0;
//assign the secret key
tdes.Key = key;
tdes.Mode = CipherMode.CBC;
tdes.Padding = PaddingMode.Zeros;
ICryptoTransform cTransform = tdes.CreateEncryptor();
//transform the specified region of bytes array to resultArray
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0,toEncryptArray.Length);
//Clear to Best Practices
tdes.Clear();
return resultArray;
}
}

Esta función nos devuelve el mismo resultado que la orginial proporcionada por Redsys en PHP.

El tipo ‘ObjectContent`1’ no pudo serializar el cuerpo de respuesta para el tipo de contenido

Si estás usando un Web API con Entity Framework, es posible que te salte este error “El tipo ‘ObjectContent`1’ no pudo serializar el cuerpo de respuesta para el tipo de contenido“, al intentar recuperar algún registro.

¿Por qué ha ocurrido esto?, bueno pues una de las posibles causas es que al intentar serializar con JSON, en nuestras tablas tenemos referencias a otras tablas (por ejemplo un foreign key) y la librería de NewtonJson nos diga que hay una referencia circular.

¿Como arreglamos este error?. Tendremos que incorporar las siguientes líneas de código o bien en el WebApiConfig.cs o bien en el Global.asax.cs

WebApiConfig

  
//Evito las referencias circulares al trabajar con Entity FrameWork         
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
            
//Elimino que el sistema devuelva en XML, sólo trabajaremos con JSON
config.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

Global.asax

  
//Evito las referencias circulares al trabajar con Entity FrameWork         
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
            
//Elimino que el sistema devuelva en XML, sólo trabajaremos con JSON
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

Otra manera de localizar este problema es cuando nos aparece este mensaje de error:
An exception has occurred while using the formatter ‘JsonMediaTypeFormatter’ to generate sample for media type ‘application/json’. Exception message: Se han producido uno o varios errores.

Espero que os con esto se resuelva vuestro problema.

 

Formato de solicitud no reconocido para la dirección URL, finaliza de manera inesperada….

Hemos creado un servicio web asmx en .NET y al probarlo en local funciona perfectamente. Vemos las definiciones los métodos, podemos hacer llamas a los mismos etc. (maravilloso!!)

Ahora lo subimos a un servidor en internet y nos aparecen las definiciones pero no podemos hacer llamadas a los métodos y nos devuelve el siguiente mensaje de error:
“Formato de solicitud no reconocido para la dirección URL, finaliza de manera inesperada xxxxx”

¿Porque nos aparece este problema?

  • Bueno pues es porque no hemos definido en el web config  los protocolos que va a usar nuestro servicio web y por defecto en IIS vienen desactivados, cosa que no ocurre cuando lo ejecutamos de manera local.

¿Como solucionamos este problema?

  • Añadiendo al web config las siguientes líneas dentro de la sección <system.web>

<webServices>
<protocols>
<add name="HttpGet"/>
<add name="HttpPost"/>
</protocols>
</webServices>

Con esto ya podríamos consumir nuestro servicio web asmx de .NET 

 

 

 

Servidor casero con direccion ip dinámica

Hace poco recibí un correo de Ángel a través del contacto de esta página preguntando lo siguiente:

Leí que estar en servidor casero montado por ti. yo monte uno también pero tuve que usar no-ip free porque mi dirección es dinámica. como tu lo hiciste en el tullo y que utilizaste? quiero aprender y resolver mi problema.
gracias

Como me pareció un tema bastante interesante he decido crear un post para explicar los métodos que utilizo yo, para solventar este problema.

Yo tengo montado un servidor en casa, precisamente donde está alojada esta página, entre otras. Actualmente tengo una dirección ip dinámica y esto ocasiona problemas de vez en cuando, puesto que si te cambia la dirección ip tu dominio, que está apuntando a la dirección ip de tu servidor, dejará de funcionar correctamente.

El cambio de dirección ip, aunque se tenga dinámica, depende de la configuración de nuestro proveedor de internet. En algunos casos cambia muy muy poco y en otros algo más a menudo. Lo normal es que si no se apaga el router la dirección ip no cambie por lo que normalmente tendremos que realizar pocos cambios.

¿Que ocurre si cambia?, si cambia nuestra ip de casa (o donde tengamos nuestro servidor), tendremos que meternos en los datos DNS de nuestro dominio y anotar la ip nueva.

En mi caso, tengo un programa creado por mí en .NET, que comprueba la dirección ip pública cada 15 minutos y si ha cambiado me manda un correo electrónico con la nueva dirección ip, por lo que lo antes posible procedo a actualizar la dirección ip en mi proveedor de dominios.

Aunque espero mejorar el programa y publicarlo para que lo pueda usar todo el mundo, la alternativa que uso con algunos clientes es http://www.noip.com/ con el que instalando un programita en el servidor siempre podrás acceder a él mediante una dirección (p.j. midirecciondecasa.no-ip.info).

Si tu ip ha cambiado, haciendo un ping a la dirección que tenemos registrada en noip.com, sabremos cuál es nuestra nueva dirección y procederemos a actualizarla en nuestro proveedor de dominios lo antes posible.

 

Como hacer comentarios en ASP.NET C#

Asp  .NEt logtoipo

Si necesitas comentar algún código mientras estás utilizando ASP.NET en el código HTML, puedes hacerlo con la siguiente sintáxis:

<%– Código a comentar –%> 

Todo lo que pongas entre los símbolos <%– y –%> será obviado por el servidor, incluso si es multilínea.

Una cosa muy cómoda en Visual Studio, es seleccionar o ponerte en la línea que quieres comentar y luego utilizar esta combinación de teclas Cntrl + e y seguidamente Cntrl + c, de esta manera tu código se comentará completamente sólo.

También existe la forma de descomentar automáticamente y sería con esta combinación des teclas Cntrl + e y seguidamente Cntrl + u.

Ejemplo:

</html>
<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”><html xmlns=”http://www.w3.org/1999/xhtml” >
<head runat=”server”>
<title>Untitled Page</title>
</head>
<body>
<form id=”form1″ runat=”server”>
<div>

        <%- -<asp:Label ID=”texto” runat=”server”></asp:Label>- -%>

<asp:TextBox ID=”texto” runat=”server”></asp:TextBox>
</div>
</form>
</body>
</html>

 

Como copiar una DateTable en C# (también DataRow)

c-sharp imagen

Si estás programando en .NET con lenguaje C# y necesitas copiar el contenido de una tabla (DataTable) a otra hay una forma muy sencilla de hacerlo.

Tenemos 2 DataTables:

DataTable tabla1 = new DataTable();
DataTable tabla2 = new DataTable();

Si hacemos tabla2 = tabla1 NO ES VÁLIDO, porque lo que hagamos en una tabla se reflejaría en la otra.

Podemos utilizar para copiarla lo siguiente:

//Clonamos la estructura
tabla2 = tabla1.Clone();
//Recorremos las filas de la tabla1 y las importamos en la tabla2
Foreach(DataRow dr in tabla1.Rows)
{
tabla2.ImportRow(dr);
}

Con esto tendríamos 2 tablas iguales pero sin estar vinculadas referencialmente. Problema resuelto