Tutorial C#
Tutorial C#
NET
Ignat Andrei
PROGRAMAREA IN .NET - PARTEA 1 - INCEPUTURILE PROGRAMAREA IN .NET - PARTEA A 2-A - CREEREA BAZEI DE DATE PROGRAMAREA IN .NET - PARTEA A 3-A - CODUL PENTRU OBIECTE PROGRAMAREA IN .NET - PARTEA A 4-A : .NET PROGRAMMING PROGRAMAREA IN .NET - PARTEA A 5A -EDITAREA DE OBIECTE PROGRAMAREA IN .NET - PARTEA A 6-A - SETUP PROGRAM PROGRAMAREA IN .NET - PARTEA A 7-A : ASP.NET APPLICATION PROGRAMAREA IN .NET - PARTEA A 8-A - EDITAREA IN ASP.NET PROGRAMAREA IN .NET - PARTEA A 9-A -SITE MAP SI LOCALIZATION PROGRAMAREA IN .NET - PARTEA A 10-A: UN PROIECT DOS PROGRAMAREA IN .NET - PARTEA A 11-A TESTE AUTOMATE CU NUNIT
2 3 8 14 25 31 35 44 57 65 66
PROGRAMAREA IN .NET - PARTEA A 12-A DOCUMENTAREA - SCRIEREA DE FIIERE HELP. 74 PROGRAMAREA IN .NET - PARTEA A 13-A - LOG-AREA OPERAIILOR CU LOG4NET 82 PROGRAMAREA IN .NET - PARTEA A 14-A SALVARE XML SI EXECUTARE DE OPERATII ASINCRONE IN WINDOWS FORMS 85 PROGRAMAREA IN .NET - PARTEA A 15-A OPERATII ASINCRONE IN ASP.NET SI AJAX 90 PROGRAMAREA IN .NET - PARTEA A 16-A RAPOARTE IN ASP.NET 99
http://www.serviciipeweb.ro/iafblog
Page 1
Ignat Andrei
Ceea ce o sa ne intereseze in acest tutorial este partea de programare a lui .NET. Codul final este la adresa http://serviciipeweb.ro/iafblog/content/binary/book2.zip De ce aveti nevoie: 1. Un calculator cu Windows instalat( de preferinta , orice de la XP in sus) 2. IIS pentru proiectul Internet . Vedeti daca exista in Control Panel => Administrative Tools => Internet Information Services (IIS) Manager. Daca nu, duceti-va la Control Panel => Add Or Remove programs => add / remove Windows components si il gasiti acolo 3. MSDN 2006 May - pentru tutoriale si exemple - free :http://www.microsoft.com/downloads/details.aspx?FamilyID=373930CB-A3D7-4EA5-B421DD6818DC7C41&displaylang=en 4.SQL Server Express - free : http://msdn.microsoft.com/vstudio/express/sql/download/ 4. Visual Studio Web Development Express free - pentru proiecte internet http://msdn.microsoft.com/vstudio/express/vwd/) 5. Visual C# Express free - pentru proiecte windows http://msdn.microsoft.com/vstudio/express/visualcsharp/) 6. Optional : ReportViewer Control in Visual Studio 2005 free - pentru raportari locale http://www.gotreportviewer.com/ Dupa ce ati downloadat si instalat aceste programe, prima aplicatie pe care o sa o facem este un proiect cu baze de date prin care o sa indexam cartile din biblioteca proprie. Proiectul o sa fie schematic, doar pentru demonstrarea programarii Windows si Internet cu .NET. Elementele principale ale proiectului or sa fie Cartea , Autorul si Editura Atributele principale ale Cartii sunt : Titlu Data Aparitiei ISBN Editura ( presupunem ca 1 carte nu este editata de mai multe edituri)
http://www.serviciipeweb.ro/iafblog
Page 2
Ignat Andrei
Atributele principale ale Autorului sunt : Nume Prenume Atributele principale ale Editurii sunt: Nume SiteWeb O carte poate avea mai multi autori, iar un autor poate aparea pe mai multe carti ( legatura multi la multi) O carte poate avea o singura editura , dar o editura poate publica mai multe carti Ce se cere : - forme de introducere a celor 3 obiecte - cautare in baza de date dupa : Editura, Carte, Autor - afisarea obiectelor in functie de relatiile dintre ele ( de exemplu, daca se selecteaza un autor, sa se afiseze toate cartile scrise de el ) Pina atunci, astept intrebarile voastre la adresa :[email protected]
Lecturi Recomandate Charles Petzold, DotNetBookZero pentru incepatorii in .NET si nu numai http://www.charlespetzold.com/dotnet/ How to be a Programmer: A Short, Comprehensive, and Personal Summary http://samizdat.mines.edu/howto/HowToBeAProgrammer.html
Ignat Andrei
BookWeb.sln (solutia care va contine proiectul Web -si aplicatia SmartClient) In acest director vom avea: BookData( fisierele mdb, scripturile de creeare sql express) BookObjects( proiectul de conectare la BD si de obiecte) BookWin( proiectul de Windows) BookDos ( proiectul de DOS) BookWeb(proiectul Web) BookDeployWeb(proiectul de deployment Web) BookDeployWin(proiectul de deployment Windows) BookDeploySmartClient(unde vom face deployment- ul SmartClient) BookTest Bun - acum haideti sa facem primul pas - creearea bazei de date Access. Haideti sa creeam impreuna MDB-ul. Pornim Acces - cream o noua baza de date - o salvam in BookData. O sa va arat cum se creeaza prima tabela: Cind sunteti pe tabul "Tables" apasati pe "New Table"
http://www.serviciipeweb.ro/iafblog
Page 4
Ignat Andrei
Pentru a face IDAuthor Primary Key - dati click dreapta pe coloana de dinainte de IDAuthor si click pe "Primary Key"
http://www.serviciipeweb.ro/iafblog
Page 5
Ignat Andrei
La fel se creeaza si celelalte tabele. Acum ar trebui sa le legam intre ele. Pentru aceasta , accesati Tools=> Relationships Adaugati tabelele
http://www.serviciipeweb.ro/iafblog
Page 6
Ignat Andrei
Acum avem Baza de date.Il puteti downloada de aici: book.mdb Haideti sa concepem obiectele.Acestea or sa fie ca in prima prezentare: <a href="http://serviciipeweb.ro/iafblog/2006/08/10/Programarea+In+NET+Partea+1.aspx">Progra marea In NET - Partea 1 </a> In a treia parte o sa scriem cod pentru accesul la Baza de date, precum si obiectele principale pentru acest proiect.
http://www.serviciipeweb.ro/iafblog Page 7
Ignat Andrei
http://www.serviciipeweb.ro/iafblog
Page 8
Ignat Andrei
si salvati in C:\book De obicei, the System.Data.dll este listat in referinte. Daca nu, va rog sa il adaugati. Oricum, adaugati va rog si o referinta la System.Configuration. Click dreapta pe Solution Explorer si Add reference laOleDBConnection ca mai jos : Redenumiti Class1.cs dinproprietati( click pe fisier in Solution Explorer si apasati F4) in Publisher.cs Daca raspundeti "yes" la urmatoarea intrebare, numele clasei va fi schimbat din Class1 in Publisher si faceti-o public class Acum o sa scriem proprietatile de baza pentru un Publisher :
using System; using System.Collections.Generic; using System.Text; namespace BookObjects {
http://www.serviciipeweb.ro/iafblog
Page 9
Ignat Andrei
http://www.serviciipeweb.ro/iafblog
Page 10
Ignat Andrei
Trebuie sa le incarcam aceste proprietati din Baza de date, asa incit o sa scriem o metoda Fill: O sa o scriem astfel incit sa nu avem dependenta de BD:
#region Database methods public void FillObject(System.Data.IDataReader idr) { this.Name = idr["NamePublisher"].ToString(); this.Site = idr["SitePublisher"].ToString(); } #endregion
http://www.serviciipeweb.ro/iafblog
Page 11
Ignat Andrei
ACum va trebui sa scriem codul de incarcare din BD a diverselor inregistrari. Asaugati o noua clasa ( Project => Add Class) si denumiti-o ColPublisher.cs. Din nou , faceti-o public class si haide sa scriem metoda care incarca datele din BD.
public void Load() { }
Cum ne dam seama ca ne trebuie cele doua conexiuni - si o metoda de a vedea pe care din ele le incarcam. Asa incit vom incepe sa scriem cod spre a incarca conexiunile :
public static string ConnectionStringMDB { get { return System.Configuration.ConfigurationManager.ConnectionStrings["MDB"]; } } public static string ConnectionStringSQLServer { get { return System.Configuration.ConfigurationManager.ConnectionStrings["SQLServer"]; } } Asa cum am tot spus, avem doua stringuri de conexiune. A venit timpul sa stim cind incarcam una si cind cealalta in functia Load. O sa adaug o noua clasa numita Settings si o sa pun acolo setarile comune
http://www.serviciipeweb.ro/iafblog
Page 12
Ignat Andrei
O sa adaug o enumerare care o sa imi spuna ce baza de date voi utiliza public enum DatabaseUsed { None, MDB, SQLServer } si o sa o citim din fisierul de configurare(App.config sau Web.Config) : public static DatabaseUsed TheDatabase { get { return Enum.Parse(typeof(DatabaseUsed), System.Configuration.ConfigurationManager.AppSettings["DatabaseUsed"]; } }
Puteti observa ca am pus configurarea in Appsetting . Putem stoca si stringurile de conexiune in acelasi loc - dar am vrut sa fim compatibili cu standardul Microsoft. Codul poate fi obtinut de aici Data viitoare o sa scriem cod pentru a incarca datele din BD si a le pune in colectie. De citit: Pentru .NET best practices, puteti citi http://www.ssw.com.au/ssw/Standards/default.aspx Pentru construirea unui ORM (Object-relational_mapping) cum facem aici, cititi articolul urmator de pe Wikipedia (http://en.wikipedia.org/wiki/Object-relational_mapping) si puteti gasi o lista de ORM la adresa http://en.wikipedia.org/wiki/List_of_object-relational_mapping_software . Cred ca ar trebui sa cititi cel putin unul, de exemplu Nhibernate : http://www.hibernate.org/343.html
Pentru SQL Server exista Data Access Application Blocks http://www.serviciipeweb.ro/iafblog Page 13
Ignat Andrei
Pentru a genera acelasi cod plecind de la tabele dintr-o baza de date, cititi Code Generation (http://en.wikipedia.org/wiki/Code_generation) si poate CodeSmith (http://www.codesmithtools.com/)
http://www.serviciipeweb.ro/iafblog
Page 14
Ignat Andrei
Vom scrie acest cod in evenimentul de post: copy $(ProjectDir)..\BookData\*.mdb $(TargetDir) Asta inseamna sa copieze toate fisierele MDB(*.mdb) din C:\Book\BookData (obtinut din folder- ul proiectului (C:\Book\BookObjects\), apoi un folder mai sus (.. C:\Book\), apoi catre BookData (C:\Book\BookData)) in TargetDir (adica acolo unde se gaseste executabilul - nu conteaza daca suntem pe debug sau release.) Salvati(CTRL+S) si compilati (CTRL + SHIFT + B) Acum in C:\Book\BookObjects\bin\Release sau in C:\Book\BookObjects\bin\Debug trebuie sa fie inca o copie a fisierului MDB. Pina aici e OK - haideti sa scriem stringul de conectare la MDB. Click cu dreaptape BookWin in Solution Explorer click Add => New Item => si alegeti Application Configuration File ( nume default :App.config nu il schimbati !) si sa scriem urmatoarele linii:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="DatabaseUsed" value="MDB"/> <!-- possible values : MDB, SQLServer--> </appSettings> <connectionStrings> <add name="MDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\book.mdb;User Id=admin;Password=;"/> <!-- TODO : add for asp.net application the connection string with SQL Server-> </connectionStrings> </configuration>
http://www.serviciipeweb.ro/iafblog
Page 15
Ignat Andrei
De ce am pus DataDirectory ? Daca aplicatia este de tip ClickOnce( mai multe date mai tirziu), atunci fisierele de date sunt puse in alta locatie decit executabilul.Acest datadirectory se va interpreta ca automat la folder-ul respectiv. Acum este momentul sa incarcam datele - mai intii sa facem legatura la baza de date. Vom pune cod in fisierul settings.cs ca sa putem schimba conexiune dupa fisierul config la rulare :
public static DbConnection TheConnection { get { switch (TheDatabase) { case DatabaseUsed.MDB: OleDbConnection oc = new OleDbConnection(ConnectionStringMDB); return oc; case DatabaseUsed.SQLServer: SqlConnection sc=new SqlConnection(ConnectionStringSQLServer); return sc; default: // Maybe throw an error that config file has not been initialized with // the database type ? return null; } } }
http://www.serviciipeweb.ro/iafblog
Page 16
Ignat Andrei
Dupa cum vedeti , intoarcem un DbConnection indiferent daca este ne conectam la Access sau SQL Server. Si acum sa scriem cod generic de incarcat datele
public static IDataReader Load(string CommandLine, DbConnection dbcon) {
DbCommand dc = null; switch (TheDatabase) { case DatabaseUsed.MDB: dc = new OleDbCommand(CommandLine); break; case DatabaseUsed.SQLServer: dc = new SqlCommand(CommandLine); break; default: //TODO : throw specific error that database type does not properly have been initialized break; } dc.CommandType = CommandType.Text; dc.Connection = dbcon; return dc.ExecuteReader();
http://www.serviciipeweb.ro/iafblog
Page 17
Ignat Andrei
return null;
namespace BookObjects { public class ColPublisher : System.Collections.ObjectModel.KeyedCollection<string,Publisher> { protected override string GetKeyForItem(Publisher item) { return "K" + item.IDPublisher; } public void Load() { DbConnection db = Settings.TheConnection;
http://www.serviciipeweb.ro/iafblog
Page 18
Ignat Andrei
} }
Acum
adaugam/stergem/identifica un Publisher. Din fericire, .NET are destule colectii ajutatoare. Sunt 3 namespace-uri mari care contin colectii :System.Collections , System.Collections.ObjectModel si System.Collections.Specialized. Veti gasi mult mai mult pe Internet( de exemplu o implementare an implementation of a Set collection : http://www.codeproject.com/csharp/sets.asp) Vom allege pentru
ColPublisher clasa
System.Collections.ObjectModel.KeyedCollection<string,Publisher>
.O
sa
trebuiasca sa scriem cum se obtine o cheie unica(identificator unic) pentru un specific Publisher si ce e o mai buna alegere decit ID ?
protected override string GetKeyForItem(Publisher item) {
http://www.serviciipeweb.ro/iafblog
Page 19
Ignat Andrei
namespace BookObjects { public class ColPublisher : System.Collections.ObjectModel.KeyedCollection<string,Publisher> { protected override string GetKeyForItem(Publisher item) { return "K" + item.IDPublisher; } public void Load() { DbConnection db = Settings.TheConnection; using (db) { db.Open(); IDataReader ir = Settings.Load("select IDPublisher, NamePublisher, SitePublisher from Publisher", db);
http://www.serviciipeweb.ro/iafblog
Page 20
Ignat Andrei
} }
Sa vedem cum o folosim din form: Faceti dublu click pe frmPublisherList.cs si trageti un DataGridView pe forma
http://www.serviciipeweb.ro/iafblog
Page 21
Ignat Andrei
http://www.serviciipeweb.ro/iafblog
Page 22
Ignat Andrei
Click pe (none) si selectati add new data source In dialogul urmator alegeti Object
http://www.serviciipeweb.ro/iafblog
Page 23
Ignat Andrei
si apasati next Acum mariti nodul BookObjects si alegeti ColPublisher. Apasati Next si apoi Finish. Pe forma a aparut un nou control numit colPublisherBindingSource - si Grid-ul are deja coloanele definite. Acum sa scriem codul pentru a incarca datele din Baza de date: Dublu click pe forma si o sa va gasiti editind evenimentul Form_Load:
private void frmPublisherList_Load(object sender, EventArgs e) { BookObjects.ColPublisher publishers = new BookObjects.ColPublisher(); publishers.Load(); colPublisherBindingSource.DataSource = publishers; }
Sa setam solutia sa porneasca cu BookWin - click dreapta pe BookWin - si selectati Set as startup project Acum apati F5 si asteptati sa vedeti rezultatele. Daca totul e OK, veti vedea forma fara nici un fel de date - si e foarte correct din cauza ca nu am introdus nici un fel de Publisher-i in Book.mdb In urmatoarea lectie vom scrie cod ca sa inseram un nou publisher si sa il vedem in lista
Lecturi optionale: CSLA : http://www.lhotka.net/cslanet/ - un framework bun pentru a se folosi pentru securitate, scalabilitate, binding si multe altele(si, mai ales, free si cu cod sursa).
http://www.serviciipeweb.ro/iafblog
Page 24
Ignat Andrei
private void btnAdd_Click(object sender, EventArgs e) { BookObjects.Publisher p = new BookObjects.Publisher(); p.Name = txtName.Text; p.Save(); this.Close();//close the form
http://www.serviciipeweb.ro/iafblog
Page 25
Ignat Andrei
E clar ca trebuie sa scriem metoda de Save pe Publisher Inapoi la clase : si acolo vom scrie metoda de save. public void Save() { string strSQL = " insert into Publisher(NamePublisher"; if (!string.IsNullOrEmpty(this.Site)) strSQL += ",SitePublisher ";
strSQL += "'" + this.Name.Replace("'","''") + "'";//terminator for string in SQL is ' - so replace with ''
if (!string.IsNullOrEmpty(this.Site)) strSQL += "," +"'"+ this.Site.Replace("'", "''") +"'";//terminator for string in SQL is ' - so replace with ''
Settings.ExecuteSQL(strSQL);
http://www.serviciipeweb.ro/iafblog
Page 26
Ignat Andrei
In sfirsit, sa scriem codul pentru adaugare de pe forma de list: E clar ca va trebui sa facem re incarcarea datelor - deci o sa luam codul de pe frmPublisherList_Load si o sa il punem in o functie generica , RebindData()
private void btnAdd_Click(object sender, EventArgs e) { frmPublisherAdd f = new frmPublisherAdd(); f.ShowDialog(this); RebindData(); }
private void RebindData() { BookObjects.ColPublisher publishers = new BookObjects.ColPublisher(); publishers.Load(); colPublisherBindingSource.DataSource = publishers; }
Sa verificam functionarea Dati CTRL+ F5 , apasati Add introduceti un nume apasati Add si verificati ca se vede in lista ceea ce ati introdus.
Sa facem acum stergerea. Adaugati alt buton(Name = btnDelete, Text = &Delete) si sa scriem cod pentru delete
http://www.serviciipeweb.ro/iafblog
Page 27
Ignat Andrei
BookObjects.Publisher p = colPublisherBindingSource.Current as BookObjects.Publisher; if (p != null) { //avert the user if (MessageBox.Show(this, "Delete " + p.Name, "Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) return;
p.Delete(); RebindData(); } }
In sfirsit, sa scriem codul pentru update: iarasi buton, iarasi cod private void btnUpdate_Click(object sender, EventArgs e) { BookObjects.Publisher p = colPublisherBindingSource.Current as BookObjects.Publisher;
if (p == null) return;
http://www.serviciipeweb.ro/iafblog
Page 28
Ignat Andrei
Pentru asta, adaugam o alta forma, in care sa facem update . Dar avem neaparata nevoie de un publisher pe care sa facem update.Vom modifica constructorul formei ca sa accepte ca parametru de intrare un publisher.
Ca sa punem valorile deja obtinute in text box-uri, avem 2 variante : Fie codam de mina de doua ori ( ceva de genul txtName.Text= m_Publisher.Name si , pe salvare, m_Publisher.Name= txtName.Text),fie lucram cu DataBindings direct . Prefer acum, pentru rapiditate, a doua varianta :
public partial class frmPublisherUpdate : Form { private BookObjects.Publisher m_Publisher; public frmPublisherUpdate(BookObjects.Publisher pub) { m_Publisher = pub; InitializeComponent(); }
http://www.serviciipeweb.ro/iafblog
Page 29
Ignat Andrei
Sa scriem si codul de salvare pe publisher : public void Update() { string strSQL = " update Publisher set "; strSQL += " NamePublisher = ";
strSQL += ",";
http://www.serviciipeweb.ro/iafblog
Page 30
Ignat Andrei
Settings.ExecuteSQL(strSQL); }
Ca tema de acasa, ramine sa faceti acelasi lucru pentru tabela Author. Data viitoare o sa facem un mic refactoring de code... si o sa facem un program de setup pentru aplicatia Windows.
http://www.serviciipeweb.ro/iafblog
Page 31
Ignat Andrei
Daca nu aveti IIS, atunci puteti alege si o cale fizica, de exemplu : C:\Book\BookSetup\ Problema de rezolvat : printre fisierele care trebuie instalate se afla si fisierul mdb. Daca aveti VS.NET Standard(sau ceva mai mult) aveti un proiect special care va ingaduie sa adaugati alte fisiere la proiectul de instalare. Pentru moment ne jucam cu ce avem. Asa ca faceti click dreapta pe proiectul Bookwin, click add=>existing item si cautati book.mdb file din C:\Book\BookData . Compilati proiectul (CTRL+Shift+B) si veti gasi acum book.mdb on intre fisierele aplicatiei ca fisier de date. Acum conditiile de instalare : Pentru ca facem instalarea de pe un CD, e mai bine sa includem si kitul de .NET 2.0 ca sa facem download tot de pe CD(cind facem instalarea de pe Internet, e preferabil sa facem instalarea .NET 2.0 de la site-ul MS)
Update-urile automane nu sunt inca valabile, din cauza ca nu avem inca un WebSite. Dar putem modifica citeva dintre Options, ca publisher name,product name si altele.
http://www.serviciipeweb.ro/iafblog
Page 32
Ignat Andrei
Acum sa apasam pe Publish Wizard : Primul pas ne intreaba un sa creeam kit-ul de instalare (C:\Book\BookSetup\deja selectat) , urmatorul sa ne intrebe suportul fizic (click from cd -rom or dvd rom). Al treilea pas ne ingaduie sa setam unde va cauta aplicatia update-urile dar, asa cum am spus nu avem inca un WebSite asa ca selectati the application will not check for updates Si apasati finish!
Daca vreo eroare se intimpla spunind can not find package, mergeti la Microsoft .NET Framework Version 2.0 Redistributable Package (x86) http://www.microsoft.com/downloads/details.aspx?FamilyID=0856eacb-4362-4b0d-8eddaab15c5e04f5&displaylang=en si downloadati kit-ul. Copiati-l in <C:\Program Files>\Microsoft Visual Studio 8\SDK\v2.0\Bootstrapper\Packages\DotNetFX Pentru instmsia.exe , duceti-va la http://go.microsoft.com/fwlink/?LinkId=37285
Acum puteti scrie folder-ul C:\Book\BookSetup pe un CD si sa testati instalarea. Daca nu vreti sa irositi un CD, puteti scrie folder-ul intr-un fisier .iso si sa il incarcati ca un CD. O metoda de a creea un fisier ISO este Alex Feinman IsoRecorder http://isorecorder.alexfeinman.com/isorecorder.htm Faceti download ( eu am testat versiunea pentru XP SP2 ) si click dreapta pe folder-ul Book Setup
http://www.serviciipeweb.ro/iafblog
Page 33
Ignat Andrei
In meniu vedeti Create ISO image file click si acceptati setarile existente. Acum aveti un CD -si puteti incarca acest CD cu Virtual CD Control Panel.
Puteti testa acum programul de pe CD-ul incarcat. Mai mult,daca vreti sa il testati pe alta versiune de Windows(pentru care aveti kit-ul de instalare) puteti face download la Virtual PC 2004 SP1 or VMWare si sa creati cu aceasta un nou Windows (repet : trebuie sa aveti CD-urile de instalare a Windows!).
http://www.serviciipeweb.ro/iafblog
Page 34
Ignat Andrei
Data viitoare o sa facem o aplicatie ASP.NET cu o baza de date SQL Server. Lecturi recomandate: Comparatie intre versiunile de VS.NET 2005:
http://www.microsoft.com/downloads/details.aspx?familyid=6d58729d-dfa8-40bf-afaf-
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=13937&SiteID=1 Virtual CD Control Panel - http://download.microsoft.com/download/7/b/6/7b6abd84-78414978-96f5-bd58df02efa2/winxpvirtualcdcontrolpanel_21.exe Alex Feinman - Make ISO http://isorecorder.alexfeinman.com/isorecorder.htm
http://www.serviciipeweb.ro/iafblog
Page 35
Ignat Andrei
Urmatorul ecran e configurat OK dupa cum vedeti utilizeaza windows authentication. Alegeti apoi Copy data from one or more table or views si click select all in urmatorul ecran. Puteti acum apasa Finish si sa asteptati terminarea operatiei.
Acum citeva modificari ale structurii se impun pentru a nu avea probleme de concurenta la creearea simultana a doi Publisher-i :
http://www.serviciipeweb.ro/iafblog
Page 36
Ignat Andrei
Alegeti Book=> Tables in SQL Server Management Studio. Click dreapta tabela Publisher si apasati modify. Vom face IDPublisher un auto number ca in Access. In SQL Server, auto number se numeste identity.
http://www.serviciipeweb.ro/iafblog
Page 37
Ignat Andrei
Imediat ce modificati proprietatea (Is Identity), veti vedea identity increment si seed fiind modificate in 1 si 1( adica creste cu 1(increment) pornind de la 1(seed)). Salvati tabela. Urmatorul pas este sa creeam un folder in care sa creeam program-ul internet. Duceti-va la C:\Book si creati un nou folder , numit BookWeb Acum din folder-ul Administrative Tools faceti dublu click pe Internet Information Services si mariti (local computer)=> WebSites=> Default Web Site.Click dreapta pe Default Web Site si alegeti New => Virtual Directory. Apasati pe next. In Alias introduceti numele BookWeb. Pentru folder alegeti C:\Book\BookWeb .Apasati de doua ori Finish si suntem gata sa incepem.
Acum suntem gata sa incepem prima noastra pagina in ASP.NET. Ca si in proiectul Windows vom avea o pagina de lista si paginile de creere/modificare/stergere pentru Publisher.Ca sa facem ca site-ul sa aiba aceeasi infatisare, vom crea o pagina master numita Book.master. Deschideti Microsoft Visual Web Developer 2005 Express Edition si alegeti Open Web Site ca in imagine:
http://www.serviciipeweb.ro/iafblog
Page 38
Ignat Andrei
In Solution Explorer click dreapta pe http://localhost/BookWeb si alegeti Add new Item si alegeti Master Page si numiti Book.master.Nu uitati sa selectatiPlace code in separate file
Vom face interfata grafica a master page mai degraba simpla, lasind cititorului sarcina de a o infrumuseta : pune o tabela care area 2 rinduri si 2 coloane , rindul de sus fiind format dintr-o singura celula Codul este urmatorul:
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="Book.master.cs" Inherits="Book" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Untitled Page</title>
http://www.serviciipeweb.ro/iafblog
Page 39
Ignat Andrei
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server"> </asp:ContentPlaceHolder> </td> </tr> </table> </div> </form> </body> </html>
http://www.serviciipeweb.ro/iafblog
Page 40
Ignat Andrei
Acum
sa
creeam
pagina
de
listare
de
publisher.
Adaugati
un
nou
item
Web
Form(frmPublisherList.aspx) - si verificati ca ati check-uit amindoua check-urile.Urmatorea fereasta va arata BookMaster pe care trebuie sa il selectati si apoi sa apasati OK.Click dreapta pe fisier si alegeti Set as start page In asp:content trageti un gridview (il gasiti in Toolbox=> Data) . Acest grid trebuie umplut cu date asa ca trebuie sa ne conectam la obiectele create(la fel ca la aplicatia Windows).Aceasta e problema cum putem sa ne conectam fie la versiunea de Release sau debug a proiectului daca nu il avem in solutie, asa cum era la Windows Forms ?Solutia este indirectia(destul de intilnita in programare) : facem un nou folder, bookdll si o sa copiem acolo obiectele, indiferent daca e debug sau release.Din acest nou folder o sa isi ia obiecteleaplicatia Web. Creati folder-ul C:\Book\BookDll , mergeti inapoi la solutia Book.sln si la Build puneti aceasta linie in Post build command line: copy $(TargetDir)*.* $(ProjectDir)..\BookDll /Y Compilati proiectul .O sa gasiti in folder-ul C:\Book\BookDll fisierul BookObjects.dll Adaugati referinta la BookObjects.dll aplicatiei BookWeb ( ca de obicei: click dreapta pe proiectul http://localhost/BookWeb, alegeti add reference, click pe tab-ul Browse si mergeti in folder-ul C:\Book\BookDll.
http://www.serviciipeweb.ro/iafblog
Page 41
Ignat Andrei
BookObjects.ColPublisher publishers = new BookObjects.ColPublisher(); publishers.Load(); grdPublisher.DataSource = publishers; grdPublisher.DataBind();// main difference ASP si Windows forms - this call }
http://www.serviciipeweb.ro/iafblog
Page 42
Ignat Andrei
Cannot open database "Book" requested by the login. The login failed. Login failed for user '<PCNAME>\ASPNET'.
De ce aceasta eroare ? In connection strings am pus Trusted_Connection=true in web.config. Asa incit utilizatorul care se conecteaza este cel sub care ruleaza site-ul(<PCNAME>/ASPNET). Avem mai multe solutii : 1) Sa punem in web.config o conexiune care sa foloseasca
autentificarea cu user name si password (de obicei buna pentru siteurile Internet) 2) Sa punem site-ul sa ruleze sub alt user- unul care sa aiba drepturi de conectare la Baza de date sites) - vezi imaginea 3) Sa punem utilizatorii sa se autentifice la conectare si sa dam drepturi lor sa se conecteze utilizand Integrated windows impreuna cu o setare in fisierul web.config <identity impersonate="true"/>(bun pentru site-uri intranet) 4) Sa cream un utilizator SQL Server pentru (IUSR_ )care sa aiba drepturi pe baza de date.
Puteti sa va faceti alegerea - personal, prefer prima solutie. OK.Data viitoare vom vedea cum sa inseram date in baza de date Sql Server.
http://www.serviciipeweb.ro/iafblog
Page 43
Ignat Andrei
Ignat Andrei
Scimbati in source view titlul de la Untitled Page la Insert Publisher Acum trebuie sa punem controalele pentru inserare, adica numele si site-ul Publisher- ului. Prefer sa pun o tabela(desi altii prefera CSS) si codul paginii o sa arate asa :
<%@ Page Language="C#" MasterPageFile="~/Book.master" AutoEventWireup="true" CodeFile="frmPublisher_Insert.aspx.cs" Inherits="frmPublisher_Insert" Title="Insert Publisher" %> <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> <table> <tr> <td colspan="2">Enter values </td> </tr> <tr> <td> Name </td> <td> <asp:TextBox ID="txtName" runat="server"> </asp:TextBox> </td> </tr> <tr> <td> Site </td>
http://www.serviciipeweb.ro/iafblog
Page 45
Ignat Andrei
<td><asp:Button ID="btnSave" Text="Insert" runat="server" /> </td> <td><asp:Button ID="btnCancel" Text="Cancel" runat="server" /> </td> </tr> </table> </asp:Content>
Acum faceti click pe design view si faceti click dublu pe butonul Insert ca sa generati evenimentul de Click. Iarasi Click dublu in solution explorer pe frmPublisher_Insert.aspx si , in Design view, click dublu pe butonul Cancel . Pentru Cancel e clar ce trebuie facut redirectionata pagina la frmPublisherList.aspx
Response.Redirect("frmPublisherList.aspx", false);
Ignat Andrei
Daca totul a mers bine (fiti sigur ca Insert cheama Save()) o sa vedeti in frmPublisherList.aspx exact numele si site-ul publisher-ului creat. Este clar ca frmPublisherList.aspx are nevoie de un buton cu ajutorul caruia sa navigam pe pagina de creare.Sa il punem:
<asp:Button ID="btnNew" runat="server" Text="New" OnClick="btnNew_Click" />
Si sa scriem codul :
protected void btnNew_Click(object sender, EventArgs e) { Response.Redirect("frmPublisher_Insert.aspx", false); }
Atita este de ajund pentru crearea de un nou publisher. Pentru editare si stergere se poate folosi chiar grid-ul dar prefer sa avem doua pagini noi. Asa ca o sa adaugam pe grid un link de edit si un buton de delete asta pentru a vedea codul diferit generat de cele doua. Pagina arata asa:
<%@ Page Language="C#" MasterPageFile="~/Book.master" AutoEventWireup="true" CodeFile="frmPublisherList.aspx.cs" Inherits="frmPublisherList" Title="Publisher Lists" %> <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> <asp:GridView ID="grdPublisher" runat="server" AutoGenerateColumns="false"> <Columns> <asp:BoundField DataField="Site" HeaderText="Site" /> <asp:BoundField DataField="Name" HeaderText="Name" /> <asp:TemplateField HeaderText="Operations"> <ItemTemplate> <asp:Button runat="server" ID="btnDelete" CommandName="deletepub" CommandArgument='<%# Eval("IDPublisher") %>' Text="Delete" />
http://www.serviciipeweb.ro/iafblog
Page 47
Ignat Andrei
<asp:HyperLink runat="server" ID="hkEdit" NavigateUrl='<%# Eval("IDPublisher","~/frmPublisher_Edit.aspx?ID={0}") %>' Text="Edit"></asp:HyperLink> </ItemTemplate> </asp:TemplateField> </Columns>
</asp:GridView> <br /> <asp:Button ID="btnNew" runat="server" Text="New" OnClick="btnNew_Click" /> </asp:Content>
Link hkEdit este clar redirecteaza pagina la frmPublisher_Edit.aspx cu ID- ul publisherului de pe rindul respectiv. Pentru buton trebuie sa cream evenimentul - si evenimentul este chiar pe grid si se numeste
RowCommand
In fisierul .cs:
protected void grdPublisher_RowCommand(object sender, GridViewCommandEventArgs e) { switch(e.CommandName) { case "deletepub": int idPublisher; if(int.TryParse(e.CommandArgument.ToString(),out idPublisher)) { Response.Redirect("frmPublisher_Delete.aspx?ID="+ idPublisher, false);
http://www.serviciipeweb.ro/iafblog
Page 48
Ignat Andrei
Acum sa creeam cele doua pagini noi frmPublisher_Delete si frmPublisher_Edit . La amindoua o sa copiem tabela de la pagina de new: si sursa fara definitia de clasa. Un singur lucru e de facut : sa regasim obiectul Publisher dupa id- ul trimis.Mai intii regasim ID-ul :
int idPublisher; if(!int.TryParse(Request.QueryString["ID"],out idPublisher)) { Response.Redirect("frmPublisherList.aspx", false); return; } //we have id of the publisher
Cum facem acum regasirea dupa ID ? Amintiti- va ca in aplicatia Windows forms ceea ce am trecut de la o forma la alta a fost chiar obiectul. Aici avem doar Id-ul.Va trebui sa adaugam acest cod de regasire al obiectului- vom deschide solutia Book.sln si vom adauga metoda respectiva. Imi place sa pun metoda pe clasa ColPublisher si sa o fac statica pentru ca nu depinde de vre-o variabila a clasei ColPublisher.
http://www.serviciipeweb.ro/iafblog Page 49
Ignat Andrei
public static Publisher sLoadFromID(int ID) { DbConnection db = Settings.TheConnection; using (db) { db.Open(); IDataReader ir = Settings.Load("select IDPublisher, NamePublisher, SitePublisher from Publisher where IDPublisher="+ ID, db); while (ir.Read()) { Publisher p = new Publisher(); p.FillObject(ir); return p; } } return null; }
http://www.serviciipeweb.ro/iafblog
Page 50
Ignat Andrei
De ce am pus (!IsPostBack ) ? Din cauza ca textboxes trebuie sa fie umplute cu numele Publisher- ului doar prima oara. Cind user-ul modifica numele si/sau site- ul si dupa ce da click pe save trebuie sa ii pastram modificarile. Pentru a regasi usor obiectul, sa il punem intr-o proprietate:
private Publisher pub { get { int idPublisher; if (!int.TryParse(Request.QueryString["ID"], out idPublisher)) {
http://www.serviciipeweb.ro/iafblog
Page 51
Ignat Andrei
if (!IsPostBack) { //now fill the text boxes txtName.Text = p.Name; txtSite.Text = p.Site; } }
http://www.serviciipeweb.ro/iafblog
Page 52
Ignat Andrei
//TODO : throw an exception that someone deleted the publisher Response.Redirect("frmPublisherList.aspx", false); return;
Va trebui sa modificati si text-ul butonului de la Insert la Save Pe pagina de delete o sa punem acelasi cod ca sa regasim Publisher-ul .Iata codul:
using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts;
http://www.serviciipeweb.ro/iafblog
Page 53
Ignat Andrei
public partial class frmPublisher_Delete : System.Web.UI.Page { private Publisher pub { get { int idPublisher; if (!int.TryParse(Request.QueryString["ID"], out idPublisher)) {
} } protected void Page_Load(object sender, EventArgs e) { Publisher p = pub; if (p == null) { Response.Redirect("frmPublisherList.aspx", false);
http://www.serviciipeweb.ro/iafblog
Page 54
Ignat Andrei
if (!IsPostBack) { //now fill the text boxes txtName.Text = p.Name; txtSite.Text = p.Site; } } protected void btnSave_Click(object sender, EventArgs e) { Publisher p = pub;
http://www.serviciipeweb.ro/iafblog
Page 55
Ignat Andrei
Nu uitati sa schimbati textul de la btnSave in Delete. Puteti de asemenea sa puneti " ReadOnly="true" pe textboxes ca sa nu dati impresia ca se editeaza ceva.
<%@ Page Language="C#" MasterPageFile="~/Book.master" AutoEventWireup="true" CodeFile="frmPublisher_Delete.aspx.cs" Inherits="frmPublisher_Delete" Title="Untitled Page" %> <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> <table> <tr> <td colspan="2">Enter values </td> </tr> <tr> <td> Name </td> <td> <asp:TextBox ID="txtName" runat="server" ReadOnly="true"> </asp:TextBox> </td> </tr> <tr> <td> Site </td> <td> <asp:TextBox ID="txtSite" runat="server" ReadOnly="true"> </asp:TextBox>
http://www.serviciipeweb.ro/iafblog
Page 56
Ignat Andrei
<td><asp:Button ID="btnCancel" Text="Cancel" runat="server" OnClick="btnCancel_Click" /> </td> </tr> </table> </asp:Content>
<siteMapNode url="frmPublisherList.aspx" title="All publishers" description="Publishers list" > <siteMapNode url="frmPublisher_Insert.aspx" title="New Publisher" description="Add new"></siteMapNode> <siteMapNode url="frmPublisher_Edit.aspx" title="Edit Publisher" description="Edit"></siteMapNode> <siteMapNode url="frmPublisher_Delete.aspx" title="Delete Publisher" description="Delete"></siteMapNode>
http://www.serviciipeweb.ro/iafblog
Page 57
Ignat Andrei
description="Book
( Numele sunt destul de descriptive url, title si description) Acum e timpul sa il vedem la lucru: Deschideti Book.master( care tine cum arata site-ul in general) , si puneti un control site map ( il gasiti in tab-ul navigation de pe toolbox) inainte de content place holder:
<asp:SiteMapPath ID="SiteMapPath1" runat="server" Font-Names="Verdana" FontSize="0.8em" PathSeparator=" : "> <PathSeparatorStyle Font-Bold="True" ForeColor="#990000" /> <CurrentNodeStyle ForeColor="#333333" /> <NodeStyle Font-Bold="True" ForeColor="#990000" /> <RootNodeStyle Font-Bold="True" ForeColor="#FF8000" /> </asp:SiteMapPath>
http://www.serviciipeweb.ro/iafblog
Page 58
Ignat Andrei
Acum , daca veti rula proiectul si va duceti pe new veti vedea urmatoarele:
Sigur ca linkul All books nu e implementat dar ramine in sarcina dvoastra sa il faceti.
Acum sa trecem la localizare. Vrem sa fim capabili ca cei care vin sa poata alege intre Engleza si Franceza O sa facem acest lucru pentru o singura forma, iar celelalte o sa le lasam ca exercitiu . O sa salvam setarea limbajului intr-un cookie pe PC-ul user-ului si o sa fie citit de fiecare data cind user- ul intra pe site. Sa adaugam un drop down list pe Book.master :
<asp:DropDownList runat="server" id="ddlLanguage" OnSelectedIndexChanged="ddlLanguage_SelectedIndexChanged" AutoPostBack="true"> <asp:ListItem Text="English" Value="en"> </asp:ListItem> <asp:ListItem Text="French" Value="fr">
http://www.serviciipeweb.ro/iafblog
Page 59
Ignat Andrei
http://www.serviciipeweb.ro/iafblog
Page 60
Ignat Andrei
http://www.serviciipeweb.ro/iafblog
Page 61
Ignat Andrei
Ca sa schimbam ar trebui sa scriem cod in fiecare pagina pe metoda InitializeCulture , sau sa o punem in global.asax file( care prinde evenimentele aplicatiei ) pe Application_BeginRequest: (adaugati new item => Global Application Class)
protected void Application_BeginRequest(object sender, EventArgs e) { string lang = System.Threading.Thread.CurrentThread.CurrentUICulture.Name; HttpCookie cookie = Request.Cookies["Language"];
In sfirsit trebuie sa creeam textele in franceza si engleza. Adaugati un folder Asp.NET, numit App_LocalResources
http://www.serviciipeweb.ro/iafblog
Page 62
Ignat Andrei
Si in acest folder adaugati trei fisiere de resurse, numite : frmPublisherList.aspx.en.resx frmPublisherList.aspx.fr.resx frmPublisherList.aspx.resx (Numele fisierului este compus din numele fisierului aspx + (optional) limba + .resx ) In aceste fisiere vom scrie un singur string de demo pentru butonul new,ca in figura:
http://www.serviciipeweb.ro/iafblog
Page 63
Ignat Andrei
Si , daca rulati aplicatia si schimbati in dropdown din Engleza in Franceza o sa vedeti textul butonului schimbindu-se Observatie 1: Daca nu aveti fisierul .resx fara a specifica limbanu merge! Observatie 2: Daca aveti mai multe text IDENTICE de translatat (exemplu : butonul de save ) putei adauga resurse resx in folder-ul App_GlobalResources. Exemplu : presupunem ca avem in App_GlobalResources fisierele : Buttons.en.resx Buttons.fr.resx Buttons.resx Si vrem sa modificam btnSaveText Accesam resursele astfel :
<%$ Resources:Buttons,btnSaveText%>
http://www.serviciipeweb.ro/iafblog
Page 64
Ignat Andrei
http://www.serviciipeweb.ro/iafblog
Page 65
Ignat Andrei
Si, desigur, numar de inregistrari va fi 0- caci nu avem nici o inregistrare. La fel ca in proiectul Windows, puteti creea un nou Publisher, sterge, etc.
http://www.serviciipeweb.ro/iafblog
Page 66
Ignat Andrei
3. E mai usor de fixat bug-urile daca, pe deasupra, rulati testele in fiecare noapte si a doua zi dimineata vedeti ceva stricat... 4. Hai sa trecem la treaba:
Mai intii downloadati NUnit de la http://www.nunit.org/index.php?p=download ( eu am folosit versiunea 2.2.8 )Exista si surse si setup de instalare. Eu as sfatui sa luati sursele sa le compilati. Apoi la solutia noastra Book.sln adaugam un nou proiect de tipul Class Library , numit BookTest , adaugam o referinta la nunit.framework.dll , aflat in NUnit-2.2.8src\src\NUnitFramework\framework\bin\Debug2005, modificam class1.cs in TestPublisher.cs si incepem sa scriem testul.Testul cel mai simplu este unul de CRUD create , read, update, delete. Avem nevoie de obiectele Publisher respective, precum si de setari in fisierul App.Config pentru a recunoaste Baza de date, precum si de Baza de date. Pentru Publisher, adaugam o referinta la BookObject in tab- ul Projects de la Add Reference. Pentru App.Config, adaugam un fisier de tipul application configuration file si copiem de la BookDos partile relevante, astfel incit fisierul arata astfel :
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="DatabaseUsed" value="MDB"/> <!-- possible values : MDB, SQLServer--> </appSettings> <connectionStrings> <add name="MDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\book.mdb;User Id=admin;Password=;"/> <!-- TODO : add for asp.net application the connection string with SQL Server-> </connectionStrings>
http://www.serviciipeweb.ro/iafblog
Page 67
Ignat Andrei
Pentru baza de date, e simplu : in Build Events, la Post Build Command Line adaugam
copy $(ProjectDir)..\BookData\*.mdb $(TargetDir)
using System; using System.Collections.Generic; using System.Text; using NUnit.Framework; using BookObjects; namespace BookTest { [TestFixture] //arata ca e o clasa care contine teste public class TestPublisher { [Test] //arata ca metoda care urmeaza este un test [Category("CRUD")] //categoria -de obicei, testele de CRUD ar trebui puse impreuna public void CRUD() { Publisher p = new Publisher(); p.Name = "Amazon"; p.Save();
http://www.serviciipeweb.ro/iafblog
Page 68
Ignat Andrei
//daca acea conditie(bFound) nu e true, atunci se afiseaza mesajul de eroare Assert.IsTrue(bFound, "Nu s-a gasit publisher cu numele " + p.Name + " dupa insert"); //sa il modificam p.Name = "O'Reilly"; p.Update();
//sa il gasim din nou cp = new ColPublisher(); cp.Load(); bFound = false; foreach (Publisher pLoop in cp) { if (pLoop.Name == p.Name)
http://www.serviciipeweb.ro/iafblog
Page 69
Ignat Andrei
//daca acea conditie(bFound) nu e true, atunci se afiseaza mesajul de eroare Assert.IsTrue(bFound, "Nu s-a gasit publisher cu numele " + p.Name + " dupa update");
//si sa vedem ca nu a fost gasit cp = new ColPublisher(); cp.Load(); bFound = false; foreach (Publisher pLoop in cp) { if (pLoop.Name == p.Name) { bFound = true; break; } }
http://www.serviciipeweb.ro/iafblog
Page 70
Ignat Andrei
Assert.IsFalse(bFound, "S-a gasit publisher cu numele " + p.Name + " dupa delete");
} } }
Il compilam si sa rulam testul. Gasiti in folderul NUnit-2.2.8-src\src\GuiRunner\nunit-guiexe\bin\Debug2005 un nunit- gui.exe si porniti- l.Apasati File=> Open si mergeti in C:\Book\BookTest\bin\Debug si incarcati BookTest.dll . Ar trebui sa apara figura urmatoare
http://www.serviciipeweb.ro/iafblog
Page 71
Ignat Andrei
Ceva a mers prost la update ... sa vedem linia 107 din Publisher.cs
strSQL += "'" + this.Site.Replace("'", "''") + "'";
Acum e clar ce s-a intimplat ... Cind am facut testul, nu am initializat Site- ul cu nimic... si atunci este null , ceea ce inseamna ca .Replace nu poate fi aplicat Sa modificam codul din Publisher.cs ca sa ia in seama si acest lucru :
if (this.Site == null) strSQL += " NULL "; else strSQL += "'" + this.Site.Replace("'", "''") + "'";
Ignat Andrei
Este destul de clar ca aplicatia nu a updatat numele ... De ce ?Ne dam seama imediat : in momentul in care aplicatia a adaugat un nou Publisher , nu a regasit ID-ul inserat ... iar cind a facut update, IDPublisher este 0 , ceea ce inseamna ca nu a putut fi facut update corect. Cum modificam acest lucru ? Pentru access , putem sa selectam maxim de ID,iar pentru SQL Server putem crea o procedura stocata ... sau sa intoarcem @@Identity Hai sa facem pentru Access , modificand Publisher.cs, procedura Save, adaugind la final:
if(Settings.TheDatabase == Settings.DatabaseUsed.MDB) {
strSQL = "select max(IDPublisher) as nr from Publisher"; using (DbConnection dc = Settings.TheConnection) { dc.Open(); using(DbCommand dco =Settings.TheCommand) {
http://www.serviciipeweb.ro/iafblog
Page 73
Ignat Andrei
E clar ca exemplu a fost mai degraba simplut, iar ceea ce conteaza, de fapt, sunt regulile de business si de validare - ca de exemplu, validarea CNP
http://www.serviciipeweb.ro/iafblog
Page 74
Ignat Andrei
In .NET sunt doua tipuri mari de fiiere Help : Cele care produc Help pentru utilizatorul final si cele care sunt auto-generate din comentarii la cod.
Avem nevoie de urmtoarele: 1.Html Help Workshop e free si putei sa l downloadati de aici http://www.microsoft.com/downloads/details.aspx?familyid=00535334-c8a6-452f-9aa0d597d16580cc&displaylang=en. Adiional putei downloada si fiiere css stil Office de aici http://www.microsoft.com/downloads/details.aspx?FamilyId=A6A76073-0E0A-49BB-8E21318B798B4CF6&displaylang=en
2. Pentru documentaia codului exista nainte NDoc dar din pcate dezvoltatorul nu mai face dezvoltarea pentru .Net 2.0( vezi http://johnsbraindump.blogspot.com/2006/07/ndoc-20-isdead.html) Alternativa este SandCastle (http://www.sandcastledocs.com) din care ultimul CTP(Martie) este aici (http://www.microsoft.com/downloads/details.aspx?FamilyID=E82EA71D-DA89-42EEA715-696E3A4873B2&displaylang=en).
3.De asemenea, pentru ca SandCastle e greu de utilizat din command line, exista mai multe GUIuri pentru el intre care vom lucra cu SandCastle Help File Builder de pe CodePlex (http://www.codeplex.com/Wiki/View.aspx?ProjectName=SHFB). O sa lucram cu ultimul release ,1.4.0.1 PROD aflat aici http://www.codeplex.com/SHFB/Release/ProjectReleases.aspx?ReleaseId=2264 si as downloada chiar sursele ...
ncepem cu documentarea codului pentru BookObjects, urmnd sa trecem la generarea de Help pentru proiectul Windows.
http://www.serviciipeweb.ro/iafblog
Page 75
Ignat Andrei
Comentariile in C# se fac scriind trei slash-uri deasupra clasei/metodei/cimpului pe care vrei sa le documentai:
/// <summary> /// Aceasta clasa tine toti publisher-ii /// Mod de utilizare : folositi Load /// </summary> public class ColPublisher : System.Collections.ObjectModel.KeyedCollection<string,Publisher> {
/// <summary> /// varianta interna de generat cheie unica pentru un Publisher /// </summary> /// <param name="item">publisher-ul</param> /// <returns></returns> protected override string GetKeyForItem(Publisher item) {
Continuai cu toate metodele sau downloadati ultima varianta de proiect de aici: http://serviciipeweb.ro/iafblog/content/binary/part12/book.zip
In plus, trebuie sa mai setai faptul ca trebuie generata documentaia XML din proprietatile proiectului:
http://www.serviciipeweb.ro/iafblog
Page 76
Ignat Andrei
Acum in folder-ul C:\Book\BookObjects\bin\Debug avei generata documentaia XML. Pornim SandCastle Help File Builder care arata cam asa:
http://www.serviciipeweb.ro/iafblog
Page 77
Ignat Andrei
Apsam pe Add si ne ducem in C:\Book\BookObjects\bin\Debug. Acolo indicam dll- ul generat iar programul o sa observe si fiierul XML. Apsam pe iconia de compilare si ... eroare... Error: Unresolved assembly reference: System.Configuration (System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a) required by BookObjects Last step completed in 00:00:02.403
Dup descriere vedem c ii lipsete o referina la System.Configuration. Acest dll se afla in GAC (Global Assembly Cache) si o vom aduga. In Project Properties , la Build=>Dependencies apsai pe butonul cu cele 3 puncte. Acum in ecranul urmtor exista un buton cu imaginea de folder si cu o icoana de o cheie care iese, iar la tooltip scrie Add GAC dependencies
http://www.serviciipeweb.ro/iafblog Page 78
Ignat Andrei
Acum rulati din nou si ceea ce se va genera este un document chm , numit Documentation.chm aflat in C:\Book\BookObjects\bin\Debug\Help:
http://www.serviciipeweb.ro/iafblog
Page 79
Ignat Andrei
http://www.serviciipeweb.ro/iafblog
Page 80
Ignat Andrei
E clar acum ca aceasta documentaie se poate regenera la cerere.Daca vreti help in forma 2.0(hxs) , downloadati Visual Studio 2005 SDK Version 4.0 de la adresa http://www.microsoft.com/downloads/details.aspx?FamilyID=51a5c65b-c020-4e08-8ac03eb9c06996f4&DisplayLang=en
Sa generam acum documentaia pentru Windows Forms. Ar trebui pentru fiecare forma sa avem cate un Help aa ca o sa cream 3 fiiere HTML care o sa tina List, Add si Update.
Vom crea un nou folder, numit HelpWindows, in C:\book\Help si vom pune in el cele 3 fiiere : add.htm,list.htm,update.htm. Pornim HTML Help Workshop, File=>New =>Project si dai next. Adaugati fiierele htm s i apsati pe Contents. Acceptai creerea unui nou fiier si apsnd pe iconia din stnga cu aspect de fiier adugat la coninut cele 3 fisiere, dindu- le numele corespunztoare. Acum, dup compilare, s-a generat un fiier chm. Haidei sa l integram cu ap licaia Windows.
Sarcina de a copia fiierul chm lng executabil o las cititorului, avnd in vedere ca am mai fcut aa ceva(Project=>Properties=>Build Events). Sa mergem la forma de list si sa adaugam din ToolBox un control HelpProvider. LA proprietati la HelpNameSpace puneti numele chm- ului. Acum pe forma, gasiti HelpKeyword on... (setati valoarea la list.htm) si HelpNavigator on...( setat la topic). Rulati, apasati F1 si iata fisierul de help!
http://www.serviciipeweb.ro/iafblog
Page 81
Ignat Andrei
Vom utiliza in acest exemplu log4net .El suporta log-area operaiilor in felurite moduri in fiier, baza de date, email, telnet si multe altele. Downloadati versiunea 1.2.10 de la adresa http://logging.apache.org/log4net/downloads.html si sa ncepem configurarea aplicaiei. Copiai coninutul folder- ului log4net1.2.10\bin\net\2.0\debug in C:\Book\sharedDll si sa ncepem modificarea proiectului Windows pentru a nregistra ce a fcut utilizatorul
Deschidem Book.sln si deschidem App.Config. Acolo scriem urmtoarele imediat sub configuration:
<configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> </configSections> <log4net> <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> <File value="Log4Net.log"/> <AppendToFile value="true"/> <rollingStyle value="Composite"/> <maximumFileSize value="1MB"/> <maxSizeRollBackups value="10"/> <datePattern value="yyyyMMdd"/>
http://www.serviciipeweb.ro/iafblog
Page 82
Ignat Andrei
<param name="ConversionPattern" value="%d [%t] %-5p %c %m%n"/> </layout> </appender> <root> <level value="Debug"/> <appender-ref ref="RollingLogFileAppender"/> </root> </log4net>
Dup cum se vede, folosim RollingLogFileAppender ( adic un fiier a crui denumire va fi diferita in fiecare zi dup modelul datePattern ) de tipul Composite(daca depaseste maximumFileSize atunci se creeaz un nou fiier in ziua respectiva).
Sa adugam referina proiectului nostru (BookWin) dll- ul log4net.dll din sharedDll .Avem de fcut urmtoarele in Program.cs : In funcia Main scriem prima linie:
log4net.Config.XmlConfigurator.Configure();
Haide sa scriem in fiier de cite ori un utilizator adaug un nou Publisher. In frmPublisherAdd.cs, la evenimentul private void btnAdd_Click(object sender, EventArgs e) vom aduga codul de log-are:
if (Program.logger.IsDebugEnabled)
http://www.serviciipeweb.ro/iafblog
Page 83
Ignat Andrei
Cam atit e de fcut. Acum rulai proiectul, adaugai un Publisher, si o sa vedei un fiier log4Net.log in care scrie urmtoarele:
E interesant la log4Net ca putei aduga mai muli appender-i, astfel ca , de pilda, sa trimit si email de cate ori o modificare e fcuta. Observatie 1: Pentru aplicatia Web, modificarile in Web.Config sunt aceleasi - iar in global.asax trebuie pusa linia urmatoare: void Application_Start(object sender, EventArgs e) { // Code that runs on application startup log4net.Config.XmlConfigurator.Configure(); } Observatie 2: In loc sa punem codul in fiecare pagina de Web si Windowspe salvare, mai bine punem in fiecare cod de "salvare" al obiectelor- de pilda in public void Save()
http://www.serviciipeweb.ro/iafblog
Page 84
Ignat Andrei
Programarea in .NET - partea a 14-a Salvare XML si Executare de operatii asincrone in Windows Forms
De ce taskuri asincrone ? In ideea ca , intr-o aplicatie Windows(si chiar ASP.NET) , operatiile lungi ar trebui sa fie executate de catre alt thread, urmind ca aplicatia sa poata sa mai afiseze ceva utilizatorulu in tot acest timp ( fie si un buton pe care scrie apasa ca sa intrerupi operatia asta lunga ...). De pilda, in aplicatia noastra, daca avem mai mult de 100 de Publisher-i si vrem sa ii vedem pe toti ar trebui incarcati intr-un nou thread.
Ne ocupam mai intii de o aplicatie Windows Forms si pe urma de ASP.NET Un thread nu e greu de pornit. Hai sa vedem un exemplu:
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(StartAction)); t.Start("obiect transmis");
public void StartAction(object o) { string s = o.ToString(); System.Threading.Thread.Sleep(5000); //executa actiunea //trimite text if (this.InvokeRequired) { this.Invoke((MethodInvoker)delegate() { this.Text = s; }); //sau //this.Invoke(new MethodInvoker(evenimentfaraparametri());
http://www.serviciipeweb.ro/iafblog
Page 85
Ignat Andrei
Totusi, exista o problema dintr-un thread nu se pot accesa DIRECT controale din alt thread si de aceea avem instructiunea this. Invoke .Diferenta intre this.Invoke si este this.BeginInvoke aceea ca prima instructiune asteapta rezultatul actiunii, pe cind a doua doar executa si se intoarce imediat sa execute codul ramas.
De aceea exista controlul numit BackgroundWorker care asigura ca , din evenimentul propriu generat, sa accesezi orice obiect de pe forma. O sa facem acest lucru pentru salvarea in XML a colectiei de Publisher-i in format XML. .NET are o forma usoara de a salva o colectie/clasa in format XML , salvindu-i proprietatile. Vom utiliza modalitatea cea mai usoara de a face acest lucru Marcam clasa Publisher si clasa colectie ColPublisher cu atributul de
[Serializable] :
http://www.serviciipeweb.ro/iafblog
Page 86
Ignat Andrei
return m_Serializer; } }
/// <summary> /// salveaza obiectul ca XML /// </summary> [XmlIgnore] public string XML { get { StringBuilder sb = new StringBuilder(); EncodingStringWriter sw = new EncodingStringWriter(sb, Encoding.Default); XmlTextWriter xtw = new XmlTextWriter(sw);
http://www.serviciipeweb.ro/iafblog
Page 87
Ignat Andrei
} } /// <summary> /// recreeeaza un Publisher dintr-un string XML /// </summary> /// <param name="XML">string care contine tot </param> /// <returns></returns> public static Publisher FromXML(string XML) { StringReader sr = new StringReader(XML); return Serializer.Deserialize(sr) as Publisher; } #endregion
Citeva comentarii despre cod: De ce am pus [XmlIgnore] peste public string XML ? Pentru a nu serializa si aceasta proprietate, dind astfel nastere la o nedorita recursivitate Ce e cu clasa EncodingStringWriter ? Este facuta pentru a putea schimba Encoding=ul- daca aveti de exemplu caractere speciale(diacritice) romanesti/franceze/etc. De ce metoda FromXML este statica- iar XML este pe instanta? Asa mi se pare normal transformarea dintr-un obiect in XML sa apartina obiectului, iar din XML in obiect nu poate sa apartina http://www.serviciipeweb.ro/iafblog Page 88
Ignat Andrei
unui obiect( ah, daca as fi putut scrie this = Serializer.Deserialize(sr) as Publisher !) - ci doar clasei. Nu se poate face codul mai generic? Ba da- una din deosebiri ar fi ca FromXML ar trebui sa fie pe instanta...
Haideti acum in proiectul Windows sa serializam o colectie de Publisher-i.Pe forma frmPublisherList adaugam un buton btnSave, cu textul Save, dublu click si scriem urmatorul cod:
private void btnSave_Click(object sender, EventArgs e) { BookObjects.ColPublisher col = colPublisherBindingSource.DataSource as BookObjects.ColPublisher; string strSave = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationD ata); strSave = Path.Combine(strSave, "pub.xml"); File.WriteAllText(strSave, col.XML); System.Diagnostics.Process.Start(strSave); }
Rulati proiectul, adaugati 2 publisher-i si apasati pe save. Este clar ca, daca sunt multi publisher-i, procesul poate deveni prea lung si blocheaza interfata.
Haideti sa folosim background worker. Il adaugam din toolbox , il redenumim bgSave, dublu click. Luam codul din btnSave_Click, il adaugam la si pe urma scriem doar bgSave.RunWorkerAsync();
http://www.serviciipeweb.ro/iafblog
Page 89
Ignat Andrei
private void bgSave_DoWork(object sender, DoWorkEventArgs e) { BookObjects.ColPublisher col = colPublisherBindingSource.DataSource as BookObjects.ColPublisher; string strSave = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationD ata); strSave = Path.Combine(strSave, "pub.xml"); File.WriteAllText(strSave, col.XML); System.Diagnostics.Process.Start(strSave);
http://www.serviciipeweb.ro/iafblog
Page 90
Ignat Andrei
Pentru 1.,o solutie recomandata este sa puneti Async=true in codul de pagina si sa executati codul cu RegisterTaskAsync . Asta este interesant, pina cind ne dam seama ca modul de afisare al paginii este acelasi adica este intirziata pina cind se termina toata de executat.
Totusi, as recomanda o alta abordare pentru ca user-ul sa vada desfasurarea detaliata a actiunilor efectuate, as recomanda scrierea cu Response.Write intr-un div si ascunderea apoi a div-ului . Ceva de genul acesta:
http://www.serviciipeweb.ro/iafblog
Page 91
Ignat Andrei
Acest model se poate combina cu evenimente generate in cadrul task-ruilor astfel incit, daca task-urile dureaza prea mult, user-ul sa aiba totusi un feedback despre ceea ce se intimpla.
Sa discutam acum despre 2, executarea de operatii rapide pe server. Sa dam un exemplu simplu, si anume cautarea de publisher dupa nume. Ar fi superb daca aplicatia noastra, la apasarea primei litere a publisher-ului, ar putea sa sugereze publisher-ii care incep cu litera respectiva. Pentru aceasta vom folosi Ajax, si vom folosi implementarea de AutoComplete de la Ajax Control Toolkit Mai intii ,trebuie sa downloadam Ajax1.0 de aici.
Apoi va trebui sa modificam Web.Config astfel incit sa suporte Ajax. Asta inseamna ca o sa luam o mare parte din Web.Config-ul unui site Ajax si o sa il mutam la noi in site. Sa incepem : De la o configuration o sa luam
<configSections> <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection,
http://www.serviciipeweb.ro/iafblog
Page 92
Ignat Andrei
De la system.web o sa luam
<pages> <controls> <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </controls> </pages>
Si http://www.serviciipeweb.ro/iafblog Page 93
Ignat Andrei
<add assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <add assembly="System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/> <add assembly="System.Web.Extensions.Design, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/></assemblies> </compilation>
http://www.serviciipeweb.ro/iafblog
Page 94
Ignat Andrei
<!-- Uncomment this line to customize maxJsonLength and add a custom converter --> <!-<jsonSerialization maxJsonLength="500"> <converters> <add name="ConvertMe" type="Acme.SubAcme.ConvertMeTypeConverter"/> </converters> </jsonSerialization> --> <!-- Uncomment this line to enable the authentication service. Include requireSSL="true" if appropriate. --> <!-<authenticationService enabled="true" requireSSL = "true|false"/> --> <!-- Uncomment these lines to enable the profile service. To allow profile properties to be retrieved and modified in ASP.NET AJAX applications, you need to add each property name to the readAccessProperties and writeAccessProperties attributes. --> <!-<profileService enabled="true" readAccessProperties="propertyname1,propertyname2" writeAccessProperties="propertyname1,propertyname2" /> --> </webServices> <!-<scriptResourceHandler enableCompression="true" enableCaching="true" /> --> </scripting> </system.web.extensions>
http://www.serviciipeweb.ro/iafblog
Page 95
Ignat Andrei
<add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </modules> <handlers> <remove name="WebServiceHandlerFactory-Integrated"/> <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </handlers> </system.webServer>
Acum downloadam Ajax Control Toolkit si vom referentia controalele existente, aflate in AjaxControlToolkit-NoSource\SampleWebSite\Bin . Vom adauga un nou tab in ToolBox, ii vom zice AjaxControls si vom adauga itemii apasind pe Choose Items:
http://www.serviciipeweb.ro/iafblog
Page 96
Ignat Andrei
Si apoi indicind prin browse calea la AjaxControlToolkit.dll pe care l-am downloadat. Apasati pe urma OK si vom avea controalele Ajax. Trageti un AutoCompleteExtender si un textbox in frmPublisherList.aspx .
Vom completa
public class wsPublisher : System.Web.Services.WebService {
cu atributul
[System.Web.Script.Services.ScriptService]
si vom adauga o metoda pentru regasirea publisher-ilor care incep cu o litera data:
http://www.serviciipeweb.ro/iafblog
Page 97
Ignat Andrei
List<string> items = new List<string>(count); BookObjects.ColPublisher publishers = new BookObjects.ColPublisher(); publishers.Load(); foreach (BookObjects.Publisher pub in publishers) { if (pub.Name.IndexOf(prefixText, StringComparison.CurrentCultureIgnoreCase) == 0) items.Add(pub.Name);
TargetControlID="txtPub"
http://www.serviciipeweb.ro/iafblog
Page 98
Ignat Andrei
Lucruri de facut: Creat o metoda prin care sa se poata incarca doar cei care au prefix, nu toti publisher-ii cum am facut in public string[] GetCompletionPublishers(string prefixText, int count) De pus scriptManager-ul in Master- ca sa nu fim nevoiti sa il punem in fiecare pagina.
De vazut celelalte controale de la Ajax Control Toolkit (live demo la adresa http://ajax.asp.net/ajaxtoolkit/Default.aspx )
http://www.serviciipeweb.ro/iafblog
Page 99
Ignat Andrei
Acum adaugam un raport care sa fie afisat de catre aplicatie deschidem aplicatia Web si adaugam un nou item de tipul Report si il numim rptPublisher.rdlc :
http://www.serviciipeweb.ro/iafblog
Page 100
Ignat Andrei
http://www.serviciipeweb.ro/iafblog
Page 101
Ignat Andrei
http://www.serviciipeweb.ro/iafblog
Page 102
Ignat Andrei
Putem salva conexiunea in Web.Config(desi o mai avem) si apasam Next. Pe urmatorul ecran lasam selectat Use SQL Statements si iarasi Next. Acum scriem codul pentru SQL:
SELECT FROM
http://www.serviciipeweb.ro/iafblog
Page 103
Tutorial programare in .NET si iarasi Next pina se termina ( sau direct Finish).
Ignat Andrei
http://www.serviciipeweb.ro/iafblog
Page 104
Ignat Andrei
Ne ducem pe Toolbox si tragem pe rptPublisher.rdlc un Table Ne intoarcem pe WebSite DataSources si tragem Name Publisher pe detaliu:
Acum sa verificam Cream o noua pagina aspx, frmPublisherReport.aspx si scriem urmatorul cod(sau tragem controlul de ReportViewer si ii spunem care e raportul)
<%@ Page Language="C#" MasterPageFile="~/Book.master" AutoEventWireup="true" CodeFile="frmPublisherReport.aspx.cs" Inherits="frmPublisherReport" Title="Report Publisher" %>
http://www.serviciipeweb.ro/iafblog
Page 105
Ignat Andrei
public partial class frmPublisherReport : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { BookObjects.ColPublisher publishers = new BookObjects.ColPublisher();
http://www.serviciipeweb.ro/iafblog
Page 106
Ignat Andrei
Si modificam fisierul rdlc deschizindu-l cu notepad-ul si scriind urmatoarele: <?xml version="1.0" encoding="utf-8"?> <Report xmlns="http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition" xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner"> <DataSources> <DataSource Name="BookConnectionString"> <ConnectionProperties> <ConnectString /> <DataProvider>SQL</DataProvider> </ConnectionProperties> <rd:DataSourceID>c649d533-64c3-42b6-9805-19adbfccd468</rd:DataSourceID> </DataSource> </DataSources> <BottomMargin>1in</BottomMargin>
http://www.serviciipeweb.ro/iafblog
Page 107
Tutorial programare in .NET <RightMargin>1in</RightMargin> <rd:DrawGrid>true</rd:DrawGrid> <InteractiveWidth>8.5in</InteractiveWidth> <rd:SnapToGrid>true</rd:SnapToGrid> <Body> <ReportItems> <Table Name="table1"> <Footer> <TableRows> <TableRow> <TableCells> <TableCell> <ReportItems> <Textbox Name="textbox7"> <rd:DefaultName>textbox7</rd:DefaultName> <ZIndex>1</ZIndex> <Style> <PaddingLeft>2pt</PaddingLeft> <PaddingBottom>2pt</PaddingBottom> <PaddingRight>2pt</PaddingRight> <PaddingTop>2pt</PaddingTop> </Style> <CanGrow>true</CanGrow> <Value /> </Textbox> </ReportItems> http://www.serviciipeweb.ro/iafblog
Ignat Andrei
Page 108
Tutorial programare in .NET </TableCell> </TableCells> <Height>0.45833in</Height> </TableRow> </TableRows> </Footer> <Left>0.5in</Left> <DataSetName>DataSet1_Publisher</DataSetName> <Top>0.25in</Top> <Width>6.5in</Width> <Details> <TableRows> <TableRow> <TableCells> <TableCell> <ReportItems> <Textbox Name="txtName"> <rd:DefaultName>Name</rd:DefaultName> <Style> <PaddingLeft>2pt</PaddingLeft> <PaddingBottom>2pt</PaddingBottom> <PaddingRight>2pt</PaddingRight> <PaddingTop>2pt</PaddingTop> </Style> <CanGrow>true</CanGrow> <Value>=Fields!Name.Value</Value> http://www.serviciipeweb.ro/iafblog
Ignat Andrei
Page 109
Tutorial programare in .NET </Textbox> </ReportItems> </TableCell> </TableCells> <Height>0.45833in</Height> </TableRow> </TableRows> </Details> <Header> <TableRows> <TableRow> <TableCells> <TableCell> <ReportItems> <Textbox Name="textbox1"> <rd:DefaultName>textbox1</rd:DefaultName> <ZIndex>2</ZIndex> <Style> <PaddingLeft>2pt</PaddingLeft> <PaddingBottom>2pt</PaddingBottom> <PaddingRight>2pt</PaddingRight> <PaddingTop>2pt</PaddingTop> </Style> <CanGrow>true</CanGrow> <Value>Name</Value> </Textbox> http://www.serviciipeweb.ro/iafblog
Ignat Andrei
Page 110
Tutorial programare in .NET </ReportItems> </TableCell> </TableCells> <Height>0.45833in</Height> </TableRow> </TableRows> </Header> <TableColumns> <TableColumn> <Width>6.5in</Width> </TableColumn> </TableColumns> <Height>1.375in</Height> </Table> </ReportItems> <Height>2in</Height> </Body> <rd:ReportID>9f0247a8-15fe-4ef9-962e-c4c670524163</rd:ReportID> <LeftMargin>1in</LeftMargin> <DataSets> <DataSet Name="DataSet1_Publisher"> <rd:DataSetInfo> <rd:ObjectDataSourceType>Publisher</rd:ObjectDataSourceType> <rd:TableName>Publisher</rd:TableName> </rd:DataSetInfo> <Query> http://www.serviciipeweb.ro/iafblog
Ignat Andrei
Page 111
Tutorial programare in .NET <rd:UseGenericDesigner>true</rd:UseGenericDesigner> <CommandText /> <DataSourceName>BookConnectionString</DataSourceName> </Query> <Fields> <Field Name="IDPublisher"> <rd:TypeName>System.Int32</rd:TypeName> <DataField>IDPublisher</DataField> </Field> <Field Name="Name"> <rd:TypeName>System.String</rd:TypeName> <DataField>Name</DataField> </Field> <Field Name="Site"> <rd:TypeName>System.String</rd:TypeName> <DataField>Site</DataField> </Field> </Fields> </DataSet> </DataSets> <Width>9.75in</Width> <InteractiveHeight>11in</InteractiveHeight> <Language>en-US</Language> <TopMargin>1in</TopMargin> </Report>
Ignat Andrei
http://www.serviciipeweb.ro/iafblog
Page 112
Ignat Andrei
Acum , rulind pagina, observam ca se poate exporta raportul in Excel si PDF mai mult decit sufficient:
Linkuri utile: http://www.gotreportviewer.com/ - in partea dreapta aveti exemple de aplicatii care fac diverse genereaza automat fisierele rdlc, scot automat fisierele Excel si multe altele
SQL Server Reporting Services pentru utilizarea avansata a rapoartelor. http://www.serviciipeweb.ro/iafblog Page 113
Ignat Andrei
http://www.serviciipeweb.ro/iafblog
Page 114
Ignat Andrei
Va duceti in BookWeb, alegeti din casuta Files of type ultima selectie All files si selectati rptPublisher.rdlc. Acum click pe el si in fereastra de proprietati alegeti la Copy to output directory Copy always
http://www.serviciipeweb.ro/iafblog
Page 115
Ignat Andrei
Bun acum au ramas 3 lucruri de facut : vizualizarea formei ca actiune, legarea controlului de raportul existent si codul de incarcare a datelor in raport.
Pentru vizualizarea formei ca actiune adaugati un buton btnPrint in frmPublisherList iar pe eveniment scrieti urmatorul cod:
private void btnPrint_Click(object sender, EventArgs e) { frmPublisherPrint p = new frmPublisherPrint(); p.ShowDialog(this); }
Pentru legarea controlului vom seta la proprietati calea catre raport(presupunem ca se va afla in acelasi folder) si processing mode la local
http://www.serviciipeweb.ro/iafblog
Page 116
Tutorial programare in .NET Ultimul lucru de facut incarcarea colectiei pe evenimentul de load :
rivate void frmPublisherPrint_Load(object sender, EventArgs e) { BookObjects.ColPublisher publishers = new BookObjects.ColPublisher(); publishers.Load(); MessageBox.Show(""+publishers.Count);
Ignat Andrei
ReportDataSource rds = new ReportDataSource("DataSet1_Publisher", publishers); rptPublisher.ProcessingMode = ProcessingMode.Local; rptPublisher.LocalReport.DataSources.Clear(); rptPublisher.LocalReport.DataSources.Add(rds); rptPublisher.LocalReport.Refresh(); rptPublisher.RefreshReport(); }
Ea previne cazul( des intilnit) in care editorul IDE adauga , cu de la sine putere, un ReportDataSource
.
http://www.serviciipeweb.ro/iafblog
Page 117
Ignat Andrei
Ce mai e de facut 1)frmPublisherPrint sa nu mai afiseze ce vrea ea - ci sa primeasca un argument(in constructor, de exemplu) care sa spun ce lista de publisher-i are de afisat 2) Avind in vedere ca rapoartele sunt aceleasi pentru Windows si Web , ar fi interesant de facut un dll care sa intoarca raport ul cerut
http://www.serviciipeweb.ro/iafblog
Page 118