asp aug2008

49
www.aspnetPRO.com Solutions for Building Enterprise Web Applications August 2008 Volume 7 Number 8 From the Source: More on Dynamic Data

Upload: faseehaarar

Post on 13-Apr-2017

132 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Asp Aug2008

www.aspnetPRO.com

Solutions for Building Enterprise Web ApplicationsAugust 2008 Volume 7 Number 8

From the Source: More on Dynamic Data

Page 2: Asp Aug2008

���������������������������������������������������������������������������������������������������������������������������������������������������������������

���������������������������������������������������������������������������������������������������������������������������������������������� �������������������������������������������������������������� ���������

�������������� ������������������������������������������������������������������������������������������������������������������������������

��������������������������������������������������������������������������������������������������������������������������������������������������������

��������������������������������������������������������������������������������������������������������������������������� ���������������� ���������������������������������������������������������������������������������

������������������ ������������������������������������� ��������������������

������������������������������������������������������������

����� �����������������������������

��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

����� �����������������������������

������������������������������������������������������������

���������������������������������������������������������������������

����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ����

������������������������

���������������������������� � �������� ���� �� ���� �

Page 3: Asp Aug2008

2 August 2008 | www.aspnetPRO.com

I n T h i s I s s u e A u g u s t 2 0 0 8 | V o l u m e 7 N u m b e r 8

Columns

18 ControlFreak: FTP TransfersExperienced Web developers are familiar with HyperText Transfer Protocol. However, many know relatively little about File Transfer Protocol. Steve C. Orris about to change that, as he demonstrates how it can be a valuable addition to your programming toolkit.

22 CoreCoder: On-demand XAML: ReloadedSilverlight lets you host rich content in a Web page that is downloaded from the server. The content is expressed using XAML. The richer you make the experience for your Web users, the more XAML code you need to download on the client. Dino Esposito revisits the issues, but specifi cally targets using managed code and Silverlight 2.0.

28 CodeTalk: Build a Message Box the AJAX Way: Part IPrompting users with a message box is common in Windows applications. Web applications, however, are restricted with JavaScript alert or confi rm functions. Bipin Joshi kicks off a two-part series that shows how to develop an AJAX client control that provides a rich and quick way to display message boxes in your AJAX-enabled Web sites.

40 Consultant’s Corner: Starting Your BusinessThis column is designed to help software developers make better business decisions. For instance, if you’re not incorporated, you should be. There are many legal, fi nancial, and marketing benefi ts to incorporating your business, as Auri Rahimzadeh explains.

43 From the Source: More on Dynamic DataOne of the new features of the .NET 3.5 SP1 release is a framework called Dynamic Data, which allows you to rapidly build a data-driven Web site with full support for CRUD operations. The ASP.NET team’s own Marcin Dobosz and Scott Hunter delve further into Dynamic Data by demonstrating how to build fi eld templates to customize the UI for displaying and editing data for specifi c data types.

48 BackDraft: Fixing Tech•EdJonathan Goodyear critiques Microsoft’s annual marquee event. Find out what he liked — and what he thinks Microsoft can improve.

Departments6 Crossword Puzzle by Ravi Nangunoori47 Advertising Index

asp.netPRO OnlineHere’s just some of the content that’s available only online at www.aspnetpro.com.• “ASP.NET Impersonation.” Will the real ASP.NET please stand up. Don Kiely tells

us about the benefi ts of impersonation in ASP.NET. • “Take the Express.” Deepak Vohra shows us how to create an ASP.NET Web

service in Visual Developer 2005 Express.• “An Introduction to the F# Programming Language.” Joydip Kanjilal provides a

brief look at using the F# programming language in ASP.NET development. • “The Bottom Line.” Viktor Mushkatin offers eight points to consider for managing

.NET applications to reduce TCO.• You’ll also fi nd additional book and product reviews, product announcements,

and more — and only available at www.aspnetpro.com.

Cover image provided by EyeWire, Inc. — www.eyewire.com

�����������������

���������������������������������������������������������������������������������

�������������������������������������

Cover Story

8 Confl ict ResolutionZeeshan Hirani discusses how concurrency problems can lead to confl ict exceptions when trying to persist objects in the database. Then he shows how LINQ to SQL uses the UpdateCheck attribute to ensure optimistic concurrency in update statements, and how LINQ to SQL provides different methods to resolve confl icts, from the entire batch to a single object to resolving confl icts at the member level.

Page 4: Asp Aug2008

2 August 2008 | www.aspnetPRO.com

Page 6: Asp Aug2008

6 August 2008 | www.aspnetPRO.com

1

2 3

9

4

5

6 7

10

8

11

14

18

20

15

16

12 13

17

19 21

22

23

24

EDITOR-IN-CHIEFDavid Riggs .................................................driggs@informant.comCONTRIBUTING EDITORSJonathan Goodyear and Mike RileyTECHNICAL EDITORSKen McNamee and Anand NarayanaswamyCONTRIBUTING WRITERSMarcin Dobosz, Dino Esposito, Zeeshan Hirani, Scott Hunter, Bipin Joshi, Ravi Nangunoori, Steve C. Orr, and Auri Rahimzadeh ART DIRECTORDiana Nishimura .................................. [email protected] SALES MANAGERCathy Sanassarian ...................................... [email protected]

SYSTEMS ADMINISTRATORBob SilvaINFORMANT COMMUNICATIONS GROUP MANAGEMENTPUBLISHERMitchell Koulouris ................................ [email protected] FINANCIAL OFFICER Nancy NomelliniADMINISTRATIVE ASSISTANTRachel MorganCustomer Support ....................... [email protected]

Phone .....................................................................916.379.0609Fax .........................................................................916.379.0610

5105 Florin-Perkins Road Sacramento, CA 95826-4817 Phone: 916.379.0609 Fax: 916.379.0610 www.informant.com

PRINTED BY SCHUMANN PRINTERS, INC.701 South Main StreetFall River, WI 53932 Phone: 920.484.3348

DISTRIBUTION BY CURTIS CIRCULATION COMPANY 730 River RoadNew Milford, NJ 07646 Phone: 201.634.7400Fax: 201.634.7497

ACROSS2. To add User Interface during a Web set up

project, for a user to enter, for example, connection string information, you must right-click on the Web set up project in VS 2005 and choose this option from the View menu.

4. This template is of primary importance to create LINQ to SQL classes using the designer in VS 2005.

5. The System._____________ namespace incorporates all the WCF functionality.

8. DropDownList, ListBox, CheckBoxList, and RadioButtonList use this property to specify whether the list of controls will be rendered horizontally or vertically.

12. This command-line tool creates entity classes that are necessary to use LINQ to SQL with a database.

15. (=>) This operator is normally used in these types of expressions.

17. This indicates the ability to transform the data that is being queried into results with a differ-ent structure.

18. This clause in a LINQ expression is a must to retrieve data from the datasource.

19. If a constructor is not provided in a class decla-ration in C#, the CLR will automatically provide an implicit constructor of this type.

21. This array is called an “array-of-arrays”.

22. The LINQ to Dataset operator that removes duplicate rows from a sequence of objects.

24. These properties in C# instruct the compiler to automate the process of creating the private fields and the default operations associated with get/set operations.

DOWN1. All LINQ expressions must have this clause,

which indicates a datasource.

3. This operator is used to compare two sequences of DataRow objects in LINQ to Dataset.

6. Health monitoring of an ASP.NET 3.5 application is achieved using these events and their cor-responding base classes.

7. All the API required to implement a workflow in .NET 3.0 reside in the System.__________ namespace.

9. This object is at the heart of AJAX-based applications.

10. An instance of this class must be created to implement LINQ to SQL queries to establish a connection to a database.

11. These methods can be defined in one class, but can be called as if they were defined in a different class.

13. The static methods of the System.Linq._______ class are used to create LINQ to Objects queries.

14. The protocol used to implement secure browser communication between client and server on port 443.

16. This keyword in C# indicates the class is not inheritable.

20. The CLR provides these services for interoperat-ing with unmanaged code.

23. This keyword declares a function or a method with no return value in VB.NET.

Ravi Nangunoori is a Principal at www.visualsoftinc.com and specializes in developing Web applications using .NET technologies. He also runs a multimedia content site (www.dotnetvideos.net) serving the Microsoft developer community around the world. He can be reached at [email protected].

Please see page 47 for answers to this puzzle.

LINQ, ASP.NET 3.5, and C# Crossword Puzzle

§ By Ravi Nangunoori

Copyright © www.dotnetvideos.net, www.visualsoftinc.com

Page 7: Asp Aug2008

6 August 2008 | www.aspnetPRO.com

Page 8: Asp Aug2008

8 August 2008 | www.aspnetPRO.com

The fi rst time you make a request for an object using LINQ to SQL, it logs the object in an identity management service based on its primary key, so the next time you request the object, LINQ to SQL checks its internal cache to see if the object has been retrieved; if the object exists in its cache, it will return the same object instance to the client. This means that if the data has changed in the database since your last retrieval, you won’t receive updated data, which leads to data mismatch between the version that is returned to the client and the version that is stored in the database.

An important point to consider is, depending on how you set up your query, LINQ to SQL may actually go to the database and run the query but give you the same instance of the object you originally had. If your query uses a single operator and searches based on a primary key, LINQ to SQL won’t even hit the database and will simply return the object from its tracking repository. Because of this specifi c behavior, you essentially get the

same object on which you’ve made changes — as com-pared to getting a fresh copy, which could potentially have new data written by some other user. LINQ to SQL delegates to DataContext the responsibility for managing the identity of the objects retrieved from the database. From the fi rst fetch of the object, DataContext starts tracking the changes you are making to the object to the point you call SubmitChanges, after which it discards all the tracking information about the object from its identity management service. DataContext will throw a change confl ict exception when you call SubmitChanges if the original values it has in its identity management service does not match the current value in the database. Let’s take a look at an example of object tracking (see Figures 1 and 2).

In this example we fi rst retrieve the customer using the contact name. At this point, LINQ has started tracking the object using its primary key. The second time around, when we query for the same customer using its primary key, DataContext goes to the database, returns the record, then checks its identity management to fi nd out if it has been tracking this new object based on its primary key. If it fi nds

Concurrency confl icts occur when a user attempts

to update data that has been changed by another

user since the last time a record was read. The

problem is a result of working in a disconnected scenario.

There are no locks placed on data during the read opera-

tion. Once you’ve closed your connection and start to

modify your object, there is no guarantee that the data

will be the same in the database and that some other

user has not modifi ed that record. This leads to optimistic

concurrency. Traditionally it has been left to the applica-

tion developer to detect and resolve confl icts in the most

appropriate manner. With LINQ to SQL, Microsoft provides

numerous ways to notify the application about optimis-

tic concurrency, and provides fairly non-trivial ways to

resolve those confl icts, as well.

Confl ict Resolution Resolving Confl icts Using LINQ to SQL

LANGUAGES: C# § ASP.NET VERSIONS: 3.5

C o v e r S t o r y

§ By Zeeshan Hirani

/// <summary> /// shows how linq to sql returns the same object /// regardless of different where clause. /// </summary> public static void ObjectTrackingInLinqToSql() { NorthWindDataContext db = new NorthWindDataContext(); db.Log = Console.Out; Customer c1 = db.Customers.Where(c => c.ContactName == "Maria Anders").First(); Customer c2 = db.Customers.Where(c => c.CustomerID == "ALFKI").First(); if (c1 == c2) { Console.WriteLine("c1 customer is same as c2 customer"); } }

Figure 1: Object tracking in LINQ to SQL.

Page 9: Asp Aug2008

8 August 2008 | www.aspnetPRO.com

centralizeyour word processing

���������� ��� ����������������

�������� ���������������������

��������������� ��������������������������������

������� ��� ��������������

�����������������������������

TX Text Control .NET Server 14.0SERVER-SIDE

Create, modify and convert • DOCX, DOC, RTF and HTML documents on a central server

Load and save MS Word documents including all merge fields•

Merge templates and create print-ready, password encrypted PDF documents•

CLIENT-SIDE

Edit documents directly in Microsoft Internet Explorer• ®

Integrate a fully featured word processing interface, including headers and • footers, text frames, images, decimal tabs, section breaks and many more

www.textcontrol.comDownload a fully functional trial version at

ASP.NET ASP WINDOWS® FORMS ACTIVEX

© 2008 The Imaging Source Europe GmbH. All rights reserved. TX Text Control is a registered trademark of The Imaging Source Europe GmbH in the United States and/or other countries. All other names of actual companies and products mentioned herein may be trademarks of their respective owners. Microsoft, Windows and Internet Explorer are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries.

CREATEprint-readyPDF documents

STORE

���������������������STORE

������������������������������������������documents on a ������������������������������������������server���������������������EDITdocuments in a

��������������������������������browser��������������������������������

��� ���������������������� ������������������� �������������������2

TX Text Control Sales: 877-462-4772 (toll free)TX Text Control Europe Sales: +49 (0) 421 3359 0

centralize.NET ACTIVEXACTIVEX

centralizeNEW

VERSION:

Section breaks

64bit and 32bit versions

Office Open XML support

Complete MS Word field compatibility

������������������������������������

�����������������������

�������

����������

�����������������������

�������

���������������������

��������������������������������

���TX Text Control® .NET Server 14.0

PDF documents

STORE

���������������������STORE

������������������������������������������documents on a ������������������������������������������server���������������������EDITdocuments in a

��������������������������������browser��������������������������������

7777777777777777

������������������������������������������������������������������������������������êêêêêêê

���������������������

��������������������������������

TX Text Control® .NET Server 14.0

777777777777777777

���������������������������������������������������������������êêêêêêêê

���������

�������

���������������������

��������������������������������

���������������������������������������������������������������

�������

���������������������

Page 10: Asp Aug2008

10 August 2008 | www.aspnetPRO.com

the object in its repository, it returns the old object (which the user has modified). This is the reason you get the modified version of the country (instead of Germany, which is what is defined in the database).

Change TrackingTo fully understand how conflicts are resolved and raised in LINQ to SQL, it is essential to understand how DataContext gets notified when you change a particular property of an object. You can implement the INotifyPropertyChanging and INotifyPropertyChanged interfaces on your domain entity and raise Property-Changing and PropertyChanged events in the setter of your property to notify the identity management service that you are changing the property. If you don’t imple-ment this interface, DataContext will manage two cop-ies of the same object, one with the original value and a second with the changed value. Based on the changes notified to the context, LINQ to SQL will generate the appropriate update statement, which would only include columns that have changed. This option may be expen-sive in a situation when you are retrieving lots of objects and DataContext must manage two copies of the same object. In those scenarios it is preferable to implement the INotifyChanging and INotifyChanged interfaces and simply notify the object tracking service that you have changed the property instead of maintaining two copies of the object.

If you are using the LINQ to SQL designer, you don’t have to worry about implementing those interfaces because the Object Relational (O/R) Designer takes care of handing all the plumbing details for you. If all you’re doing is retrieving objects and you don’t intend to send changes back to the database, you have the option to completely disable object tracking by setting the ObjectTrackingEnabled property to false on the DataContext. Let’s look at some generated code from the Category class to see how the O/R Designer takes care of object tracking (see Figure 3). I’ve taken out some additional code so we can concentrate on the tracking feature.

Notice that we are implementing the INotifyProperty-Changing and INotifyPropertyChanged interfaces, which allows us to notify the object tracking service when we change a property. We declare two events: Property-Changing and PropertyChanged. The first time DataContext starts tracking the object it will register with these events. The next time I change the property, I raise the Changing and then a Changed event after the property is changed. In addition, I am passing in the PropertyChanged event the property name that is changed, which tells DataContext which property is being changed.

Raising ConflictsSo far we’ve discussed how DataContext tracks the object; we have not discussed what causes LINQ to SQL to throw a change conflict exception, nor how it knows that the value in the database has changed since the last retrieval. Figures 4 and 5 illustrate this concept with a simple example.

You’ll get an exception when you run the code from Figure 4, because context1 has modified and updated the data in the database and context2’s original values no longer match what’s in the database. You may be wondering how LINQ to SQL was able to figure out that data has changed in the database when

Figure 2: Results from Figure 1 display showing both objects have the same reference.

[Table(Name = "dbo.Categories")] public partial class Category : INotifyPropertyChanging, INotifyPropertyChanged { private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty); public event PropertyChangingEventHandler PropertyChanging; public event PropertyChangedEventHandler PropertyChanged;

private string _CategoryName;

[Column(Storage = "_CategoryName", DbType = "NVarChar(15) NOT NULL", CanBeNull = false)] public string CategoryName { get { return this._CategoryName; } set { if ((this._CategoryName != value)) { PropertyChanging(this, emptyChangingEventArgs); this._CategoryName = value; PropertyChanged(this, new PropertyChangedEventArgs("CategoryName"));

} } } }

Figure 3: Category-generated class implementing the Notify interfaces.

C o v e r S t o r y | Conflict Resolution

Page 11: Asp Aug2008

10 August 2008 | www.aspnetPRO.com

���������������

��������������

��������������������������������������������

�������������������������������������������

�������������������������������

����������������������������������

����������������������������������������������

����������������������������������������

����������������������������������������

���������������������������������������

����������������������������������������

����������������

���������������

����������������������������������

����������������������������������

���������������

��������������

����������������������������������������������������

�������������������������������������������������������

������������������������������������������������������

��������������������������������������������������������

�����������������������������������������������������������

���������������������������������������������������������

���������������������������������������������������������

�����������������������������������������������

������������������������������������������������������

�������������������������������������������������������

�����������������������������������������������������

������������������������������������������������������

�������������������������������������������������������

���������������������������������������������������������

����������������

Page 12: Asp Aug2008

12 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 13

it sent the update. It’s because of the UpdateCheck attribute defined on the Supplier object.

The UpdateCheck attribute determines how DataContext is going to ensure optimistic concurrency. UpdateCheck is an enum that can have three values: Never, Always, and WhenChanged. Basically, all the columns that are marked as “Always” will participate as the Where clause using their original values tracked by the identity management service. Typically, if one of the columns is defined with an attri-bute of IsVersion that is set to true, then DataContext will only use that column to perform optimistic concurrency by appending that column in the Where clause of the update statement. If there is no column in entity that is defined with the IsVersion attribute, then, by default, all columns will participate in optimistic concurrency and they would default to UpdateCheck.Always.

You can turn off conflict detection by setting UpdateCheck to Never on each member, which would force DataContext to put anything but the primary key in the Where clause (which would cause the last record to always win). So, when an update fails to affect any rows, LINQ to SQL throws a change conflict exception. Notice the update SQL statement includes all the columns in the Where clause because, by default, all the columns have their UpdateMode set to Always (as there is no column marked as IsVersion). If we were to add a new column to the suppliers table and set an attribute on the column as IsVersion, LINQ to SQL will only use that column in the Where clause to ensure optimistic concurrency (see Figure 6).

Notice we added a new column named IsVersion and marked it as IsVersion (see Figure 7). The result is the same and we get a change conflict exception — but this time our Where clause includes the IsVersion column only (along with the primary key column that we expect).

Resolving ConflictsSubmitChanges has two overloads you can use to specify how DataContext will react to change conflicts. The first, FailOnFirstConflict, means that as soon as DataContext

[Column(Storage="_IsVersion", AutoSync=AutoSync.Always, DbType="rowversion", IsDbGenerated=true, IsVersion=true, UpdateCheck=UpdateCheck.Never)] public System.Data.Linq.Binary IsVersion { get { return this._IsVersion; } set { if ((this._IsVersion != value)) { this.OnIsVersionChanging(value); this.SendPropertyChanging(); this._IsVersion = value; this.SendPropertyChanged("IsVersion"); this.OnIsVersionChanged(); } } }

Figure 6: Add a new column and set the attribute to IsVersion and LINQ to SQL will only use that column in the Where clause to ensure optimistic concurrency.

Figure 5: Result of code (in Figure 4) showing exception caused by change conflict.

Figure 7: Added IsVersion column for concurrency.

C o v e r S t o r y | Conflict Resolution

/// <summary>/// example illustrates how we can cause change conflicts./// </summary>public static void CausingConflicts(){ NorthWindDataContext context1 = new NorthWindDataContext(); context1.Log = Console.Out; NorthWindDataContext context2 = new NorthWindDataContext(); context2.Log = Console.Out; Supplier supcontext1 = context1.Suppliers.Single(s => s.CompanyName == "Exotic Liquids"); Supplier supcontext2 = context2.Suppliers.Single(s => s.CompanyName == "Exotic Liquids");

//change the contact title to Purchasing Manager 1 supcontext1.ContactTitle += " context1"; context1.SubmitChanges();

supcontext2.ContactTitle = " context2"; // will raise an exception since the original value no // longer matches what's in the database. context2.SubmitChanges();}

Figure 4: Code showing an exception caused by change conflict.

Page 13: Asp Aug2008

12 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 13

encounters a change conflict, it will throw an exception and the entire transaction will be rolled back. The second option, ContinueOnConflict, means DataContext will con-tinue to process all the enti-ties while building a list of conflicted objects. Once it’s done processing, it will throw a change conflict exception and also roll back the entire trans-action. When you call SubmitChanges, DataContext will look for an existing transaction it can join. If there is none, it will create a new transaction and all the changes will be made in that transaction. So, then, it is up to the developer to resolve the conflicts and resubmit the entire batch to the database again. Let’s look at FailOnFirstConflict first to see how we can resolve the conflict.

The result of this simple query is shown in Figure 8:

select supplierid,companyname,Country from suppliers where country = 'France'

Looking at Figure 9, notice we are using two DataContexts. Using the first DataContext we retrieve three suppliers from France, then we print them (as shown in Figure 10). Using the second DataContext we retrieve the last two suppliers from France and modify their country to USA.

The first DataContext is not aware we made changes to the country (to USA) using the second DataContext. Hence, its original value will not match what is now defined in the country column in the database. Therefore, when the first DataContext tries to change the country column to UK, it throws a change conflict exception.

In this case I’m using an overloaded version of Submit-Changes with ConflictMode set to FailOnFirstConflict. Calling SubmitChanges with no parameter is the same as FailOnFirstConflict because that’s what it defaults to. We then use the DataContext’s ChangeConflict property to access all the objects in conflict. Because we are failing the entire batch on the first failure, our ChangeConflict con-tains only the first failure — even though there were two suppliers in conflict.

We are also retrieving three values of the country. As men-tioned earlier, LINQ to SQL uses a tracking service on the objects it retrieves from the database. So the original value is basically the value that the tracking service originally had when it retrieved the object the first time. After we changed the country to USA, that became the current value and the value in the database is what is defined in the database at the time SubmitChanges gets called. It’s important to under-stand that a single conflict could be caused by more than one member of an entity conflicting with columns in the

database. However, it is still considered one conflict. Let’s run the same example, but this time we’ll change Conflict-Mode to ContinueOnConflict (see Figure 11).

I’m not showing the entire code in Figure 12 because every-thing is the same except the SubmitChanges is called with

Figure 8: Result of a select query for suppliers in France.

public static void CausingConflictInaBatch() { NorthWindDataContext db = new NorthWindDataContext(); NorthWindDataContext db2 = new NorthWindDataContext(); //this will retrieve 3 records var suppliers = db.Suppliers.Where(s => s.Country == "France").ToList(); foreach (Supplier supplier in suppliers) { Console.WriteLine("Company: " + supplier.CompanyName + " Country: " + supplier.Country); }

//using the second datacontext to modify the country of //the second supplier from France to USA and causing //conflict for the first context List<Supplier> twosuppliers = db2.Suppliers.Where(s => s.Country == "France").Skip(1).ToList(); foreach (Supplier supp in twosuppliers) { supp.Country = "UK"; Console.WriteLine("Modifying Country for supplier" + supp.CompanyName + " to UK"); }

db2.SubmitChanges();

//now change the country for the customers from first //datacontext to USA and call submit changes.

foreach (Supplier supplier in suppliers) { supplier.Country = "USA"; }

try { db.SubmitChanges(ConflictMode.FailOnFirstConflict); } catch (ChangeConflictException) {

foreach (ObjectChangeConflict conflict in db.ChangeConflicts) { Supplier s = conflict.Object as Supplier; Console.WriteLine("Conflicting supplier {0}", s.CompanyName); foreach (MemberChangeConflict member in conflict.MemberConflicts) { Console.WriteLine("Orignal Supplier Country {0}", member.OriginalValue); Console.WriteLine("Changed Supplier Country {0}", member.CurrentValue); Console.WriteLine("Supplier Country in Database {0}", member.DatabaseValue); } }

} db.SubmitChanges();}

Figure 9: Code illustrating batch conflicts.

Page 14: Asp Aug2008

14 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 15

ContinueOnConflict. Because of this, DataContext continues to process the rows; in the end, all the conflicts are present inside the context’s change conflict collection, as shown in Figure 12. For the entire code, look at the ContinueOnConflict method in the download accompanying this article (see end of article for download details).

Earlier in this article we saw ways of catching a change conflict exception by using overloaded versions of Submit-Changes. Now we’ll explore how we can resolve those con-flicts we captured. Because a major part of the code will be the same as earlier, I’ll simply show you the code snippet

that’s relevant to the context. The first method of conflict resolution we’ll explore is Refresh.

RefreshRefresh is one of the methods available on the DataContext; it allows you to refresh your existing objects with new changes from the database. Refresh has three overloaded methods that allow you to refresh a single entity or the entire collection. The first parameter of the Refresh method is RefreshMode, an enum with three values:

§ RefreshMode.KeepCurrentValues: Discards original values with what’s defined in the database.

§ RefreshMode.KeepChanges: Doesn’t touch what you modified, but the rest of the values are refreshed from the database.

§ RefreshMode.OverwriteCurrentValues: Refreshes all the column values from the database regardless of if they’ve been modified. You basically lose all the changes you made.

The way you can use the Refresh method is by prevent-ing change conflicts in the first place. Just before you call

C o v e r S t o r y | Conflict Resolution

Figure 10: Batch conflict results.

Page 15: Asp Aug2008

14 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 15

SubmitChanges you can refresh your objects from the database. Therefore, when you call SubmitChanges, Data-Context will not throw any exception. Let’s modify our existing example to illustrate the behavior (see Figure 13).

From the result shown in Figure 14, notice that we didn’t get any excep-tion — because we refreshed our original values from the database right before we called SubmitChanges. For the entire code see the CallingRefresh method in the accompanying down-load. We’ll now explore how to resolve change conflicts when an exception is thrown.

In Figure 15, we are telling DataContext to continue on conflict — so after all the objects have been processed, DataContext throws an exception and we simply call ResolveAll on the change conflicts to resolve all the con-flicts, which in this case happens to be two conflicts. This option is the most flexible in the sense that if you don’t have a specific way of resolving conflicts for each indi-vidual object that is in conflict, calling ResolveAll solves most of the problems. If you like to handle each con-flict object differently, we can loop through the change conflicts and resolve each of them separately by calling Resolve on ObjectChangeConflict (see Figure 16).

In Figure 16 we loop through each change conflict and resolve them separately. We also could have checked some property

on an object, then determined on a per-object basis which refresh mode we wanted to apply. For the complete code of the example shown in Figure 16, look at the ResolvingChange-ConflictsPerObject method in the accompanying download. DataContext also provides a more granular level in terms of solving concurrency issues. Say, for example, a particular object comes under conflict because there are properties on the object that don’t match with what’s defined in the data-base. In a scenario like that — where you want to resolve conflicts differently for each column that is in conflict in the conflicted object — we can use the MemberChangeConflict property (see Figure 17).

try { db.SubmitChanges(ConflictMode.ContinueOnConflict); } catch (ChangeConflictException) {

foreach (ObjectChangeConflict conflict in db.ChangeConflicts) { Supplier s = conflict.Object as Supplier; Console.WriteLine("Conflicting supplier {0}", s.CompanyName); foreach (MemberChangeConflict member in conflict.MemberConflicts) { Console.WriteLine("Orignal Supplier Country {0}", member.OriginalValue); Console.WriteLine("Changed Supplier Country {0}", member.CurrentValue); Console.WriteLine("Supplier Country in Database {0}", member.DatabaseValue); } }

} db.SubmitChanges();

Figure 11: Example catching all exceptions by using ContinueOnConflict.

Figure 12: Example showing ContinueOnConflict.

Do you love the FREE PDF version of asp.netPRO, but want access to all the code, as well?

This is the perfect complement to the free asp.netPRO PDF. Now get access to all Premium Downloads that accompany feature articles. A one-year online-only subscription to asp.netPRO magazine is only US$14.99.

To order your online subscription, please contact Customer Service at [email protected] and include your contact information:

•Name •E-mail•Address •Daytime telephone number

We will then provide you your Customer Number so you can set up your online account.

���������������������������������

�����������������

Microsoft, Visual Studio, Visual Basic, MSDN, and ASP.NET are registered trademarks or trademarks of Microsoft Corportaion in the United States and/or other countries and are used by ICG under license from owner, asp.netPRO and Informant are trademarks or registered trademarks of Informant Communications Group, Inc.

Page 16: Asp Aug2008

16 August 2008 | www.aspnetPRO.com

Notice that at this granular level we can determine exactly which member was in conflict, as well as resolve the conflict at the member level using a different RefreshMode. Not only can you use RefreshMode, but there’s also another overload that takes in the actual value so you can basically specify an exact value that will be used as the current value.

ConclusionIn this article we talked about how concurrency problems can lead to conflict exception when we are trying to persist our objects in the database. We also learned how LINQ to SQL uses the UpdateCheck attribute to ensure optimistic concurrency in update statements, and how LINQ to SQL provides different methods to resolve conflicts, from the entire batch to a single object to resolving conflicts at the member level. </>

Source code accompanying this article is available for down-load to asp.netPRO subscribers at www.aspnetPRO.com.

Zeeshan Hirani is a senior developer at CheaperThanDirt.com.

He specializes mainly in ASP.NET, AJAX, and leveraging OR-mapping

solutions like LINQ in business applications. He has written several

articles for CodeProject.com and is an active member in the user-

group community in Dallas/Fort Worth. He is a frequent blogger. You

can find his blog at weblogs.asp.net/zeeshanhirani. Contact him with

any questions at [email protected].

C o v e r S t o r y | Conflict Resolution

try { db.SubmitChanges(ConflictMode.ContinueOnConflict); } catch (ChangeConflictException) { foreach (ObjectChangeConflict conflict in db.ChangeConflicts) { conflict.Resolve(RefreshMode.KeepCurrentValues); } }

Figure 16: Resolving conflicts using ObjectChangeConflict.

try { db.SubmitChanges(ConflictMode.ContinueOnConflict); } catch (ChangeConflictException) { foreach (ObjectChangeConflict conflict in db.ChangeConflicts) { foreach (MemberChangeConflict member in conflict.MemberConflicts) { Console.WriteLine("Member in conflict {0}",member.Member.Name); member.Resolve(RefreshMode.KeepCurrentValues); } } }

Figure 17: Resolving conflicts at the member level.

Figure 14: Example showing use of Refresh to resolve conflicts.

foreach (Supplier supplier in suppliers) { supplier.Country = "USA"; Console.WriteLine("Modifying Supplier {0} country to {1} using hte first context", supplier.CompanyName, supplier.Country); }

try { db.SubmitChanges(ConflictMode.ContinueOnConflict); } catch (ChangeConflictException) { db.ChangeConflicts.ResolveAll(RefreshMode.KeepCurrentValues); }

Figure 15: Resolving conflicts using ResolveAll.

try {

db.Refresh(RefreshMode.KeepCurrentValues, suppliers);

db.SubmitChanges(ConflictMode.ContinueOnConflict); } catch (ChangeConflictException) {

foreach (ObjectChangeConflict conflict in db.ChangeConflicts) { Supplier s = conflict.Object as Supplier; Console.WriteLine("Conflicting supplier {0}", s.CompanyName); foreach (MemberChangeConflict member in conflict.MemberConflicts) { Console.WriteLine("Orignal Supplier Country {0}", member.OriginalValue); Console.WriteLine("Changed Supplier Country {0}", member.CurrentValue); Console.WriteLine("Supplier Country in Database {0}", member.DatabaseValue); } }

}

Figure 13: Refresh objects from the database before you call SubmitChanges. When you call SubmitChanges, DataContext will not throw an exception.

Page 17: Asp Aug2008

16 August 2008 | www.aspnetPRO.com

� � � � � � � � � � � � � �

�����������������

����������������������������

��������������

�����������������������

�������������� ������������������

� �����������

� ����������������������������������������

����� ���� �����������������������������������������������������

��������������������������������������������������������������������������������������

��������������� � ���������������������� � ������������ � ������������

���������������������������������������������������������������������������������������

�����������������������������������������������������������������

� ��������������������� ����������������������� ����������������������� ����������������������� ���������������� ������������

�������������������������������������������������������������������������������������������������������������������

�����������������������������������������������������������������

�������������������������������������������������������������������������������������������������������������������

���������������

TCI_ASP_Aug08_v1 6/9/08 12:37 PM Page 1

Page 18: Asp Aug2008

18 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 19

These days, Web services tend to be favored by software developers (rather than FTP) for sharing data between distributed systems. However, such architectures generally require relatively modern software tools, as well as coopera-tion between the companies, developers, and systems on both ends. This is a luxury that’s not always available. Many legacy systems still support only FTP for data transfers.

Despite the common bias toward newer data transfer techniques, FTP can still be a valuable part of modern software systems. It can serve as an efficient and reli-able way to transfer data (especially large files) between distributed systems. FTP should certainly be considered when data transfer requirements are as simple as the need to transfer one or more files between systems.

Version 1.x of the .NET Framework contained no direct programmatic support for FTP. In version 2.0, the System.Net namespace was enhanced with new FTP classes that were based on the preexisting WebRequest and WebResponse classes. Let’s explore these FTPWeb-Request and FTPWebResponse classes by exploring some

ASP.NET code samples that employ them to transfer files between servers.

Delete a FileOne of the simplest FTP tasks to achieve is file deletion. The code in Figure 1 logs into a remote FTP server and deletes the file named test.txt.

The first code block declares the variables that will be need-ed, including one that specifies the address of the remote FTP server (in this case, ftp://contoso.com/).

The second code block starts by creating a reference to a specific file (named test.txt) located in the root of that FTP server. The FTPWebRequest’s unfortunately named Method

LANGUAGES: VB.NET | C# § ASP.NET VERSIONS: 2.0

C o n t r o l F r e a k

§ By Steve C. Orr

A ll experienced Web developers have some

familiarity with HyperText Transfer Protocol

(HTTP) — after all, it is the foundation of

the World Wide Web that keeps us employed. However,

extensive knowledge of its partner protocol is not quite

as common these days. Many Web developers know rela-

tively little about File Transfer Protocol (FTP) — other

than the fact that many of us commonly use it to manu-

ally deploy our code files to distant Web servers.

FTP Transfers Transfer Files Programmatically with FTP

'Imports System.NetDim ftpWebReq As FtpWebRequestDim ftpWebResp As FtpWebResponseDim ftpRoot As String = "ftp://contoso.com/"Dim status As String = ""

'Configure the requestftpWebReq = FtpWebRequest.Create(ftpRoot + "test.txt")ftpWebReq.Method = WebRequestMethods.Ftp.DeleteFileftpWebReq.Credentials = _ New NetworkCredential(_userName, _password)

Try 'Send the request ftpWebResp = ftpWebReq.GetResponse() 'deletes the file status = ftpWebResp.StatusDescription ftpWebResp.Close()Catch ex As Exception status = ex.MessageEnd TrylblResult.Text = status

Figure 1: This code uses the System.Net namespace to delete a remote file using File Transfer Protocol (FTP).

Page 19: Asp Aug2008

18 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 19

property is then used to specify the intention to delete that file. The final line of the second code block provides log-in credentials to the FTP server. This line would be unnecessary if the specified FTP server were configured to allow anonymous users.

The first line of code inside the Try..Catch block is the one that actually sends the delete request to the server. It also retrieves the FTP server’s response, then closes the response. The final line of code in Figure 1 displays the status text retrieved from the response object (or from the error han-dler, if things went awry).

Assuming the FTP server successfully found and deleted the specified file, a response code of 250 (Command Successful) will be returned, as shown in Figure 2. An error code of 550 (File Unavailable) is returned if the specified file could not be found on the FTP server. An error code of 530 (Not Logged In) is returned if the log-in credentials were rejected by the FTP server.

Upload a FileThe code required to upload a file is similar to the file deletion code in Figure 1, requiring only a couple extra lines of code. Figure 3 lists code that uploads a file from a local Web server to a remote FTP server.

Figure 3 begins by declaring a couple of variables, includ-ing a StreamWriter object from the System.IO namespace. The request is then configured in much the same way as Figure 1’s file deletion code. In this case, the Create meth-od is used to specify the file name that should be assigned to the soon-to-be uploaded file (test.txt). This FTP filename doesn’t necessarily have to be the same as the source file’s name. Another notable difference from the previous code sample is the line of code that sets the method property to an upload request instead of a file deletion request.

You might also have noticed a new line of code that sets the FTPWebRequest’s UseBinary property to False. While not strictly necessary, this optimization allows our simple text file to be transferred more efficiently by avoiding the overhead required to transfer more complex binary files. Most other (non-text) file types require a binary transfer, so in such cases the UseBinary property should be left at its default value of True.

The Try..Catch block of Figure 3 begins by opening the test.txt file from the local Web root and loads its entire contents into a StreamWriter object. (While the .NET Framework provides multiple techniques for opening and reading files, this technique is adequate for a small text file such as the one used in this example. Alternate techniques might be more optimal when dealing with large files.)

Just as in the previous file deletion example, the request is then sent to the FTP server and the response is retrieved and

Figure 2: This sample application demonstrates a variety of FTP commands and displays (in red) the result of each such request.

Dim sw As StreamWriter 'Imports System.IODim status As String = ""

'Configure the request_ftpWebReq = FtpWebRequest.Create(_ftpRoot + "test.txt")_ftpWebReq.Method = WebRequestMethods.Ftp.UploadFile_ftpWebReq.Credentials = _ New NetworkCredential(_userName, _password)_ftpWebReq.UseBinary = False

Try 'Read the local file in preparation for upload sw = New StreamWriter(_ftpWebReq .GetRequestStream()) sw.Write(New StreamReader(Server.MapPath("test.txt")) _ .ReadToEnd) sw.Close()

'Send the request _ftpWebResp = _ftpWebReq .GetResponse() 'upload the file status = _ftpWebResp.StatusDescription _ftpWebResp.Close()Catch ex As Exception status = ex.MessageEnd TrylblResult.Text = status

Figure 3: This code demonstrates how to programmatically upload a file to an FTP server.

Dim sw As StreamWriter 'Imports System.IODim status As String = ""

'Configure the request_ftpWebReq = WebRequest.Create(_ftpRoot + "test.txt")_ftpWebReq.Method = WebRequestMethods.Ftp.DownloadFile_ftpWebReq.Credentials = _ New NetworkCredential(_userName, _password)_ftpWebReq.UseBinary = False

Try 'Send the request _ftpWebResp = _ftpWebReq .GetResponse()

'Save the downloaded file to the local web root. sw = New StreamWriter(Server.MapPath("test2.txt")) sw.Write(New StreamReader( _ _ftpWebResp.GetResponseStream()).ReadToEnd) sw.Close()

status = _ftpWebResp.StatusDescription _ftpWebResp.Close()Catch ex As Exception status = ex.MessageEnd TrylblResult.Text = status

Figure 4: This code requests a file download from an FTP server.

Page 20: Asp Aug2008

20 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 21

closed. The result is then displayed in a Label control on the page. A successful upload will return code 226 (Transfer Complete).

Download a FileThe process for downloading a file is similar to the process for uploading a file. The code in Figure 4 can be used to request a file download from an FTP server.

The download request is configured similarly to the previously listed upload request. The FTP server’s source file name test.txt is specified, and the method property is set to DownloadFile. The request is then sent to the FTP server, and the contents of the response stream are saved into a new file named test2.txt, which is placed in the local Web root folder.

List Directory ContentsTransferring files to a server can become problematic if you are oblivious to the list of files that are already there. To ease such pains, you may want to harvest the current file list from the FTP server using the code shown in Figure 5.

The code listed in Figure 5 begins in a familiar way, declaring variables and setting up the FTP request. This time, however, the ListDirectory method is specified in order to retrieve the contents of the directory specified in the Create method.

The request is then sent to the FTP server and its poten-tially large response is streamed into a local string vari-able named list. This text is then massaged a bit for improved readability. Carriage returns are replaced with HTML line breaks, and the rest of the output is HTML encoded to ensure the browser doesn’t attempt to inter-pret the text as HTML.

The output (shown in Figure 6) is an alphabet-ized list of files and subdirecto-ries. While this list may be ade-quate for simple needs, an unfor-tunate drawback of this technique is the inability to distinguish files from sub-directories. For situations where you need this or other details about the direc-tory contents, an alternate request must be employed.

List Directory DetailsThankfully, retrieving more advanced directory information from the FTP server doesn’t require more advanced program-ming techniques. In fact, only one line from Figure 5 need be modified. The method property value needs to be changed from ListDirectory to ListDirectoryDetails, as shown in Figure 7.

Now the resulting output will include file dates and times, and files can be distinguished from subdirectories by the <DIR> prefix placed in front of each subdirectory. This enhanced output is illustrated in Figure 8.

Dim list As String = ""Dim status As String = ""

'Configure the request_ftpWebReq = FtpWebRequest.Create(_ftpRoot)_ftpWebReq.Method = WebRequestMethods.Ftp.ListDirectory_ftpWebReq.Credentials = _ New NetworkCredential(_userName, _password)

Try 'Send the request _ftpWebResp = _ftpWebReq.GetResponse() list = New StreamReader(_ftpWebResp.GetResponseStream()) _ .ReadToEnd _ftpWebResp.Close()Catch ex As Exception status = ex.MessageEnd Try

'Display the file listlblResult.Text = Server.HtmlEncode(list) _ .Replace(Chr(13), "<br/>")

Figure 5: This code will retrieve and display a simple list of files found in the specified directory of the FTP server. Figure 6: The code in Figure 5 outputs

this simple alphabetical list of the files and subdirectories retrieved from the FTP server.

Dim list As String = ""Dim status As String = ""

'Configure the request_ftpWebReq = FtpWebRequest.Create(_ftpRoot)_ftpWebReq.Method = _ WebRequestMethods.Ftp.ListDirectoryDetails_ftpWebReq.Credentials = _ New NetworkCredential(_userName, _password)

Try 'Execute the request _ftpWebResp = _ftpWebReq.GetResponse() list = New StreamReader(_ftpWebResp.GetResponseStream()) _ .ReadToEnd _ftpWebResp.Close()Catch ex As Exception status = ex.MessageEnd Try

'Display the file listlblResult.Text = Server.HtmlEncode(list) _ .Replace(Chr(13), "<br/>")

Figure 7: This code will retrieve and display a more detailed list of files and subdirectories than the code in Figure 5.

C o n t r o l F r e a k | FTP Transfers

Page 21: Asp Aug2008

20 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 21

Other Useful FTP CommandsIn addition to the examples listed so far, File Transfer Pro-tocol also supports a number of other potentially useful file management functions. For example, a new FTP directory can be programmati-cally created with code that looks very similar to the samples you’ve seen so far. The primary difference will be the value assigned to the Method property of the FTPWeb-Request object. For example, to create a subdirec-tory on the FTP server, this line of code is the key:

_ftpWebReq.Method = WebRequestMethods.Ftp.MakeDirectory

Deleting a subdirectory is just as simple:

_ftpWebReq.Method = WebRequestMethods.Ftp.RemoveDirectory

The WebRequestMethods.Ftp type demonstrated above has several other handy members, too. They include: AppendFile, GetFileSize, and Rename.

SecuritySome developers shun FTP for being insecure based primarily on the fact that all data and credentials are sent in plain text by default (which could be intercepted by skilled hackers). However, this situation isn’t much different than HTTP — and the solution is the same: Secure Sockets Layer. SSL can be used to secure FTP communications in the same way it is used to secure HTTP requests. To encrypt an FTP request with SSL, set the FTPWebRequest’s EnableSSL property to True.

The FTPWebRequest class also has several other security-related properties to help you meet your system’s security requirements. For example, there are properties for work-ing with certificates, adjusting authentication, and using impersonation.

When accessing a remote FTP server from ASP.NET code (as has been done in the code samples here), NTFS security settings may need to be adjusted on your local server(s) so that files downloaded from the FTP site can be successfully written to the desired location(s).

IIS 7.0 includes significantly improved FTP support over previous versions. Multiple FTP sites can be established on each server, and FTP directories can be independently configured to permit or deny various actions for individual users or groups of users. Standard NTFS and IIS security set-tings can be used to make such adjustments, so there really isn’t much of a learning curve required.

Large File TransfersVery large files can take a long time to transfer. Systems that need to support large file transfers may face unique design challenges. When large file transfers are initiated from ASP.NET code, it can cause a lengthy delay for the user and potentially violate one or more timeout periods. ASP.NET provides many standard ways to configure its timeout periods, and for simple situations this may suffice. The FTPWebRequest class also has a ReadWriteTimeout property that is set to 5 minutes by default (300,000 milliseconds). Even if no timeout occurs, it is likely that valuable Web request threads are being tied up unnecessarily during lengthy transfers, thus limiting scalability of the Web server.

More robust and scalable solutions rely on asynchronous communications. ASP.NET provides techniques to help with asynchronous requests, such as the Async page direc-tive. Depending on your needs, that may be sufficient. Cutting-edge technologies such as AJAX may also be tempting solutions. Additionally, the .NET Framework has long provided useful patterns for building asynchronous solutions, such as the BeginInvoke and EndInvoke meth-ods. If you’ve done this kind of development before, you’ll find the FTPWebRequest’s built-in asynchronous methods to be quite intuitive. Specifically, these FTPWebRequest members are named BeginGetResponse, EndGetResponse, BeginGetRequestStream, and EndGetRequestStream.

ConclusionFile Transfer Protocol is useful for many more things than simply deploying your ASPX files to your Web server. It can be a valuable asset to your programming toolkit. Now that you know how to program with FTP, keep it in mind as a possible component in your future software projects! </>

C# and VB.NET source code accompanying this article is available for download to asp.netPRO subscribers at www.aspnetPRO.com/download.

Steve C. Orr is an ASPInsider, MCSD, Certified ScrumMaster, Microsoft

MVP in ASP.NET, and author of Beginning ASP.NET 2.0 AJAX by Wrox.

He’s been developing software solutions for leading companies in the

Seattle area for more than a decade. When he’s not busy designing

software systems or writing about them, he often can be found

loitering at local user groups and habitually lurking in the ASP.NET

newsgroup. Find out more about him at SteveOrr.net or e-mail him at

[email protected].

Figure 8: The code listed in Figure 7 renders this more detailed directory information.

Page 22: Asp Aug2008

22 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 23

So what’s the purpose of this month’s article? Am I here simply repurposing content I just presented a few months back? The (hopefully obvious) answer is no. You probably know that Silverlight 2.0 is in Beta (and may have shipped by the time you read this). The content of the previous article is still valid, but it mostly refers to Silverlight 1.0. It is also valid if you upgrade to Silverlight 2.0 and program it using JavaScript. This article, instead, reloads the topic of getting content on demand, but specifically targets using managed code and Silverlight 2.0.

Silverlight 2.0The breakthrough aspect of Silverlight 2.0 is the support it offers for a tailor-made version of the .NET Common Language Runtime (CLR). If this statement is not evocative enough for you, let me rephrase: Silverlight 2.0 allows you to host .NET managed code in any browser that supports plug-ins and on any supported platforms. Microsoft supplies Silverlight 2.0 for Windows and Mac; the Mono group will have available a Linux edition of Silverlight by the time the product ships in the summer of 2008.

Built-in support for the CLR and managed code means that developers can say goodbye to JavaScript — at least to the

script that is normally used to implement the client-side logic of a page. The user interface of the plug-in is largely determined by the XAML file it downloads; the service pro-vided by the plug-in, in the context of the hosting page, is fully determined by the code-behind class that decorates and accompanies the XAML file. In Silverlight 2.0, much like in a fully-fledged WPF application, you create an XAML docu-ment and corroborate it with a code-behind class that gath-ers event handlers and helper routines, and exposes public properties and methods.

The user interface of a Silverlight 2.0 page is expressed as a WPF user control and persisted to an XAML file. The plug-in XAML parser recognizes nearly all elements of the full WPF syntax. The correspondence is not on 100% of the elements, but refers to a compatible subset (maybe not all elements, but certainly all key functionalities except 3D).

It comes as a foregone conclusion that if any content is to be downloaded on demand, that content can’t simply be limited to an XAML text file. At the very minimum, it will come with a companion code-behind class. To deal with this need, Microsoft formalized a new package format — the XAP package. A Silverlight 2.0 plug-in now points to an XAP URL rather than to an XAML resource.

Internally, the XAP package contains a manifest file and all the assemblies that make up the document. The XAML source code is attached as a resource to one of the assem-blies. The manifest file lists the contents of the package-constituent assemblies and additional auxiliary resources, such as images and XML files. The list of packaged assemblies includes the assembly that contains the code-behind class, plus any other auxiliary assembly that is referenced in the project. In Beta 1, for instance, the man-ifest also lists a couple of system assemblies that contain

In the April 2008 issue of asp.netPRO I talked about

a common issue for the fast-growing community of

Silverlight developers: deferred loading of XAML

content. I discussed how to embed XAML content as

a data island in the host HTML page, and touched on

the use of the Downloader object from inline JavaScript

code. You typically employ the Downloader object to

download a new XAML file from the server — with the

precise intent of updating the user interface dynamically.

LANGUAGES: C# § ASP.NET VERSIONS: 3.5 § By Dino Esposito

C o r e C o d e r

On-demand XAML: Reloaded Getting XAML and Code — but Only When You Need It

Page 23: Asp Aug2008

22 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 23

some common controls. Past Beta 1, however, these extra assemblies will become part of the plug-in setup. The XAP package is merely a renamed ZIP archive. You can try it out yourself by simply renaming an XAP resource to ZIP, then using any program to snoop (see Figure 1).

Designing for On-demandAn XAML document that accepts on-demand content should contain one or more placeholder elements. In ASP.NET, you typically use an ad hoc control as a placeholder — the PlaceHolder server control. No such element exists in WPF, but you can use an empty stack panel instead:

<StackPanel x:Name="Placeholder"></StackPanel>

Any document-wide event can trigger the additional down-load. Once downloaded, the data is massaged into an XAML subtree and appended to the overall UI tree. Most of the time, you might also want to cache at least the generated subtree to avoid both additional roundtrips and any extra work to make the downloaded content really usable. Here’s a simple pattern you can implement in any event handler that triggers the on-demand feature:

if (!IsDownloaded()) DownloadExtraStuff();else AddExtraStuff();

Any content available on demand should be organized in WPF user controls. Quite simply, given the default behavior of Visual Studio 2008, this means that you create multiple Silverlight applications: one for each piece that has to be downloaded separately. From an XAML perspective, each separate download adds a user control to the main tree.

Let’s take a look at the tools you use to set up an on-demand feature. In the first place, you need a managed object that connects to a remote URL and brings data down to the client browser. In the April column I dis-cussed the Downloader object you use from JavaScript. In Silverlight 2.0, that object is still available to JavaScript callers, but can’t be used from C# or VB. Here’s how you would use it:

var downloader = plugin.createObject("downloader");downloader.addEventListener("completed", onCompleted);downloader.open("GET", "../xaml/ellipses.xaml");downloader.send();

In Silverlight 2.0, JavaScript’s Downloader object is a wrapper for a new managed class — the WebClient class. Defined in the system.net namespace and compiled in the System.Windows assembly, the WebClient class is currently available only to Silverlight developers. For the most part, the .NET Framework in Silverlight is a subset of the full framework. The WebClient class is an excep-tion, but it will likely find its way in to the full .NET Framework in a future release.

The WebClient ClassAn extremely simple class, WebClient is essentially an object-oriented wrapper for an HTTP GET call — but you can’t use it to post data if not through the query string. The class has an asynchronous programming interface and fea-tures a couple of executors: the DownloadStringAsync and OpenReadAsync methods:

Uri endpoint = new Uri(resourceURL);WebClient wc = new WebClient();wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(OnCompleted);wc.DownloadStringAsync(endpoint);

Figure 1: Looking into the content of an XAP package.

private void OnOpenReadCompleted(object sender, OpenReadCompletedEventArgs e){ // Local variables String assembly = "extrastuff.dll"; String className = "Samples.ExtraStuffPage";

if (e.Error != null) return;

// Load a particular assembly from XAP Assembly a = LoadAssemblyFromXAP(assembly, e.Result);

// Get an instance of the XAML object UserControl page = a.CreateInstance(className) as UserControl;}

private Assembly LoadAssemblyFromXAP(string assemblyName, Stream xapStream){ Uri assemblyUri = new Uri(assemblyName, UriKind.Relative); StreamResourceInfo xapSri = new StreamResourceInfo(xapStream, null); StreamResourceInfo assemblySri = Application.GetResourceStream(xapSri, assemblyUri);

AssemblyPart assemblyPart = new AssemblyPart(); Assembly a = assemblyPart.Load(assemblySri.Stream); return a;}

Figure 2: Extracting and instantiating a downloaded XAML subtree.

Page 25: Asp Aug2008

26 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 27

As the name implies, the DownloadStringAsync method returns the response as a plain string. It is good to download raw XAML, XML configuration files, or per-haps JavaScript files. It is not as good to grab compiled code, such as an assem-bly or, worse yet, an assembly that contains viable resources to be extracted. This is where the OpenReadAsync method fits in.

The OpenReadAsync method has the same signature as DownloadStringAsync, but fires the OpenReadCompleted event when done. Figure 2 shows a handler for the event that extracts an assembly and instantiates the contained XAML code-behind class.

The OpenReadCompletedEventArgs data structure exposes the downloaded content as a stream through its Result property:

Stream xap = e.Result as Stream;

The stream contains all assemblies referenced in the manifest file. Figure 3 shows a sample XAML manifest file that is the root dictionary of an XAP package.

The next step requires that you extract the parts of the stream in which you’re interested. In particular, you extract the assembly that contains the code-behind class for the chunk of XAML you want to add to the current tree.

The StreamResourceInfo class allows you to identify the various assemblies in the package. Each of these constituent assemblies is known as an assembly part and is represented with an instance of a new class: AssemblyPart.

The assembly is identified with a URI and extracted from the returned stream using the global GetResourceStream method on the Application class:

Uri uriAsm = new Uri(assembly, UriKind.Relative);StreamResourceInfo sriMain = new StreamResourceInfo(xap, null);StreamResourceInfo sriAsm = Application.GetResourceStream(sriMain, uriAsm);

To finally get a reference to an assembly class, use the AssemblyPart class and its Load method. The Load method takes the stream with the assembly bits as read from the XAP stream:

AssemblyPart assemblyPart = new AssemblyPart();Assembly a = assemblyPart.Load(sriAsm.Stream);

You’re pretty much done at this point. The only thing that remains to do is to instantiate the class with XAML and code:

<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" EntryPointAssembly="DynamicStuff" EntryPointType="DynamicStuff.App" RuntimeVersion="2.0.30226.2"> <Deployment.Parts> <AssemblyPart x:Name="DynamicStuff" Source="DynamicStuff.dll" /> <AssemblyPart x:Name="MySilverToys" Source="MySilverToys.dll" /> : </Deployment.Parts></Deployment>

Figure 3: An XAP manifest file.

��������������������

���������������

�������������������

�������������������

���������������

�������������������

�������������������

�������������������

����������������

����������������

���������������������

���������������������

���������

�����������������������������������������������������������������������������������������������������������������������������

�����������������������������������������������������������������������������������������������

��������������������������������������������������������������������������

����������������������������������������������������������������������������

����������������������������������������������������������������������������������������

���������������������������������������������������������������������������������������������������������������������������������������������

��������������������������������������������������������������������������������

������������������������������������������������������������������������������������������������������ ��������������

��������������������������������������������������������������������

���������������������������������

��������������������������������������������������

����������������������������������������������

�������������������������������

���������������������������������

������

������������������������������������������������������������������

C o r e C o d e r | On-demand XAML: Reloaded

Page 26: Asp Aug2008

26 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 27

UserControl page = a.CreateInstance(className) as UserControl;

The CreateInstance method on the Assembly class simply takes the fully qualified name of the class and returns an instance of it. Because this class represents an XAML page, it inherits from UserControl.

Updating the Tree DynamicallyThe user interface of the currently displayed page is an XAML tree and is rooted in a UserControl object. As the effect of the download, you now have a second UserControl that can be appended everywhere in the existing tree. The trick is using the Children property that any UI element in XAML exposes:

this.Placeholder.Children.Add(page);

Likewise, by using the Remove method on the Children property, you can detach any XAML subtree from display. The detached subtree will remain in memory until it goes out of scope. However, you might want to persist it to the Silverlight local storage and read it back at a later time to save a few round trips and processing power over time. The XamlWriter and XamlReader classes are there to help you with just this task. The former saves a Silverlight tree down to an XAML string. The latter reads it back to an XAML object that can be attached to the existing UI.

ConclusionFor the most part, programming Silverlight applications is a matter of making asynchronous calls to the Web server to get configuration data, settings, preferences, and, of course, extra pieces of user interface and related code. The larger the application, the smaller its network footprint. Deferred loading is a key technique to optimize the use of the band-width while keeping the client machine as lean and mean as possible. In Silverlight 2.0, a downloadable package is a zipped archive that includes at least one assembly. This assembly contains the compiled version of the class that acts as the code-behind back-end of the XAML user inter-face. No XAML stream is downloaded explicitly because the XAML is embedded into the assembly as a resource. The plug-in parser takes care of extracting and processing it from within the browser. As a developer, you only need to get acquainted with the XAP package and the API to deal with it. To install what you download, create an instance of the XAML root class. That’s it — and it works. </>

Dino Esposito is an architect at IDesign and specializes mainly

in ASP.NET, AJAX, and RIA solutions. Dino is the author of

Programming ASP.NET 3.5 Core Reference (Microsoft Press, 2008).

He also wrote Introducing ASP.NET AJAX, also for Microsoft Press.

Late-breaking news is available at weblogs.asp.net/despos.

Co-Sponsored by:

• More than 700 technical articles, as well as product reviews, book reviews, and other content appearing in asp.netPRO and asp.netNOW!

• Supporting code and sample fi les that you can use in your applications immediately.

• Easily searchable CD-ROM — fi nd what you need, when you need it.

• FREE shipping!*

ORDER Your Copy Now for ONLY US$39.99*

Microsoft and ASP.NET are registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries and are used by ICG under license from owner. asp.netPRO and Informant are trademarks or registered trademarks of Informant Communications Group, Inc.

2007 asp.netPRO Complete Works CD-ROM

Visit us online at www.aspnetPRO.com/cd

or Call Toll-free in the U.S. (800) 884-6367

Outside the U.S. dial (916) 379-0609

* Free Shipping and Handling to US and Canada! All other countries US$10.00 for shipping and handling. Applicable sales tax will be added for California residents. Payment must be in US dollars drawn on a US bank. Your purchase may be tax deductible if used for business purposes. Please check with your tax advisor.

Page 27: Asp Aug2008

28 August 2008 | www.aspnetPRO.com

Functional RequirementsEven though our message box will closely resemble the Windows counterpart, there will be some differences because of the way AJAX works. It is worthwhile to note the functional requirements we want our message box to fulfill:§ We should be able to display a message box with text or

an HTML message.§ The message box should provide all the standard button

combinations as Windows-based message boxes.§ We should be able to display, along with the message,

standard message box icons; i.e., question, information, exclamation, and error.

§ The images of the standard message box icons should be customizable.

§ We should be able to customize the look and feel of the message box via CSS classes.

§ Upon selecting a particular button, the message box should notify us about the selection so further action can be taken.

§ The location and dimensions of the message box should be configurable.

Software RequirementsTo follow the code of this article you need ASP.NET 3.5. We’ll use Visual Studio 2008 as the development tool, though Visual Web Developer Express also can be used. And although this article is written and tested for ASP.NET 3.5, it will work on ASP.NET 2.0 with AJAX extensions installed.

MessageBox ControlOur message box will take the form of an AJAX client control that can be instantiated and consumed through the client script. Before we delve into the details of the control, let’s first see how it will look. Figure 1 shows a sample message box with a caption, an icon, and two but-tons (Yes and No).

As you can see, this message box closely resembles the Windows Forms MessageBox. However, it is more flexible in terms of look and feel.

Properties and Methods of the MessageBox ControlThe MessageBox client control we’ll develop is highly con-figurable. The table in Figure 2 shows the key properties of the MessageBox control.

LANGUAGES: C# § ASP.NET VERSIONS: 2.0 | 3.5

C o d e T a l k

§ By Bipin Joshi

P rompting users with a message box is common

in Windows applications. Indeed, the Windows

Forms MessageBox class provides a rich and

standardized way of displaying message boxes. Web appli-

cations, on the other hand, are restricted with JavaScript

alert or confirm functions. These built-in ways of display-

ing message boxes are very limited, and developers often

need to develop a custom solution for the same. Wouldn’t

it be nice if we had something similar to the Windows

MessageBox class? This article will show you how to

develop an AJAX client control that provides a rich and

quick way of displaying message boxes in your AJAX-

enabled Web sites.

Build a Message Box the AJAX Way Part I: Getting Started

Figure 1: An AJAX-based message box.

Page 28: Asp Aug2008

28 August 2008 | www.aspnetPRO.com

Page 29: Asp Aug2008

30 August 2008 | www.aspnetPRO.com

The MessageBox class has only one public method (Show). The Show method takes various parameters and displays the message box depending on the parameters passed.

Beginning the DevelopmentNow that you have some understanding of the MessageBox control, let’s start building it! Begin by creating a new Web site using Visual Studio (Figure 3).

Be sure to choose a coding lan-guage (C# in our example) in the New Web Site dialog box; name the Web site MessageBoxDemo. Open the default Web form and add a ScriptManager control (see Figure 4). Every Web form that makes use of AJAX features must have one — and only one — instance of ScriptManager on it.

Then switch to the Source view of the Web form and add a <script> block somewhere below the ScriptManager markup. The first step in writing an AJAX client control is to declare a namespace to house all the classes, interfaces, and enumerations related to the control. Add this line at the top of the <script> block to declare a namespace:

Type.registerNamespace("BinaryIntellect");

The registerNamespace method of the Type class registers a client-side namespace with the AJAX framework. The parameter to the registerNamespace method is the name of the namespace. In the above example we created a namespace with the name BinaryIntellect.

Creating EnumerationsThe MessageBox control relies on four enumerations for its proper functioning. These enumerations are summarized in Figure 5.

The DialogResult enumeration is shown in Figure 6. The prototype of the DialogResult enumeration defines various options, such as Abort, Cancel, and Ignore. The DialogResult enumeration contains all the possible button selections. Note that AJAX enumeration values are essentially numeric val-ues and can be compared with an enumeration or a number directly. Nowhere does the prototype of the DialogResult specify it to be an enumeration. That is done while register-ing the enumeration using the registerEnum method. The registerEnum method accepts the fully qualified name of an enumeration that is being registered.

The MessageBoxButtons enumeration contains all the pos-sible button combinations our MessageBox control can have. The MessageBoxButtons enumeration is shown in Figure 7.

The MessageBoxButtons enumeration defines six combina-tions of buttons: OK, OKCancel, YesNo, YesNoCancel, Abort-RetryIgnore, and RetryCancel. This enumeration is used to decide which buttons to display on the message box. These

Property Description

CaptionCss The CSS class name that provides the look and feel to the caption of the message box.

BoxCss The CSS class name that controls the look and feel of the message box.

BackgroundCss The CSS class name that controls the look and feel of the background content.

ButtonCss The CSS class name that controls the look and feel of the message box buttons.

QuestionImageUrl URL of the icon that displays the question mark on the message box.

InformationImageUrl URL of the image that displays the information icon on the message box.

ExclamationImageUrl URL of the icon that displays the exclamation mark on the message box.

ErrorImageUrl URL of the image that displays the error icon on the message box.

Left The left coordinate of the message box.

Top The top coordinate of the message box.

Height The height of the message box.

Width The width of the message box.

DialogResult After the user selects a message box button, this property indicates the selection made by the user.

CloseCallback After the user selects a message box button, a callback function as indicated by this property is invoked.

Figure 2: Properties of the MessageBox control.

Figure 4: AJAX server controls.

Figure 3: Creating a new Web site using Visual Studio.

C o d e T a l k | Build a Message Box the AJAX Way

Page 30: Asp Aug2008

30 August 2008 | www.aspnetPRO.com

Page 31: Asp Aug2008

32 August 2008 | www.aspnetPRO.com

C o d e T a l k | Build a Message Box the AJAX Way

are the same combinations available to a Windows message box.

When a message box displays more than one button, we may want to control the focus amongst the available but-tons. This default focus is indicated by the MessageBox-DefaultButton enumeration, as shown in Figure 8.

Because there can be a maximum of three buttons to the message box, the MessageBoxDefaultButton enumeration defines only three values: Button1, Button2, and Button3.

The message box can optionally display an icon that is relevant to the message being displayed. The possible icons are question, information, exclamation, and error. The MessageBoxIcon enumeration provides these possi-bilities (see Figure 9).

The MessageBox ClassNow that we’ve defined the required enumerations, let’s move ahead and create the MessageBox class. Add below the enumerations the code shown in Figure 10 to declare the MessageBox class.

The constructor of the MessageBox class accepts reference to an HTML element that is acting as the message box. You’ll usually use elements such as <DIV> or <SPAN>

Enumeration Description

DialogResult Provides options that represent the mes-sage box button selected by the user.

MessageBoxButtons Provides options to indicate possible com-binations of message box buttons.

MessageBoxIcon Provides options that indicate the icon displayed on the message box.

MessageBoxDefaultButton Provides options that indicate the default button selection of the message box.

Figure 5: Enumerations required by the MessageBox control.

BinaryIntellect.MessageBoxButtons=function(){}BinaryIntellect.MessageBoxButtons.prototype={ AbortRetryIgnore:0, OK:1, OKCancel:2, RetryCancel:3, YesNo:4, YesNoCancel:5}BinaryIntellect.MessageBoxButtons.registerEnum ('BinaryIntellect.MessageBoxButtons');

Figure 7: The MessageBoxButtons enumeration.

BinaryIntellect.DialogResult=function(){}BinaryIntellect.DialogResult.prototype={ Abort:0, Cancel:1, Ignore:2, No:3, OK:4, Retry:5, Yes:6}BinaryIntellect.DialogResult.registerEnum ('BinaryIntellect.DialogResult');

Figure 6: The DialogResult enumeration.

BinaryIntellect.MessageBoxDefaultButton=function(){}BinaryIntellect.MessageBoxDefaultButton.prototype={ Button1:0, Button2:1, Button3:2}BinaryIntellect.MessageBoxDefaultButton.registerEnum ('BinaryIntellect.MessageBoxDefaultButton');

Figure 8: The MessageBoxDefaultButton enumeration.

����������������������������������������

����������������������������������������������������

���������������������������

Page 32: Asp Aug2008

32 August 2008 | www.aspnetPRO.com

Page 33: Asp Aug2008

34 August 2008 | www.aspnetPRO.com

C o d e T a l k | Build a Message Box the AJAX Way

as the message box. What follows is a series of private vari-ables required by the MessageBox class. Class members in AJAX prefixed with an underscore ( _ ) character are con-sidered private. We’ll expose these private variables to the external world later through a set of public properties. Many of the variables are initialized to default values — especially icon image URLs and bounds of the message box.

The prototype of the MessageBox class wraps the private variables shown in Figure 10 into public properties. These public properties take the form of getter and setter methods, and are shown in Listing One (on page 38).

We discussed the significance of these properties in earlier sections. The MessageBox class has only one public method named Show, which is overloaded to accept a varying num-ber of parameters. There is no official way of implementing overloaded methods in AJAX client script (or JavaScript in general). If you create two functions with the same name, the last function definition silently replaces all the previous definitions. Developers often use workarounds to implement method overloading. In our example, we’ll also use one such workaround that is based on the length of the JavaScript arguments array. Our approach will be clear once you go through Figure 11.

The code from Figure 11 checks the length of the JavaScript arguments array. All JavaScript functions have access to this array, and the array contains the parameters passed to the function. Depending on the number of parameters, we call the respective private method (the private methods will be discussed in detail in Part II). Notice that this workaround for implementing method overloading doesn’t take into account the data type of the parameters.

Now that we’ve developed the prop-erties, and the skeleton of the Show method, it’s time to code some

private helper methods that are used elsewhere in the MessageBox class.

Adding a Message to the Message BoxRecollect that the MessageBox class accepts a reference to the HTML element that acts as the message box. This ele-ment is, however, the outermost container of the message box. The actual message is displayed inside this container. One way to display a message is to use the innerHTML property of the outermost container itself. However, this approach is troublesome, as there are other constituents of the message box, such as caption, icon, and buttons. Set-ting the innerHTML property of the outermost container will replace all of its contents with the message. A more appro-priate approach would be to create a <DIV> dynamically and add it to the outermost container. The _AddMessage private method does just that (see Figure 12).

Show:function(){ switch(arguments.length) { case 1: this._ShowPlain(arguments[0]); break; case 2: this._ShowCaption(arguments[0],arguments[1]); break; case 3: this._ShowButtons(arguments[0],arguments[1],arguments[2]); break; case 4: this._ShowIcon(arguments[0],arguments[1],arguments[2],arguments[3]); break; case 5: this._ShowDefaultButton(arguments[0],arguments[1], arguments[2],arguments[3],arguments[4]); break; }}

Figure 11: Skeleton of the Show method.

BinaryIntellect.MessageBoxIcon=function(){}BinaryIntellect.MessageBoxIcon.prototype={ Error:0, Exclamation:1, Information:2, Question:4}BinaryIntellect.MessageBoxIcon.registerEnum ('BinaryIntellect.MessageBoxIcon');

Figure 9: The MessageBoxIcon enumeration.

BinaryIntellect.MessageBox = function(element){ this._element=element; this._captionCss=""; this._boxCss=""; this._backgroundCss=""; this._buttonCss="";

this._dialogResult=null; this._callback=null;

this._questionImageUrl='images/question.jpg'; this._informationImageUrl='images/information.jpg'; this._exclamationImageUrl='images/exclamation.jpg'; this._errorImageUrl='images/error.jpg'; this._left=-1; this._top=-1; this._height=90; this._width=200;}

Figure 10: Private variables of the MessageBox class.

Page 34: Asp Aug2008

34 August 2008 | www.aspnetPRO.com

Page 35: Asp Aug2008

36 August 2008 | www.aspnetPRO.com

The _AddMessage method accepts two parameters: a reference to the outermost element and the message to be displayed. It then creates a new <DIV> using the createElement method of the document object. The innerHTML property of the newly created <DIV> is then set to the message we wish to display. Finally, the newly created <DIV> is appended to the outer-most container.

Adding a CaptionAdding a caption to the message box is similar to adding the message, with a few differences. The _AddCaption private method does the job of adding a caption (see Figure 13).

The AddCaption method takes two parameters: a refer-ence to the outermost container and a caption to be displayed. Inside it creates a new <DIV> dynamically. Recollect that we declared the _captionCss variable that holds the name of the CSS class to be applied to the caption. The CSS class is applied to the dynamically created <DIV> using the addCssClass method of the DomElement class. The addCssClass accepts the element to which the CSS class is to be applied, as well as the name of the CSS class. The dynamically created <DIV> is then appended to the outermost container (as before).

Adding an IconAdding an icon is slightly different than adding a message or caption. The _AddIcon private method accepts a reference to the outermost container, the message to be displayed, and the icon type to be displayed (see Figure 14). The icon parameter is of type MessageBoxIcon, the enumeration we created earlier.

The method checks the type of the icon to be displayed (as indicated by the MessageBoxIcon enumeration). Accordingly, it makes use of the appropriate private variables (_questionIconUrl, _exclamationImageUrl, _informationImageUrl, or _errorImageUrl). It then forms a <TABLE> with two cells. The first cell of the table con-

tains the icon; the second cell contains the message to be displayed. The <TABLE> is then added to a dynamically created <DIV>. Finally, the <DIV> is appended to the outermost container.

ConclusionIn this first installment we started developing the Message-Box AJAX client control. The control is intended to provide functionality closely resembling a Windows message box. We developed several properties that allow us to config-ure the message box appearance. We also developed a few helper methods that will be used further. In Part II, we’ll complete the MessageBox class by adding a few more helper methods and various ShowXXXX methods. We’ll also iso-late our MessageBox class in a separate assembly for easy deployment. </>

The source code accompanying this article is available for download to asp.netPRO subscribers at www.aspnetPRO.com/download.

Bipin Joshi is the proprietor of BinaryIntellect Consulting

(www.binaryintellect.com) where he conducts premier training

programs on a variety of .NET technologies. He wears many hats,

including software consultant, mentor, prolific author, Webmaster,

Microsoft MVP, and member of ASPInsiders. Having adopted Yoga

as a way of life, Bipin also teaches Kriya Yoga. He can be reached

via his blog at www.bipinjoshi.com.

_AddIcon:function(msgbox,message,icon){var iconUrl="";if(icon==BinaryIntellect.MessageBoxIcon.Question){iconUrl=this._questionImageUrl;}if(icon==BinaryIntellect.MessageBoxIcon.Exclamation){ iconUrl=this._exclamationImageUrl; } if(icon==BinaryIntellect.MessageBoxIcon.Information) { iconUrl=this._informationImageUrl; } if(icon==BinaryIntellect.MessageBoxIcon.Error) { iconUrl=this._errorImageUrl; } var strHTML="<table cellpading=3>"; strHTML += "<tr><td valigh='top'>"; strHTML += "<img src='" + iconUrl + "'>"; strHTML += "</td><td valigh='top'>"; strHTML += message + "</td>"; strHTML += "</tr></table>"; var msgDiv=document.createElement('div'); msgDiv.innerHTML= strHTML; msgbox.appendChild(msgDiv); }

Figure 14: Adding an icon to the message box.

_AddMessage:function(msgbox,message){ var msgDiv=document.createElement('div'); msgDiv.innerHTML=message + "<br/><br/>"; msgbox.appendChild(msgDiv);}

Figure 12: Adding a message to the message box.

_AddCaption:function(msgbox,caption){ var captionDiv=document.createElement('div'); captionDiv.innerHTML=caption; Sys.UI.DomElement.addCssClass(captionDiv,this._captionCss); msgbox.appendChild(captionDiv);}

Figure 13: Adding a caption to the message box.

C o d e T a l k | Build a Message Box the AJAX Way

Page 36: Asp Aug2008

36 August 2008 | www.aspnetPRO.com

Page 37: Asp Aug2008

38 August 2008 | www.aspnetPRO.com

Begin Listing One — Public Properties of the MessageBox ControlBinaryIntellect.MessageBox.prototype ={ get_CaptionCss:function() { return this._captionCss; }, set_CaptionCss:function(value) { this._captionCss=value; }, get_BoxCss:function() { return this._boxCss; }, set_BoxCss:function(value) { this._boxCss=value; }, get_BackgroundCss:function() { return this._backgroundCss; }, set_BackgroundCss:function(value) { this._backgroundCss=value; }, get_ButtonCss:function() { return this._buttonCss; }, set_ButtonCss:function(value) { this._buttonCss=value; }, get_DialogResult:function() { return this._dialogResult; }, get_CloseCallback:function() { return this._callback; }, set_CloseCallback:function(value) { this._callback=value; }, get_QuestionImageUrl:function() { return this._questionImageUrl; }, set_QuestionImageUrl:function(value) { this._questionImageUrl=value; }, get_InformationImageUrl:function() { return this._informationImageUrl; }, set_InformationImageUrl:function(value) { this._informationImageUrl=value; }, get_ExclamationImageUrl:function() { return this._exclamationImageUrl; },

set_ExclamationImageUrl:function(value) { this._exclamationImageUrl=value; }, get_ErrorImageUrl:function() { return this._errorImageUrl; }, set_ErrorImageUrl:function(value) { this._errorImageUrl=value; }, get_Left:function() { return this._left; }, set_Left:function(value) { this._left=value; }, get_Top:function() { return this._top; }, set_Top:function(value) { this._top=value; }, get_Width:function() { return this._width; }, set_Width:function(value) { this._width=value; }, get_Height:function() { return this._height; }, set_Height:function(value) { this._height=value; }...

End Listing One

C o d e T a l k | Build a Message Box the AJAX Way

Page 38: Asp Aug2008

38 August 2008 | www.aspnetPRO.com

������������������� ��������������������������������������

�����������������������������������������

�����

�� ������ �������������� ��������������������� ������������� ��������� ��������������

��������������

����������������� �������������������

�� �������������������������

�� ���

�� ���������������������

�� ��������������������������

�� ������������������������

�� �����������������������

�� �����������������

�� �����������������

������������������������������

����������������������������������������

Page 39: Asp Aug2008

40 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 41

IncorporateI’ve heard it time and again, “I don’t need to incorpo-rate.” The reasoning often goes something like, “I just pay myself a 1099-MISC and have no liabilities like employees and such.” This is unwise. If you’re not incorporated, all your personal assets are at risk if you get sued for business-related matters. Incorporating prop-erly and following certain corporate formalities protects your personal assets from your business’ liabilities. If you get sued, the worst that could happen is that you lose your business; at least you can prevent being plunged into personal financial ruin, as well.

It’s easy to incorporate; simply contact your Secretary of State’s office and register with them. In Indiana the filing fee is only $80! The forms are readily available, and many attorneys offer these kinds of services for a relatively small investment. You will also need to obtain a Federal Tax ID from the IRS, and many larger organizations you do business with will want your Tax ID. Yes, you can give them your social security number if you don’t incor-porate, but that makes you look like a small — possibly unreliable — shop.

There’s another benefit to having all your business profits flow through your corporation: the tax rate is often much lower. Paying yourself as a contractor can push your taxes higher than 33%, but dividends from a business can be taxed at a much more digestible 18%. Still think incorporat-ing isn’t worth it? Of course, individual tax situations vary, so check with your accountant.

Make Friends with Your GovernmentState governments and the Federal government offer a multitude of free resources to answer your questions and help you run your business. Each has different require-ments for forms and processes your business must be aware of. Make friends with your government entities, especially your Secretary of State and State and Federal tax departments. Their inner workings are often complex, but they will usually have people available to address your needs if you take the time to work with them. Of course, these free services are not a complete replacement for an accountant or an attorney, but it will keep you from having to pay someone else for every business issue that arises.

§ By Auri Rahimzadeh

C o n s u l t a n t ’ s C o r n e r

Even if you’re a subcontractor, there are many

legal, financial, and marketing benefits to

incorporating your business. Most importantly,

incorporation provides “limited liability,” which means

your personal assets (other than the assets you have

invested in the corporation) are protected from liability

to third parties. Second, an incorporated entity simply

seems more legitimate. It will make it easier to land

larger projects if you project an official and stable image.

Perception can mean nearly everything when you deal

with larger organizations. There are a multitude of bases

you need to cover to get yourself properly incorporated.

I’m going to be somewhat general, so at the very least

visit the Web sites I cite. And I strongly recommend you

find an accountant and an attorney, as well.

Starting Your Business The Legal Stuff

Page 40: Asp Aug2008

40 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 41

Pay Attention to Filing Requirements!Once you take the formal step of filing incorporation papers, you must follow some additional processes. These vary from state to state, but generally include:§ Filing yearly or bi-yearly entity reports.§ Filing wage reports, even if you have no employees.§ Filing your taxes properly.§ Keeping corporate minutes and other records.

Your accountant and attorney can help with this. So can great Web sites like NoloLaw.com, AllBusiness.com, and smallbusiness.yahoo.com.

A corporation is a separate legal entity. If you don’t respect the separate legal existence of your corporation, neither will the law. You can lose the liability limitations the corporation would otherwise give you. This is called “piercing the corporate veil,” and complying with corpo-rate formalities is one important way to help prevent it.

Hire an AttorneyYou will need an attorney, or at the very least to consult a Web site like LegalZoom.com or NoloLaw.com, to draft the following documents for you (at a bare minimum; require-ments may vary from state to state, so make sure you ask

your Secretary of State or other authoritative source which other documents must be in your corporate books):§ Articles of Incorporation§ Corporate Bylaws§ Corporate Minutes§ Federal Tax Forms§ Annual or Biennial State Filings

You should also develop a relationship with a qualified corpo-rate attorney. As your business grows, so does your need for an attorney, and they will be better able to meet your legal needs with an increased understanding of your operations.

Getting Your Corporate Books in OrderYou should keep your collection of documents, includ-ing your State and Federal Tax ID documents, Articles of Incorporation, etc., in one place. This is often called a “Corporate Minute Book.” Web sites such as BizFilings.com, CorpKit.com, and MinuteBook.com afford-ably provide “Minute Book Kits” to help you keep all these documents organized. They come in both plain and fancy bindings. The kits contain most of the basics, plus a few other important items, such as Corporate Resolutions, Transfer of Stock certificates, and even a cool official embossed corporate seal.

��������������������������������������������������������������������������������������������

�� �������������������������������

�� ���������������������������������

�� �����������������������������������

�� ����������������������������������������

�� ���������������������������������������������������������

�� ����������������������������

���������������������������������������������������������������������������������������

����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

���������������������������������������

Page 41: Asp Aug2008

42 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 43

Separate Your FinancesWhen your business is paid by a client, you must keep that income in a separate bank account. Remember that “piercing the corporate veil” I discussed earlier? Well, it’s a big no-no to mix your business and personal finances. Treat them as completely separate entities. The best bet is to have your personal and business accounts at separate banks. Business checking and savings accounts are easy to open, although they usually have fees associated with them if your balances are small. Call the bank ahead of time to know which documents you should bring with you when opening an account — at a minimum they’ll likely need the State Tax ID and Federal Tax ID certificates.

Hire an AccountantUnless you’re a CPA (Certified Public Accountant) by trade — which is unlikely because you’re reading a devel-opment magazine instead of a spreadsheet — you need an accountant. A good CPA knows the ins and outs of keeping all your finances in order, and can handle your taxes at the end of the year more effectively because they know your books. Accountants also can suggest ways for you to save money, invest, grow your business, and more — all while saving your business money.

You Need InsuranceThere is no excuse for going without business insurance, whether you decide to incorporate or decide to remain a sole proprietor or unincorporated partnership. You never know when you’ll find yourself needing protection, such as from property damage after a heavy storm, or from legal liabilities from a rotten contractor. Your clients may even require you to carry certain types of insurance before they’ll let you start a project. Talk to a qualified insurance agent who can help you obtain the appropriate coverage.

At the very least, you’ll want business general liability insurance, often called “commercial general liability” or CGL. However, in the software business, you need better protection. This comes in the form of “Errors and Omis-sions” insurance, which the insurance industry calls “E&O coverage.” Because E&O insurance usually covers defects in your code and, to a certain extent, the damage those defects may cause, this coverage will cost more than your basic CGL coverage.

If you work with a lot of Web sites, or even content authored by others, you may also want Trademark and Copyright (sometimes called “Intellectual Property”) insurance to protect you from lawsuits arising out of the use of media elements you don’t own. You also can mitigate this exposure by having all your clients sign a Consulting Services Agreement that outlines their liability for any media assets they provide you — although you would still be on the hook for any media assets you use for which you don’t have rights. To be safe, make sure

you always have permission to use the media you use in your projects, regardless of whether you feel it should be free. In lieu of a Consulting Services Agreement, any engagement letter or statement of work should have a clause stating the client represents they have permission to use all content on the site, and that they hold you harmless from any liability arising out of its use. Be sure your attorney reviews or drafts this language for you.

Moving ForwardIncorporating your business gives you many benefits and, done properly, should yield a higher payout to you while protecting your personal assets. You also will likely gain the ability to lure bigger fish, who often require businesses to be incorporated and have policies against working with individual contractors.

While getting started and staying on top of the bureau-cratic requirements may seem daunting, it’s actually all pretty easy, with lots of Web sites, government agencies, attorneys, and accountants to help you along the way. As your business grows, these tasks will actually become more transparent. Get started today! </>

I’m excited about this series, and I want to make sure I’m addressing your needs. If there’s a topic you would like me to cover, or you simply have questions, please don’t hesitate to e-mail me at [email protected].

Auri Rahimzadeh is President and Senior Engineer at TAG (The

Auri Group, LLC, www.aurigroup.com), a Microsoft Gold Certified

Partner based in Indianapolis, IN. Rahimzadeh has authored three

books, including Hacking the PSP and Geek My Ride. He has been

technical editor on Wrox and Wiley titles, and has written a number

of technical articles ranging from .NET development to consumer

electronics. Auri started his technology career working for Steve

Wozniak, co-founder of Apple Computer, and enjoys writing and

teaching others about all sorts of technology.

C o n s u l t a n t ’ s C o r n e r | Starting Your Business

Page 42: Asp Aug2008

42 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 43

We first wrote about Dynamic Data in “An Introduction to Dynamic Data” in the June 2008 issue. In this follow-up article, we provide information about how to build field templates to customize the UI for displaying and editing data for specific data types. Our example shows how to use the SliderExtender control from the ASP.NET AJAX Control Toolkit in a field template. (For more information about the AJAX Control Toolkit, and to download it, see the ASP.NET Control Toolkit page on the ASP.NET Web site at www.asp.net/ajax/ajaxcontroltoolkit/.)

Introduction to Field TemplatesData-bound controls such as the GridView and DetailsView controls can automatically generate UI for displaying and edit-ing data, based on the type of data to which they are bound. (This is the behavior that you get when you set the AutoGen-erateColumns or AutoGenerateRows properties to true.) How-ever, this is an all-or-nothing option — if you want to modify the UI or behavior of even a single column (for example, by adding styles or validators), you must declare data control fields for all columns. Even then, the automatically generated controls do not offer any built-in validation support. Thus, using the GridView and DetailsView controls to write a data-bound page with customized display or edit behavior requires you to define individual columns or rows that include ASP.NET controls, then to add hard-coded validation rules

and error messages. This results in large and hard-to-main-tain pages that often have significant amounts of duplicated or very similar code. It also makes it difficult to separate the data model (the business layer) from the presentation layer.

Dynamic Data solves these problems by introducing field tem-plates. A field template is a user control that is responsible for rendering a single data-bound field. As with user controls in general, field templates can contain any number of controls to manage UI, such as TextBox, DropDownList, and Range-Validator controls. Dynamic Data project templates provide a number of field templates out of the box that create UI for displaying and editing common data types, such as Boolean, integer, and text, as well as foreign-key relation columns. Each field template can have up to three variants, which are used depending on the mode that the data control is in: read-only, edit, or insert. The variants of the field templates are identified by a naming convention. The table in Figure 1 describes each variant.

At run time, Dynamic Data picks the field template for a given column type and given mode from the available field tem-plates. For example, a string column will be displayed using the Text.ascx template in display (read-only) mode and the Text_Edit.ascx template in edit mode. If a particular variant of a field template does not exist in the project, Dynamic Data will try to choose the most appropriate fallback. For example, the default Dynamic Data project template contains

LANGUAGES: VB.NET § ASP.NET VERSIONS: 3.5

F r o m t h e S o u r c e

More on Dynamic Data Building Field Template Controls

§ By Marcin Dobosz and Scott Hunter

ASP.NET Dynamic Data is a new feature that ships

with the .NET Framework version 3.5 Service

Pack 1 (SP1). Dynamic Data allows you to rapid-

ly build a data-driven Web site with full support for create-

read-update-delete (CRUD) operations. It also supports data

validation based on the database schema, which requires

you to write only minimal code. Dynamic Data works on

top of the LINQ-to-SQL and ADO.NET Entity Framework

object-relational mapping (ORM) technologies, and it can

be extended to work with other frameworks. It relies on

templates, conventions, and metadata to deliver highly

functional, yet easily customizable Web sites.

Field Template Name Pattern Mode Behavior

FieldTemplate.ascx Read-only Displays the field in non-editing scenarios.

FieldTemplate_Edit.ascx Edit Displays the field for editing scenarios. This template should contain validation controls.

FieldTemplate_Insert.ascx Insert Optional variant of the field template for inser t scenarios. The template should contain validation controls. If this variant is not found, the edit-mode variant will be used.

Figure 1: Variants of the field templates.

Page 43: Asp Aug2008

44 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 45

F r o m t h e S o u r c e | More on Dynamic Data

an Integer_Edit.ascx field template, but it does not con-tain an Integer.ascx template. Therefore, Dynamic Data falls back to the Text.ascx template to render UI for integers in read-only mode.

By default, field templates are located in the \Dynamic-Data\FieldTemplates directory of a Dynamic Data proj-ect. As the page developer, you can modify the default templates to customize how data types are represented in the UI. You also can create your own field templates, then provide “hints” that tell Dynamic Data how to map a data field in the data model to your field tem-plate. In addition, the logic for how Dynamic Data maps data fields to field templates is fully customizable.

DynamicField and DynamicControl ClassesYou can use field templates in the auto-generate mode of properly configured GridView and DetailsView controls. To do this, place a DynamicDataManager control (a new control that ships as part of Dynamic Data) on the page and call its RegisterControl method in the page’s Init event. This con-figures the GridView or DetailsView to work with Dynamic Data. Figure 2 shows the markup for a DynamicDataManager control and a GridView control. Figure 3 shows the Page_Init handler where the GridView control is registered with the DynamicDataManager control.

In situations where you need to specify the precise order-ing or layout of the data-bound control’s fields, you can use a new type of data control field named DynamicField. The DynamicField acts as a host that automatically chooses the right field template control for rendering a field. The new DynamicControl control behaves the same way as the DynamicField class, but DynamicControl can be used in data controls that use templates to define UI. This includes templates in the FormView and ListView controls, and TemplateField instances in GridView or DetailsView controls.

Building a Custom Field TemplateThe example in this section illustrates how to build a cus-tom field template for editing integer values. It uses the SliderExtender control from the ASP.NET AJAX Control Toolkit to provide a custom UI for setting the integer value. When a page in a Dynamic Data Web site uses this field template, the result might look something like Figure 4.

To be able to use the AJAX Control Toolkit, you must add the AjaxControlToolkit.dll to the project. For a Web Site project, you can create a Bin directory and copy the file into it. For a Web Application project, use the Add Reference dialog box to add the DLL. You’ll also need to modify the web.config file by adding the tag-mapping section in the <pages><controls> section, as shown in Figure 5. This change lets you reference the controls in the AJAX Control Toolkit by using the ajaxToolkit: prefix.

To build a new field template, right-click the \DynamicData\FieldTemplates\ directory, then click Add New Item. Select Dynamic Data Field, then in the Name box, enter IntegerSlider.ascx. Click Add. This creates the IntegerSlider.ascx and IntegerSlider_Edit.ascx field templates, as well as the asso-ciated code-behind files. These files contain default versions of the read-only and edit field templates, along with simple display and edit logic. They are very similar to the Text.ascx and Text_Edit.ascx field templates. For this example, you need only a custom edit field template (that is, you do not need a read-only version of the template). Therefore, delete the IntegerSlider.ascx file from the project.

Next, open the IntegerSlider_Edit.ascx and IntegerSlider_Edit.ascx.vb files and replace the default code with the code shown in Figures 6 and 7, respectively.

Field templates must derive from the FieldTemplateUser-Control class. This parent class provides a number of helper properties and methods that perform work that is common

<asp:DynamicDataManager id="DynamicDataManager1" runat="server" /><asp:GridView id="GridView1" runat="server" />

Figure 2: Markup for DynamicDataManager and GridView controls.

Protected Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs) DynamicDataManager1.RegisterControl(GridView1)End Sub

Figure 3: The Page_Init handler where the GridView control is registered with the DynamicDataManager control.

Figure 4: A custom field template.

Page 44: Asp Aug2008

44 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 45

to all field templates. The most important of these members is the Column property, which contains information about the column with which this field template is associated. The property provides information about the column’s metadata (that is, information about the column in the data model) and provides access to the Dynamic Data abstraction of the entire data model.

The IntegerSlider_Edit.ascx markup (see Figure 6) is simple. The TextBox1 control is the main data control and contains the value that will be used for the data field on postback. Label1 is an auxiliary control that simply displays the cur-rent value of the data field as the user interacts with the slider. SliderExtender1 is the compo-nent from the AJAX Control Toolkit that turns TextBox1 into a slider. It is associated with Text-Box1 and Label1 via their IDs.

The only unfamiliar control is the Dynamic-Validator control. This is a control specific to Dynamic Data that catches any validation errors that might be thrown by the data model, then displays error messages in the UI. For example, a LINQ-to-SQL model enables you to add cus-tom validation logic using the partial extension method mechanism, as illustrated later in this article. The validation logic can throw a Vali-dationException error if a property or object fails validation. When the user submits invalid data, the DynamicValidator control catches the validation exception and displays its own error message to the user.

Field templates are designed to behave like any other data-bound control, and they there-

fore support ordinary data-binding syntax to populate values in the controls. The base FieldTemplateUserControl class provides the FieldValue property to retrieve the raw value object. The FieldValueString and FieldValueEditString properties return formatted and HTML-encoded strings for display and edit purposes, respectively. In addition, the Row property can be used to retrieve the entire data row.

The code-behind file for the field template contains initializa-tion and data-binding logic. The IntegerSlider_Edit.ascx.vb example (see Figure 7) illustrates how the slider’s minimum and maximum allowed values are specified based on meta-data about the range information that is derived from the model. The SetUpValidator method is used to configure all standard ASP.NET validators (such as RequiredValidator) as well as DynamicValidator controls with values appropriate to the data field that the template is being used to display. This includes initializing default error messages and other param-eters based on the data model’s metadata.

Because the IntegerSlider template is an edit template, during postback you must get the value that the user has entered. To do this, override the ExtractValues method defined in the IBindableControl interface that is imple-mented by the FieldTemplateUserControl class. The Extract-Values method gets the modified data and populates a dictionary with the new values. This dictionary will later be passed to a data source control that will in turn perform the appropriate update operation. The example field tem-plate also overrides the DataControl property, which can be used in pages that contain DynamicField or DynamicControl controls to obtain a reference to the actual control that is responsible for displaying the data. For example, this can be

Partial Class DynamicData_FieldTemplates_IntegerSlider_EditField Inherits System.Web.DynamicData.FieldTemplateUserControl

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Dim metadata = MetadataAttributes.OfType(Of System.ComponentModel.DataAnnotations.RangeAttribute).FirstOrDefault() If Not metadata Is Nothing Then SliderExtender1.Minimum = metadata.Minimum SliderExtender1.Maximum = metadata.Maximum End If

TextBox1.ToolTip = Column.Description SetUpValidator(DynamicValidator1) End Sub

Protected Overrides Sub ExtractValues(ByVal dictionary As IOrderedDictionary) dictionary(Column.Name) = ConvertEditedValue(TextBox1.Text) End Sub

Public Overrides ReadOnly Property DataControl() As Control Get Return TextBox1 End Get End PropertyEnd Class

Figure 7: Open the IntegerSlider_Edit.ascx.vb file and replace the default code.

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="IntegerSlider_Edit.ascx.vb" Inherits="IntegerSlider_EditField" %>

<asp:TextBox ID="TextBox1" runat="server" Text='<%# FieldValueEditString %>'

<asp:Label ID="Label1" runat="server" />

<ajaxToolkit:SliderExtender ID="SliderExtender1" runat="server" TargetControlID="TextBox1" BoundControlID="Label1" />

<asp:DynamicValidator runat="server" ID="DynamicValidator1" ControlToValidate="TextBox1" Display="Dynamic" />

Figure 6: Open the IntegerSlider_Edit.ascx file and replace the default code.

<add namespace="AjaxControlToolkit" assembly="AjaxControlToolkit" tagPrefix="ajaxToolkit"/>

Figure 5: Add tag-mapping.

Page 45: Asp Aug2008

46 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 47

F r o m t h e S o u r c e | More on Dynamic Data

used to associate a Label control declared on a page with the instance of the data control (such as a TextBox) that is declared in the field template.

Annotating the Data Model with MetadataThe IntegerSlider_Edit.ascx name does not match the naming convention used by Dynamic Data to choose the appropriate template — by default, when Dynamic Data displays editing UI for integer data, it will look for the field template named Integer_Edit.ascx. To get Dynamic Data to use the custom IntegerSlider_Edit.ascx template, you must add metadata to the data model that maps a specific data column to your new field template.

In Dynamic Data, you add metadata to the data model in the form of an associated metadata class. Figure 8 illustrates how you apply metadata for this example. The code assumes that you have a data model class named Widget that has proper-ties named LowRange and HighRange, and that you want to use the IntegerSlider_Edit.ascx field template to edit the data in this class.

The primary purpose of the Widget partial class is to pro-vide a place to apply attributes that extend the data model; therefore, it contains no actual logic. However, its name must match the name of the data-model type you want

to extend. The WidgetMetadata class in turn contains the actual logic for extending the data-model type. To extend individual data columns, you create properties in the meta-data class that match the data column names.

The MetadataTypeAttribute applied to the Widget partial class specifies the type to use as the metadata class (here, WidgetMetadata class). The attributes applied to the proper-ties of the metadata type are treated by Dynamic Data as if they were applied directly to matching properties of the actual data-model type. In this example, the LowRange and HighRange properties of the Widget class each have the RangeAttribute and UIHintAttribute attributes applied.

UIHintAttribute overrides the default field-template map-ping. In this case, Dynamic Data will try to load the IntegerSlider_Edit.ascx control when a field template is requested in order to produce UI for editing the LowRange or HighRange column values. RangeAttribute declares the range of values for a specific column. It is used by the field template initialization method to set the bounds for the SliderExtender control. RangeAttribute inherits from ValidationAttribute. The ValidationAttribute class encap-sulates validation checks. Therefore, RangeAttribute can perform its own validation checks. This ensures that even if a client is able to bypass the range limitations set by the slider UI and submit an invalid value, the submitted value will be validated on the server by RangeAttribute and result in an error. These errors will then be captured and displayed by the DynamicValidator control.

ConclusionField templates are a powerful feature that provide a compelling reason to use Dynamic Data, even in exist-ing ASP.NET Web applications. The ability to extend the data model, combined with centralized field templates, significantly reduces the need for code (and maintenance) in creating data-bound UI. By creating a suite of field templates that define the UI for your needs, you can get a sophisticated, highly functional Web application UI up and running in no time, and with very little coding. </>

Source code accompanying this article is available for down-load to asp.netPRO subscribers at www.aspnetPRO.com.

Marcin Dobosz is a developer on the ASP.NET team. He currently is

working on the Dynamic Data feature. You can find him online at

blogs.msdn.com/MarcinOn/.

Scott Hunter is a program manager on the ASP.NET team. He

currently is working on the Dynamic Data feature. Scott has been

working in the industry for more than 20 years and has spent the

past seven years building Web applications on the ASP.NET platform.

You can find him online at blogs.msdn.com/scothu/.

<MetadataType(GetType(WidgetMetadata))> _Partial Public Class WidgetEnd Class

Public Class WidgetMetadata Public ReadOnly Property Id() As Object Get Return Nothing End Get End Property

Public ReadOnly Property Name() As Object Get Return Nothing End Get End Property

<Range(50, 100)> _ <UIHint("IntegerSlider")> _ Public ReadOnly Property LowRange() As Object Get Return Nothing End Get End Property

<Range(150, 200)> _ <UIHint("IntegerSlider")> _ Public ReadOnly Property HighRange() As Object Get Return Nothing End Get End Property

End Class

Figure 8: How to apply metadata.

Page 46: Asp Aug2008

46 August 2008 | www.aspnetPRO.com asp.netPRO | August 2008 47

asp.netPRO is published monthly by Informant Communications Group, Inc., 5105 Florin-Perkins Road, Sacramento, California, 95826-4817. Basic one-year subscription rates: U.S. $34.99, Canada $44.99, all other countries $79.99, must be prepaid in U.S. dollars drawn on a U.S. bank. Printed in the USA.

Postage paid at Elk Grove, CA and additional mailing offices. POSTMASTER: Send address changes to asp.netPRO, 5105 Florin-Perkins Road, Sacramento, California, 95826-4817. Post International Publications Mail Product (Canadian Distribution) Sales Agreement No. 40028783. Subscription inquiries and orders should be directed to the Circulation Department, asp.netPRO, 5105 Florin-Perkins Road, Sacramento, California, 95826-4817, Phone 916-379-0609, Fax 916-379-0610. Code listings may be downloaded from the asp.netPRO Web site at www.aspnetPRO.com.

Informant Communications Group, Inc. assumes no responsibility whatsoever for the uses made of any software code in this issue, whether modified or not. Informant Communications Group, Inc. will not be liable for special, incidental, consequential, indirect, or other similar damages, even if we have been advised of the possibility of such damages. In no event will our liability for any damages to you or any other person ever exceed the price paid for your subscription to asp.netPRO, regardless of any form of the claim. Editorial contained within does not necessarily reflect the opinions of Informant Communications Group, Inc. Informant Communications Group, Inc. assumes no responsibility for the products or services advertised within this publication.

Copyright©2008 Informant Communications Group, Inc. All rights reserved. No part of this publication may be reproduced in any way without the written consent of Informant Communications Group, Inc. asp.netPRO is a publication of Informant Communications Group, Inc. and is not sponsored by or affiliated with Microsoft Corporation. Microsoft is not responsible in any way for the editorial policy or other contents of this publication.

We welcome your comments and suggestions about the content of asp.netPRO, as well as your commentary on the subject of ASP.NET development. We reserve the right to edit all submissions. Letters should include your name and address. Please direct all letters to asp.netPRO, ATTN: Letters, 5105 Florin-Perkins Road, Sacramento, California, 95826-4817. Letters may also be sent via e-mail to [email protected].

Informant is a registered trademark of Informant Communications Group, Inc., Elk Grove, California. Microsoft and Visual Basic are trade-marks of Microsoft Corporation and asp.netPRO is used by Informant Communications Group, Inc. under license from owner. Windows is a trademark of Microsoft Corporation. All other products mentioned within are trademarks of their respective owners.

Microsoft, Visual Basic, Visual Studio, MSDN, ASP.NET, and the Visual Studio, .NET, Microsoft Office, and Visual Basic Logos are registered trade-marks or trademarks of Microsoft Corporation in the United States and/or other countries and are used by LICENSEE under license from owner. asp.netPRO, C# PRO, Informant, Microsoft Office Solutions Conference, and ASP.NET and XML Web Services Solutions Conference are trademarks or registered trademarks of Informant Communications Group, Inc.

Writers interested in having works published in asp.netPRO may obtain a style guide by e-mailing David Riggs at [email protected]. For direct mailings/e-mailings to our subscriber list please contact Rich Parker at [email protected].

Advertising Index

/n software ................................................................................ 29

ASPOSE ...................................................................................... 7

asp.netPRO ................................................................... 15, 32, 41

asp.netPRO CD Works .............................................................. 27

ceTe Software.................................................. Inside Back Cover

CMP Media................................................................................ 39

ComponentArt..........................................................................4-5

ComponentOne, LLC .................................. Outside Back Cover

DevConnections........................................................................ 17

Developer Express.................................................. 31, 33, 35, 37

dtSearch.................................................................................... 26

FarPoint Technologies ................................................................ 3

HostMySite................................................................................ 11

Infragistics ................................................... Inside Front Cover, 1

Server Intellect .......................................................................... 14

Telerik ...................................................................................24-25

Text Control ................................................................................. 9

LINQ, ASP.NET 3.5, and C# Crossword Puzzle (continued from page 6)

All told, it was a pretty successful event, and I enjoyed it. There definitely weren’t as many people there the week I attended, but that was because the system engineers all attended the following week. It also didn’t sell out like it almost always does, but that is probably because many developers are holding off for PDC in October. I’ll be there as well, and will surely have a lot to report here for those of you who are not able to be there. In the mean-time, there is always room for improvement at Tech•Ed; hopefully Microsoft will take these suggestions to heart and act on at least some of them for next year. </>

Jonathan Goodyear is president of ASPSOFT (www.aspsoft.com), an

Internet consulting firm based in Orlando, FL. Jonathan is Microsoft

Regional Director for Florida, an ASP.NET MVP, a Microsoft Certified

Solution Developer (MCSD), and co-author of ASP.NET 2.0 MVP

Hacks (Wrox). Jonathan also is a contributing editor for asp.netPRO.

E-mail him at [email protected] or through his angryCoder eZine at

www.angryCoder.com.

Fixing Tech•Ed(continued from page 48)

Page 47: Asp Aug2008

48 August 2008 | www.aspnetPRO.com

Tech•Ed wasn’t without its warts, though, and I have assembled a list of things (in no particular order) that I would like to see fixed/implemented for next year’s event (note that I attended only developer week):§ More introductory content. With all the new technologies

Microsoft is releasing, it is very difficult for even experi-enced developers to keep up. I felt that too many of the sessions assumed we were already versed in the underlying technologies (e.g., WPF, WCF, WF, Silverlight, etc.) and jumped right in to advanced topics. In fact, there should even be a track dedicated to getting developers started on .NET. Microsoft should not forget that there are thousands of developers who still haven’t had the need or opportunity to make the switch, and may be using Tech•Ed as a jump-ing off point.

§ The abolishment of the session numbering system. Nobody knows (or pays attention to) the numbers associated with sessions. Instead, they get frustrated when they are a new-bie who accidentally ends up in a 400-level expert session or an expert who ends up in a 200-level intermediate ses-sion. Why not clearly mark the sessions using the words “Introductory”, “Intermediate”, and “Advanced”? Better yet, simply use a color coding system like red, yellow, and green. In any case, the abstract should list the skills required for one to understand the session.

§ Profile-based agendas. Not every developer who attends Tech•Ed can be pigeon-holed into a profile, but it would be nice to have starter agendas that can be customized to suit. A couple of examples of starter agendas might be “SharePoint: zero to expert” and “Moving to .NET solutions from Linux/Apache/MySQL/PHP (LAMP)”.

§ More concentration on “here and now” technologies. In my opinion, there was too much concentration on Silverlight. I realize that it is new and exciting (and has no Go Live restrictions), but it is still beta technology that most corporations won’t be able to touch for many months; maybe even a year or more. Even my recent favorite Model View Controller Framework shouldn’t really have been discussed all that much. Tech•Ed is supposed to be about technologies that you can use as soon as you get home. Leave the Greek letters to the Professional Developers Conference (PDC).

§ More power, more seating. There were precious few power outlets on the show floor and in the session rooms. There also weren’t any seats in the wireless “lounge”; only stand-up tables. That was a pretty big oversight and the area was vacant every time I went by.

§ Better keynotes. They were boring, and didn’t show real customers solving real problems with Microsoft technology. That would have gone over better, in my opinion.

§ Where were all the snacks? The snacks were very hard to find, which was a disappointment. It was probably a good thing for my waistline, though — an unlimited supply of ice cream bars is a dangerous thing.

§ The attendee party needs to be somewhere OTHER than Universal Studios, where it has been for the last three years. It was also a big downer (and I’m not sure if Micro-soft controlled this) that half of the park was closed off.

It certainly wasn’t all bad at Tech•Ed. Here are a few exam-ples of things that Microsoft did right:§ Booths staffed by actual dev team members. This was a

great opportunity to ask deep questions to people who actually have the answers.

§ Whiteboards everywhere. These were great for impromptu arguments, um, I mean discussions.

§ The interactive theaters were great for smaller sessions with more (you guessed it) interaction with the speakers.

§ The atmosphere seemed upbeat and was geared toward social interaction. That’s a very good thing, as it gets the attendees talking to each other, as well as with the speakers and Microsoft staff.

§ By Jonathan Goodyear

B a c k D r a f t

Iattended Tech•Ed again this year. It was held in

my hometown of Orlando, Florida (as usual), so it

makes for an easy conference for me to get to. This

year was a bit different in that they spread the confer-

ence over two weeks; one dedicated to developers and

one dedicated to systems engineers. I think this was a

good idea, as it allowed Microsoft to focus on these two

unique audiences better.

Fixing Tech•Ed

“Fixing Tech•Ed” continued on page 47

Page 48: Asp Aug2008

48 August 2008 | www.aspnetPRO.com

������������������������������������������������������������������������

����������������������������������������������������������������������������������������������

����������������������������������������������������������������������������������������

�����������������������������������������������������������������������������������

�����������������������������������������������������������������������������������������������������������������

�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

���������������������������������������������������������������������������

����������������������������������������������������������������������������������������

������������������������������������������������������������������������������

��������������������

������������������

����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

��������������� ��������������������������������������������� �����������������

���������������������������������������������������������������������������������������������������������������������������������������������������

����������������������������������������������������

����������������������������������������������������������������������������

���������������������������������������������������������������������

��

��

��

���

������������������������������������������������

Page 49: Asp Aug2008

������������������������������������������������������