Framework: Defensive Development Deborah Kurata Consultant InStep Technologies, Inc.
-
Upload
david-miles -
Category
Documents
-
view
221 -
download
0
description
Transcript of Framework: Defensive Development Deborah Kurata Consultant InStep Technologies, Inc.
DEV353 .NET Framework:Defensive Development
Deborah KurataDeborah KurataConsultantConsultantInStep Technologies, IncInStep Technologies, Inc
Defensive Development?A set of coding techniques for A set of coding techniques for minimizing application failure?minimizing application failure?
OROR
Security techniques for protecting your Security techniques for protecting your application against hackers?application against hackers?
Deborah Kurata Is...Author of:Author of:
““Doing Objects in VB 6.0”Doing Objects in VB 6.0”““Doing Web Development”Doing Web Development”““Best Kept Secrets in .NET”Best Kept Secrets in .NET”““Doing Objects in .NET” (coming soon!)Doing Objects in .NET” (coming soon!)
Software designer and developerSoftware designer and developerINETA Speakers BureauINETA Speakers BureauMicrosoft MVPMicrosoft [email protected]@insteptech.com
InStep Technologies Is...ConsultingConsulting
Strategic technology consulting, Strategic technology consulting, mentoring and training servicesmentoring and training servicesSoftware architecture and designSoftware architecture and designCustom software development for the Custom software development for the desktop and the Internetdesktop and the InternetKick-start services to get you started Kick-start services to get you started and keep you goingand keep you going
TrainingTrainingwww.insteptech.comwww.insteptech.com
You Are...Using a defined set of programming Using a defined set of programming standards?standards?Implementing exception handling Implementing exception handling in your applications?in your applications?Logging exceptions?Logging exceptions?Using a Unit Testing tool?Using a Unit Testing tool?Implementing advanced security Implementing advanced security features in your applications?features in your applications?
Defensive Development Is…Anticipating where failures can occurAnticipating where failures can occurCreating an infrastructure that Creating an infrastructure that mitigates failuresmitigates failuresUsing damage-control techniques to Using damage-control techniques to manage failuresmanage failuresUsing notification techniques to collect Using notification techniques to collect information useful for diagnosing information useful for diagnosing failures when they do occurfailures when they do occur
This Session Is...
7 defensive development 7 defensive development practices for .NETpractices for .NET
OROR
7 “walls” for defending your 7 “walls” for defending your application against failureapplication against failure
Anticipating Failures
Common Failure PointsDesign errorsDesign errorsUnauthorized application accessUnauthorized application accessUser entryUser entryBad data (from database or other feed)Bad data (from database or other feed)Coding errorsCoding errorsThird-party controlsThird-party controlsDatabase errors (concurrency, timeout)Database errors (concurrency, timeout)Unanticipated system crashesUnanticipated system crashesUnanticipated system attacksUnanticipated system attacks
Threat Modeling1.1. Identify your assetsIdentify your assets
Find out what hackers could wantFind out what hackers could want2.2. Create an architecture overviewCreate an architecture overview
Identify common technology-specific threatsIdentify common technology-specific threats3.3. Decompose the applicationDecompose the application
Trust boundaries, data flow, and entry pointsTrust boundaries, data flow, and entry points4.4. Identify the threatsIdentify the threats
Network, host, and application threatsNetwork, host, and application threats5.5. Document the threatsDocument the threats
Description, target, techniques, countermeasuresDescription, target, techniques, countermeasures6.6. Rank the threatsRank the threats
DREAD modelDREAD model
DREAD ModelDamage potentialDamage potentialReproducibilityReproducibilityExploitationExploitationAffected usersAffected usersDiscoverabilityDiscoverabilityMore information in MSDN Patterns More information in MSDN Patterns and Practicesand Practiceshttp://msdn.microsoft.com/library/en-us/dnnhttp://msdn.microsoft.com/library/en-us/dnnetsec/html/ThreatCounter.aspetsec/html/ThreatCounter.asp
Creating An Infrastructure: Building The Seven Walls
1st Wall Of Defense:Application Design
Define a methodology for the designDefine a methodology for the designDocument the designDocument the design
List the scenarios and business rulesList the scenarios and business rulesConsider installation and security issuesConsider installation and security issues
Ensure the users review and approve Ensure the users review and approve the designthe design
Best done with the user interface designBest done with the user interface designProvide a conduit for getting design Provide a conduit for getting design questions answeredquestions answered
2nd Wall Of Defense:Application Security
Ensure your application has the proper Ensure your application has the proper security mechanismssecurity mechanisms
Username, passwordUsername, passwordRequirements depend on the deploymentRequirements depend on the deployment
Internet versus Intranet versus Smart ClientInternet versus Intranet versus Smart ClientRequirements depend on the applicationRequirements depend on the application
Catalog application versus bank applicationCatalog application versus bank applicationRequirements may be different for different Requirements may be different for different features of the applicationfeatures of the application
Catalog feature versus purchase featureCatalog feature versus purchase feature
Password TipsUse a one-way hashUse a one-way hashUse a salt valueUse a salt value
Salt is pre-pended to the encrypted keySalt is pre-pended to the encrypted keyIncreases the work required to mount a brute-Increases the work required to mount a brute-force (dictionary) attackforce (dictionary) attack
public static String ComputeHash(string textToHash)public static String ComputeHash(string textToHash){{ SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider();SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider(); byte[] byteValue = System.Text.Encoding.UTF8.GetBytes(textToHash);byte[] byteValue = System.Text.Encoding.UTF8.GetBytes(textToHash); byte[] byteHash = SHA1.ComputeHash(byteValue);byte[] byteHash = SHA1.ComputeHash(byteValue); SHA1.Clear();SHA1.Clear(); return Convert.ToBase64String(byteHash);return Convert.ToBase64String(byteHash);}}
3rd Wall Of Defense: User Entry Validation
Validate the data entered by the usersValidate the data entered by the usersRestrictionRestriction
Using controls to prevent invalid entryUsing controls to prevent invalid entryDate controls, masked edit controls, etc.Date controls, masked edit controls, etc.
ValidationValidationUsing code to verify user’s entry is validUsing code to verify user’s entry is validValidating event (WinForms)Validating event (WinForms)Client-side validation (WebForms)Client-side validation (WebForms)
User Entry ValidationWeb ApplicationWeb Application
Use Validator controlsUse Validator controlsWindows ApplicationWindows Application
Use Validating eventUse Validating eventUse ErrorProvider controlUse ErrorProvider controlCan do the above with a base form classCan do the above with a base form classDefine validation rules in the middle tierDefine validation rules in the middle tier
4th Wall Of Defense: Data Validation
Cannot assume that incoming data is validCannot assume that incoming data is validNot all incoming data is from the userNot all incoming data is from the userData from the database may also be invalidData from the database may also be invalid
Translated dataTranslated dataUpdates to data from other applicationsUpdates to data from other applicationsErrors due to changes in the databaseErrors due to changes in the database
Example: Nulls in newly added fieldsExample: Nulls in newly added fieldsErrors in data due to programming errorsErrors in data due to programming errors
Parameter CheckingGive some thought to your method signatureGive some thought to your method signature
Minimizes the amount of refactoring that needs Minimizes the amount of refactoring that needs to be done laterto be done later
Verify each parameter passed into a routineVerify each parameter passed into a routineConfirms parameter assumptions made Confirms parameter assumptions made by the routineby the routine
These assumptions should be documented These assumptions should be documented in the parameter commentsin the parameter comments
Add as the first code lines of the routineAdd as the first code lines of the routineExceptionsExceptionsAssertionsAssertions
ExceptionsThrow an exception when the Throw an exception when the parameter is not as expectedparameter is not as expected
Public Function Retrieve(ByVal iID As Int32) As DataSetPublic Function Retrieve(ByVal iID As Int32) As DataSet If iID <= 0 ThenIf iID <= 0 Then Throw New ArgumentExceptionThrow New ArgumentException(String.Format("ID must be (String.Format("ID must be greater than 0. ID was {0}", iID.ToString))greater than 0. ID was {0}", iID.ToString)) End IfEnd If
Public Function ValLogin(ByVal oUserEntity As UserEntity) _Public Function ValLogin(ByVal oUserEntity As UserEntity) _As BooleanAs Boolean
If oUserEntity Is Nothing ThenIf oUserEntity Is Nothing Then Throw New ArgumentExceptionThrow New ArgumentException("UserEntity object must be ("UserEntity object must be set before calling this function")set before calling this function") End IfEnd If
AssertionsAssert when the parameter is not as expectedAssert when the parameter is not as expected
Public Function Retrieve(ByVal iID As Int32) As DataSetPublic Function Retrieve(ByVal iID As Int32) As DataSet Debug.Debug.AssertAssert(iID > 0, _(iID > 0, _ String.Format("ID must be greater than 0. ID was {0}", iID.ToString))String.Format("ID must be greater than 0. ID was {0}", iID.ToString))
Public Function ValLogin(ByVal oUserEntity As UserEntity) _Public Function ValLogin(ByVal oUserEntity As UserEntity) _As BooleanAs Boolean
Debug.Debug.AssertAssert(Not oUserEntity Is Nothing, _(Not oUserEntity Is Nothing, _ "UserEntity object must be set before calling this function")"UserEntity object must be set before calling this function")
Exceptions Versus Assertions
Uses more codeUses more codeLess performantLess performantIncluded in the Included in the release buildrelease buildCan be logged in Can be logged in a production a production environmentenvironmentCannot easily be Cannot easily be turned on/offturned on/off
Uses less codeUses less codeMore performantMore performantOnly included in the Only included in the debug builddebug buildCan be included in Can be included in trace informationtrace informationCan easily be Can easily be turned on/off using turned on/off using configuration fileconfiguration file
Configuring AssertionsUse a configuration fileUse a configuration file
Turn on/off assertionsTurn on/off assertionsLog assertionsLog assertions
<configuration><configuration> <system.diagnostics> <system.diagnostics> <assert assertuienabled="true" logfilename="c:\\myFile.log" /> <assert assertuienabled="true" logfilename="c:\\myFile.log" /> </system.diagnostics> </system.diagnostics> </configuration></configuration>
5th Wall Of Defense: Code Correctness
Prevent coding errors byPrevent coding errors byUsing good coding practicesUsing good coding practicesAnticipating potential problem areasAnticipating potential problem areas
Including third-party coding errorsIncluding third-party coding errorsIncluding system (database and framework) errorsIncluding system (database and framework) errors
Use damage control techniques when a Use damage control techniques when a failure does occurfailure does occurLog any failures for evaluation and correctionLog any failures for evaluation and correction
Defining Good Coding Practices
Develop a set of programming standardsDevelop a set of programming standardsDefines "best practices"Defines "best practices"Makes maintenance easierMakes maintenance easier
Perform code reviews to ensure adherence Perform code reviews to ensure adherence to standardsto standards.NET Framework Design Guidelines: .NET Framework Design Guidelines: http://msdn.microsoft.com/library/default.asp?url=/lihttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/brary/en-us/cpgenrefcpgenref/html/ /html/ cpconnetframeworkdesignguidelines.aspcpconnetframeworkdesignguidelines.asp
Type Your DataDeclare your typesDeclare your typesCatches inconsistencies before they Catches inconsistencies before they become bugsbecome bugsUse Option ExplicitUse Option ExplicitUse Option StrictUse Option Strict
Dim dsProduct As DataSetDim dsProduct As DataSetDim sConn As StringDim sConn As String
Use Constants When Appropriate
Declare constants for values that should Declare constants for values that should not changenot change
Reused stringsReused stringsAction codesAction codesField namesField namesEtc.Etc.
Public Const PRODUCT_DESCRIPTION As String = "Description"Public Const PRODUCT_DESCRIPTION As String = "Description"Public Const PRODUCT_PRICE As String = "Price"Public Const PRODUCT_PRICE As String = "Price"
Public Const VALIDATE_REQUIRED As String = "ValidateRequired"Public Const VALIDATE_REQUIRED As String = "ValidateRequired"Public Const VALIDATE_NUMERIC As String = "ValidateNumeric"Public Const VALIDATE_NUMERIC As String = "ValidateNumeric"Public Const VALIDATE_REG_EX_PHONE As String = "^\d{10}$"Public Const VALIDATE_REG_EX_PHONE As String = "^\d{10}$"
Make A Statement For Success
When using a Case statement, always include a Case When using a Case statement, always include a Case Else to prevent falling throughElse to prevent falling through
Select Case e.Button.TextSelect Case e.Button.Text Case tbBtnCancel.TextCase tbBtnCancel.Text Me.Close()Me.Close()
Case tbBtnNew.TextCase tbBtnNew.Text MessageBox.Show("This would perform a new operation")MessageBox.Show("This would perform a new operation")
Case ElseCase Else Debug.Assert(False, "Missing handler for button with text: " _Debug.Assert(False, "Missing handler for button with text: " _
& e.Button.Text)& e.Button.Text) End SelectEnd Select
Keep Your Code CleanOrganize your codeOrganize your code
Refactor when neededRefactor when neededEncapsulate your classesEncapsulate your classesRemove duplicate codeRemove duplicate code
Duplicated code can lead to MANY bugs – Duplicated code can lead to MANY bugs – code is updated in one place but not the othercode is updated in one place but not the other
Keep it simpleKeep it simpleObfuscation can be badObfuscation can be bad
Document your codeDocument your codePrevents other developers (or yourself) from making coding Prevents other developers (or yourself) from making coding errors when making changes/enhancements latererrors when making changes/enhancements later
Clean Up Your ObjectsImplement IDisposableImplement IDisposable
This is important to do now in This is important to do now in preparation for the Using statement preparation for the Using statement in Whidbeyin Whidbey
Public Class ProductPublic Class Product Implements IDisposableImplements IDisposable Public Sub Dispose() Implements System.IDisposable.DisposePublic Sub Dispose() Implements System.IDisposable.Dispose ' Code here to dispose of your object' Code here to dispose of your object End SubEnd SubEnd ClassEnd Class
Marking Old RoutinesObsolete AttributeObsolete Attribute
This notifies other developers of a This notifies other developers of a routine that should no longer be usedroutine that should no longer be used
<ObsoleteAttribute("This method is obsolete. Please use <ObsoleteAttribute("This method is obsolete. Please use Retrieve(iID) instead", False)> _Retrieve(iID) instead", False)> _Public Function Retrieve(ByVal sProduct As String) As DataSetPublic Function Retrieve(ByVal sProduct As String) As DataSet ' Code here to get using the product string' Code here to get using the product stringEnd FunctionEnd Function
Damage Control Techniques
Damage ControlThe application should never terminate The application should never terminate abnormallyabnormallyRather, throw an exception when Rather, throw an exception when a failure occursa failure occursCatch the exception in the calling codeCatch the exception in the calling code
Throw ExceptionsThrow simple exceptions with the Throw simple exceptions with the Throw statementThrow statement
Public Function ValidateLogin(ByVal sUserName As String, _Public Function ValidateLogin(ByVal sUserName As String, _ ByVal sPassword As String) As BooleanByVal sPassword As String) As Boolean If sUserName <> "DeborahK" ThenIf sUserName <> "DeborahK" Then ThrowThrow New ApplicationException("Invalid username") New ApplicationException("Invalid username") End IfEnd If If sPassword <> "password" ThenIf sPassword <> "password" Then ThrowThrow New ApplicationException("Invalid password") New ApplicationException("Invalid password") End IfEnd If Return TrueReturn True End FunctionEnd FunctionEnd FunctionEnd Function
Catch ExceptionsCatch exceptions using Catch exceptions using a Try Catch blocka Try Catch blockTryTry Dim oUser As New User()Dim oUser As New User() bValid = oUser.ValidateLogin(txtUserName.Text, _bValid = oUser.ValidateLogin(txtUserName.Text, _ txtPassword.Text)txtPassword.Text) DialogResult = DialogResult.OKDialogResult = DialogResult.OK
Catch ex As ExceptionCatch ex As Exception MessageBox.Show(ex.Message)MessageBox.Show(ex.Message)End TryEnd Try
Add FinallyAdd a Finally to the Try Catch block for clean-Add a Finally to the Try Catch block for clean-up code that must be executed on success or up code that must be executed on success or failurefailure
TryTry Dim oUser As New User()Dim oUser As New User() bValid = oUser.ValidateLogin(txtUserName.Text, _bValid = oUser.ValidateLogin(txtUserName.Text, _ txtPassword.Text)txtPassword.Text) DialogResult = DialogResult.OKDialogResult = DialogResult.OKCatch ex As ExceptionCatch ex As Exception MessageBox.Show(ex.Message)MessageBox.Show(ex.Message)FinallyFinally ‘ ‘Clean up code hereClean up code hereEnd TryEnd Try
Build Your Own Exception Classes
Add exception classes to same code fileAdd exception classes to same code fileInherits properties and methods – Inherits properties and methods – not constructorsnot constructors
Public Class Public Class UsernameNotFoundExceptionUsernameNotFoundException : Inherits Exception : Inherits Exception Public Sub New()Public Sub New() MyBase.New()MyBase.New() End SubEnd Sub Public Sub New(ByVal message As String)Public Sub New(ByVal message As String) MyBase.New(message)MyBase.New(message) End SubEnd Sub Public Sub New(ByVal message As String, ByVal innerEx As Exception)Public Sub New(ByVal message As String, ByVal innerEx As Exception) MyBase.New(message, innerEx)MyBase.New(message, innerEx) End SubEnd SubEnd ClassEnd Class
Multiple ExceptionsTryTry Dim oUser As New User()Dim oUser As New User() bValid = oUser.ValidateLogin(txtUserName.Text, _bValid = oUser.ValidateLogin(txtUserName.Text, _
txtPassword.Text)txtPassword.Text) DialogResult = DialogResult.OKDialogResult = DialogResult.OK
Catch ex As UsernameNotFoundExceptionCatch ex As UsernameNotFoundException MessageBox.Show(ex.Message)MessageBox.Show(ex.Message) txtUserName.Focus()txtUserName.Focus()
Catch ex As PasswordInvalidExceptionCatch ex As PasswordInvalidException MessageBox.Show(ex.Message)MessageBox.Show(ex.Message) txtPassword.Focus()txtPassword.Focus()End TryEnd Try
Another ExampleCatch ex As System.Data.SqlClient.SqlExceptionCatch ex As System.Data.SqlClient.SqlException Me.TransactionRollback()Me.TransactionRollback() Select Case ex.NumberSelect Case ex.Number Case UNIQUE_CONSTRAINT_ERRORCase UNIQUE_CONSTRAINT_ERROR Throw New UniqueConstraintException(ex.Message, _Throw New UniqueConstraintException(ex.Message, _
oDS.Tables(sTableName(iTableIndex)), iRowIndex, ex)oDS.Tables(sTableName(iTableIndex)), iRowIndex, ex)
Case DEADLOCK_ERROR_NUMBERCase DEADLOCK_ERROR_NUMBER Throw New DacDeadlockException(ex.Message)Throw New DacDeadlockException(ex.Message)
Case Is >= SQLSERVERS_RULES_BEGINCase Is >= SQLSERVERS_RULES_BEGIN Throw New SQLServerRulesException(ex.Message, _Throw New SQLServerRulesException(ex.Message, _ iRowIndex, ex)iRowIndex, ex)
Case ElseCase Else ThrowThrow End SelectEnd Select
Catch Any Other FailureUse the ThreadException event to trap Use the ThreadException event to trap any other failuresany other failures
AddHandler Application.ThreadException, _AddHandler Application.ThreadException, _ New System.Threading.ThreadExceptionEventHandler(AddressOf New System.Threading.ThreadExceptionEventHandler(AddressOf gEx.OnThreadException)gEx.OnThreadException)
Notification Mechanisms
Logging ExceptionsUse notification techniques to collect Use notification techniques to collect information useful for diagnosing the information useful for diagnosing the problemproblemInclude information on the contextInclude information on the context
Operation performedOperation performedValue of key variablesValue of key variablesEtc.Etc.
The easier you make the defect analysis, The easier you make the defect analysis, the easier it will be to fix the defectsthe easier it will be to fix the defectsDon’t count on the users!Don’t count on the users!
Log Exception RoutinePublic Sub LogException(ByVal sError As String, _Public Sub LogException(ByVal sError As String, _ ByVal sUserName As String, _ByVal sUserName As String, _ ByVal eLogEntryType As EventLogEntryType)ByVal eLogEntryType As EventLogEntryType)
' Write the error to the Output window' Write the error to the Output window Debug.WriteLine(sError)Debug.WriteLine(sError)
' If there are any errors, put up a message box if debugging' If there are any errors, put up a message box if debugging#If DEBUG Then#If DEBUG Then MsgBox(sError, MsgBoxStyle.Critical, "Debug Message")MsgBox(sError, MsgBoxStyle.Critical, "Debug Message")#End If#End If
AddEventLogEntry(sError, eLogEntryType)AddEventLogEntry(sError, eLogEntryType) SendEmail(sError)SendEmail(sError)End SubEnd Sub
Writing To The Event LogPrivate Sub AddEventLogEntry(ByVal sText As String, _Private Sub AddEventLogEntry(ByVal sText As String, _ ByVal eEntryType As EventLogEntryType)ByVal eEntryType As EventLogEntryType) Dim EvtLog As New System.Diagnostics.EventLog()Dim EvtLog As New System.Diagnostics.EventLog()
' Ensure application is registered in event log' Ensure application is registered in event log If Not EventLog.SourceExists(me.ApplicationName) ThenIf Not EventLog.SourceExists(me.ApplicationName) Then EventLog.CreateEventSource(me.ApplicationName, "Application")EventLog.CreateEventSource(me.ApplicationName, "Application") End IfEnd If
' Add entry' Add entry EvtLog.WriteEntry(me.ApplicationName, sText, eEntryType)EvtLog.WriteEntry(me.ApplicationName, sText, eEntryType)End SubEnd Sub
Unit TestingValidates functionalityValidates functionalityValidates functional changesValidates functional changes
Regression testingRegression testing
Unit Testing Versus Defensive Coding
Unit testing does NOT prevent the need for Unit testing does NOT prevent the need for other defensive development techniquesother defensive development techniquesThe golden rule of testing: “Testing can only The golden rule of testing: “Testing can only prove the presence of errors, not the absence prove the presence of errors, not the absence of errors”of errors”Reliability = correctness + robustnessReliability = correctness + robustness
Unit Unit TestingTesting
Defensive Defensive CodingCoding
Testing Class LibrariesChange the project type to “Console Change the project type to “Console Application”Application”Add a Class with Sub Main as a test Add a Class with Sub Main as a test harnessharnessAdd testing code to the Sub MainAdd testing code to the Sub Main
Alternatively, use a unit testing toolAlternatively, use a unit testing tool
Class eOrderOnlineBOMainClass eOrderOnlineBOMain Public Shared Sub Main()Public Shared Sub Main() End SubEnd SubEnd SubEnd Sub
NUnit Unit Testing Toolhttp://sourceforge.net/projects/nunithttp://sourceforge.net/projects/nunitFramework for unit testingFramework for unit testing
TIPUse the Console to write testing dataUse the Console to write testing data
Console.WriteLineConsole.WriteLineConsole.ReadLine will keep the console Console.ReadLine will keep the console window openwindow openOr use the Debug windowOr use the Debug window
Debug.WriteLineDebug.WriteLineDump the contents of a datasetDump the contents of a dataset
Debug.WriteLine(ds.GetXml())Debug.WriteLine(ds.GetXml())
6th Wall Of Defense: Database Security
Secure the database serverSecure the database serverSecure the databaseSecure the databaseDefine one ID and password for the Define one ID and password for the application and only allow access application and only allow access through this IDthrough this ID
Do NOT use saDo NOT use saDo NOT use no passwordDo NOT use no password
Secure the connection stringSecure the connection string
7th Wall Of Defense:Monitor System Security
Review the following on a regular basisReview the following on a regular basisTHREAT modelTHREAT modelSecurity logSecurity logError logError log
Summary: 7 Walls Of Defense1.1. Ensure the design is clearEnsure the design is clear2.2. Implement an application security schemeImplement an application security scheme3.3. Validate user entryValidate user entry4.4. Validate data coming into/out of the systemValidate data coming into/out of the system5.5. Use good development practices to prevent Use good development practices to prevent
coding errorscoding errors Perform damage control when exceptions occurPerform damage control when exceptions occur Log exceptions to assist in diagnosing problemsLog exceptions to assist in diagnosing problems
6.6. Implement a database security schemeImplement a database security scheme7.7. Monitor system security regularlyMonitor system security regularly
AssessmentsAssessments http://www.microsoft.com/assessment/http://www.microsoft.com/assessment/
CoursesCourses
2415: Programming with the Microsoft .NET Framework 2415: Programming with the Microsoft .NET Framework (Microsoft Visual Basic .NET)(Microsoft Visual Basic .NET)2349: Programming with the Microsoft .NET Framework 2349: Programming with the Microsoft .NET Framework (Microsoft Visual C# .NET)(Microsoft Visual C# .NET)
BooksBooks
The Microsoft Platform Ahead, ISBN: 0-7356-2064-4The Microsoft Platform Ahead, ISBN: 0-7356-2064-4Network Programming for the Microsoft .NET Framework, Network Programming for the Microsoft .NET Framework, ISBN: 0-7356-1959-XISBN: 0-7356-1959-XProgramming Microsoft .NET, ISBN: 0-7356-1376-1Programming Microsoft .NET, ISBN: 0-7356-1376-1Applied Microsoft Windows .NET Framework Programming, Applied Microsoft Windows .NET Framework Programming, ISBN: 0-7356-1422-9ISBN: 0-7356-1422-9Applied Microsoft Windows .NET Framework Programming in Microsoft Applied Microsoft Windows .NET Framework Programming in Microsoft Visual Basic .NET, ISBN: 0-7356-1787-2Visual Basic .NET, ISBN: 0-7356-1787-2Microsoft Windows .NET Framework 1.1 Class Library ReferencesMicrosoft Windows .NET Framework 1.1 Class Library ReferencesPerformance Testing Microsoft .NET Web Applications, ISBN: 0-7356-1538-1Performance Testing Microsoft .NET Web Applications, ISBN: 0-7356-1538-1
Microsoft Products and Services for Lifelong LearningMicrosoft Products and Services for Lifelong Learning
Microsoft Products And Services For Lifelong Learningwww.microsoft.com/learning
© 2004 Microsoft Corporation. All rights reserved.This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.