mercoledì 21 dicembre 2011

How To: View proxy credentials o Window 7

Ecco una di quelle cose completamente out-of-topic che torna sempre utile.

Da buon "Consulente" ho un trascorso di varie credenziali salvate sul mio Pc, il problema e che Windows 7 non sempre riesce a comprendere quali utilizzare per connettersi e come utilizzarle e quando utilizzarle... e soprattutto perchè.

Per quanto riguarda i vari browser ogniuno si salva le sue ( Eccetto IE ), ma immancabilmente il vostro buon sistema operativo farà di tutto per salvarsi anche quelle relative ai proxy.

Solo che se cambia il proxy... o vi scade la password windows che cosa fa ? semplice crea una nuova entry e poi cerca di gestirla al meglio. Ancora una volta mi domando che cosa possa voler dire AL MEGLIO.

Andiamo a cercare tutte le nostre credenziale.

Start > Control Panel > User Account
Avvio > Pannello di controllo > Account Utente


Vi apparirà il pannello riportante le informazioni relative al vostro utente,
a questo punto selezionate la voce:
"Manage my network passwords"
"Gestione delle credenziali"

Vi troverete quindi un pannello con tutto l'elenco delle vostre credenziali... per me è stato bello rivedere credenziali di 2 anni fa o reti di amici e tanto altro ancora.. PER ALTRO le password sono mostrate con gli asterischi.

Bene per me è stato più o meno semplice, ho rimosso tutto quello che non mi serve.

Spero come sempre nell'utilità del post!

venerdì 16 dicembre 2011

How To: auto reference Class

Ed è proprio mentre cercavo di ottimizzare la mia soluzione alla sfida che mi imbatto in questa circostanza.

Onestamente ho sempre usato oggetti che referenziano se stessi ma non mi ero mai avventurato nello scrivere un codice di prova.

class b
{
public string n { get; set; }
public string v { get; set; }
public b[] c { get; set; }
}

class Program {
static void Main(string[] a)
{
b z = new b();
z.n = "Root";
z.v = "---";

b z1 = new b();
z1.n = "Child";
z1.v = "---";

b z2 = new b();
z2.n = "Child";
z2.v = "---";

z.c = new b[] { z1, z2 };
}
}


In questo esempio la classe b referenzia se stessa in forma d'array... chiaramente chi partecipa alla sfida troverà interessante questa classe... ma credo anche gli altri.

Saluti

lunedì 12 dicembre 2011

C# Sfida XML Viewer

E visto che vi è piaciuto si parte subito con questa nuova sfida, e vediamo come va.
Questa volta le regole sono ferree...

a) leggere un file xml
a.1) questo potrà contenere commenti.
a.2) questo potrà contenere [cdata[STRING]].
a.3) questo dovrà per forza rispettare le aperture e le chiusure dei tag.
a.4) questo potrà contenere sia nodi semplici che complessi.
a.5) il file non deve essere inferente o generare inferenza.

b) pubblicare i dati
b.1) il risultato dovrà essere mostrato in una o più griglie o liste.
b.2) il risultato non dovrà essere editabile.
b.3) il risultato non dovrà essere nuovamente salvato.

c) l'host dei dati ( il contenitore )
c.1) deve essere un form.
c.2) non può utilizzare dataTable.
c.3) non può utilizzare librerie esterne o di terze parti.
c.4) non può utilizzare propertyGrid.
c.5) non può utilizzare oggetti o controlli di terze parti.
c.6) può essere una soluzione console o windows application.
c.7) deve esistere almeno una seconda classe oltre al main.

d) il linguaggio
d.1) si può utilizzare C# o VB ( non XAML )
d.2) non si può utilizzare WPF

File XML di esempio ..
------------------------------------------------------------------------------

16.12.2011 Fabio Arosio
Dato che mi è stato richiesto pubblico anche un xml d'esempio.


<?xml version="1.0" encoding="UTF-8"?>
<utenti>
<utente>
<nome>Fabio</nome>
<cognome>Arosio</cognome>
<professione>Team Leader</professione>
<indirizzi>
<casa> piazza g.cesare</casa>
<ufficio> vicolo stretto</ufficio>
</indirizzi>
</utente>
<utente>
<nome>Claudio</nome>
<cognome>Eridani</cognome>
<professione>Sviluppatore Senior</professione>
<indirizzi>
<casa>stazione nord</casa>
<ufficio>via verdi</ufficio>
</indirizzi>
</utente>
<utente>
<nome>Nudru</nome>
<cognome>Bufu</cognome>
<professione>Divinita</professione>
<indirizzi>
<casa>piazza della vittoria</casa>
<ufficio>viale dei giardini</ufficio>
</indirizzi>
</utente>
</utenti>


------------------------------------------------------------------------------

16.12.2011 Fabio Arosio
760 Byte.. fatto finito e funzionante !!



Ma per il momento non pubblico il codice.. !!

Ora chi propone di meno !!


------------------------------------------------------------------------------

03.01.2011 Fabio Arosio
1120 Byte

Posto che il primo utilizzasse una treeView ho dovuto rivedere qualcosa... nel senso che questo sicuramente è corretto ...



e questo è il file..

giovedì 1 dicembre 2011

How To: SQL Server JSON parser

Ed eccomi ancora qui a pensare a qualcosa come sempre fuori dagli schemi... ammetto questa volta la cosa è stata decisamente complessa. Ma ha dato un risultato davvero inatteso.

Per una necessità mi serve passare un array ad una stored procedure, tuttavia non mi è possibile determinare a priori i campi, presenti nell'array... diciamo anche che il fantastico mondo dei varchar, mi ha menato una zappa sul malleolo.

Quindi ho pensato a json ( anche se questa versione è un po stravolto ) ma molto sta nella convenzione che utilizzerò per scriverlo.

/* 
    Questo mi rappresenta il parametro iniziale
        indicativamente
        sono la
        - definizione del parametro
        - il suo valore
*/
DECLARE @jMasterText AS VARCHAR(max)
SET @jMasterText = '{{d:01/01/2010,v:-,t:5007.79}|
{d:01/01/2011,v:5080.84,t:5132.98}|
{d:01/01/2012,v:5180.84,t:5432.98}}'

/*
    Per prima cosa è necessario
        spezzare i campi sapendo che
        [a:x,b:y,c:z]
        dove
        a è il nome del 1 campo
        x è il valore del 1 campo
        i : separano i campi da i valori
        i | separano i recodr
*/

DECLARE @iTime as int

SET @iTime = 0

WHILE (charindex('|',@jMasterText)>0 )
BEGIN

DECLARE @jText AS VARCHAR(max)

SET @jText = ltrim(rtrim(Substring(@jMasterText,1,Charindex('|',@jMasterText)-1)))
SET @jMasterText = Substring(@jMasterText,Charindex('|',@jMasterText)+1,len(@jMasterText))

DECLARE @jTempText AS VARCHAR(MAX)
DECLARE @jField AS VARCHAR(MAX)
DECLARE @jValue AS VARCHAR(MAX)

DECLARE @jValueList AS VARCHAR(MAX)
DECLARE @jFieldListD AS VARCHAR(MAX)
DECLARE @jFieldList AS VARCHAR(MAX)

SET @jTempText = @jText

SET @jTempText = replace(@jTempText,'{','')
SET @jTempText = replace(@jTempText,'}','')

SET @jFieldListD = ''
SET @jFieldList = ''
SET @jValueList = ''

/* ciclo per l'estazione degli elementi */

WHILE (charindex(',',@jTempText)>0 )
BEGIN
SET @jField = ltrim(rtrim(Substring(@jTempText,1,Charindex(',',@jTempText)-1)))
SET @jTempText = Substring(@jTempText,Charindex(',',@jTempText)+1,len(@jTempText))

SET @jValue = ltrim(rtrim(Substring(@jField,Charindex(':',@jField)+1,len(@jField))))
SET @jField = ltrim(rtrim(Substring(@jField,1,Charindex(':',@jField)-1)))

SET @jFieldListD = @jFieldListD + ',' + @jField +' varchar (max) '
SET @jFieldList = @jFieldList + ',' + @jField
SET @jValueList = @jValueList + ',*' + @jValue +'*'
END

/*
        rimane l'ultimo campo da elaborare
    */

SET @jField = ltrim(rtrim(Substring(@jTempText,1,len(@jTempText))))

SET @jValue = ltrim(rtrim(Substring(@jField,Charindex(':',@jField)+1,len(@jField))))
SET @jField = ltrim(rtrim(Substring(@jField,1,Charindex(':',@jField)-1)))

SET @jFieldListD = @jFieldListD + ',' + @jField +' varchar (max) '
SET @jFieldList = @jFieldList + ',' + @jField
SET @jValueList = @jValueList + ',*' + @jValue +'*'

/*
        in questo punto abbiamo l'elenco
        completo dei campi
    */

SET @jFieldListD =Substring(@jFieldListD,2,len(@jFieldListD))
SET @jFieldList =Substring(@jFieldList,2,len(@jFieldList))
SET @jValueList =Substring(@jValueList,2,len(@jValueList))

SET @jValueList =replace(@jValueList,'*','''')

/*
        Questa è la definizione della sintassi
            sql che dovrò creare per poi effettuare
            la selezione
    */

DECLARE @jResultCreate AS VARCHAR(max)
DECLARE @jResultInsert AS VARCHAR(max)

IF @iTime = 0
BEGIN
SET @jResultCreate = 'CREATE TABLE ##tbJResult ('+ @jFieldListD +')'
EXEC(@jResultCreate)
SET @iTime = 1
END


SET @jResultInsert = 'INSERT INTO ##tbJResult (' + @jFieldList+ ') VALUES (' + @jValueList+ ')'
EXEC(@jResultInsert)

END

/*
    rimane l'ultimo elemento da elaborare
*/
SET @jText = ltrim(rtrim(Substring(@jMasterText,1,len(@jMasterText))))

SET @jTempText = @jText

SET @jTempText = replace(@jTempText,'{','')
SET @jTempText = replace(@jTempText,'}','')

SET @jFieldListD = ''
SET @jFieldList = ''
SET @jValueList = ''

WHILE (charindex(',',@jTempText)>0 )
BEGIN
SET @jField = ltrim(rtrim(Substring(@jTempText,1,Charindex(',',@jTempText)-1)))
SET @jTempText = Substring(@jTempText,Charindex(',',@jTempText)+1,len(@jTempText))

SET @jValue = ltrim(rtrim(Substring(@jField,Charindex(':',@jField)+1,len(@jField))))
SET @jField = ltrim(rtrim(Substring(@jField,1,Charindex(':',@jField)-1)))

SET @jFieldListD = @jFieldListD + ',' + @jField +' varchar (max) '
SET @jFieldList = @jFieldList + ',' + @jField
SET @jValueList = @jValueList + ',*' + @jValue +'*'
END

SET @jField = ltrim(rtrim(Substring(@jTempText,1,len(@jTempText))))

SET @jValue = ltrim(rtrim(Substring(@jField,Charindex(':',@jField)+1,len(@jField))))
SET @jField = ltrim(rtrim(Substring(@jField,1,Charindex(':',@jField)-1)))

SET @jFieldListD = @jFieldListD + ',' + @jField +' varchar (max) '
SET @jFieldList = @jFieldList + ',' + @jField
SET @jValueList = @jValueList + ',*' + @jValue +'*'

SET @jFieldListD =Substring(@jFieldListD,2,len(@jFieldListD))
SET @jFieldList =Substring(@jFieldList,2,len(@jFieldList))
SET @jValueList =Substring(@jValueList,2,len(@jValueList))

SET @jValueList =replace(@jValueList,'*','''')

SET @jResultInsert = 'INSERT INTO ##tbJResult (' + @jFieldList+ ') VALUES (' + @jValueList+ ')'
EXEC(@jResultInsert)

SELECT * FROM ##tbJResult
DROP Table ##tbJResult


Qui c'e' tutta la parte di codice che a sua volta è inclusa in una stored molto più considerevole.

Spero che tutto ciò possa essere utile anche per altri .. !

C# Sfida a 250 byte

Ed ecco che prima di natale mi passa per la testa questa malsana idea, ammetto l'originale non è mia, ma è una cosa che mi ha sempre gasato.

La sfida è semplice semplice scrivere un programma in soli "250 byte" ossia il [file.cs] deve essere di 250 byte.

L'applicazione deve :
presentare un form secondo queste specifiche:
->Aprire e leggere e mostrare un file.
->Avere almeno un EventHandler Gestito.
->Non andare in errore.
->Mostrare il testo fisso "POI" ( point of interest )

L'applicazione deve essere in un solo file ( la cui lunghezza massima è di 250 byte )
deve essere compilabile, e naturalmente funzionante.

L'applicazione può usufruire delle librerie standard del framework e non di terze parti.

L'applicazione può essere fatta o in c# o in vb.Net.

L'applicazione deve rendere fruibile il file letto.

Prima di partire c'e' qualcuno che ha altre regole ?

Qui sotto il log e le considerezioni chi tecnicamente sta già partecipando...
Saranno pubblicate sole le versioni che rientreranno nell corrette caratteristiche.

----------------------------------------------------------------------------------
Fabio Arosio

Dopo una prima prova (dove ho limato davvero il limabile) direi che 250 forse sono davvero pochi ... quindi estendiamo almeno a 500 byte.

----------------------------------------------------------------------------------
Fabio Arosio

Raccolta del primo giorno :
- FDI grp 313b versione I ( minimo )

- V.Simone 450b versione II
- A.Fabio 440b versione III
- A.Fabio 413b versione IV

Secondo me i 313b sono davvero irraggiungibili... !

----------------------------------------------------------------------------------
Fabio Arosio

- FDI grp 292b versione II ( nuovo minimo )

Come smentirsi da solo !

----------------------------------------------------------------------------------
Fabio Arosio

- FDI grp 288b versione III ( nuovo minimo )

Sempre più in basso ( ma ora credo di aver proprio toccato il minimo ).


----------------------------------------------------------------------------------
Fabio Arosio

- Zocram15 277 versione I ( nuovo minimo )

E ora ?? chi riuscirà a scendere sotto questo limite ??

----------------------------------------------------------------------------------
Fabio Arosio

- Zocram15 283 versione II ( nuovo minimo )

nella versione precedente ci è stata comunicata la scomparsa del testo "poi" ..


----------------------------------------------------------------------------------
Fabio Arosio

- Zocram15 256 versione III ( nuovo minimo )

E sono sempre più curioso di vedere che cosa cavolo ha scritto in 256 byte...

cmq spedirsi un progetto intero via chat non ha prezzo !!


----------------------------------------------------------------------------------
Fabio Arosio

- A.Fabio 252 versione V ( nuovo minimo ) !! sorry !!
( sono sul filo della legalità ! )

Però funziona... !!

----------------------------------------------------------------------------------
Fabio Arosio

NON HO PAROLE !!!




----------------------------------------------------------------------------------
Fabio Arosio

V.Simone
ATTENTI ATTENTI non so se sia una bomba o una sola 200 byte !!!
RIPETO 200 byte !!
(ERA UNA BOMBA !!! )

----------------------------------------------------------------------------------
Fabio Arosio

C.Tiziano



Sempre meno sempre meno ... !!!


----------------------------------------------------------------------------------
Fabio Arosio

V.Simone



189 ( reali 187 mi sono stati comunicati due \s in più )


----------------------------------------------------------------------------------
Fabio Arosio

Abbiamo anche concorrenti esterni .. pupleDev aka c.Tiziano credo via commento
ha pubblicato anche il sorgente in Vb.Net ...
fissando il tutto a 184 byte !!



----------------------------------------------------------------------------------
Eccoci di nuovo qui ... !!

Fabio Arosio
Completamente fuori conconcorso .. perchè non prevede proprio tutto tutto pubblicherei anche questa versione da 148 byte...

using System;using System.IO;using System.Windows.Forms;class Program{static void Main(string[] a){MessageBox.Show(File.ReadAllText(a[0]),"poi");}}

Legge il file mostra un form l'evento è già gestito dalla messagebox... tuttavia già
so che questa versione non va bene !!!

La sfida rimane ancora open... !!

----------------------------------------------------------------------------------

Con oggi direi che questo capitolo si chiude... pubblicate tutti la vostra versione
come commento e questo punto che la giuria si faccia avanti !

A tutti quelli che hanno partecipato ( e che si sono divertiti nel farlo ) porgo i miei complimenti ( che magari sono poca cosa ) ma è stato davvero splendido!


Fabio!

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.