mercoledì 16 novembre 2011

Multi thread ... console application...

Questa volta è colpa mia...

mi sono messo in mente di realizzare un command che mi estragga da una tabella un campo xml, chiaro per quel che mi rigurada la query e statica, ma nulla ci vieta di prendere questa soluzione e di estenderla.

Come sono solito sostenere quello che ho realizzato è sempre una base.. di contro si può fare qualcosa per migliorarlo.

La gigioneria è che per questa situazione è possibile ottenere un thread per ogni stringa di connessione presenete nel app.config, dandomi la possibilità di lavorare su basi dati differenti senza troppe complessità.

Ancora una piccola chicca.. chiamandolo come comando dos.. l'output è già un xml formattato e fruibile...

Che cosa volete di più ?? che legga la query dall'app.config.. ? naaa fatelo voi.


using System;
using System.Configuration;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

namespace XMLextractor
{
/// <summary>
/// State Object per invocare il thread
/// </summary>
public class stateObject
{
/// <summary>
/// Imposta o restituisce gli elementi da cercare
/// </summary>
public string[] trids;
/// <summary>
/// Imposta o restituisce il percorso
/// </summary>
public string path;
/// <summary>
/// Imposta o restituisce la connessione.
/// </summary>
public string sCnn;
}

class Program
{
/// <summary>
/// Resituisce la query da eseguire
/// </summary>
/// <returns>SELECT *** </returns>
private static string getQuery()
{
//impostare qui la query di ricerca
return "SELECT [campo XML] from Tabella WHERE campo = [CHIAVE]"
}
/// <summary>
/// Restituisce se il file esiste
/// </summary>
/// <param name="fName">Nome del file </param>
/// <returns>True - False</returns>
private static bool fileExist(string fName)
{
return File.Exists(fName);
}

/// <summary>
/// Restituisce se la directory esiste
/// </summary>
/// <param name="dName">Nome della directory</param>
/// <returns>True - False </returns>
private static bool directoryExist(string dName)
{
return Directory.Exists(dName);
}

/// <summary>
/// Scrive il file in base al numero di polizza
/// </summary>
/// <param name="nChiave">Nome del file</param>
/// <param name="path">percorso</param>
/// <param name="fileBody">corpo letto da db</param>
private static void WirteFile(string nChiave,
string path,
string fileBody)
{
TextWriter tw = new StreamWriter(Path.Combine(path, nChiave));
tw.Write(fileBody);
tw.Close();
tw = null;
}

/// <summary>
/// Restituisce l'elenco dei trID letti dal file
/// </summary>
/// <param name="fName">string nome del file</param>
/// <returns>array di file</returns>
private static string[] GetIDs(string fName)
{
string[] dataFile = { };

TextReader tr = new StreamReader(fName);
dataFile = tr.ReadToEnd().Replace("\r", "").Split(new char[] { '\n' });
tr.Close();
tr = null;

return dataFile;

}


/// <summary>
/// Legge da db le chiavi presenti nel file.
/// </summary>
private static void ReadDbData(object obj)
{

stateObject curProcessData = (stateObject)obj;

string[] trID = curProcessData.trids;
string sConn = curProcessData.sCnn;
string dPath = curProcessData.path;


string ext = "<extraction>";
string thrId = Thread.CurrentThread.ManagedThreadId.ToString();
ext += "<thread>" + thrId + "</thread>";
ext += "<connection> " + sConn + "</connection>";

for (int j = 0; j < trID.Length; j++)
{
string sql = getQuery().Replace("[CHIAVE]", trID[j]);

ext += "<node current=\"" + j.ToString() +"\">";
ext += "<trid>" + trID[j]+"</trid>";
ext += "<query>" + sql +"</query>";

using (SqlConnection conn = new SqlConnection(sConn))
{
try
{
conn.Open();
SqlCommand scm = new SqlCommand(sql, conn);
string tdata = (string)scm.ExecuteScalar();

if (tdata != null)
{
WirteFile(trID[j] + ".xml", dPath, tdata);
ext += "<dataSaved>true</dataSaved>";
}
else
ext += "<dataSaved>flase</dataSaved>";

scm = null;
conn.Close();

}
catch (Exception ex)
{

}
finally
{

}
}
ext += "</node>";
}
ext += "</extraction>";
Console.WriteLine(ext);
}

/// <summary>
/// ingresso dell'applicazione.
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
if (args.Contains("h") || args.Contains("H"))
{
Console.WriteLine(
"prototipo chiamata XMLextractor [file id] [outputfolder]");
Console.WriteLine(
"prototipo chiamata XMLextractor [file id] [outputfolder] > xmlDataFile.xml");
Console.ReadLine();
return;
}
string fName = args[0];
string dName = args[1];
Console.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\" ?><root>");
if (!directoryExist(dName))
{
Console.WriteLine("<error>Verificare la directory di output</error>");
Console.ReadLine();
return;
}
List<Thread> TRS = new List<Thread>();
if (fileExist(fName))
{
for (int i = 0;
i < System.Configuration.ConfigurationManager.ConnectionStrings.Count;
i++)
{
string sConn = System.Configuration.ConfigurationManager.ConnectionStrings[i].ConnectionString;
ParameterizedThreadStart realThread = new ParameterizedThreadStart(ReadDbData);
Thread tx = new Thread(realThread);
stateObject sO = new stateObject(){
trids = GetIDs(fName),
path=dName,
sCnn = sConn
};
tx.Start(sO);
TRS.Add(tx);
}
}
else
{
Console.WriteLine("<error>il file dei transaction id Non esiste</error>");
}
while (TRS.Count > 0)
{
if (!TRS[0].IsAlive) { TRS.RemoveAt(0); }
}
Console.WriteLine("</root>");
}
}
}


Devo essere onesto l'unica cosa con cui ho litigato forte... è stata la chiusura del tag root...

martedì 15 novembre 2011

C# Sequence contains no elements

Questo problema ha tante possibili radici, ma generalmente si verifica quando una lambda fallisce, o meglio quando i criteri della lambda portano al fallimento della richiesta stessa.

In questo primo esempio ci si presenta l'eccezione nella First

public class item
{
public int id;
public string name;
}


static void Main(string[] args)
{
List<item> items = new List<item>();

items.Add(new item() { id = 1, name = "ME" });
items.Add(new item() { id = 2, name = "TE" });

var item = items.First(c => c.id == 3);

Console.ReadLine();
}


Una via di risoluzione è la seguente tuttavia non è sempre la migliore.

var item = items.FirstOrDefault(c => c.id == 3);


Oppure verificando prima con un count

static void Main(string[] args)
{
List<item> items = new List<item>();

items.Add(new item() { id = 1, name = "ME" });
items.Add(new item() { id = 2, name = "TE" });


item iSelected = new item();
if (items.Count(c=>c.id ==3)> 0)
{
iSelected = items.FirstOrDefault(c => c.id == 3);
}

Console.ReadLine();
}


In questo modo si avrà sempre la possibilità di ovviare all'errore..

lunedì 14 novembre 2011

How To: Do a TFS Query via C#

Una cosa sicuramente interessante di T.f.s è la gestione delle porprie query e di come lavorarci sopra.

Per comodo mi sono fatto un breve applicativo, per poter verificare che cosa ho aperto.

Ho creato un form è ho incluso le due referenze / librerie...
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;


public partial class frmQuery : Form
{

private string teamURL = "http://[URL]";

private string query = "SELECT * " +
" FROM WorkItems " +
" WHERE [System.TeamProject] " +
"=\"PATH\" and [System.AssignedTo] in " +
" ([User LIST]) " +
" ORDER BY [System.State] ";


private List<string> DefectList = new List<string>();

private NetworkCredential nc = new
NetworkCredential("[NomeUtente]", "[Password]", "[Dominio]");

public frmQuery()
{
InitializeComponent();

GetDefect();
}

public void GetDefect()
{

TfsTeamProjectCollection tpc = new
TfsTeamProjectCollection(new Uri(teamURL), nc);
WorkItemStore store = (WorkItemStore)tpc.GetService(typeof(WorkItemStore));


DefectList.Clear();

var wiCollection = store.Query(query);

// Iterate through all work items
foreach (WorkItem wi in wiCollection)
{
if (wi.Fields[35].Value.ToString() != "")
{
DefectList.Add(wi.Fields[35].Value.ToString()
+ "-" + wi.Fields[1].Value.ToString());
}
}
lstResult.DataSource = DefectList.ToArray<string>();
}
}


Ancora una volta il concetto è molto semplice, la resa è buona.

How To: Add and Find Control Type.

Mi sono sempre domandato "ma come sarà quando sarò io a fare delle domande sul codice..." e ancora non ho risposta a questa domanda...
Ringrazio tuttavia il personaggio che in questi giorni mi sta ponendo i questi più astratti del pianeta.

Oggi la sua richiesta "meritevole di risposta" è stata...
Ho un controllo il cui scopo è di contenere controlli, questi sono caricati dinamicamente, come faccio a sapere che controlli contiene alla fine del flusso ??

Bhe di metodi ce ne sono davvero tanti per cui è addirittura possibile utilizzare una lambda per le estrazioni specifiche...

Tuttavia il seguente è il più semplice.

Per prima cosa realizziamo un form con 2 bottoni, un flowlayout panel e una listbox.

La forma e l'aspetto lo lascio al vostro estro.

public partial class frmTest : Form
{
int i = 0;

public frmTest()
{
InitializeComponent();
}

private void btnAdder_Click(object sender, EventArgs e)
{
flpMaster.Controls.Add(NewControl());
}


public System.Windows.Forms.Control NewControl()
{

if (i == 0)
{

Label l = new Label();
l.Text = " hahahhah !";

i++;
return l;

}

if (i == 1)
{

TextBox l = new TextBox();
l.Text = "Ma dai ";

i++;
return l;

}


return new RadioButton();
}

private void btnLister_Click(object sender, EventArgs e)
{
lstControls.Items.Clear();

foreach (Control c in flpMaster.Controls)
{
lstControls.Items.Add(c.GetType().ToString());
}

}


Il codice devo essere onesto è il più semplice di questo pianeta, ma tuttavia riesce a dare una visione più o meno completa di quello che era la richiesta iniziale.

giovedì 10 novembre 2011

Customs Class Property ( No Emit ).

Mi sono imbattuto in questa "cosa", e sulle prime ho pensato "GENIALE". Ma la gioia si è spenta in meno di un minuto. Mi sono reso conto di quanto questa "cosa" sia pericolosa.

L'idea iniziale era di creare un oggetto a run Time, e quindi partendo della classe Emit e IlGenerator, mi sono poi domandato per quale motivo creare un intera classe quando la necessità era di creare solo propietà ?

Da qui quintali di possibili ragionamenti su come agire, senza trovare troppo conforto su web.

La conclusione è stata questa:

public class ghost         
{
public Dictionary<string, object> Properties = new Dictionary<string, object>();

public object this[string name]
{
get
{
if (Properties.ContainsKey(name))
{
return Properties[name];
}
return null;
}
set
{
Properties[name] = value;
}
}

public ghost(string[] properties)
{
for ( int i = 0; i <properties.Length; i++)
{
Properties.Add(properties[i],null);
}
}
}


Fantastico, bellissimo... MA ANCHE NO... l'ho rinominato come ABOMINIO !

Già perchè in mano a programmatori "folli" ( sai che sto parlando di TE M.C.) questa classe è un danno di prima categoria.


Già perchè non solo non generica, usa dictionary che ammazza ram e performance, ma è pure "comoda" perchè ti permette di accedere alle proprietà indicandole per nome...

ghost g=    new ghost(   new string[] {"ID","Name","Description"});
ghost g1 = new ghost( new string[] { "ID", "Name", "Description","Cammello" });
ghost g2 = new ghost( new string[] { "Arosio", "Justina", "cheNeso" });



List<ghost> gx = new List<ghost>();

gx.Add(g);
gx.Add(g1);
gx.Add(g2);


string curProperty ="ID";
object curValue = new DataColumn("case");

g1["ID"] = g1["Name"];

g1[curProperty] = curValue;


Arrivando a poter fare cose di questo tipo ...

Ammetto da piccole classi dipendo grandi problematiche...