Χρυσό και καλό το καινούριο Visual Studio 2005 αλλά το migration των Web Project είναι το λιγότερο … μανίκι. Την προηγούμενη εβδομάδα δοκίμασα να κάνω migrate ένα αρκετά μεγάλο project από 2003 σε 2005 και συνάντησα αρκετές δυσκολίες. Μόνο και μόνο για να κάνει compile έφυγε όλη η εβδομάδα. Αλλά ακόμα και τώρα, μπορεί να κάνει compile τη μία στιγμή και την επόμενη να πετάξει ένα «circular reference error” χωρίς καμία πληροφορία πού και γιατί συνέβη αυτό.
Τα προβλήματα οφείλονται στο ότι έχει αλλάξει ο τρόπος με τον οποίο γίνονται compile τα web projects. Όλα τα άλλα είδη project, class libraries, windows projects, setup projects μετατρέπονται χωρίς κανένα πρόβλημα (τουλάχιστον, κανένα που να έχω βρει ακόμα). Ευτυχώς για εμάς, η Microsoft θα επαναφέρει σαν επιλογή τον παλιό τρόπο compile. Μέχρι να συμβεί αυτό όμως, θα πρέπει να αντιμετωπίσουμε τις δυσκολίες του migration.
Α, ναι! Και δεν υπάρχει πλέον αρχείο web project! Ό,τι αποθηκευόταν σε αυτό έχει μεταφερθεί στο web.config και τις σελίδες.
Πρόβλημα 1ο. Η κάθε σελίδα μπαίνει στο δικό της assembly.
Το καλό με αυτή τη λύση είναι ότι έτσι μπορεί να κάνει κανείς compile μια σελίδα κάθε φορά. Ακόμα καλύτερα, μπορεί η κάθε σελίδα να είναι γραμμένη στη δική της γλώσσα!
Το κακό είναι ότι δεν είναι πλέον δυνατό να χρησιμοποιήσει μια σελίδα τα public ή internal πεδία μιας άλλης σελίδας, γιατί αυτά βρίσκονται σε άλλο assembly! Για να χρησιμοποιήσει μία σελίδα τα πεδία μιας άλλης, θα πρέπει να έχει reference στο assembly της άλλης σελίδας. Απλό?
Αμ δε! Οι σελίδες δεν γίνονται compile μαζί με το υπόλοιπο project, αλλά όταν ζητηθούν πρώτη φορά από κάποιο browser! Τα ονόματά τους μάλιστα δημιουργούνται δυναμικά από το όνομα της αρχικής σελίδας και άλλα στοιχεία! Έτσι ούτε references μπορείς να προσθέσεις, αλλά ούτε και να δουλέψεις με reflection!
Και τώρα?
Τα καλά νέα
Τα καλά νέα είναι ότι το Visual Studio περιέχει ένα migration Wizard του Visual Studio. Κάθε site που χρησιμοποιεί ASP.NET 2.0 έχει ένα ειδικό folder, το App_Code folder. Τα περιεχόμενα του App_Code γίνονται πάντα compile σε ένα καλά ορισμένο assembly. Μία λύση λοιπόν θα ήταν να βγει ο public κώδικας της κάθε σελίδας και να μπει σε μια parent κλάση σε αυτό το folder.
Ο migration wizard δημιουργεί δύο δομές folder μέσα στο App_Code:
· Η μία είναι αντίγραφο της δομής του αρχικού site και περιέχει τα αρχεία κώδικα πέρα από τις σελίδες και τα user controls.
· Η δεύτερη βρίσκεται κάτω από το folder Migrated μέσα στο App_Code και έχει επίσης την ίδια δομή. Εκεί θα βάλει ο migration wizard τις parent κλάσεις με τον public κώδικα κάθε σελίδας. Το κάθε αρχείο βρίσκεται σε ένα folder αντίστοιχο με αυτό της αρχικής σελίδας και όνομα της μορφή “stub_MyPageName_aspx_vb.vb”. Το αρχείο αυτό θα περιέχει την κλάση MyPageName ενώ η κλάση της αρχικής σελίδας μετονομάζεται σε Migrated_MyPageName και να κάνει inherit από τη MyPageName.
Μετά από αυτές τις μετατροπές, ο wizard προσθέτει reference tags σε κάθε σελίδα που χρησιμοποιεί τα τροποποιημένα controls ή σελίδες.
Τα κακά νέα
Δυστυχώς, ο migration wizard δεν τα καταφέρνει πάντα να μαντέψει ποιος κώδικας πρέπει να μεταφερθεί στις parent κλάσεις.
Το μεγαλύτερο πρόβλημα υπάρχει με τα user controls. Υπάρχουν περιπτώσεις που ο wizard δεν καταφέρνει να εντοπίσει όλο τον κώδικα που πρέπει να γίνει migrate. Τέτοιες περιπτώσεις είναι αν πχ. ένα user control κάνει inherit κάποιο άλλο. Άλλη περίπτωση είναι ο κώδικας μιας σελίδας να αναφέρεται στο base class ενός control. Άλλο πρόβλημα είναι να περιέχει ένα base user control κάποιες protected μεθόδους ή μεταβλητές. Ή μπορεί η base σελίδα να μην έχει codebehind αρχείο για να μεταφερθεί στο App_Code.
Σε κάθε περίπτωση, ο νέος κώδικας θα αναφέρεται σε μια κλάση που δεν έχει όλες τις αναμενόμενες μεθόδους ή σε μια κλάση που δεν βρίσκεται στο App_Code αλλά θα βρίσκεται ακόμα στο αρχικό folder.
Η λύση
Η μόνη λύση είναι να φτιάξουμε με το χέρι τις απαραίτητες stub κλάσεις και να προσθέσουμε τις μεθόδους που λείπουν. Δυστυχώς, σε ένα project με πολλές σελίδες θα αναγκαστούμε να κάνουμε ένα κύκλο compile-fix-compile μέχρι να μας τελειώσουνε τα compile errors.
Πρόβλημα 2ο Οι σελίδες δεν γίνονται compile μαζί με όλο το site!
Το οποίο σημαίνει ότι και να υπάρχουν compile errors δεν θα τα δούμε μέχρι να ανοίξουμε την προβληματική σελίδα! Αυτό θα έπρεπε να αντιμετωπίζεται εύκολα γυρίζοντας σε batch build mode.
Στο web.config πηγαίνουμε στο tag compilation και προσθέτουμε το attribute batch=”true”:
<compilation defaultLanguage="vb" debug="true" batch="false">
Με αυτό τον τρόπο όλες οι σελίδες θα γίνονται build όταν κάνουμε build και το υπόλοιπο site.
Αλλά
Για κάποιο μυστήριο λόγο κάποια compile errors δεν εμφανίζονται σε κάθε build! Το πιο εκνευριστικό από αυτά είναι το επόμενο
Πρόβλημα 3ο. Έλεος! Όχι άλλα circular references!
Από τη στιγμή που οι σελίδες και τα user controls δεν βρίσκονται σε κοινό assembly, θα πρέπει να μπούνε references σε κάθε σελίδα που τα χρησιμοποιεί. Το πρόβλημα δημιουργείται όταν χρησιμοποιούμε σύνθετα user controls και inheritance. Στην περίπτωση αυτή, κάπου, κάπως καταλήγει ένα control να κάνει reference ένα που κάνει reference το πρώτο. Κάτι τέτοιο δεν υποστηρίζεται οπότε εμφανίζεται compile error. Μόνο που ...
ΔΕΝ αναφέρεται ποιος κάνει circular reference σε ποιόν!
Εδώ σηκώνω τα χέρια ψηλά. Ακόμα δεν έχω βγάλει άκρη. Άσε που λόγο του Προβλήματος #2 άλλες φορές εμφανίζονται τα λάθη και άλλες όχι!
Μετά από τα παραπάνω, ότι ακολουθεί είναι μικρό προβληματάκι!
Προβληματάκι 4ο Δεν δουλεύει το Handles για τα Events των control της φόρμας
Μικρό το κακό εδώ. Μπορούμε πλέον να ορίσουμε τον event handler στο tag του κάθε control. Πάμε λοιπόν και βάζουμε στο button πχ. <asp:button ….. OnButtonClick=”MyEventHandler_Name”>
Α, ναι και σβήνουμε και το Handles MyButton.ButtonClik!
Επίσης πρέπει ο event handler να είναι τουλάχιστον protected αντί για private
Προβληματάκι 5ο Τα excluded files δεν είναι πλέον excluded μετά το conversion!
Ο λόγος για αυτό είναι ότι πλέον δεν υπάρχει web project file! Έτσι ό,τι αρχείο υπάρχει μέσα στο folder του web site θεωρείται ότι ανήκει στο project. Ευτυχώς, ο migration wizard αναφέρει ποια αρχεία είναι αυτά, αλλά θα πρέπει να πάμε μετά με το χέρι και να τα σβήσουμε ή να τα κάνουμε exclude. Στην περίπτωση αυτή το αρχείο μαρκάρεται με την κατάληξη .excluded.
Προβληματάκι 6ο Οι μεταβλητές των user control είναι πλέον περιττές αλλά δεν αφαιρούνται!
Ως τώρα, όταν προσθέταμε ένα user control σε μια φόρμα έπρεπε να δηλώσουμε και μια μεταβλητή με το ίδιο όνομα για να έχουμε πρόσβαση στις μεθόδους και τα events του. Αυτό πλέον είναι περιττό, καθώς δημιουργούνται οι μεταβλητές αυτές αυτόματα αλλά … οι μεταβλητές που είχαμε ήδη φτιάξει δεν αφαιρούνται! Αυτό θα δημιουργήσει compile error για duplicate declaration οπότε πάμε απλά και το διορθώνουμε.
Προβληματάκι 7ο Τι έπαθε το cookieless session management?
Από σελίδα σε σελίδα χάνεται το SessionID! Εδώ δεν έβγαλα άκρη. Απλά ενεργοποίησα τα cookies για να μπορέσω επιτέλους να κάνω compile
Κατάληξη και Συμβουλές
Τι μπελάς κι αυτός! Μέχρι να βγει το πακέτο με το παλιό μοντέλο compile, το migration ενός web project προβλέπεται μεγάλο μανίκι. Για την ώρα τουλάχιστον δεν φαίνεται άλλη λύση από το compile-fix-test.
Θα σας βοηθήσουν και τα παρακάτω άρθρα: Common Web Project Conversion Issues and Solutions και το "First Preview Download of VS 2005 Web Application Project Model Now Available" από το blog του Scott Guthrie.
Υπάρχουν πάντως μερικά πράγματα που μπορεί να κάνει κανείς για να αποφύγει μερικές από τις δυσκολίες:
· Βεβαιωθείτε ότι το site παίζει ήδη! Σε μεγάλες ομάδες, ή εκεί που το version control δεν χρησιμοποιείται σωστά, είναι πολύ εύκολο να κάνει κάποιος checkin κώδικα που δεν κάνει compile. Τουλάχιστον να διορθώνουμε τα bug του migration, όχι να παλεύουμε ταυτόχρονα και με τα bugs του προγράμματος!
· Κάντε ένα γερό refactoring! Όσο πιο μπερδεμένη είναι η αρχιτεκτονική του site, τόσο δυσκολότερο θα είναι το migration. Είναι που είναι μανίκι όταν χρειάζεται να ψάξει κανείς τώρα σε 3-4 κλάσεις για να δει τι γίνεται, αν ο κώδικας έχει γίνει copy-paste σε 10 σελίδες ή αν μια σελίδα έχει από πίσω της 10 κιλά κώδικα με όλο το business logic. Φανταστείτε τώρα αυτό να σπάσει σε τρεις διαφορετικές δομές folder, και να μπουν τα προβλήματα των circular references και των migrated classes!
Όσοι βέβαια έχουν ήδη κάνει μια σωστή σχεδίαση, όπου οι web σελίδες περιέχουν μόνο τον κώδικα για το UI και τίποτε άλλο, θα έχουν ένα πολύ εύκολο migration. Όσοι αναγκάστηκαν να δουλέψουν με μια άναρχη σχεδίαση … τι να πω …
Συμπάσχω!
Παναγιώτης Καναβός, Freelancer
Twitter: http://www.twitter.com/pkanavos