Ok, ja tenim les imatges sel·leccionades, posades en una estructura FormData i enviades al servidor. Ara doncs és el moment de guardar-les on toca i posar-les a la BBDD (només el path). Sempre he estat de la filosofia que qui millor guarda els fitxers són els sistemes de fitxers, les BBDD les deixo sempre per dades (cadenes de text, números etc... no fitxers). Així doncs la rutina següent fa:
- Gestió de la carpeta on es guarden els fitxers.
- Un bucle que per cada imatge...
- La guarda a disc
- Insereix les seves dades a la BBDD
private void GetFileAndSave()
{
try
{
Resp.ContentType = "plain/text";
string Arrel = Servr.MapPath("/");
string Any = DateTime.Now.Year.ToString();
string Mes = DateTime.Now.Month.ToString();
clsImatges Imatges = new clsImatges(ConnStr);
Dictionary<string, string> Params = new Dictionary<string, string>();
string Imatge;
string IdPost = Req["IdPost"];
string HDDPathImgs;
HDDPathImgs = Arrel + PathImgs + "/" + Any + "/" + Mes;
if (!Directory.Exists(HDDPathImgs))
{
Directory.CreateDirectory(HDDPathImgs);
}
foreach (string strFile in Req.Files)
{
HttpPostedFile postedFile = Req.Files[strFile];
Imatge = HDDPathImgs + "/" + postedFile.FileName;
if (!File.Exists(Imatge))
{
postedFile.SaveAs(Imatge);
Params.Add("Imatge", Imatge);
Params.Add("IdPost", IdPost);
Imatges.INS(Params);
Params.Clear();
}
}
Resp.Write("OK");
}
catch (Exception Err)
{
Resp.Write("ERROR: " + Err.Message);
}
}
Un cop guardades les imatges al servidor, el javascript pregunta quines imatges té associades el post per posar-les i que es puguin fer servir. Es fa servir una clase per després serialitzar en JSON. D'això s'encarrega la següent rutina:
public class clsImatgeJSON
{
public string IdImatge { get; set; }
public string PathImatge { get; set; }
}
private void LoadData()
{
Resp.ContentType = "application/json";
clsImatges Imatges = new clsImatges(ConnStr);
Dictionary<string, string> Params = new Dictionary<string, string>();
DataTable tblImatges;
string IdPost = Req["IdPost"];
List<clsImatgeJSON> ImatgesJSON = new List<clsImatgeJSON>();
clsImatgeJSON ImatgeJSON;
string Arrel = Servr.MapPath("/");
Params.Add("IdPost", IdPost);
tblImatges = Imatges.GET(Params);
foreach (DataRow DR in tblImatges.Rows)
{
ImatgeJSON = new clsImatgeJSON();
ImatgeJSON.IdImatge = DR["IdImatge"].ToString();
ImatgeJSON.PathImatge = DR["Imatge"].ToString().Replace(Arrel, "/");
ImatgesJSON.Add(ImatgeJSON);
}
Resp.Write(clsJSON.Serialize(ImatgesJSON));
}
Una altra funcionalitat que cobreix la part servidora és la eliminació de fitxers (peticions que també arriben via Ajax). S'ha d'eliminar de la BBDD i del sistema de fitxers.
private void Delete()
{
try
{
Resp.ContentType = "plain/text";
string IdImatge = Req["IdImatge"];
clsImatges Imatges = new clsImatges(ConnStr);
Dictionary<string, string> Params = new Dictionary<string, string>();
DataTable tblImatges;
Params.Add("IdImatge", IdImatge);
tblImatges = Imatges.GET(Params);
if (File.Exists(tblImatges.Rows[0]["Imatge"].ToString()))
{
File.Delete(tblImatges.Rows[0]["Imatge"].ToString());
Imatges.DEL(Params);
Resp.Write("OK");
}
else
{
Resp.Write("ERROR: Fitxer no trobat");
}
}
catch (Exception Err)
{
Resp.Write("ERROR: " + Err.Message);
}
}
L'acces a BBDD es fa mitjançant la capa d'acces a BBDD que faig servir habitualment, de la que ja parlaré en un altra post. |
Sembla que l'upload d'imatges via Ajax sigui el sant grial o la pedra filosofal d'internet. Algo que hauria de ser senzill es complica sobremanera, troves múltiples opcions i solucions. I quan enlloc d'un únic fitxer es volen pujar uns quants alhora ja és la bomba, si afegim barres de progrés UUUAHHH!!! Sembla que les queixes continues dels desenvolupadors ha aconseguit que aquest tema es vagi posant en l'HTML5, aleshores el que passa és que el suport en diferents navegadors varia. Jo faig servir Firefox, així que per mi que funcioni en FF ja hi ha prou. He triat una solució que fa servir jQuery i FormData (és una característica de HTML5 i sembla que IE10 la suporta i FF també). De fet disposar d'aquesta eina fa que sigui senzill. El procés consta de varies fases:
- HTML amb salsa especial que permet la multiple selecció de fitxers en el quadre de dialeg que s'obre
- Un processat previ en Javascript per omplir l'objecte FormData
- Fer una crida ajax amb jQuery configurada d'una forma especial que no causi errors al contenir fitxers (aqui m'he saltat el tema de les barres de progres, posaré com es fa però no ho he implementat)
- Guardar el fitxers en el servidor
- Refrescar els fitxers al navegador
En els propers posts aniré desgranant cada un d'aquest punts |
Fent proves i més proves he trobat que el resaltador de sintaxis en el seu estat original no troba correctament algunes paraules. Per exemple les paraules reservades "get" o "set", o String i StringBuilder. Mirant mirant he trobat el tros de codi ofensiu.
public bool IsKeyword(string s)
{
return (Keywords.BinarySearch(s, Comparer) >= 0);
}
El que funciona és:
public bool IsKeyword(string s)
{
bool Trobat = false;
if (CaseSensitive)
{
foreach (string Keyword in Keywords)
{
if (String.Equals(s, Keyword, StringComparison.Ordinal))
{
Trobat = true;
break;
}
}
}
else
{
foreach (string Keyword in Keywords)
{
if (String.Equals(s, Keyword, StringComparison.OrdinalIgnoreCase))
{
Trobat = true;
break;
}
}
}
return Trobat;
}
|
Estic muntant aquesta pàgina, poc a poc vaig afegint coses que em semblen interessants. Tinc pensat afegir codi que trobi interessant al blog, com eina de consulta, per aquelles vegades que passa allò de: "això ho tenia fet en algun lloc". I clar si afegeixo codi queda una mica lleig que estigui com text pla. I és aquí on entra el resaltador de sintaxis, per donar-li un xic de color. Això mateix passa en la demo de jquery que tinc muntada, que en la documentació vaig afegir trossos de codi. Aleshores vaig posar una llibreria javascript que fa aquesta tasca, i funciona prou bé. Com a avantatge té que no es modifica el codi original (es a dir que a la BBDD on està el text del post, el codi està sense modificacions, tal com estava a l'editor), i aleshores desde el manteniment per moltes vegades que s'editi el contingut no es fa cap embolic al guardar (es a dir, quan es guarda des de el manteniment no torna a recalcular la coloració del codi). Com inconvenient té que és javascript, no tots els navegadors van igual, no tothom té el javascript en marxa, començant per un servidor. Per això m'he decidit a fer un resaltador de sintaxis, però l'he fet en Winforms (sí, sí, la tecnologia en teoria morta), té un "textbox" i un botó. El resultat va a a parar al clipboard i després ho puc engaxar aquí. El blog l'únic que ha de tenir en compte és afegir uns estils al CSS i llestos. Haig de conservar el codi original en fitxers de text per si haig de retocar el codi colorejat. I que millor que fer servir d'exemple que el propi codi del colorejador...
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
namespace Colorizer
{
public class clsColorizer
{
public LanguageRulesCollection Languages { get; set; }
public string CssClassKeyword { get; set; }
public string CssClassSymbol { get; set; }
public string CssClassString { get; set; }
public string CssClassOperator { get; set; }
public string CssClassComment { get; set; }
public clsColorizer(string languageRulesFile)
{
Languages = new LanguageRulesCollection(languageRulesFile);
}
public string ColorizeCode(string code, string language)
{
LanguageRules rules = Languages.GetLanguageRules(language);
if (rules == null)
throw new Exception(String.Format("Undefined language \"{0}\" was specified", language));
Dictionary<TokenClass, string> cssClasses = new Dictionary<TokenClass, string>()
{
{ TokenClass.Keyword, CssClassKeyword },
{ TokenClass.Symbol, CssClassSymbol },
{ TokenClass.String, CssClassString },
{ TokenClass.Operator, CssClassOperator },
{ TokenClass.Comment, CssClassComment },
};
StringBuilder builder = new StringBuilder();
LanguageTokenizer tokenizer = new LanguageTokenizer(rules, code);
for (Token token = tokenizer.ParseNext(); token.Class != TokenClass.Null; token = tokenizer.ParseNext())
{
token.Value = WebUtility.HtmlEncode(token.Value);
string style;
if (cssClasses.TryGetValue(token.Class, out style) && !String.IsNullOrWhiteSpace(style))
builder.AppendFormat("<span class=\"{0}\">{1}</span>", style, token.Value);
else
builder.Append(token.Value);
}
return builder.ToString();
}
}
}
El més difícil alhora de fer un resaltat de sintaxis és trobar els identificadors de tipus, no he trobat cap resaltador que ho faci bé. Bé això no és del tot cert, hi ha un que sí ho fa però gairebé et compila l'aplicació (per saber quins tipus hi ha, i no és capaç de trobar-los en trossos de codi petits o aillats). També hi ha unes "productivity tools" del VisualStudio que et permeten guardar el codi com HTML, però al final m'he decidit per una cosa senzilleta i que no tingui que afegir res al VisualStudio, encara que no troba gaire bé els identificadors de tipus, he afegit els més comuns StringBuilder, DataTable etc... |