Recentment he trobat un article que es preguntava si encara és necessari aprendre jQuery, o si ja es podia abandonar. Segons el noi que escriu ja no cal aprendre jQuery ja que el Javascript normal ja fa tot el que el jQuery fa. Posa els següents exemples:
Selectors:
// jQuery
$('.myClass');
// JavaScriptdocument.getElementsByClassName('myClass');
// jQuery
$('#myID');
// JavaScriptdocument.getElementById('myID');
//Fer servir el nou QuerySelector/*
* Classes
*/// Agafar el primer node amb la classe .myClass document.querySelector('.myClass');
// Retorna una llista de nodes amb .myClassdocument.querySelectorAll('.myClass');
/*
* ID
*/// Obté el IDdocument.querySelector('#myID');
/*
* Tags
*/// Una llista de nodes dels 'div'document.querySelectorAll('div');
També comenta que es poden fer coses amb afegir i treure una classe:
// jQuery
$('div').addClass('myClass');
// JavaScriptvar div = document.querySelector('div');
div.classList.add('myClass');
// jQuery
$('div').removeClass('myClass');
// JavaScriptvar div = document.querySelector('div');
div.classList.remove('myClass');
// jQuery
$('div').toggleClass('myClass');
// JavaScriptvar div = document.querySelector('div');
div.classList.toggle('myClass');
// JavaScript Document.readydocument.addEventListener('DOMContentLoaded', function() {
// DOM ready, run it!
}, false);
L'article segueix amb més exemples sobre events, arrays, modificació d'atributs d'un node, manipulació del CSS etc...
Jo penso que sí, que encara cal fer servir i aprendre jQuery, no només per que jo en faci un us extensiu (de fet Noticias3D té molta cosa feta amb javascript normal) si no per que hi ha coses que amb jQuery són més còmodes, per exemple les crides ajax. Tot el codi d'una crida ajax en jQuery està en un sol lloc, en Javascript invoca a una funció callback. Amb jQuery hi ha tot un munt de controls i llibreries que no seran fàcils de subtituir, jqGrid, el deserialitzador de JSON, etc... només per dir-ne dues).
També en l'article menciona que per exemple els nous atributs data-* d'HTML 5 encara no estan estandaritzats del tot i tenen comportaments diferents segons el navegador, en aquest sentit jQuery farà el que se li dóna millor, es a dir proporcionar una capa d'abstracció que programes les coses una vegada i prou. Si per sota canvia la forma en que es fa aleshores només cal modificar la versió de la llibreria jQuery i llestos. Així que jo de moment seguiré fent servir jQuery.
#29/04/2015 18:17 Programació Javascript Autor: Alex Canalda
Les petites funcions sempre cal tenir-les a mà. Es fan servir un cop, i un altra, i un altra... Aquesta és una d'aquelles funcions que sempre estem repetint.
Donat un string com per exemple: "Lorem ipsum dolor sit amet, 'consectetur' adipisici elit". Es vol obtenir "consectetur", es a dir el text que està entre els '. Per això es pot fer:
string Text = "Lorem ipsum dolor sit amet, 'consectetur' adipisici elit";
string Resultat = SubString(Text, "'", "'");
//Resultat = consecteturpublicstring SubString(string OnBusquem, string CaracterInicial, string CaracterFinal)
{
int Inici = OnBusquem.IndexOf(CaracterInicial) + CaracterInicial.Length;
int Fi = OnBusquem.IndexOf(CaracterFinal, Inici);
return OnBusquem.Substring(Inici, Fi - Inici);
}
També es pot fer d'una altra manera amb el mateix resultat:
Quina és millor? Quina s'entén millor? Per gustos els colors. Encara que a mi m'agrada més la primer opció ja que té algo més de flexibilitat. Per exemple, imaginem que enlloc que el separador sigui un caràcter, que sigui varis. Com quan volem extreure un valor de dins d'un string XML (sense muntar l'objecte XML), quedaria algo com:
Per validar que un string té una pinta com "0F4D3398FFDD", és a dir és un string Hexadecimal. Es pot fer una funció com:
publicbool OnlyHexInString(string test)
{
// For C-style hex notation (0xFF) you can use @"\A\b(0[xX])?[0-9a-fA-F]+\b\Z"returnSystem.Text.RegularExpressions.Regex.IsMatch(test, @"\A\b[0-9a-fA-F]+\b\Z");
}
Fer servir una expressió regular està molt bé, però ho trobo una mica excessiu ja que no cal tanta potència per fer algo senzill. Penso que és millor fer:
privatebool IsHex(IEnumerable<char> chars)
{
bool isHex;
foreach (var c in chars)
{
isHex = ((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F'));
if (!isHex)
returnfalse;
}
returntrue;
}
#25/03/2015 18:22 Programació C# Autor: Alex Canalda
He tingut que implementar la firma MAC ANSI X9.19 (MAC = Message Authentication Code) i com tots els temes de seguretat és curiós la poca informació que hi ha.
Una firma (MAC) d'aquest tipus serveix per verificar que un missatge no ha estat manipulat i ens arriba tal com es va enviar. Si hi ha un error a la xarxa es detectarà, o si un "algú" dolent modifica el missatge no podrà regenerar la firma per que no coneix la clau a partir de la que es genera la MAC. El receptor com sí té aquesta clau pot verificar el contingut del missatge.
Aquesta firma MAC ANSI X9.19 és un estàndard bancari "made in USA". És una evolució del X9.9 i també es coneix com a Retail-MAC. És un xifrat dels anomenats DES-CBC, on DES vol dir "Data Encryption Standard" i CBC és el "Cipher Block Chaining". Existeix una norma internacional semblant, una mica més permissiva, la ISO 9807 ja que permet fer servir altres algoritmes de xifrat. Diguem que la ANSI X9.19 és una possible implementació de la ISO 9797 quan la mida del bloc a xifrar és de 64 bits, la longitud de la MAC 32 i es fa servir el DES com algoritme de xifrat.
El DES es un algoritme de xifrat ja força antic que fa servir claus de 56 bits però amb la X9.19 també s'aplica un xifrat extra en l'últim pas fent servir una clau de 128bits com si fos un 3DES normal. Els passos a seguir són els següents:
Al missatge d'entrada s'ha de posar padding (relleno). En aquest cas com no cal treure'l posteriorment es posen els bytes a 00 que facin falta fins que la longitud del missatge és múltiple de 8 bytes.
Es divideix la clau de 128bits en dues sub-claus de 64, la part esquerra s'anomena K, la part dreta K'.
Es divideix el missatge en blocs de 8 bytes.
Es xifra amb DES el primer bloc amb la clau K.
Al resultat es fa una XOR byte a byte amb el següent bloc (és el CBC).
Es xifra el resultat de la XOR amb la clau K. Si NO és l'últim bloc tornem al pas anterior. Si és l'últim bloc anem al pas següent.
Aquest últim resultat es desxifra amb la clau K'. Òbviament encara que sigui un desxifrat no s'obté res coherent.
Es xifra altra cop amb la clau K. És com si fos un 3DES en aquest últim pas. El resultat és la MAC.
Però millor una imatge:
MAC ANSI X9.19
He fet dues implementacions en C#, una fent les coses manuals i l'altra amb llibreries de sistema, ambdues ofereixen el mateix resultat. Al codi hi ha un exemple que he trobat amb els valors calculats.
publicbyte[] SubArray(byte[] data, int index, int length)
{
byte[] result = newbyte[length];
Array.Copy(data, index, result, 0, length);
return result;
}
privatevoid btnFirma_Click(object sender, EventArgs e)
{
try
{
if (!ValidarClau()) return;
NetejaTXTs();
byte[] IV = newbyte[8]; //empty byte arraybyte[] key = ConvertHexStringToByteArray(txtKey.Text);
byte[] LeftKey = SubArray(key, 0, 8);
byte[] RightKey = SubArray(key, 8, 8);
byte[] data;
if (chkHexString.Checked)
{
data = ConvertHexStringToByteArray(Neteja(txtOriginal.Text));
}
else
{
data = Encoding.ASCII.GetBytes(Neteja(txtOriginal.Text));
}
//Exemple//Dades = 4E6F77206973207468652074696D6520666F7220616C6C20//Clau = 0123456789ABCDEFFEDCBA9876543210//Firma = A1C72E74EA3FA9B6
DES DESalg = DES.Create();
DESalg.Mode = CipherMode.CBC;
DESalg.Padding = PaddingMode.None;
ICryptoTransform SimpleDES_Encriptador = DESalg.CreateEncryptor(LeftKey, IV);
ICryptoTransform SimpleDES_Desencriptador = DESalg.CreateDecryptor(RightKey, IV);
byte[] result = newbyte[8];
byte[] datablock = newbyte[8];
int remain = data.Length % 8;
int LoopCount = data.Length / 8;
/*
//Padding a 0
if (remain != 0)
{
int extra = 8 - (data.Length % 8);
int newLength = data.Length + extra;
byte[] newData = new byte[newLength];
Array.Copy(data, newData, data.Length);
data = newData;
}
result = SimpleDES_Encriptador.TransformFinalBlock(data, 0, data.Length);
byte[] block = new byte[8];
// Agafem l'ultim block
Array.Copy(result, result.Length - 8, block, 0, 8);
// Desencriptar l'ultim bloc a la K'
block = SimpleDES_Desencriptador.TransformFinalBlock(block, 0, 8);
// Encriptar altra cop el resultat amb K
block = SimpleDES_Encriptador.TransformFinalBlock(block, 0, 8);
result = block;
*///Si el que s'ha de firmar és multiple de 8...if (remain == 0)
{
LoopCount--;
remain = 8;
}
//Primer block
Array.Copy(data, 0, datablock, 0, 8);
result = EncryptBlock(SimpleDES_Encriptador, datablock);
for (int i = 1; i < LoopCount; i++)
{
datablock = newbyte[8];
Array.Copy(data, i * 8, datablock, 0, 8);
//Això fa el CBC
datablock = XorArray(datablock, result);
result = EncryptBlock(SimpleDES_Encriptador, datablock);
}
//Ultim blockbyte[] LastBlock = newbyte[8];
//Això fa padding a zeros
Array.Copy(data, data.Length - remain, LastBlock, 0, remain);
LastBlock = XorArray(LastBlock, result);
result = EncryptBlock(SimpleDES_Encriptador, LastBlock);
result = EncryptBlock(SimpleDES_Desencriptador, result);
result = EncryptBlock(SimpleDES_Encriptador, result);
if (!chkHexString.Checked) txtBase64.Text = ConvertByteArrayToHexString(data);
txtEncrypted.Text = ConvertByteArrayToHexString(result);
}
catch(Exception E)
{
MessageBox.Show(E.Message);
}
}
publicbyte[] XorArray(byte[] buffer1, byte[] buffer2)
{
for (int i = 0; i < buffer1.Length; i++)
buffer1[i] ^= buffer2[i];
return buffer1;
}
privatebyte[] EncryptBlock(ICryptoTransform crypt, byte[] toEncrypt)
{
try
{
MemoryStream mStream = new MemoryStream();
CryptoStream cStream = new CryptoStream(mStream,
crypt,
CryptoStreamMode.Write);
cStream.Write(toEncrypt, 0, toEncrypt.Length);
cStream.FlushFinalBlock();
byte[] ret = mStream.ToArray();
cStream.Close();
mStream.Close();
Console.WriteLine("DES OUTPUT : " + ConvertByteArrayToHexString(ret));
return ret;
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
returnnull;
}
}
#17/03/2015 18:28 Programació C# Autor: Alex Canalda
El C# 6 portarà noves formes de fer coses, es modifica la sintaxi del llenguatge afectant a l'estil de codificar de cadascú, a mi particularment aquestes són les que més m'han cridat l'atenció
Interpolació d'strings:
//Abans es feia això:string STRWS = StarWars;
StringBuilder Build = newStringBuilder;
Build.AppendFormat("Ja falta poc per la nova peli de {0}", STRWS);
string Frase = Build.Tostring();
//---- En C# 6 es faràstring Frase = $"Ja falta poc per la nova peli de {STRWS}";
Nou operador nameof: abans es tenia que reflection per obtenir noms de variables, etc... ara amb aquest operador es com si es tingués la reflection ja muntada dins el llenguatge.
Exceptions filtrades, que ja es podia fer llançant exceptions més detallades però bueno...
try
{
thrownewException("Error");
}
catch (Exception ex) if (ex.Message == "ErrorMoltXungo")
{
// Aquest no s'executa.
}
catch (Exception ex) if (ex.Message == "Error")
{
// Aquest sí s'executa
WriteLine("Error");
}
Per obtenir metadades del SQL Server s'han de fer consultes de les taules de sistema. Allí hi ha les descripcions de tota la BBDD. Per exemple per obtenir el nom de les taules:
SELECT name FROM sys.objects WHERE type='u'ORDERBY name
Seguint amb el tema de les stored procedures, per obtenir el nom, tipus, longituds etc... dels paràmetres de les storeds cal fer:
SELECT
SO.name AS [ObjectName],
SO.Type_Desc AS [ObjectType],
P.name AS [ParameterName],
TYPE_NAME(P.user_type_id) AS [ParameterDataType],
P.max_length AS [ParameterMaxBytes],
P.precision AS [Precision],
P.scale AS [Scale],
P.is_output AS [IsOutPutParameter]
FROM sys.objects AS SO
INNERJOIN sys.parameters AS P
ON SO.OBJECT_ID = P.OBJECT_ID
WHERE SO.TYPE ='P'ORDERBY SO.name, P.parameter_id
Amb aquesta informació es poden fer validacions en temps d'execució...
#16/02/2015 15:38 Programació SQLServer Autor: Alex Canalda
En la llibreria que crida a SQL Server que m'he fet falta la crida a Stored Procedures, i estic mirant de com fer-ho. He trobat llocs on fan d'una manera, hi ha per tots els gustos. El que he trobat és una forma un xic arriscada: la que fa servir el tipus "object" de C#. Primer cal veure que és el "boxing/unboxing".
int i = 123;
// La següent linia "boxes" (encapsa) i.object o = i;
Boxing
Cal observar que encara que sigui un "object" la variable conserva el tipus, i també que ocupa un espai de memòria diferent a la variable que a encapsat. Es a dir, que si "i" modifica el seu valor el "object" no. Igualment un cop des-encapsada si es modifica l'object no es modifica la variable on s'ha assignat el seu valor.
int i = 123; // un valorobject o = i; // encapsatint j = (int)o; // des-encapsat
Unboxing
Cal vigilar molt que quan es el des-encapsat la variable a la que es fa l'assignació ha de ser del mateix tipus que la original, si no es produeix una InvalidCastException.
I els SQL Parameters? Doncs resulta que els SqlParameter tenen un constructor que té els següents paràmetres: Constructor (String, Object). On el "string" és el nom del paràmetre i el "object" és el valor. El constructor dedueix el tipus del paràmetre a partir del tipus de l'objecte encapsat. I ho fa seguint la següent taula:
Tipus de la variable
Tipus a la BBDD
Boolean
Bit
Byte
TinyInt
byte[]
VarBinary (cal vigilar si la longitud de l'array supera la longitud del varbinary)
Char
No suportat
DateTime
DateTime
DateTimeOffset
DateTimeOffset (només a partir de SQL Server 2008 inclòs)
Decimal
Decimal
Double
Float
Single
Real
Guid
UniqueIdentifier
Int16
SmallInt
Int32 (els int normals)
Int
Int64
BigInt
String
NVarChar (cal vigilar si la longitud de l'string supera la longitud del nvarchar)
TimeSpan
Time (només a partir de SQL Server 2008 inclòs)
Aleshores és molt perillós passar un object al constructor del SqlParameter perquè es fàcil despistar-se i que no encaixi amb el tipus de base de dades i com està "boxed" no hi ha una visió del que està passant exactament.
#13/02/2015 13:32 Programació C# SQLServer Autor: Alex Canalda
Un cop està preparada tota la configuració necessària per fer la invocació només queda aquesta pròpiament dita. En l'aplicació també hi han els botons de "Load" i "Save" que el que fan és escriure els valors dels controls en un fitxer XML i recuperar els valors, no cal que els expliqui...
Abans de pròpiament fer la invocació a Webservice, cal configurar l'accés. S'ha de tenir en compte que la URL pot ser HTTPS, pot haver-hi un proxy previ per accedir al servidor web o potser el servidor web fa servir autenticació bàsica HTTP.
Aquests 3 punts requereixen una configuració prèvia a la invocació.
HTTPS: Per acceptar connexions HTTPS el EndPoint local ha de reconèixer el certificat com a vàlid. Per això cal afegir un validador de certificats (només cal afegir-lo un cop), que en aquesta eina per fer proves és un validador que els accepta tots. Per això en l'event Form_Load es posa un call back a la rutina que fa l'acceptació.
Si es vol fer l'autenticació bàsica HTTP, cal fer:
//Afegir una capçalera HTTP a la crida, l'string es fa a partir de la//clase de més a sota, req és una variable de tipus HttpRequest.if (HTTPBasic != null)
{
string auth = HTTPBasic.CreateAuthorization();
req.Headers.Add("Authorization", "Basic " + auth);
}
publicclass clsHTTPBasicAuthorization
{
publicstring Domini { get; set; }
publicstring Usr { get; set; }
publicstring Pwd { get; set; }
/// <summary>/// Retorna un string per posar en header authorization d'una petició HTTP/// </summary>/// <param name="domini">Sense HTTP ni el subdomini , només google.es. Es opcional, es pot passar ""</param>/// <param name="userName">Usuari</param>/// <param name="password">Pwd</param>/// <returns>L'string en Base64 que s'ha de posar en totes les peticions</returns>publicstring CreateAuthorization()
{
string auth = "";
if (!string.IsNullOrWhiteSpace(Domini)) auth = Domini + @"\";
auth += Usr + ":" + Pwd;
auth = Convert.ToBase64String(Encoding.Default.GetBytes(auth));
return auth;
}
}
Finalment si es vol fer servir un proxy cal afegir la configuració del mateix a la crida:
publicclass clsProxy
{
publicstring ProxyURL { get; set; }
publicstring ProxyUsr { get; set; }
publicstring ProxyPwd { get; set; }
publicstring ProxyPort { get; set; }
public WebProxy GetProxy()
{
if (string.IsNullOrWhiteSpace(ProxyURL)) returnnull;
else
{
WebProxy Pxy = new WebProxy();
UriBuilder UriBld = new UriBuilder(ProxyURL);
if(!string.IsNullOrWhiteSpace(ProxyPort)) UriBld.Port = int.Parse(ProxyPort);
Pxy.Address = UriBld.Uri;
if (!string.IsNullOrWhiteSpace(ProxyUsr))
{
Pxy.Credentials = new NetworkCredential(ProxyUsr, ProxyPwd);
}
else Pxy.UseDefaultCredentials = true;
return Pxy;
}
}
}
//Després a la HttpRequest cal fer:
req.Proxy = pProxy.GetProxy();
#11/02/2015 17:37 Programació C# Autor: Alex Canalda