dev383 taking control of the base classes in the.net framework keith pleas architect, guided design...

46
DEV383 Taking Control of the Base Classes in the .NET Framework Keith Pleas Architect, Guided Design [email protected] m

Upload: polly-fox

Post on 28-Dec-2015

229 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

DEV383

Taking Control of the Base Classes in the .NET Framework

Keith PleasArchitect, Guided [email protected]

Page 2: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

2

Preventing Code Defects

Focus for this talkManaged code

Code that looks correct

Works correctly most of the time

May not work all the time, in all places or with all inputs

Expensive problems

Interludes…

Non FocusSecurity feature usage

Globalization feature usage

Page 3: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

3

TakeAways …

Identify specific coding patterns to avoid

Remember to keep an eye out for issues, and guidelines

Test, Test, Test!

Page 4: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

4

“I was sure it was June”

demo #1demo #1

Let’s begin with an easy oneLet’s begin with an easy oneControlling your date formats yourself …Controlling your date formats yourself …

Page 5: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

5

Example #1 Coding Guideline

Case matters: format specifiers/identifiersBe careful in case-agnostic languages: VB!

Consider using predefined formatsThere are many available, predefined formats. For example, short (d), long (D), full (f), or universal (u)

Consider using a CultureInfo to reset specific formats

Dim ci As New CultureInfo( Thread.CurrentThread.CurrentCulture.ToString())

ci.DateTimeFormat.ShortDatePattern = “MM/dd”

labelDate.Text = DateTime.Now.ToString(“d”, ci)

Page 6: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

6

Example #1 Testing Guideline

QuestionWhy should I have to verify date formatting?

Simple problem: simple solutionThis issue can be very easily solved with some quick and easy date range checks

Attempting to parse dates you output can help

Be careful to ensure you consider your current culture when testing: datetime formatting/parsing varies with culture

Page 7: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

7

“That wasn’t in the script!”

demo #2demo #2

Simple tasks, simple problems…Simple tasks, simple problems…An ASP.NET “Hello World!” applicationAn ASP.NET “Hello World!” application

Page 8: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

8

Example #2 Coding Guideline

All uncontrolled inputs must either be checked or encoded

Input properties like TextBox.TextOther uncontrolled information like URI parameters and cookies

Encoding is best if just echoing content Use HttpUtility.HtmlEncode

Validation of content is better!Also protects against other forms of injection, such as SQL injectionRegularExpressionValidator is very useful

Page 9: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

9

Example #2 Testing Guideline

No significant change to general web testing methodology

Test every source of inputForm inputs

URI parameters

More complex forms: cookies, raw request data, etc.

Test injection of client script blocks, SQL statements, C#, VB and JScript

Page 10: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

10

“A strange sort of case”

demo #3demo #3

Saving important information…Saving important information…Warning when overwriting in Warning when overwriting in Windows.FormsWindows.Forms

Page 11: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

11

Example #3 Problem

The string comparison of “Important.txt” and “important.txt” will not be equal in these cultures

TurkeyTurkey AzerbaijanAzerbaijan

Page 12: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

12

Example #3 Explanation

““important” does not equal “IMPORTANT”important” does not equal “IMPORTANT”

Page 13: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

13

// this was the line: if (String.Compare(file, tempFile, true) == 0) // this was the line: if (String.Compare(file, tempFile, true) == 0)

if (String.Compare(file, tempFile, true, CultureInfo.InvariantCulture) == 0) if (String.Compare(file, tempFile, true, CultureInfo.InvariantCulture) == 0) {{ if (MessageBox.Show(if (MessageBox.Show( "Are you sure you want to overwrite the existing file?", "Are you sure you want to overwrite the existing file?", "Overwrite File: " + file, MessageBoxButtons.YesNo)"Overwrite File: " + file, MessageBoxButtons.YesNo) != DialogResult.Yes) != DialogResult.Yes) {{ return false;return false; } } else else {{ break;break; }}}}

Example #3 The Fix

Page 14: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

14

Example #3 Reasoning

Traditionally programming for non-English alphabets is difficult

The framework makes it easier to create an application targeting a single non-English language, but…

More care is required for components that must work in all cultures

Page 15: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

15

Example #3 Scope

Another 9 cultures have multi-character differences within the ASCII range (e.g. Czech, Vietnamese)Another 6 cultures have sorting differences within the ASCII rangeAffected APIs

String.Compare, String.CompareToString.ToUpper, String.ToLower, Char.ToUpper, Char.ToLower

Unaffected APIsString.Equals, ‘==’, String.CompareOrdinal

Page 16: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

16

Example #3 Coding Guideline

Comparison should be invariant forComparison to fixed ASCII strings

Persisted data such as XML tag names

String IDs like file names, or registry keys

Comparison should be culture-aware forLocalized text displayed to the user

Most user-entered text

Problem affects sorting as well as casing

Page 17: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

17

Example #3 Testing Guideline

Option 1: Support only a fixed set of culturesKnow and test the corner cases for those cultures

Option 2: Test sensitive culturesTurkish or Azeri should be regularly included for automated tests

Ideally, test a culture with multi-character difference like Vietnamese

Include sensitive strings in test data “I” for Turkish

“nG” for Vietnamese

Page 18: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

18

Strings vs. StringBuilder

interlude: building stringsinterlude: building strings

Building that house as fast as Building that house as fast as possible …possible …

Page 19: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

19

“Thy buffer runneth over”

demo #4demo #4

CheckedMate…CheckedMate…What was that about safe code?What was that about safe code?

Page 20: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

20

Example #4: Hang On!

What happened to “no more buffer overruns” ?

This is true only for verifiable managed code

Buffer overruns are still a concern in the following situations

Platform Invokes (P/Invoke)

COM Interop

Unsafe C#

Unverifiable languages like MC++

Page 21: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

21

// WARNING: caller must do argument checks// WARNING: caller must do argument checksprivate unsafe static void InternalCopyUnguarded(private unsafe static void InternalCopyUnguarded( byte[ ] src, int srcIndex, byte[ ] src, int srcIndex, byte[ ] dest, int destIndex, byte[ ] dest, int destIndex, int length) {int length) { fixed(byte* srcPointer = src, fixed(byte* srcPointer = src, destPointer = dest) { destPointer = dest) { byte* srcPosition = srcPointer + srcIndex;byte* srcPosition = srcPointer + srcIndex; byte* destPosition = destPointer + destIndex;byte* destPosition = destPointer + destIndex; while (length-- > 0) {while (length-- > 0) { *destPosition++ = *srcPosition++;*destPosition++ = *srcPosition++; }} } } }}

Example #4: The Source

Page 22: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

22

public static void MemoryCopy(byte[ ] src, int srcIndex, public static void MemoryCopy(byte[ ] src, int srcIndex, byte[ ] dest, int destIndex, byte[ ] dest, int destIndex, int length) {int length) { if ((length < 0) if ((length < 0) || (srcIndex < 0) || (srcIndex < 0) || (destIndex < 0)|| (destIndex < 0) || (srcIndex + length > src.Length)|| (srcIndex + length > src.Length) || (destIndex + length > dest.Length)) {|| (destIndex + length > dest.Length)) { throw new ArgumentException(throw new ArgumentException( Resources.OneOfYourArgumentsWasBad);Resources.OneOfYourArgumentsWasBad); }} InternalCopyUnguarded(src, srcIndex, InternalCopyUnguarded(src, srcIndex, dest, destIndex, length);dest, destIndex, length);}}

Example #4: The Problem

Page 23: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

23

Example #4 The Problem

public static void MemoryCopy(byte[ ] src, int srcIndex, public static void MemoryCopy(byte[ ] src, int srcIndex, byte[ ] dest, int destIndex, byte[ ] dest, int destIndex, int length) {int length) { if ((length < 0) if ((length < 0) || (srcIndex < 0) || (srcIndex < 0) || (destIndex < 0)|| (destIndex < 0) || || (srcIndex + length > src.Length)(srcIndex + length > src.Length) || || (destIndex + length > dest.Length)(destIndex + length > dest.Length)) {) { throw new ArgumentException(throw new ArgumentException( Resources.OneOfYourArgumentsWasBad);Resources.OneOfYourArgumentsWasBad); }} InternalCopyUnguarded(src, srcIndex, InternalCopyUnguarded(src, srcIndex, dest, destIndex, length);dest, destIndex, length);}}

Page 24: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

24

Example #4 The Fix

public static void MemoryCopy(byte[ ] src, int srcIndex, public static void MemoryCopy(byte[ ] src, int srcIndex, byte[ ] dest, int destIndex, byte[ ] dest, int destIndex, int length) {int length) { if ((length < 0) if ((length < 0) || (srcIndex < 0) || (srcIndex < 0) || (destIndex < 0)|| (destIndex < 0) || || (src.Length - srcIndex < length)(src.Length - srcIndex < length) || || (dest.Length - destIndex < length)(dest.Length - destIndex < length)) {) { throw new ArgumentException(throw new ArgumentException( Resources.OneOfYourArgumentsWasBad);Resources.OneOfYourArgumentsWasBad); }} InternalCopyUnguarded(src, srcIndex, InternalCopyUnguarded(src, srcIndex, dest, destIndex, length);dest, destIndex, length);}}

Page 25: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

25

Example #4 Coding Guideline

Limit usage of “unsafe” codeOnly marginally faster

JIT compiler will eliminate redundant checks

VB does not suffer from this!

C# and MC++ guidelinesUse subtraction of positive integers when checking arguments

Alternatively, use the “checked” operator, particularly if multiplication is involved

Page 26: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

26

Example #4 Testing Guideline

Invalid Argument TestingIdentify APIs that are passed through into unsafe code

Test a wide variety and combination of invalid arguments (e.g. 0, 1, -1, 2, -2, Int32.MaxValue, Int32.MinValue, 216, 216 + 1 etc.)

White box testing: look for these patterns in code

Page 27: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

27

“Like a broken record”

demo #5demo #5

If at first you don’t succeed…If at first you don’t succeed…An application that keeps tryingAn application that keeps trying

Page 28: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

28

Public Sub TryConnect(ByVal timeoutSeconds As Integer)Public Sub TryConnect(ByVal timeoutSeconds As Integer)

Dim start As Date = DateTime.NowDim start As Date = DateTime.Now DoDo TryTry Connect()Connect() ReturnReturn Catch ex As ExceptionCatch ex As Exception LogConnectionFailure(ex)LogConnectionFailure(ex) End TryEnd Try Loop Until DateDiff( DateInterval.Second, start, _Loop Until DateDiff( DateInterval.Second, start, _ DateTime.Now ) > timeoutSecondsDateTime.Now ) > timeoutSeconds

Throw New Exception(Resources.ConnectionTimedOut)Throw New Exception(Resources.ConnectionTimedOut) End SubEnd Sub

Example #5: The Problem

Page 29: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

29

Example #5 The Fix Public Sub TryConnect(ByVal timeoutSeconds As Integer)Public Sub TryConnect(ByVal timeoutSeconds As Integer)

Dim start As Date = Dim start As Date = DateTime.UtcNowDateTime.UtcNow ‘ was Now‘ was Now DoDo TryTry Connect()Connect() ReturnReturn Catch ex As ExceptionCatch ex As Exception LogConnectionFailure(ex)LogConnectionFailure(ex) End TryEnd Try Loop Until DateDiff( DateInterval.Second, start, _Loop Until DateDiff( DateInterval.Second, start, _ DateTime.UtcNowDateTime.UtcNow ) > timeoutSeconds ) > timeoutSeconds

Throw New Exception(Resources.ConnectionTimedOut)Throw New Exception(Resources.ConnectionTimedOut) End SubEnd Sub

Page 30: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

30

Example #5 Guidelines

Use universal times for all date arithmeticFixes daylight savings time arithmetic

Works across time zones

No loss of context if persisted

If your component must work 24/7Test critical operations at daylight savings time boundaries

Beware: processing timezone interaction information may also be difficult

Page 31: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

31

interlude: Do the right thinginterlude: Do the right thing

Designing For The FutureDesigning For The Future

Avoiding traps …Avoiding traps …

Page 32: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

32

ICloneable

Has a single Clone method

Not implemented in a consistent mannerShallow Copy: only the references are copied

Deep Copy: objects are exhaustively copied

How can you rely on the ICloneable nature of an object?ICloneable[] GetCopies ( ICloneable[] clones )

Does a copy share state with the original?

Page 33: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

33

The Design Guidelines

Contain excellent guidance on what to do, and what NOT to do

In the case of ICloneable, the guideline would state something like …

Do not implement ICloneable

Note: If you need a cloning mechanism, define your own Clone, or Copy methodology, and ensure that you document clearly whether it is a deep or shallow copy. An appropriate pattern is:

public <type> Copy();

Guidelines can be found in the docs, or at:

http://www.gotdotnet.com/team/libraries/

Page 34: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

34

“Across the Great Divide”

demo #6demo #6

It’s a topsy-turvy world…It’s a topsy-turvy world…

Page 35: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

35

Example #6 Testing Guideline

For a multi-tier applicationTest scenarios of different tiers running on computers in different time zones

Test both positive and negative time zone offsets

For applications with special date and time logic (calendars, schedulers etc.)

Test all the time zones your application could be running in

Page 36: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

36

“Sewing up loose threads”

demo #7demo #7

A server component customizing its A server component customizing its behaviorbehavior

Page 37: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

37

Private Shared cachedCulture As CultureInfoPrivate Shared cachedCulture As CultureInfo

Public Shared ReadOnly Property ApplicationCulture() _Public Shared ReadOnly Property ApplicationCulture() _ As CultureInfoAs CultureInfo GetGet If cachedCulture Is Nothing ThenIf cachedCulture Is Nothing Then cachedCulture = New CultureInfo("en-NZ")cachedCulture = New CultureInfo("en-NZ") cachedCulture.DateTimeFormat.ShortDatePattern _cachedCulture.DateTimeFormat.ShortDatePattern _ = "yyyy/MM/dd"= "yyyy/MM/dd" End IfEnd If Return cachedCultureReturn cachedCulture End GetEnd Get End PropertyEnd Property

Example #7 The Problem

Page 38: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

38

Private Shared cachedCulture As CultureInfoPrivate Shared cachedCulture As CultureInfo Public Shared ReadOnly Property ApplicationCulture() _Public Shared ReadOnly Property ApplicationCulture() _ As CultureInfoAs CultureInfo GetGet If cachedCulture Is Nothing ThenIf cachedCulture Is Nothing Then

cachedCulture = New CultureInfo("en-NZ")cachedCulture = New CultureInfo("en-NZ")

cachedCulture.DateTimeFormat.ShortDatePattern _cachedCulture.DateTimeFormat.ShortDatePattern _ = "yyyy/MM/dd"= "yyyy/MM/dd" End IfEnd If Return cachedCultureReturn cachedCulture End GetEnd Get End PropertyEnd Property

Example #7 Race Condition

Thread 1Thread 1

Thread 2Thread 2

Page 39: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

39

Private Shared cachedCulture As CultureInfoPrivate Shared cachedCulture As CultureInfo

Public Shared ReadOnly Property ApplicationCulture() _Public Shared ReadOnly Property ApplicationCulture() _ As CultureInfoAs CultureInfo GetGet If cachedCulture Is Nothing ThenIf cachedCulture Is Nothing Then Dim culture As New CultureInfo("en-NZ")Dim culture As New CultureInfo("en-NZ") culture.DateTimeFormat.ShortDatePattern _culture.DateTimeFormat.ShortDatePattern _ = "yyyy/MM/dd"= "yyyy/MM/dd" cachedCulture = culturecachedCulture = culture End IfEnd If Return cachedCultureReturn cachedCulture End GetEnd Get End PropertyEnd Property

Example #7 The Fix

Page 40: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

40

Example #7 Coding Guideline

Design guideline for threadingShared or static methods and properties should be thread safe

Instance methods and properties are generally not thread safe

Coding techniquesUse a temporary variable so you make a single assignment to the shared field

The garbage collector will take care of extra instances created

Page 41: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

41

Example #7 Testing Guideline

Race conditions are hard to findReviewing code is generally the most successful

Stress testingDedicate machines to continually run scenarios for extended periods

Targeted testingImmediately spin up multiple threads

Call static members and properties

Page 42: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

42

Key Takeaways

Make whole classes of errors go away

Next StepsParticipate in communities: keep an eye out for similar issues

Read .NET Framework Design Guidelineshttp://www.gotdotnet.com/team/libraries/

Use automated tools: FxCop

Page 43: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

43

Ask The ExpertsGet Your Questions Answered

13:00 to 15:00 Thursday 3 July

Page 44: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

44

Community Resources

Community Resourceshttp://www.microsoft.com/communities/default.mspx

Most Valuable Professional (MVP)http://www.mvp.support.microsoft.com/

NewsgroupsConverse online with Microsoft Newsgroups, including Worldwidehttp://www.microsoft.com/communities/newsgroups/default.mspx

User GroupsMeet and learn with your peershttp://www.microsoft.com/communities/usergroups/default.mspx

Page 45: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

45

evaluationsevaluations

Page 46: DEV383 Taking Control of the Base Classes in the.NET Framework Keith Pleas Architect, Guided Design keithp@guideddesign.com

46© 2003 Microsoft Corporation. All rights reserved.© 2003 Microsoft Corporation. All rights reserved.

This presentation is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR IMPLIED, IN THIS SUMMARY.This presentation is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR IMPLIED, IN THIS SUMMARY.