Saturday, September 30, 2006

Short Update

It's been quite a while since my last post so I thought I'd provide a quick update on what's been happening in my life and taking up all my time.

First off, I have two Uni assignments due next week. The first assignment is on design patterns and I need to write a book review on a patterns related book (I've chosen to use the Smart Client Architecture and Design Guide and base my review around the "Model-View-Controller" pattern) as well as illustrating the Transaction Script, Domain Model and Table Module patterns (as discussed in the book Patterns of Enterprise Application Architecture by Martin Fowler) using code, class diagrams, interaction diagrams and text. The second assignment is on providing programming solutions for exercises contained within the first 3 chapters of C# by Dissection by Ira Pohl. Assignment 2 is pretty easy, even for a C# newbie like me. Assignment 1 on-the-other-hand is proving to be quite a challenge, especially considering that I don't like books with more than 1 page!

I've also been studying for 70-529 (TS: Microsoft .NET Framework 2.0 - Distributed Application Development) which I sat and passed last Tuesday.

Work is what's really been taking up all my time as we're in the final stages of releasing a new version of our product (ASISCaseManager) and finalising two big contracts with NSW Maritime and NZ Post. Will be glad when we're not as busy as working very long hours and then coming home and spending 3-4 hours studying for Uni and MS certification is knocking me around a bit.

Oh, I forgot that I've also been fairly busy organising the Canberra SQL Server Users Group; in particular transport for our members to attend SQL Down Under Code Camp being held on 7/8th October 2006 at Charles Sturt University.

As you can see, I've been pretty busy and I'm really looking forward to the Xmas break.

For all those waiting for Part 2 of "Using XML to Pass Parameters to SQL Server Stored Procedures", I haven't forgotten about you and hope to have it posted in the next week.

Anyway, back to study it is.

Cheers
Jeff

P.S. You little beauty. The West Coast Eagles beat the Sydney Swans in the AFL Grand Final. The next best thing to Geelong winning!

Wednesday, September 20, 2006

Sat 71-540 Today

Sat 71-540 today and I have to say congratulations to Microsoft for putting together such a great exam. An exam that I believe most people won't be able to pass just by reading a few books.

The spread of questions across the various technologies covered in the Preparation Guide was good and the time given to complete the exam was spot-on (for me!). I have to admit, there were a few questions that had me wondering "What was the person smoking when they wrote this question?" and a few that had me completely stumped. Amazing how you think you know something but really don't.

So, the million dollar question is;"Do I think I passed"? I don't believe so. I think I will come close, probably in the range of 630-680. Oh well, it was a great experience and now I have some more topics to research.

Tuesday, September 19, 2006

Getting started with SQL Server 2005 Everywhere Edition

While doing some research for the 71-540 Beta Exam, I stumbled across a great post by Bart De Smet [MVP Visual C#] on "Getting started with SQL Server 2005 Everywhere Edition".

Besides providing a general overview of what SQL Server 2005 Everywhere Edition (SSEv) is, Bart has included some C# code examples on how to:

  • Create a Database
  • Define a Database Schema
  • Use a SSEv Database.
Bart also provides a good example on how to encrypt and store Database passwords using the ProtectedData class to overcome the limitation of SSEv not being able to use SecureString.

This post, and many others, are well worth reading.

Friday, September 15, 2006

Having Fun At Tech-Ed 2006 (Australia)

 

(Left) Laird, Tom, Me and Warren

Shaun

Champage

Home Time :-)

Wise Guy's

Wow that was a great Tech-Ed

Wednesday, September 13, 2006

Using XML to Pass Parameters to SQL Server Stored Procedures - Part 1a

Since posting Part 1, I've had a number of people request to see the code used to submit XML to SQL Server; so, here it is.


Example

NOTE: The following code uses the Data Access Application Block (DAAB) which is part of the Enterprise Library for .NET Framework 2.0. If you intend to play with this code in your environment, you will need to download and install the Enterprise Library first.

When developing any application, one of your goal's should be to limit the data flowing across the wire. Without starting a debate about the use of Typed Datasets vs. Untyped Datasets vs. Data Transfer Objects (DTO's), the biggest mistake I see developers doing is retrieving and sending unnecessary data rows to/from the database. By this I mean using SELECT statements without a where clause (or wrongly constructed where clauses) and filtering the data on the client or sending all rows back to the database when only one row was updated. This practice may seem fine when your application is only supporting a hand-full of users and they are all connecting via LAN, but when you try and implement this using Windows Mobile, remotely connected Smart Client's or end up deploying to a large user base, your application will more than likely grind to a halt.

By far the easiest way to ensure that you only send updates to the database if changes have actually been made to data on the client is to check the HasChanges() property of the dataset. If HasChanges() returns true, you should then call GetChanges() which will return a child dataset containing all changes made since the parent dataset was last loaded or since AcceptChanges() was last called. The child dataset returned from GetChanges() is what you should send to the database, not the parent dataset.

The code to implement this checking and retrieval of changed rows is very simple:

VB.NET

If thisDS.HasChanges Then

'SaveData accepts a dataset and it's code will be explained below.

SaveData(thisDS.GetChanges)

End If

C#

if (thisDataSchema.HasChanges())
{

//SaveData accepts a dataset and it's code will be explained below.

SaveData(thisDataSchema.GetChanges());

}

Once you ascertain that changes have been made on the client and decide to submit them to the database for processing, you simply create a connection to the database, create a DbCommand for the stored procedure, create an "In" DbParameter object to to pass your XML to the database and then issue the appropriate execute command of the DBCommand object. Because we are not retrieving any data from the database as part of our update, we use ExecuteNonQuery instead of ExecuteDataSet.

Therefore, the code to perform our update looks like this:

VB.NET

Private Sub SaveData(thisDS as DataSet)

' Method for invoking a default Database object using the DAAB. Reads default settings from the app.config file.
Dim db As Database = DatabaseFactory.CreateDatabase()

' Creates a DbCommand for a stored procedure using the DAAB.
Dim dbCommand As Common.DbCommand = db.GetStoredProcCommand("usp_UpdateCaseDetails")

' Object thisDS is the dataset that contains the data you wish to save. FixXML is the function that fixes the UTC datetime and Typed DataSet issues discussed in Part 1

' Adds a new In DbParameter object to the given command.
db.AddInParameter(dbCommand, "@dsXML", DbType.Xml, FixXML(thisDS))

' Note: Connection was closed by ExecuteNonQuery method call
db.ExecuteNonQuery(dbCommand)

db = Nothing

End Function

C#

public void SaveData(DataSet thisDS)
{

// Method for invoking a default Database object using the DAAB. Reads default settings from the app.config file.
Database db = DatabaseFactory.CreateDatabase();

// Creates a DbCommand for a stored procedure using the DAAB.
DbCommand dbCommand = db.GetStoredProcCommand("usp_UpdateCaseDetails");

/* Object thisDS is the dataset that contains the data you wish to save. FixXML is the function that fixes the UTC datetime and Typed DataSet issues discussed in Part 1
*/

// Adds a new In DbParameter object to the given command.
db.AddInParameter(dbCommand, "@dsXML", DbType.Xml, FixXML(thisDS));

// Note: connection was closed by ExecuteNonQuery method call
db.ExecuteNonQuery(dbCommand);

db = null;

}

The app.config settings used for the above code are as follows:

<configuration>

<configSections>

<section name = "dataConfiguration" type = "Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data" />

</configSections>
<connectionStrings>

<add name = "CANBUG" connectionString = "server = (local)\sqlexpress;database = CANBUG;Integrated Security = true" providerName = "System.Data.SqlClient" />

</connectionStrings>

<dataConfiguration defaultDatabase = "CANBUG"/>

</configuration>

That's it. Your changes have been sent to the database.

Of course you'd implement a proper Data Access Tier and error handling to catch any data processing errors returned from the database, but for simplicity and ease of demonstration, SaveData() has been implemented in the client and no error handling has been included.

Cheers
Jeff

Monday, September 11, 2006

Just sat 71-500

Well, I've just got back from sitting 71-500 and can say that it was a very satisfying experience.

Obviously I can't say much due to the NDA, however as the title suggests, this is an exam about deploying and provisioning mobile devices and support infrastructure. Probably not a good exam for a developer to sit :-) That said, it does provide some grounding in why/how you do some of the things covered in 71-540.

Anyway, not sure how I went as after the first review I thought "I've nailed it". After the second review I thought 'I've failed it". I'll let you know when I get my results in 8 weeks.

Time to study for 71-540 which I'm sitting at 1pm on Wednesday 20th September 2006.

Cheers
Jeff

Saturday, September 09, 2006

Using XML to Pass Parameters to SQL Server Stored Procedures - Part 1

One of the things that I really hate doing as a developer is passing lots of parameters to stored procedures. The main reason why I hate doing this is because I’m lazy. I can’t be bothered creating the stored procedure with all the parameters and then having to modify the parameters when I add or remove a field in a table. I also hate creating the code to pass the parameters to the db and subsequently modifying it when db changes are made.

Over the years I've experimented with different techniques for passing parameters to make my life easier. Most of these have worked out fine and others have been a real pain in the backside. When SQL Server 2000 was released, I started using XML to pass parameters to stored procedures. To date, I am still using this method.

I've modified the way I do things for SQL Server 2005 to use the new XML Data Type (instead of nvarchar) and to handle XML created via typed datasets. I've also had to make some minor changes to my application code to handle a peculiar problem caused by the way datetime fields are formatted in .Net 2.0.

Below is a very simple example of how to use XML to pass parameters to SQL Server stored procedures. This example also illustrates some of the annoyances with using XML to insert data into SQL Server and I will highlight these when we come to them.


A sample application can be downloaded from here to illustrate what is discussed below

Example


First off we need to create a simple DB with a table and a stored procedure to retrieve data from the table.

-- *** Create database
USE master
GO
CREATE DATABASE [CanbUG]
GO
USE CanbUG
GO


-- *** Create table
CREATE TABLE [dbo].[CaseDetails]
(

[CaseID] [int] IDENTITY(1,1) NOT NULL,
[CaseName] [varchar](50),
[RegistrationDate] [datetime],
[Notes] [varchar](max),
[DateLastModified] [datetime],
CONSTRAINT [PK_CaseDetails] PRIMARY KEY NONCLUSTERED

(
[CaseID] ASC
)
) ON [PRIMARY]


GO


-- *** Create Select stored Procedure
CREATE PROCEDURE [dbo].[usp_GetCaseDetails]
AS

SELECT CaseID, CaseName, RegistrationDate, Notes, DateLastModified
FROM dbo.CaseDetails
ORDER BY RegistrationDate

GO

Next we’ll insert a record into our newly created table and execute the “usp_GetCaseDetails” stored procedure to ensure everything is working fine so far.

-- *** Insert some test data
INSERT INTO CaseDetails
VALUES('Start Here','05/09/2006','Here we go','05/09/2006')

EXEC [dbo].[usp_GetCaseDetails]

In a minute we will create an insert stored procedure to insert records into our “CaseDetails” table using XML. Firstly, we need to see how to format our XML and an easy way to do this is to execute the following SQL statement:

-- *** Retrive XML
SELECT CaseID, CaseName, RegistrationDate, Notes, DateLastModified
FROM CaseDetails
ORDER BY RegistrationDate
FOR XML AUTO, ELEMENTS

Auto mode returns query results as nested XML elements. The ELEMENTS directive constructs XML in which each column value maps to an element in the XML. I have chosen this XML format as it is the default format used by a .Net 2.0 dataset when you issue the GetXML method. Your XML should look something like this:

<CaseDetails>
<CaseID>1</CaseID>
<CaseName>Start Here</CaseName>
<RegistrationDate>2006-05-09T00:00:00</RegistrationDate>
<Notes>Here we go</Notes>
<DateLastModified>2006-05-09T00:00:00</DateLastModified>
</CaseDetails>


Now let’s create the insert stored procedure and use it to insert another record.

-- *** Create Insert stored Procedure
CREATE PROCEDURE [dbo].[usp_InsertCaseDetails] @dsXML as xml

AS

DECLARE @docHandle int

EXEC sp_xml_preparedocument @docHandle OUTPUT , @dsXML


INSERT INTO CaseDetails
SELECT CaseName, RegistrationDate, Notes, DateLastModified
FROM OPENXML(@docHandle , N'/CaseDetails',2)
WITH CaseDetails


EXEC sp_xml_removedocument @docHandle

GO

-- *** Insert some more data
DECLARE @dsXML xml

SET @dsXML = '
<CaseDetails>
<CaseName>Test Case 1</CaseName>
<RegistrationDate>2006-04-20T00:00:00</RegistrationDate>
<Notes>This is my first Test Case</Notes>
<DateLastModified>2006-04-20T00:00:00</DateLastModified>
</CaseDetails>'

EXECUTE [CanbUG].[dbo].[usp_InsertCaseDetails] @dsXML

EXEC [dbo].[usp_GetCaseDetails]

GO

The key function in the “usp_InsertCaseDetails” stored procedure is OPENXML. OPENXML provides a rowset view over an XML document. Because OPENXML is a rowset provider, OPENXML can be used in Transact-SQL statements in which rowset providers such as a table, view, or the OPENROWSET function can appear. To use OPENXML, you need to firstly execute the function"sp_XML_preparedocument" which returns a handle that can be used to access the newly created internal representation of the XML document. This handle is then passed into the OPENXML function as the "idoc" argument.

Ok, so far we have created a DB called “CanbUG”, a table called “CaseDetails”, two stored procedures called “usp_GetCaseDetails” and “usp_InsertCaseDetails” and inserted two rows of data; one of which was inserted using XML. Now we need to create our update stored procedure. This is where we come to our first annoying factor about using XML in SQL Server.

Looking at the “usp_InsertCaseDetails” stored procedure, and doing a little bit of reading on the OPENXML function, you’ll probably come to the conclusion that the update stored procedure would look something like this:

-- *** Create Update stored Procedure

CREATE PROCEDURE [dbo].[usp_UpdateCaseDetails] @dsXML as xml
AS

DECLARE @docHandle int

EXEC sp_xml_preparedocument @docHandle OUTPUT , @dsXML

UPDATE CaseDetails
SET CaseName = DataXML.CaseName,
RegistrationDate = DataXML.RegistrationDate,
Notes = DataXML.Notes,
DateLastModified = DataXML.DateLastModified
FROM OPENXML(@docHandle , N'/CaseDetails',2)
WITH CaseDetails DataXML
WHERE CaseDetails.CaseID = DataXML.CaseID

EXEC sp_xml_removedocument @docHandle

If so, you’re pretty close. The only problem is that CaseID is an Identity column which means that for some unknown reason, this column is not made available when using “TableName” as the value for the “with” argument. If you try to create this stored procedure, you’ll receive the following error which is rather misleading and annoying as the CaseID column does exist in both the table and the XML:

Msg 207, Level 16, State 1, Procedure usp_UpdateCaseDetails,

Line 15 Invalid column name 'CaseID'.

After many hours of reading documentation and various forums posts, I finally realise that I haven’t made a mistake in my stored procedure and that this is another one of Microsoft’s famous “it works that way by design” features.

Now there are two ways around this “bug”, one is to use a “SchemaDeclaration” instead of a “TableName” as the value for the “with” argument:


WITH (CaseID INT, CaseName VARCHAR(50), RegistrationDate datetime, Notes varchar(max), DateLastModified datetime) DataXML

and the other is to modify the where clause to look like this:

WHERE CaseDetails.CaseID = @dsXML.value('(/CaseDetails/CaseID)[1]', 'INT' )

I know which one I’d prefer to use, especially if my table contained 20 or 30 columns. Besides, the first option reminds me of passing parameters to stored procedures so I'm just replacing one annoyance with another and gaining nothing.

Now let’s create the update stored procedure and test if it works by updating some data.

CREATE PROCEDURE [dbo].[usp_UpdateCaseDetails] @dsXML as xml
AS

DECLARE @docHandle int

EXEC sp_xml_preparedocument @docHandle OUTPUT , @dsXML

UPDATE CaseDetails
SET CaseName = DataXML.CaseName,
RegistrationDate = DataXML.RegistrationDate,
Notes = DataXML.Notes,
DateLastModified = DataXML.DateLastModified
FROM OPENXML(@docHandle , N'/CaseDetails',2)
WITH CaseDetails DataXML
WHERE CaseDetails.CaseID = @dsXML.value('(/CaseDetails/CaseID)[1]', 'INT' )

EXEC sp_xml_removedocument @docHandle


GO


-- *** Update record
DECLARE @dsXML xml

SET @dsXML =

'<CaseDetails>

<CaseID>2</CaseID>

<CaseName>Test Case 1</CaseName>

<RegistrationDate>2006-04-20T00:00:00</RegistrationDate>

<Notes>Our new data</Notes>

<DateLastModified>2006-04-20T00:00:00</DateLastModified>

</CaseDetails>'

EXECUTE [CanbUG].[dbo].[usp_UpdateCaseDetails] @dsXML

EXEC [dbo].[usp_GetCaseDetails]

You’ll see from the returned records that the data in our table has been updated successfully.



When you use a typed dataset to store your data on the client side and then issue the GetXML method of the dataset to retrieve the XML, the format of the XML is a little different than that shown above. If the typed dataset is called dsCaseDetails, the XML turns out looking like this:


<dsCaseDetails xmlns="http://tempuri.org/dsCaseDetails.xsd">

<CaseDetails>

<CaseID>1</CaseID>

<CaseName>Start Here</CaseName>

<RegistrationDate>2006-05-09T00:00:00+11:00 </RegistrationDate>

<Notes>Here we go</Notes>

<DateLastModified>2006-05-09T00:00:00+11:00 </DateLastModified>

</CaseDetails>

</dsCaseDetails>

As you can see, the DatasetName and Namespace of the typed dataset have been appended to the XML. You may have also noticed that datetime fields have the value +11:00 appended to them. This is a UTC formated date and the +11:00 represents my timezone. Yours may be different.


If we try to pass this XML into our “usp_UpdateCaseDetails” stored procedure, nothing gets updated as the structure of the XML has changed and our OPENXML statement does not recognize this structure. There are basically two ways to get our update stored procedure working again. I use Method 2 as it makes our stored procs easier to understand and because of another fix we need to implement to address the UTC datetime values (more on this in a while).

Method 1



Modify the stored procedure to include the namespace and a namespace alias (in this case dsCD). Notice that we have to revert to using the "SchemaDeclaration" value for the "with" argument.

-- *** Alter Update stored Procedure for Schema
ALTER PROCEDURE [dbo].[usp_UpdateCaseDetails] @dsXML as xml
AS

DECLARE @docHandle int
EXEC sp_xml_preparedocument @docHandle OUTPUT , @dsXML, '<root xmlns:dsCD="http://tempuri.org/dsCaseDetails.xsd"/>'

UPDATE CaseDetails
SET CaseName = [dsCD:CaseName],
RegistrationDate = [dsCD:RegistrationDate],
Notes = [dsCD:Notes],
DateLastModified = [dsCD:DateLastModified]
FROM OPENXML(@docHandle , '//dsCD:CaseDetails',2)
WITH ([dsCD:CaseID] INT, [dsCD:CaseName] VARCHAR(50), [dsCD:RegistrationDate] datetime, [dsCD:Notes] varchar(max), [dsCD:DateLastModified] datetime)
WHERE CaseDetails.CaseID = [dsCD:CaseID]

EXEC sp_xml_removedocument @docHandle

GO

Method 2

Add one line of code to your application to slightly modify the XML being passed back to the DB:

myXML = Replace(dsCaseDetails.GetXML, "xmlns=", "xmlns:" & dsCaseDetails.DataSetName & "=")

resulting in XML that looks like this:

<dsCaseDetails xmlns:dsCaseDetails="http://tempuri.org/dsCaseDetails.xsd">

<CaseDetails>

<CaseID>1</CaseID>

<CaseName>Start Here</CaseName>

<RegistrationDate>2006-05-09T00:00:00+11:00</RegistrationDate>

<Notes>Here we go</Notes>

<DateLastModified>2006-05-09T00:00:00+11:00</DateLastModified>

</CaseDetails>

</dsCaseDetails>

and modify the OPENXML lines of the stored procedure to look like this:

FROM OPENXML(@docHandle , N'/dsCaseDetails/CaseDetails',2)
WITH CaseDetails DataXML
WHERE CaseDetails.CaseID = @dsXML.value('(/dsCaseDetails/CaseDetails/CaseID)[1]', 'INT' )

That fixes the issue relating to the typed dataset, when you run the application and press on the save button, you will get the following error:

Msg 241, Level 16, State 1, Procedure usp_UpdateCaseDetails

Conversion failed when converting datetime from character string.

The first thing that comes to mind is that you must be using the wrong data to update your fields so you’ll spend countless hours trying to figure out what the heck is going on. Well, the cause of this problem is another one of Microsoft’s “it works that way by design” features.

In .Net 2.0, timezone information is appended to all datetime fields of a dataset. This is supposed to help with internationalization as the dataset will automagically adjust datetime values to reflect what the value should represent in a new timezone. Sounds like a great idea but the OPENXML function of SQL Server doesn't process this information, resulting in the above error. The strange thing is that SQL Server itself has no problem with this datetime format as it will allow you to copy one of the datetime values in the above XML and paste it directly into the relevant column of the table. Therefore, I assume this is a bug with the OPENXML function.

To get around this problem, I had to implement a Regular Expression in my code to strip out the timezone information so that OPENXML would parse the XML correctly. The code used was leveraged from an article written by Craig Geil's (How to fix DateTime values after .NET Xml Serialization) and modified to meet my requirement. The new function also implements the fix for the typed dataset issues raised above.

Private Function FixXML(ByVal ds As DataSet) As String

Dim fixedString As String
Dim sRegex As String
Dim xmlString As String

sRegex = "(?<DATE>\d{4}-\d{2}-\d{2})(?<TIME>T\d{2}:\d{2}:\d{2}\.{0,1}[\d]{0,3})[\d]*[/+-](?<HOUR>\d{2})(?<LAST>:\d{2})"

Dim r As Regex = New Regex(sRegex)
Dim myEvaluator As MatchEvaluator = New MatchEvaluator(AddressOf getHourOffset)

xmlString = ds.GetXml
fixedString = r.Replace(xmlString, myEvaluator)

fixedString = Replace(fixedString, "xmlns=", "xmlns:" & ds.DataSetName & "=")


Return fixedString

End Function

Private Function getHourOffset(ByVal m As Match) As String

Return m.Result("${DATE}" + "${TIME}")

End Function

Now if you run the application and save your changes again, you’ll see that the data is updated correctly. This code works just as well if you create an assembly and host it in SQL Server. All you need to do is call the function in your stored procedure just before you issue the "sp_xml_preparedocument" function. We've implemented it in our data access layer as we had concerns that most DBA's probably won't allow CLR to be enabled on their servers.


Conclusion

XML is a very poverful and flexible standard that can be used for all types of information exchange. In this instance, it is being used as a simple means of passing parameters to stored procedures.

In Part 2, I will show you how to use the same method to pass multiple rows of data to the database in one transaction; a process that not only reduces trips across the wire, but makes it a breeze to synchronise changes when your smart client application reconnects to it's source.

Cheers
Jeff

Feedburner

Rob persuaded me to use feedburner for my RSS feed. So feel free to change your subscription to http://feeds.feedburner.com/blogspot/whartonj. The old one will keep working of course.

Adam Cogan presenting in Canberra this week




Reporting Services
Tuesday, 12th September 2006 5:00pm - 7:00pm

Location: Microsoft Office,
Level 2, 44 Sydney Ave, Canberra




Up and Running with Microsoft SQL Server 2005 Reporting Services

OK, so you know about how the new powerful reporting platform from Microsoft will change the landscape of enterprise reporting. Come and see Sydney based SQL Guru and MS Regional Director Adam Cogan show the developer features of this latest addition to the Microsoft SQL Server family of products.

You will see real world examples of this server-based platform when used for creating, managing and delivering both traditional, paper-oriented reports and interactive, Web-based reports. Reporting Services 2005 combines the data management capabilities of SQL Server and Microsoft Windows Server with familiar and powerful Microsoft Office System applications to deliver real-time information to support daily operations and decisions.

Twelve Tips for Better Reporting Services

Reporting Services makes viewing your data a breeze and SQL Server 2005 brings database reporting to a whole new level. In this session, you will learn how to take full advantage of the new Report Designer that is integrated into Visual Studio 2005. We will discuss the core product improvements, reporting improvements, the better integration and the richer developer experience.

Come and see Adam show the right and wrong ways to develop reports and show data to users.

More information: www.sqlserver.org.au/Events/ViewEvent.aspx?EventId=186

Wednesday, September 06, 2006

More 71-500 and 71-540 Study Material

Apart from reading copious amounts of text, I've been slowly working through a number of Mobile and Embedded HOL's from Tech-Ed 2006.

Now that I've been advised it's ok to share them around and the fact that Chuck has posted a link to these, and a number of other HOL's, on his blog (http://blogs.msdn.com/charles_sterling/archive/2006/09/05/740899.aspx), I thought that you might enjoy doing them as well.

Supporting files for some of the labs are not available, however with a little creativity you can create your own.

Hope you enjoy them as much as I have.

Sunday, September 03, 2006

71-540 Study Material

First off, Happy Fathers Day to all the fathers out there. I know I've had a great day so far and I hope you guys (and families) are having a great day too.

I've decided to put up what research I've completed so far as this is a pretty huge study guide and it's taking forever to complete.

As with my post on the 71-500 Study Material, some of these resources may not be an exact fit with the preparation guide topic, but at least they provide some background on the topic which should be enough to help me pass the exam (hopefully!).

I have provided my research below to assist others with exam preperation, however I give no guarantee that these linked resources will result in passing the exam. It is provided as is and as a supplement to any study you may already be doing. If anyone using this guide finds a mistake or a resource that better explains the topic, please let me know and I'll update this blog.


71-540 Microsoft Windows Mobile 5.0 App Development

General How-To Topics

General Code Samples

.NET Compact Framework FAQ

Developing Mobile Applications by Using the Microsoft .NET Compact Framework 2.0

Manage data in a .NET Compact Framework 2.0 application by using .NET Compact Framework 2.0 system types. (
Refer System namespace)

Manage a group of associated data in a .NET Compact Framework 2.0 application by using collections. (Refer System.Collections namespace)

Improve type safety and application performance in a .NET Compact Framework 2.0 application by using generic collections. (Refer System.Collections.Generic namespace)

Manage data in a .NET Compact Framework 2.0 application by using specialized collections. (Refer System.Collections.Specialized namespace)

Implement .NET Compact Framework 2.0 interfaces to cause components to comply with standard contracts. (Refer System namespace)

Control interactions between .NET Compact Framework 2.0 application components by using events and delegates. (Refer System namespace)

Develop multithreaded .NET Compact Framework 2.0 applications. (Refer System.Threading namespace)

Implement reflection functionality in a .NET Compact Framework 2.0 application. (Refer System.Reflection namespace)

Enhance the text-handling capabilities of a .NET Compact Framework 2.0 application (Refer System.Text namespace), and search, modify, and control text within a .NET Compact Framework 2.0 application by using regular expressions. (Refer System.RegularExpressions namespace)