Con queste classi è possibile monitorare molti aspetti vitali delle nostre applicazioni, come utilizzo di memoria, i/o sul disco ecc..
Questo link della Microsoft contiene molta documentazione interessante.
Il codice che segue analizza lo stato della memoria relativa un singolo processo, corrispondente ad una applicazione .NET.
// Questa è l'area di cui vogliamo i contatori, ovvero ".NET CLR Memory"
System.Diagnostics.PerformanceCounterCategory area = new System.Diagnostics.PerformanceCounterCategory(".NET CLR Memory");
Il seguente codice mostra a video tutte le istanze dentro l’area .NET CLR Memory analizzabili in quel momento sulla macchina:
string[] instanceNames;
instanceNames = mycat.GetInstanceNames();
for (int i=0; i < instanceNames.Length; i++)
{
Console.WriteLine("Nome Istanza: {0}", instanceNames[i]);
}
Il suo output è simile a questo:
C:\Documents and Settings\colonnan\Documenti\Visual Studio 2008\Projects\Console
Application3\ConsoleApplication3\bin\Debug>MonitorProcesso.exe
Nome Istanza: MonitorProcesso
Nome Istanza: devenv
Nome Istanza: _Global_
Nome Istanza: MonitorProcesso.vshost
In questo esempio "MonitorProcesso.exe" è l'applicazione che sto lanciando, rappresentato dall'istanza "MonitorProcesso".
Per analizzare lo stato di memoria di MonitorProcesso.exe:
//Array dei contatori di un singolo processo.
System.Diagnostics.PerformanceCounter[] counters = area.GetCounters("MonitorProcesso");
for (int i = 0; i < counters.Length;i++)
{
Console.WriteLine("Performance counter: {0} = {1}", counters[i].CounterName, counters[i].NextValue());
}
Il cui risultato è:
Performance counter: # Gen 0 Collections = 1
Performance counter: # Gen 1 Collections = 0
Performance counter: # Gen 2 Collections = 0
Performance counter: Promoted Memory from Gen 0 = 271400
Performance counter: Promoted Memory from Gen 1 = 0
Performance counter: Gen 0 Promoted Bytes/Sec = 0
Performance counter: Gen 1 Promoted Bytes/Sec = 0
Performance counter: Promoted Finalization-Memory from Gen 0 = 0
Performance counter: Promoted Finalization-Memory from Gen 1 = 1320
Performance counter: Gen 0 heap size = 524288
Performance counter: Gen 1 heap size = 524480
Performance counter: Gen 2 heap size = 12
Performance counter: Large Object Heap size = 541560
Performance counter: Finalization Survivors = 0
Performance counter: # GC Handles = 35
Performance counter: Allocated Bytes/sec = 0
Performance counter: # Induced GC = 0
Performance counter: % Time in GC = 1,227221
Performance counter: Not Displayed = 0
Performance counter: # Bytes in all Heaps = 1131064
Performance counter: # Total committed Bytes = 1662976
Performance counter: # Total reserved Bytes = 3,354624E+07
Performance counter: # of Pinned Objects = 0
Performance counter: # of Sink Blocks in use = 0
Ecco un esempio di come utilizzare i Parameters all’interno di un oggetto OLEDBCommand.
La query
INSERT INTO TABELLA VALUES ('25/04/1972 10:40:00')
eseguita su un campo di tipo DATETIME si traduce grossolanamente in:
OleDbConnection conn;
OleDbCommand comando;
String connStr;
String sql;
connStr = @"Provider = SQLOLEDB.1;Password=" + password + ";User ID=" + user + ";Initial Catalog=" + database + ";Data Source=" + server;
conn = new OleDbConnection(connStr);
conn.Open();
sql = "INSERT INTO TABELLA VALUES ('25/04/1972 10:40:00')";
comando = new OleDbCommand(sql, conn);
comando.ExecuteNonQuery();
Può capitare che l’ultima istruzione dia errore, per problemi di sintatti del formato data. A seconda delle impostazioni predefinite del server il formato per la data può variare (ad esempio può essere ‘1972-04-25 10:40:00).
L’utilizzo dei Parameters ovvia questa problematica. Ecco come diventa il codice:
DateTime dt = new DateTime(1972,4,25,10,40,0);
sql = "INSERT INTO TABELLA VALUES (?)";
comando = new OleDbCommand(sql, conn);
comando.Parameters.AddWithValue("@dataora", dt);
comando.ExecuteNonQuery();
Tutto qua.
- Il metodo ReferenceEquals verifica le uguaglianze per riferimento
- Il metodo Equals verifica le uguaglianze per valore
- l’operatore “==” a volte per riferimento e a volte per valore.
Ecco qualche esempio:
Se dichiariamo a e b in questo modo:
System.Object a = new System.Object();
System.Object b = a;
a e b sono riferimento allo stesso oggetto. Per avere la prova sul campo basta eseguire questo codice:
class Program
{
static void Main(string[] args)
{
ObjectClass o1 = new ObjectClass();
ObjectClass o2 = o1;
o1.Value = 3;
Console.WriteLine("o1: {0}", o1.Value);
Console.WriteLine("o2: {0}", o2.Value);
o2.Value = 5;
Console.WriteLine("o1: {0}", o1.Value);
Console.WriteLine("o2: {0}", o2.Value);
Console.WriteLine("ReferenceEquals: {0}", System.Object.ReferenceEquals(o1, o2));
}
class ObjectClass
{
private int value;
public int Value
{
get { return this.value; }
set { this.value = value; }
}
}
}
Il risultato è:
o1: 3
o2: 3
o1: 5
o2: 5
ReferenceEquals: True
Equals: True
==: True
quindi modificare uno dei due oggetti significa modificare anche l’altro. Il metodo System.Object.ReferenceEquals verifica appunto l’uguaglianza per riferimento di due oggetti.
Se invece li dichiariamo così:
ObjectClass o1 = new ObjectClass();
ObjectClass o2 = new ObjectClass();
o1.Value = 3;
o2.Value = 3;
Console.WriteLine("ReferenceEquals: {0}", System.Object.ReferenceEquals(o1, o2));
Console.WriteLine("Equals: {0}", System.Object.Equals(o1, o2));
Console.WriteLine("==: {0}", o1 == o2);
il risultato è:
ReferenceEquals: False
Equals: False
==: False
- ReferenceEquals è False perche o1 e o2 sono due oggetti separati, che nulla hanno in comune se non il valore uguale.
- Equals è False perchè sto confrontando due oggetti che ho creato io, e in cui non ho specificato nessun ovverride per il metodo Equals.
- == è false perchè in questo caso si comporta come ReferenceEquals
Un esempio interessante è questo, sulle stringhe:
String s1 = "pippo";
String s2 = "pippo";
Console.WriteLine("Risultato ReferenceEquals: {0}", System.Object.ReferenceEquals(s1, s2));
Console.WriteLine("Risultato Equals: {0}", System.Object.Equals(s1, s2));
Console.WriteLine("Risultato ==: {0}", s1 == s2);
il risultato è:
Risultato ReferenceEquals: True
Risultato Equals: True
Risultato ==: True
- ReferenceEquals restituisce True perche s1 e s2 sono riferimento allo stesso oggetto. Così funziona c# quando si dichiarano più stringhe con lo stesso valore.
- Equals resituisce True perchè sto confrontando un’oggetto con se stesso
- == restituisce True perchè in questo caso si comporta come Equals
Invece:
String s1 = "pippo";
String s2 = String.Copy(s1);
Console.WriteLine("Risultato ReferenceEquals: {0}", System.Object.ReferenceEquals(s1, s2));
Console.WriteLine("Risultato Equals: {0}", System.Object.Equals(s1, s2));
Console.WriteLine("Risultato ==: {0}", s1 == s2);
(il metodo String.Copy crea una nuova istanza con valore uguale a quella in input)
genera questo risultato:
Risultato ReferenceEquals: False
Risultato Equals: True
Risultato ==: True
- ReferenceEquals restituisce false, perchè s1 e s2 non puntano allo stesso oggetto
- Equals restituisce True, perchè s1 e s2 hanno lo stesso valore
- == restituisce True perchè in questo caso si comporta come Equals
L’operatore ==, al contrario del Java, può essere usato per il confronto fra stringhe. Ma vediamo cosa succede se facciamo un downgrade di String a Object:
String s1 = "pippo";
String s2 = String.Copy(s1);
Console.WriteLine("Risultato ReferenceEquals: {0}", System.Object.ReferenceEquals(s1, s2));
Console.WriteLine("Risultato ReferenceEquals: {0}", System.Object.ReferenceEquals((Object)s1, (Object)s2));
Console.WriteLine("Risultato Equals: {0}", System.Object.Equals(s1, s2));
Console.WriteLine("Risultato Equals: {0}", System.Object.Equals((Object)s1, (Object)s2));
Console.WriteLine("Risultato ==: {0}", s1 == s2);
Console.WriteLine("Risultato ==: {0}", (Object)s1 == (Object)s2);
Il risultato è:
Risultato ReferenceEquals: False
Risultato ReferenceEquals: False
Risultato Equals: True
Risultato Equals: True
Risultato ==: True
Risultato ==: False
Il suo comportamento è definito dall’msdn di mamma Microsoft:
For predefined value types, the equality operator (==) returns true if the values of its operands are equal, false otherwise. For reference types other than string, == returns true if its two operands refer to the same object. For the string type, == compares the values of the strings.
Ovvero: l’uguaglianza è verificata per valore se è verificata fra tipi predefiniti e stringhe, in tutti gli altri casi è per riferimento.
Ecco degli esempi della funzione di aggregazione GROUPING associata all’utilizzo del GROUP BY WITH ROLLUP
GROUPING è una funzione di aggregazione che aggiunge una colonna al resultset, valorizzata ad 1 per ogni record aggiunto dalla clausola CUBE o ROLLUP.
Questi esempi si applicano a SQL Server 2005. Le clausole ROLLUP e CUBE, e la funzione GROUPING sono presenti anche in altri DBMS.
Creiamo una tabella ORDINI con questi campi:
CREATE TABLE [ORDINI] (
[ID_ORDINE] [int] NOT NULL ,
[PRODOTTO] [varchar] (50) COLLATE Latin1_General_CI_AS NOT NULL ,
[QTA] [int] NULL ,
[PREZZO] [money] NULL ,
CONSTRAINT [PK_ORDINI] PRIMARY KEY CLUSTERED
(
[ID_ORDINE],
[PRODOTTO]
) ON [PRIMARY]
) ON [PRIMARY]
GO
con i seguenti dati (con prezzi casuali):
INSERT INTO ORDINI VALUES (1, 'PS3', 1, 249.99)
INSERT INTO ORDINI VALUES (2, 'PS3', 1, 249.99)
INSERT INTO ORDINI VALUES (2, 'XBOX', 2, 499.99)
INSERT INTO ORDINI VALUES (3, 'WII', 1, 149.99)
INSERT INTO ORDINI VALUES (3, 'PS3', 1, 249.99)
INSERT INTO ORDINI VALUES (3, 'XBOX', 1, 199.99)
Quindi, tanto per dire, l’ordine 1 composto da una PS3, l’ordine 2 composto da una PS3 e due XBOX e l’ordine 3 con una WII, una PS3 e una XBOX.
Il risultato è questo:
SELECT * FROM ORDINI
| ID_ORDINE |
PRODOTTO |
QTA |
PREZZO |
| 1 |
PS3 |
1 |
249.9900 |
| 2 |
PS3 |
1 |
249.9900 |
| 2 |
XBOX |
2 |
499.9900 |
| 3 |
PS3 |
1 |
249.9900 |
| 3 |
WII |
1 |
149.9900 |
| 3 |
XBOX |
1 |
199.9900 |
Se eseguiamo un normale GROUP BY sul prodotto otteniamo:
SELECT PRODOTTO, SUM(QTA) AS QUANTITA, SUM(PREZZO) AS PREZZO
FROM ORDINI
GROUP BY PRODOTTO
| PRODOTTO |
QTA |
PREZZO |
| PS3 |
3 |
749.9700 |
| WII |
1 |
149.9900 |
| XBOX |
3 |
699.9800 |
Aggiungendo la clausola WITH ROLLUP sul prodotto otteniamo la riga aggiuntiva con la somma del GROUP BY relativo (evidenziata in grassetto):
SELECT PRODOTTO, SUM(QTA) AS QUANTITA, SUM(PREZZO) AS PREZZO
FROM ORDINI
GROUP BY PRODOTTO WITH ROLLUP
| PRODOTTO |
QTA |
PREZZO |
| PS3 |
3 |
749.9700 |
| WII |
1 |
149.9900 |
| XBOX |
3 |
699.9800 |
| NULL |
7 |
1599.9400 |
Adesso vediamo l’effetto della funzione GROUPING sul campo PRODOTTO, e vediamo che la colonna ‘GROUPING PRODOTTO è valorizzata ad 1 solo per il record aggiunto dal WITH ROLLUP:
SELECT PRODOTTO, SUM(QTA) AS QUANTITA, SUM(PREZZO) AS PREZZO, GROUPING(PRODOTTO) AS 'GROUPING PRODOTTO'
FROM ORDINI
GROUP BY PRODOTTO WITH ROLLUP
| PRODOTTO |
QTA |
PREZZO |
GROUPING PRODOTTO |
| PS3 |
3 |
749.9700 |
0 |
| WII |
1 |
149.9900 |
0 |
| XBOX |
3 |
699.9800 |
0 |
| NULL |
7 |
1599.9400 |
1 |
Adesso raggruppiamo oltre che per prodotto anche per id dell’ordine:
SELECT PRODOTTO, ID_ORDINE, SUM(QTA) AS QUANTITA, SUM(PREZZO) AS PREZZO
FROM ORDINI
GROUP BY PRODOTTO, ID_ORDINE
| PRODOTTO |
ID_ORDINE |
QTA |
PREZZO |
| PS3 |
1 |
1 |
249.9900 |
| PS3 |
2 |
1 |
249.9900 |
| XBOX |
2 |
2 |
499.9900 |
| PS3 |
3 |
1 |
249.9900 |
| WII |
3 |
1 |
149.9900 |
| XBOX |
3 |
1 |
149.9900 |
E aggiungiamo il ROLLUP. Ogni raggruppamento genera una riga di totale:
SELECT PRODOTTO, ID_ORDINE, SUM(QTA) AS QUANTITA, SUM(PREZZO) AS PREZZO
FROM ORDINI
GROUP BY PRODOTTO, ID_ORDINE WITH ROLLUP
| PRODOTTO |
ID_ORDINE |
QTA |
PREZZO |
| PS3 |
1 |
1 |
249.9900 |
| PS3 |
2 |
1 |
249.9900 |
| PS3 |
3 |
1 |
249.9900 |
| PS3 |
NULL |
3 |
749.9700 |
| WII |
3 |
1 |
149.9900 |
| WII |
NULL |
1 |
149.9900 |
| XBOX |
2 |
2 |
499.9900 |
| XBOX |
3 |
1 |
199.9900 |
| XBOX |
NULL |
3 |
699.9800 |
| NULL |
NULL |
7 |
1599.9400 |
E adesso aggiungiamo due GROUPING, uno per PRODOTTO e uno per ID_ORDINE. Ecco il risultato.
SELECT PRODOTTO, ID_ORDINE, SUM(QTA) AS QUANTITA, SUM(PREZZO) AS PREZZO, GROUPING(ID_ORDINE) AS 'GROUPING ORDINE', GROUPING(PRODOTTO) AS 'GROUPING PRODOTTO'
FROM ORDINI
GROUP BY PRODOTTO, ID_ORDINE WITH ROLLUP
| PRODOTTO |
ID_ORDINE |
QTA |
PREZZO |
GROUPING ORDINE |
GROUPING PRODOTTO |
| PS3 |
1 |
1 |
249.9900 |
0 |
0 |
| PS3 |
2 |
1 |
249.9900 |
0 |
0 |
| PS3 |
3 |
1 |
249.9900 |
0 |
0 |
| PS3 |
NULL |
3 |
749.9700 |
1 |
0 |
| WII |
3 |
1 |
149.9900 |
0 |
0 |
| WII |
NULL |
1 |
149.9900 |
1 |
0 |
| XBOX |
2 |
2 |
499.9900 |
0 |
0 |
| XBOX |
3 |
1 |
199.9900 |
0 |
0 |
| XBOX |
NULL |
3 |
699.9800 |
1 |
0 |
| NULL |
NULL |
7 |
1599.9400 |
1 |
1 |
Nella stessa query abbiamo, per ogni prodotto, una riga col dettaglio per ogni ordine, ed una riga di totale, più una riga di totale generale.
L’oggetto Request di una pagina ASP contiene la collection ServerVariables, che contiene tutte le varibili del Web server.
La pagina di riferimento della Microsoft:
http://msdn.microsoft.com/en-us/library/system.web.httprequest.servervariables.aspx
Qui per esempio si puù trovare l’elenco delle varibili ed una loro descrizione:
http://www.w3schools.com/asp/coll_servervariables.asp
Quello che segue è una piccola applicazione Web creata di prova per visualizzare tutte le variabili a video.
<body>
<form id="form1" runat="server">
<div>
<h1>Variabili Server</h1>
<p>
<asp:Table ID="Table1" runat="server" Width="80%" HorizontalAlign="Center" CssClass="mytable">
</asp:Table>
</p>
</div>
</form>
</body>
questo invece il realtivo codice sottostante:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
NameValueCollection coll;
coll = Request.ServerVariables;
String[] arr1 = coll.AllKeys;
for (int loop1 = 0; loop1 < arr1.Length; loop1++)
{
String[] arr2 = coll.GetValues(arr1[loop1]);
for (int loop2 = 0; loop2 < arr2.Length; loop2++)
{
TableRow row = new TableRow();
TableCell cellName = new TableCell();
cellName.Controls.Add(new LiteralControl(arr1[loop1]));
row.Cells.Add(cellName);
TableCell cellValue = new TableCell();
cellValue.Controls.Add(new LiteralControl(arr2[loop2]));
row.Cells.Add(cellValue);
Table1.Rows.Add(row);
}
}
}
}
Il risultato di questa complicatissima applicazione è il seguente:

