Business is good and we need YOU! Wintellect is currently seeking senior level technical development resources for both contract and permanent employment for our current client projects. If you want the challenge of keeping up with co-workers like Jeffrey Richter, Jeff Prosise, Keith Rome, or Jeremy Likness, have we got the opportunity of a lifetime. Please have lots of hands on development experience in the following technologies: C#, ASP.NET MVC, WPF, WCF, Silverlight and SQL Server. Experience with HTML5 and jQuery would be ideal also. If you can't tell, it's all cutting edge here at Wintellect so if you like doing the latest technology we'd love to talk with you. Please forward your resume and availability to Barbara Keihm, Director of Human Resources,bkeihm@wintellect.com.

http://usergroup.tv/videos/net-nuggets---houston-tech-fest-keynote

When you create a new .NET Metro style application in Visual Studio, it spits out a project template that doesn't reference any .NET assemblies. Well, this isn't completely true, because when you run the C# compiler it references MSCorLib.dll by default. For a Metro style application, the referenced MSCorLib.dll contains a bunch of TypeForwardedToAttribute attributes (http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.typeforwardedtoattribute.aspx). This means that it exposes a bunch of types that you can use from your Metro style application that are actually implemented in various other assemblies. I wrote a small tool that reflects over this MSCorLib.dll are shows all of the core .NET types. The output of the tool is shown below. I grouped types by namespace and under each namespace I show the name of the type and the name of the assembly that defines the type in square brackets. Any type with a back tick in it (like Action`1) represents a generic type.

System

Action [System.Runtime]

Action`1 [System.Runtime]

Action`2 [System.Runtime]

Action`3 [System.Runtime]

Action`4 [System.Runtime]

Action`5 [System.Runtime]

Action`6 [System.Runtime]

Action`7 [System.Runtime]

Action`8 [System.Runtime]

Activator [System.Runtime]

AggregateException [System.Threading.Tasks]

ArgumentException [System.Runtime]

ArgumentNullException [System.Runtime]

ArgumentOutOfRangeException [System.Runtime]

ArithmeticException [System.Runtime]

Array [System.Runtime]

ArraySegment`1 [System.Runtime]

ArrayTypeMismatchException [System.Runtime]

AsyncCallback [System.Runtime]

Attribute [System.Runtime]

AttributeTargets [System.Runtime]

AttributeUsageAttribute [System.Runtime]

BadImageFormatException [System.Runtime]

BitConverter [System.Runtime.Extensions]

Boolean [System.Runtime]

Byte [System.Runtime]

Char [System.Runtime]

CLSCompliantAttribute [System.Runtime]

Convert [System.Runtime.Extensions]

DataMisalignedException [System.Runtime]

DateTime [System.Runtime]

DateTimeKind [System.Runtime]

DateTimeOffset [System.Runtime]

DayOfWeek [System.Runtime]

Decimal [System.Runtime]

Delegate [System.Runtime]

DivideByZeroException [System.Runtime]

DllNotFoundException [System.Runtime]

Double [System.Runtime]

Enum [System.Runtime]

Environment [System.Runtime.Extensions]

EnvironmentVariableTarget [System.Runtime.Extensions]

EventArgs [System.Runtime]

EventHandler [System.Runtime]

EventHandler`1 [System.Runtime]

Exception [System.Runtime]

FlagsAttribute [System.Runtime]

FormatException [System.Runtime]

Func`1 [System.Runtime]

Func`2 [System.Runtime]

Func`3 [System.Runtime]

Func`4 [System.Runtime]

Func`5 [System.Runtime]

Func`6 [System.Runtime]

Func`7 [System.Runtime]

Func`8 [System.Runtime]

Func`9 [System.Runtime]

GC [System.Runtime.Extensions]

GCCollectionMode [System.Runtime.Extensions]

Guid [System.Runtime]

IAsyncResult [System.Runtime]

IComparable [System.Runtime]

IComparable`1 [System.Runtime]

ICustomFormatter [System.Runtime]

IDisposable [System.Runtime]

IEquatable`1 [System.Runtime]

IFormatProvider [System.Runtime]

IFormattable [System.Runtime]

IndexOutOfRangeException [System.Runtime]

Int16 [System.Runtime]

Int32 [System.Runtime]

Int64 [System.Runtime]

IntPtr [System.Runtime]

InvalidCastException [System.Runtime]

InvalidOperationException [System.Runtime]

InvalidTimeZoneException [System.Runtime]

IObservable`1 [System.Runtime]

IObserver`1 [System.Runtime]

IProgress`1 [System.Runtime]

Lazy`1 [System.Runtime]

Math [System.Runtime.Extensions]

MemberAccessException [System.Runtime]

MidpointRounding [System.Runtime]

MissingMemberException [System.Runtime]

MTAThreadAttribute [System.Runtime]

MulticastDelegate [System.Runtime]

NotImplementedException [System.Runtime]

NotSupportedException [System.Runtime]

Nullable [System.Runtime]

Nullable`1 [System.Runtime]

NullReferenceException [System.Runtime]

Object [System.Runtime]

ObjectDisposedException [System.Runtime]

ObsoleteAttribute [System.Runtime]

OperationCanceledException [System.Threading.Tasks]

OutOfMemoryException [System.Runtime]

OverflowException [System.Runtime]

ParamArrayAttribute [System.Runtime]

PlatformNotSupportedException [System.Runtime]

Predicate`1 [System.Runtime]

Progress`1 [System.Runtime.Extensions]

Random [System.Runtime.Extensions]

RankException [System.Runtime]

RuntimeFieldHandle [System.Runtime]

RuntimeMethodHandle [System.Runtime]

RuntimeTypeHandle [System.Runtime]

SByte [System.Runtime]

Single [System.Runtime]

STAThreadAttribute [System.Runtime]

String [System.Runtime]

StringComparer [System.Runtime.Extensions]

StringComparison [System.Runtime]

StringSplitOptions [System.Runtime]

ThreadStaticAttribute [System.Runtime]

TimeoutException [System.Runtime]

TimeSpan [System.Runtime]

TimeZoneInfo [System.Runtime]

Tuple [System.Runtime]

Tuple`1 [System.Runtime]

Tuple`2 [System.Runtime]

Tuple`3 [System.Runtime]

Tuple`4 [System.Runtime]

Tuple`5 [System.Runtime]

Tuple`6 [System.Runtime]

Tuple`7 [System.Runtime]

Tuple`8 [System.Runtime]

Type [System.Runtime]

TypeAccessException [System.Runtime]

TypedReference [System.Runtime]

TypeInitializationException [System.Runtime]

TypeLoadException [System.Runtime]

UInt16 [System.Runtime]

UInt32 [System.Runtime]

UInt64 [System.Runtime]

UIntPtr [System.Runtime]

UnauthorizedAccessException [System.Runtime]

ValueType [System.Runtime]

Version [System.Runtime]

Void [System.Runtime]

WeakReference [System.Runtime.Extensions]

WeakReference`1 [System.Runtime.Extensions]

 

System.Collections

BitArray [System.Collections]

ICollection [System.Runtime]

IComparer [System.Runtime]

IEnumerable [System.Runtime]

IEnumerator [System.Runtime]

IEqualityComparer [System.Runtime]

IList [System.Runtime]

IStructuralComparable [System.Runtime]

IStructuralEquatable [System.Runtime]

StructuralComparisons [System.Collections]

 

System.Collections.Concurrent

ConcurrentDictionary`2 [System.Collections.Concurrent]

ConcurrentQueue`1 [System.Collections.Concurrent]

ConcurrentStack`1 [System.Collections.Concurrent]

EnumerablePartitionerOptions [System.Collections.Concurrent]

IProducerConsumerCollection`1 [System.Collections.Concurrent]

OrderablePartitioner`1 [System.Collections.Concurrent]

Partitioner [System.Collections.Concurrent]

Partitioner`1 [System.Collections.Concurrent]

 

System.Collections.Generic

Comparer`1 [System.Collections]

Dictionary`2 [System.Collections]

EqualityComparer`1 [System.Collections]

ICollection`1 [System.Runtime]

IComparer`1 [System.Runtime]

IDictionary`2 [System.Runtime]

IEnumerable`1 [System.Runtime]

IEnumerator`1 [System.Runtime]

IEqualityComparer`1 [System.Runtime]

IList`1 [System.Runtime]

IReadOnlyDictionary`2 [System.Runtime]

IReadOnlyList`1 [System.Runtime]

KeyNotFoundException [System.Runtime]

KeyValuePair`2 [System.Runtime]

List`1 [System.Collections]

 

System.Collections.ObjectModel

Collection`1 [System.Runtime]

KeyedCollection`2 [System.Collections.ObjectModel]

ReadOnlyCollection`1 [System.Runtime]

ReadOnlyDictionary`2 [System.Collections.ObjectModel]

 

System.Diagnostics

ConditionalAttribute [System.Runtime]

DebuggableAttribute [System.Runtime]

Debugger [System.Diagnostics.Debug]

DebuggerBrowsableAttribute [System.Diagnostics.Debug]

DebuggerBrowsableState [System.Diagnostics.Debug]

DebuggerDisplayAttribute [System.Diagnostics.Debug]

DebuggerHiddenAttribute [System.Diagnostics.Debug]

DebuggerNonUserCodeAttribute [System.Diagnostics.Debug]

DebuggerStepThroughAttribute [System.Diagnostics.Debug]

DebuggerTypeProxyAttribute [System.Diagnostics.Debug]

 

System.Diagnostics.CodeAnalysis

SuppressMessageAttribute [System.Diagnostics.Tools]

 

System.Diagnostics.Contracts

Contract [System.Diagnostics.Contracts]

ContractAbbreviatorAttribute [System.Diagnostics.Contracts]

ContractArgumentValidatorAttribute [System.Diagnostics.Contracts]

ContractClassAttribute [System.Diagnostics.Contracts]

ContractClassForAttribute [System.Diagnostics.Contracts]

ContractFailedEventArgs [System.Diagnostics.Contracts]

ContractFailureKind [System.Diagnostics.Contracts]

ContractInvariantMethodAttribute [System.Diagnostics.Contracts]

ContractOptionAttribute [System.Diagnostics.Contracts]

ContractPublicPropertyNameAttribute [System.Diagnostics.Contracts]

ContractReferenceAssemblyAttribute [System.Diagnostics.Contracts]

ContractRuntimeIgnoredAttribute [System.Diagnostics.Contracts]

ContractVerificationAttribute [System.Diagnostics.Contracts]

PureAttribute [System.Diagnostics.Contracts]

 

System.Diagnostics.Tracing

EventAttribute [System.Diagnostics.Tracing]

EventCommand [System.Diagnostics.Tracing]

EventCommandEventArgs [System.Diagnostics.Tracing]

EventKeywords [System.Diagnostics.Tracing]

EventLevel [System.Diagnostics.Tracing]

EventListener [System.Diagnostics.Tracing]

EventOpcode [System.Diagnostics.Tracing]

EventSource [System.Diagnostics.Tracing]

EventSourceAttribute [System.Diagnostics.Tracing]

EventTask [System.Diagnostics.Tracing]

EventWrittenEventArgs [System.Diagnostics.Tracing]

NonEventAttribute [System.Diagnostics.Tracing]

 

System.Globalization

Calendar [System.Globalization]

CalendarWeekRule [System.Globalization]

CharUnicodeInfo [System.Globalization]

CompareInfo [System.Globalization]

CompareOptions [System.Globalization]

CultureInfo [System.Globalization]

CultureNotFoundException [System.Globalization]

DateTimeFormatInfo [System.Globalization]

DateTimeStyles [System.Runtime]

NumberFormatInfo [System.Globalization]

NumberStyles [System.Runtime]

RegionInfo [System.Globalization]

StringInfo [System.Globalization]

TextElementEnumerator [System.Globalization]

TextInfo [System.Globalization]

TimeSpanStyles [System.Runtime]

UnicodeCategory [System.Globalization]

 

System.IO

BinaryReader [System.IO]

BinaryWriter [System.IO]

EndOfStreamException [System.IO]

FileNotFoundException [System.IO]

IOException [System.IO]

MemoryStream [System.IO]

SeekOrigin [System.IO]

Stream [System.IO]

StreamReader [System.IO]

StreamWriter [System.IO]

StringReader [System.IO]

StringWriter [System.IO]

TextReader [System.IO]

TextWriter [System.IO]

 

System.Reflection

AmbiguousMatchException [System.Reflection]

Assembly [System.Reflection]

AssemblyCompanyAttribute [System.Runtime]

AssemblyConfigurationAttribute [System.Runtime]

AssemblyContentType [System.Reflection]

AssemblyCopyrightAttribute [System.Runtime]

AssemblyCultureAttribute [System.Runtime]

AssemblyDefaultAliasAttribute [System.Runtime]

AssemblyDelaySignAttribute [System.Runtime]

AssemblyDescriptionAttribute [System.Runtime]

AssemblyFileVersionAttribute [System.Runtime]

AssemblyFlagsAttribute [System.Runtime]

AssemblyInformationalVersionAttribute [System.Runtime]

AssemblyKeyFileAttribute [System.Runtime]

AssemblyKeyNameAttribute [System.Runtime]

AssemblyName [System.Reflection]

AssemblyNameFlags [System.Runtime]

AssemblyProductAttribute [System.Runtime]

AssemblySignatureKeyAttribute [System.Runtime]

AssemblyTitleAttribute [System.Runtime]

AssemblyTrademarkAttribute [System.Runtime]

AssemblyVersionAttribute [System.Runtime]

CallingConventions [System.Reflection]

ConstructorInfo [System.Reflection]

CustomAttributeExtensions [System.Reflection.Extensions]

DefaultMemberAttribute [System.Runtime]

EventInfo [System.Reflection]

FieldInfo [System.Reflection]

GenericParameterAttributes [System.Reflection]

IntrospectionExtensions [System.Reflection]

IReflectableType [System.Reflection]

ManifestResourceInfo [System.Reflection]

MemberInfo [System.Reflection]

MethodBase [System.Reflection]

MethodInfo [System.Reflection]

Missing [System.Runtime.InteropServices]

ParameterInfo [System.Reflection]

PropertyInfo [System.Reflection]

ReflectionContext [System.Reflection]

ResourceLocation [System.Reflection]

TargetInvocationException [System.Reflection]

TargetParameterCountException [System.Reflection]

TypeInfo [System.Reflection]

 

System.Resources

MissingManifestResourceException [System.Resources.ResourceManager]

NeutralResourcesLanguageAttribute [System.Resources.ResourceManager]

ResourceManager [System.Resources.ResourceManager]

SatelliteContractVersionAttribute [System.Resources.ResourceManager]

 

System.Runtime

GCLatencyMode [System.Runtime.Extensions]

GCSettings [System.Runtime.Extensions]

 

System.Runtime.CompilerServices

AccessedThroughPropertyAttribute [System.Runtime]

AsyncTaskMethodBuilder [System.Threading.Tasks]

AsyncTaskMethodBuilder`1 [System.Threading.Tasks]

AsyncVoidMethodBuilder [System.Threading.Tasks]

CompilerGeneratedAttribute [System.Runtime]

CompilerMarshalOverride [System.Runtime]

ConditionalWeakTable`2 [System.Dynamic.Runtime]

ConfiguredTaskAwaitable [System.Threading.Tasks]

ConfiguredTaskAwaitable`1 [System.Threading.Tasks]

ContractHelper [System.Diagnostics.Contracts]

CustomConstantAttribute [System.Runtime]

DateTimeConstantAttribute [System.Runtime]

DecimalConstantAttribute [System.Runtime]

ExtensionAttribute [System.Runtime]

FixedBufferAttribute [System.Runtime]

IndexerNameAttribute [System.Runtime]

InternalsVisibleToAttribute [System.Runtime]

IsBoxed [System.Runtime]

IsByValue [System.Runtime]

IsConst [System.Runtime]

IsExplicitlyDereferenced [System.Runtime]

IsImplicitlyDereferenced [System.Runtime]

IsLong [System.Runtime]

IsSignUnspecifiedByte [System.Runtime]

IsUdtReturn [System.Runtime]

IsVolatile [System.Runtime]

MethodImplAttribute [System.Runtime]

MethodImplOptions [System.Runtime]

NativeCppClassAttribute [System.Runtime]

ReferenceAssemblyAttribute [System.Runtime]

RuntimeCompatibilityAttribute [System.Runtime]

RuntimeHelpers [System.Runtime]

TaskAwaiter [System.Threading.Tasks]

TaskAwaiter`1 [System.Threading.Tasks]

TypeForwardedFromAttribute [System.Runtime]

TypeForwardedToAttribute [System.Runtime]

YieldAwaitable [System.Threading.Tasks]

 

System.Runtime.ExceptionServices

ExceptionDispatchInfo [System.Runtime]

 

System.Runtime.InteropServices

AllowReversePInvokeCallsAttribute [System.Runtime.InteropServices]

ArrayWithOffset [System.Runtime.InteropServices]

AssemblyRegistrationFlags [System.Runtime.InteropServices]

AutomationProxyAttribute [System.Runtime.InteropServices]

BestFitMappingAttribute [System.Runtime.InteropServices]

BStrWrapper [System.Runtime.InteropServices]

CallingConvention [System.Runtime.InteropServices]

CharSet [System.Runtime]

ClassInterfaceAttribute [System.Runtime.InteropServices]

ClassInterfaceType [System.Runtime.InteropServices]

CoClassAttribute [System.Runtime.InteropServices]

ComAliasNameAttribute [System.Runtime.InteropServices]

ComCompatibleVersionAttribute [System.Runtime.InteropServices]

ComConversionLossAttribute [System.Runtime.InteropServices]

ComDefaultInterfaceAttribute [System.Runtime.InteropServices]

ComEventInterfaceAttribute [System.Runtime.InteropServices]

ComEventsHelper [System.Runtime.InteropServices]

COMException [System.Runtime.InteropServices]

ComImportAttribute [System.Runtime.InteropServices]

ComInterfaceType [System.Runtime.InteropServices]

ComMemberType [System.Runtime.InteropServices]

ComRegisterFunctionAttribute [System.Runtime.InteropServices]

ComSourceInterfacesAttribute [System.Runtime.InteropServices]

ComUnregisterFunctionAttribute [System.Runtime.InteropServices]

ComVisibleAttribute [System.Runtime]

CriticalHandle [System.Runtime.InteropServices]

CurrencyWrapper [System.Runtime.InteropServices]

CustomQueryInterfaceMode [System.Runtime.InteropServices]

CustomQueryInterfaceResult [System.Runtime.InteropServices]

DefaultCharSetAttribute [System.Runtime.InteropServices]

DispatchWrapper [System.Runtime.InteropServices]

DispIdAttribute [System.Runtime.InteropServices]

DllImportAttribute [System.Runtime.InteropServices]

ErrorWrapper [System.Runtime.InteropServices]

ExporterEventKind [System.Runtime.InteropServices]

ExtensibleClassFactory [System.Runtime.InteropServices]

ExternalException [System.Runtime.InteropServices]

FieldOffsetAttribute [System.Runtime]

GCHandle [System.Runtime.InteropServices]

GCHandleType [System.Runtime.InteropServices]

GuidAttribute [System.Runtime.InteropServices]

HandleRef [System.Runtime.InteropServices]

ICustomAdapter [System.Runtime.InteropServices]

ICustomMarshaler [System.Runtime.InteropServices]

ICustomQueryInterface [System.Runtime.InteropServices]

ImportedFromTypeLibAttribute [System.Runtime.InteropServices]

ImporterEventKind [System.Runtime.InteropServices]

InAttribute [System.Runtime.InteropServices]

InterfaceTypeAttribute [System.Runtime.InteropServices]

InvalidComObjectException [System.Runtime.InteropServices]

InvalidOleVariantTypeException [System.Runtime.InteropServices]

IRegistrationServices [System.Runtime.InteropServices]

ITypeLibExporterNameProvider [System.Runtime.InteropServices]

ITypeLibExporterNotifySink [System.Runtime.InteropServices]

ITypeLibImporterNotifySink [System.Runtime.InteropServices]

LayoutKind [System.Runtime]

LCIDConversionAttribute [System.Runtime.InteropServices]

ManagedToNativeComInteropStubAttribute [System.Runtime.InteropServices]

Marshal [System.Runtime.InteropServices]

MarshalAsAttribute [System.Runtime.InteropServices]

MarshalDirectiveException [System.Runtime.InteropServices]

ObjectCreationDelegate [System.Runtime.InteropServices]

OptionalAttribute [System.Runtime.InteropServices]

OutAttribute [System.Runtime]

PreserveSigAttribute [System.Runtime.InteropServices]

PrimaryInteropAssemblyAttribute [System.Runtime.InteropServices]

ProgIdAttribute [System.Runtime.InteropServices]

RegistrationClassContext [System.Runtime.InteropServices]

RegistrationConnectionType [System.Runtime.InteropServices]

RegistrationServices [System.Runtime.InteropServices]

RuntimeEnvironment [System.Runtime.InteropServices]

SafeArrayRankMismatchException [System.Runtime.InteropServices]

SafeArrayTypeMismatchException [System.Runtime.InteropServices]

SafeBuffer [System.Runtime.InteropServices]

SafeHandle [System.Runtime.InteropServices]

SEHException [System.Runtime.InteropServices]

StructLayoutAttribute [System.Runtime]

TypeIdentifierAttribute [System.Runtime.InteropServices]

TypeLibConverter [System.Runtime.InteropServices]

TypeLibExporterFlags [System.Runtime.InteropServices]

TypeLibFuncAttribute [System.Runtime.InteropServices]

TypeLibFuncFlags [System.Runtime.InteropServices]

TypeLibImportClassAttribute [System.Runtime.InteropServices]

TypeLibImporterFlags [System.Runtime.InteropServices]

TypeLibTypeAttribute [System.Runtime.InteropServices]

TypeLibTypeFlags [System.Runtime.InteropServices]

TypeLibVarAttribute [System.Runtime.InteropServices]

TypeLibVarFlags [System.Runtime.InteropServices]

TypeLibVersionAttribute [System.Runtime.InteropServices]

UnknownWrapper [System.Runtime.InteropServices]

UnmanagedFunctionPointerAttribute [System.Runtime.InteropServices]

UnmanagedType [System.Runtime.InteropServices]

VarEnum [System.Runtime.InteropServices]

VariantWrapper [System.Runtime.InteropServices]

 

System.Runtime.InteropServices.ComTypes

BIND_OPTS [System.Runtime.InteropServices]

BINDPTR [System.Runtime.InteropServices]

CALLCONV [System.Runtime.InteropServices]

CONNECTDATA [System.Runtime.InteropServices]

DESCKIND [System.Runtime.InteropServices]

DISPPARAMS [System.Runtime.InteropServices]

ELEMDESC [System.Runtime.InteropServices]

EXCEPINFO [System.Runtime.InteropServices]

FILETIME [System.Runtime.InteropServices]

FUNCDESC [System.Runtime.InteropServices]

FUNCFLAGS [System.Runtime.InteropServices]

FUNCKIND [System.Runtime.InteropServices]

IBindCtx [System.Runtime.InteropServices]

IConnectionPoint [System.Runtime.InteropServices]

IConnectionPointContainer [System.Runtime.InteropServices]

IDLDESC [System.Runtime.InteropServices]

IDLFLAG [System.Runtime.InteropServices]

IEnumConnectionPoints [System.Runtime.InteropServices]

IEnumConnections [System.Runtime.InteropServices]

IEnumMoniker [System.Runtime.InteropServices]

IEnumString [System.Runtime.InteropServices]

IEnumVARIANT [System.Runtime.InteropServices]

IMoniker [System.Runtime.InteropServices]

IMPLTYPEFLAGS [System.Runtime.InteropServices]

INVOKEKIND [System.Runtime.InteropServices]

IPersistFile [System.Runtime.InteropServices]

IRunningObjectTable [System.Runtime.InteropServices]

IStream [System.Runtime.InteropServices]

ITypeComp [System.Runtime.InteropServices]

ITypeInfo [System.Runtime.InteropServices]

ITypeInfo2 [System.Runtime.InteropServices]

ITypeLib [System.Runtime.InteropServices]

ITypeLib2 [System.Runtime.InteropServices]

LIBFLAGS [System.Runtime.InteropServices]

PARAMDESC [System.Runtime.InteropServices]

PARAMFLAG [System.Runtime.InteropServices]

STATSTG [System.Runtime.InteropServices]

SYSKIND [System.Runtime.InteropServices]

TYPEATTR [System.Runtime.InteropServices]

TYPEDESC [System.Runtime.InteropServices]

TYPEFLAGS [System.Runtime.InteropServices]

TYPEKIND [System.Runtime.InteropServices]

TYPELIBATTR [System.Runtime.InteropServices]

VARDESC [System.Runtime.InteropServices]

VARFLAGS [System.Runtime.InteropServices]

VARKIND [System.Runtime.InteropServices]

 

System.Runtime.InteropServices.WindowsRuntime

DefaultInterfaceAttribute [System.Runtime.InteropServices.WindowsRuntime]

DisposableRuntimeClass [System.Runtime.InteropServices.WindowsRuntime]

EnableCompositionAttribute [System.Runtime.InteropServices.WindowsRuntime]

EventRegistrationToken [System.Runtime.InteropServices.WindowsRuntime]

EventRegistrationTokenTable`1 [System.Runtime.InteropServices.WindowsRuntime]

InterfaceImplementedInVersionAttribute [System.Runtime.InteropServices.WindowsRuntime]

WindowsRuntimeMarshal [System.Runtime.InteropServices.WindowsRuntime]

 

System.Runtime.Serialization

OnDeserializedAttribute [System.Serialization.DataContract]

OnDeserializingAttribute [System.Serialization.DataContract]

OnSerializedAttribute [System.Serialization.DataContract]

OnSerializingAttribute [System.Serialization.DataContract]

SerializationException [System.Serialization.DataContract]

StreamingContext [System.Serialization.DataContract]

 

System.Runtime.Versioning

TargetFrameworkAttribute [System.Runtime]

 

System.Security

SecurityCriticalAttribute [System.Runtime]

SecurityException [System.Runtime]

SecuritySafeCriticalAttribute [System.Runtime]

SecurityTransparentAttribute [System.Runtime]

UnverifiableCodeAttribute [System.Runtime]

VerificationException [System.Runtime]

 

System.Security.Principal

IIdentity [System.Security.Principal]

IPrincipal [System.Security.Principal]

 

System.Text

Decoder [System.Runtime]

DecoderFallbackException [System.Runtime]

Encoder [System.Runtime]

EncoderFallbackException [System.Runtime]

Encoding [System.Runtime]

NormalizationForm [System.Runtime]

StringBuilder [System.Runtime]

UnicodeEncoding [System.Text.Encoding]

UTF8Encoding [System.Text.Encoding]

 

System.Threading

AbandonedMutexException [System.Threading]

ApartmentState [System.Threading]

AutoResetEvent [System.Threading]

CancellationToken [System.Threading.Tasks]

CancellationTokenRegistration [System.Threading.Tasks]

CancellationTokenSource [System.Threading.Tasks]

CountdownEvent [System.Threading]

EventResetMode [System.Threading]

EventWaitHandle [System.Threading]

ExecutionContext [System.Threading]

Interlocked [System.Threading]

IOCompletionCallback [System.Threading]

LazyInitializer [System.Threading]

LazyThreadSafetyMode [System.Runtime]

LockRecursionException [System.Threading]

ManualResetEvent [System.Threading]

ManualResetEventSlim [System.Threading]

Monitor [System.Threading]

Mutex [System.Threading]

NativeOverlapped [System.Threading]

Overlapped [System.Threading]

ParameterizedThreadStart [System.Threading]

RegisteredWaitHandle [System.Threading]

SemaphoreFullException [System.Threading]

SemaphoreSlim [System.Threading]

SendOrPostCallback [System.Threading]

SpinLock [System.Threading]

SpinWait [System.Threading]

SynchronizationContext [System.Threading]

SynchronizationLockException [System.Threading]

Thread [System.Threading]

ThreadAbortException [System.Threading]

ThreadInterruptedException [System.Threading]

ThreadLocal`1 [System.Threading]

ThreadPool [System.Threading]

ThreadPriority [System.Threading]

ThreadStart [System.Threading]

ThreadStartException [System.Threading]

ThreadState [System.Threading]

ThreadStateException [System.Threading]

Timeout [System.Runtime]

Timer [System.Threading]

TimerCallback [System.Threading]

Volatile [System.Threading]

WaitCallback [System.Threading]

WaitHandle [System.Runtime]

WaitHandleCannotBeOpenedException [System.Threading]

WaitOrTimerCallback [System.Threading]

 

System.Threading.Tasks

Parallel [System.Threading.Tasks.Parallel]

ParallelLoopResult [System.Threading.Tasks.Parallel]

ParallelLoopState [System.Threading.Tasks.Parallel]

ParallelOptions [System.Threading.Tasks.Parallel]

Task [System.Threading.Tasks]

Task`1 [System.Threading.Tasks]

TaskCanceledException [System.Threading.Tasks]

TaskCompletionSource`1 [System.Threading.Tasks]

TaskContinuationOptions [System.Threading.Tasks]

TaskCreationOptions [System.Threading.Tasks]

TaskFactory [System.Threading.Tasks]

TaskFactory`1 [System.Threading.Tasks]

TaskScheduler [System.Threading.Tasks]

TaskSchedulerException [System.Threading.Tasks]

TaskStatus [System.Threading.Tasks]

UnobservedTaskExceptionEventArgs [System.Threading.Tasks]

 

Here is the list the assemblies that make up the core types.

System.Collections.dll
System.Colection.ObjectModel.dll
System.Collections.Concurrent.dll

System.Dynamic.Runtime.dll

System.Threading.dll
System.Threading.Tasks.dll
System.Threading.Tasks.Parallel.dll

System.Diagnostics.Debug.dll
System.Diagnostics.tools.dll
System.Diagnostics.Tracing.dll
System.Diagnostics.Contracts.dll

System.Globalization.dll
System.IO.dll
System.Reflection.dll
System.Reflection.Extensions.dll
System.Resources.ResourceManager.dll

System.Runtime.dll
System.Runtime.Extensions.dll
System.Runtime.InteropServices.dll
System.Runtime.InteropServices.WindowsRuntime.dll

System.Serialization.DataContract.dll
System.Security.Principal.dll
System.Text.Encoding.dll

I know a lot of people believe that the new Windows Runtime APIs included in Windows 8 can only be accessed from Metro style applications. A big part of the reason why people believe this is because the version of Visual Studio that ships with the Windows 8 Developer Preview only supports creating Metro style applications. However, I set out this morning to use Windows Runtime APIs from a non-Metro application. Here's what I did.

First, in Notepad, I created the following C# source code in EnumDevices.cs:

using System;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Foundation;

class App {
static void Main() {
EnumDevices().Wait();
}

private static async Task EnumDevices() {
// To call DeviceInformation.FindAllAsync:
// Reference Windows.Devices.Enumeration.winmd when building
// Add the "using Windows.Devices.Enumeration;" directive (as shown above)
foreach (DeviceInformation di in await DeviceInformation.FindAllAsync()) {
Console.WriteLine(di.Name);
}
}
}

Second, I created a Build.bat file which I run from the Developer Command Prompt to build this code (This should be 1 line but I wrap it here for read ability):

csc EnumDevices.cs
/r:c:\Windows\System32\WinMetadata\Windows.Devices.Enumeration.winmd
/r:c:\Windows\System32\WinMetadata\Windows.Foundation.winmd
/r:System.Runtime.WindowsRuntime.dll
/r:System.Threading.Tasks.dll

Then, at the command prompt, I just run the EnumDevices.exe to see the output.

 

Let me also explain how the async stuff works:

The XxxAsync methods (like DeviceInformation.FindAllAsync above) is a Windows Runtime method (defined in Windows.Devices.Enumeration.winmd) that returns a DeviceInformationFindAllAsyncOperation object which implements the Windows Runtime's IAsyncOperation<TResult> interface where TResult is the Windows.Devices.Enumeration.DeviceInformationCollection type. This interface is defined in the Windows.Foundation.winmd file.

Using the await keyword causes the compiler to look for a GetAwaiter method on this interface. Since IAsyncOperation<TResult> does not define a GetAwaiter method, the compiler wants to look for an extension method. In the System.Runtime.WindowsRuntime.dll assembly is the static System.WindowsRuntimeSystemExtensions class. This class defines several GetAwaiter extensions methods and the compiler emits code that invokes the GetAwaiter extension method that takes an IAsyncOperation<TResult> and returns a System.Runtime.CompilerServices.TaskAwaiter<TResult> object (defined in the System.Threading.Tasks.dll which is why this assembly is referenced). Since TResult is the Windows.Devices.Enumeration.DeviceInformationCollection type, the await operator ultimately returns this type which is then used by the foreach loop. Inside the loop, I just display the Name property for each DeviceInformation object.

 

Because you cannot mark an entry point method (like Main) as being async, I moved the code that calls await into its own EnumDevices method, marked this method as async, and make it return a Task. Then Main invokes this method and calls Wait on the returned Task so that the application doesn't terminate until EnumDevices has run all the way through to completion.

Recently, I have been involved with some videos related to threading and Windows Azure which I’d like to share with you:

  • I was the guest on an episode of AppFabric.TV released today! In this episode, I explain how asynchronous programming allows you to build scalable services. Watch the video here.
  • I recently did a Windows Azure roadshow in New York, Boston, Atlanta, and Washington, DC. The New York event was recorded and the introduction of it is available here.
  • Mads Torgersen of Microsoft’s Visual Studio team did a Channel 9 video discussing the new Async CTP and he mentions my involvement with it. The cideo is available here. Mads mentions me around 10 minutes into the video.

I hope you enjoy these,
-- Jeffrey Richter (http://Wintellect.com/)

Just $23.99. Save 50% w/code DDCV3 http://oreil.ly/musvJw

Wintellect is conducting a contest where you could win an XBOX 360 Kinect Bundle. THis contest requires minimal effort from you. To register, all you have to do is signup up for a free Windows Azure pass and deploy a service that is provided for you. You do not need to install anything on your computer to participate. For instructions and to see your chances of winning (updated in real-time), go to http://WintellectAzureContest.cloudapp.net/.

As I write this blog post, only 1 person has registered so far so your odds of winning are VERY good!

I am doing a FREE full-day seminar on programming for Windows Azure in 4 cities in mid-May 2011. The New York event will be broadcast live over the internet. To register for an in-person event, please see https://www.wintellect.com/Training/Webinar/Registration. To register for the live streaming event, please see https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032484438&EventCategory=4&culture=en-US&CountryCode=US.

Wintellect is working with Microsoft to offer a free 1-day Windows Azure event hosted by me. You can find more information at https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032484438&EventCategory=4&culture=en-US&CountryCode=US

http://blogs.msdn.com/b/devpara/archive/2011/04/01/jeffrey-richter-speaks-about-windows-azure-and-asynchronous-programming.aspx

In a few editions of my book, I showed how to implement weak event handlers which allow an object to be GCd if no other reference is keeping the object alive. If the object is alive, it recieves the event notification and if it isn’t alive, it doesn’t receive the event notification. It has come to my attention that the code I show in my book is incorrect and does not work as advertised. I have corrected that code and the working version is shown below:

public static class WeakEventHandler {
   private class WeakEventHandlerImpl {
      protected readonly WeakReference m_wrTarget; // WeakReference to original delegate's target object
      protected Delegate m_openEventHandler;       // "Open" delegate to invoke original target's delegate method

      public WeakEventHandlerImpl(Delegate d) { m_wrTarget = new WeakReference(d.Target); }
         
      // Match is used to compare a WeakEventHandlerImpl object with an actual delegate.
      // Typically used to remove a WeakEventHandlerImpl from an event collection.
      public Boolean Match(Delegate strongEventHandler) {
         // Returns true if original target & method match the WeakEventHandlerImpl's Target & method
         return (m_wrTarget.Target == strongEventHandler.Target) && (m_openEventHandler.Method == strongEventHandler.Method);
      }
   }

   // "Open" delegate definition to quickly invoke original delegate's callback
   private delegate void OpenEventHandler<TTarget, TEventArgs>(TTarget target, Object sender, TEventArgs eventArgs)
      where TTarget : class
      where TEventArgs : EventArgs;

   // A proxy object that knows how to invoke a callback on an object if it hasn't been GC'd
   private sealed class WeakEventHandlerImpl<TEventHandler> : WeakEventHandlerImpl where TEventHandler : class {
      // Refers to a method that removes a delegate to this proxy object once we know the original target has been GC'd
      private readonly Action<TEventHandler> m_cleanup;

      // This is the delegate passed to m_cleanup that needs to be removed from an event
      private readonly TEventHandler m_proxyHandler;

      public static TEventHandler Create(TEventHandler eh, Action<TEventHandler> cleanup) {
         Contract.Requires(eh != null && cleanup != null);
         // We don't create weak events for static methods since types don't get GC'd
         Delegate d = (Delegate)(Object)eh;  // We know that all event handlers are derived from Delegate
         if (d.Target == null) return eh;

         var weh = new WeakEventHandlerImpl<TEventHandler>(d, cleanup);
         return weh.m_proxyHandler; // Return the delegate to add to the event
      }

      private WeakEventHandlerImpl(Delegate d, Action<TEventHandler> cleanup) : base(d) {
         m_cleanup = cleanup;

         Type targetType = d.Target.GetType();
         Type eventHandlerType = typeof(TEventHandler);
         Type eventArgsType = eventHandlerType.IsGenericType
            ? eventHandlerType.GetGenericArguments()[0]
            : eventHandlerType.GetMethod("Invoke").GetParameters()[1].ParameterType;

         // Create a delegate to the ProxyInvoke method; this delegate is registered with the event
         var miProxy = typeof(WeakEventHandlerImpl<TEventHandler>)
            .GetMethod("ProxyInvoke", BindingFlags.Instance | BindingFlags.NonPublic)
            .MakeGenericMethod(targetType, eventArgsType);
         m_proxyHandler = (TEventHandler)(Object)Delegate.CreateDelegate(eventHandlerType, this, miProxy);

         // Create an "open" delegate to the original delegate's method; ProxyInvoke calls this
         Type openEventHandlerType = typeof(OpenEventHandler<,>).MakeGenericType(d.Target.GetType(), eventArgsType);
         m_openEventHandler = Delegate.CreateDelegate(openEventHandlerType, null, d.Method);
      }

      private void ProxyInvoke<TTarget, TEventArgs>(Object sender, TEventArgs e)
         where TTarget : class
         where TEventArgs : EventArgs {
         // If the original target object still exists, call it; else call m_cleanup to unregister our delegate with the event
         TTarget target = (TTarget)m_wrTarget.Target;
         if (target != null) 
            ((OpenEventHandler<TTarget, TEventArgs>)m_openEventHandler)(target, sender, e);
         else m_cleanup(m_proxyHandler);
      }
   }

   // We offer this overload because it is so common
   public static EventHandler Wrap(EventHandler eh, Action<EventHandler> cleanup) {
      return WeakEventHandlerImpl<EventHandler>.Create(eh, cleanup);
   }
   public static TEventHandler Wrap<TEventHandler>(TEventHandler eh, Action<TEventHandler> cleanup) where TEventHandler : class {
      return WeakEventHandlerImpl<TEventHandler>.Create(eh, cleanup);
   }
   public static EventHandler<TEventArgs> Wrap<TEventArgs>(EventHandler<TEventArgs> eh, Action<EventHandler<TEventArgs>> cleanup) where TEventArgs : EventArgs {
      return WeakEventHandlerImpl<EventHandler<TEventArgs>>.Create(eh, cleanup);
   }
   public static Boolean Match(Delegate weakEventHandler, Delegate strongEventHandler) {
      return ((WeakEventHandlerImpl) weakEventHandler.Target).Match(strongEventHandler);
   }
}

To use it, instead of registerring an event callback like this:
      someButton.Click += o.ClickHandler;

Do this:
      someButton.Click += WeakEventHandler.Wrap(o.ClickHandler, eh => someButton.Click -= eh);

I love computing technologies. I've been programming since 1975 and experimenting with various languages (Basic, Pascal, COBOL, FORTRAN, RPG, APL, C, C++, C#, a little Python) and platforms (mostly DOS, Windows, .NET Framework and Android). During these years, I've consulted, published books, published magazine articles, and produced classes to help others work with these some of the more popular of these technologies. To this day, I've kept up with many of these technologies and I will certainly continue to do so. For example, I expect that I will update my CLR via C# book to cover the next version of the CLR and C# (release date unknown).

However, my nature is such that I'm always looking for the next thing to embrace. After much deliberation, I decided to focus on Windows Azure. And, as such, I along with Paul Mehner (another Wintellectual who has been working with Azure even longer than I) have been working together with it almost daily since August 2010. In addition, I've had numerous meetings and e-mail exchanges with Microsoft Azure team members. And now, I'm finally ready to make some announcements:

  • Wintellect now offers a rich 2-day Windows Azure class taught by Paul & myself. We have built a class that we are very proud of. It is packed full of deep information and practical demos & sample code. We have compared our content to many others and truly believe that our class offers much deeper, useful, and practical information than the competition. You can find the syllabus for the class here. A much more detailed class syllabus can be obtained by contacting one of Wintellect's sales people via phone (877-968-5528) or this web page. As always, we are always happy to customize our course content for our customers.

     

  • Wintellect is offering its Devscovery conference three times in 2011 and at all these events I will be leading a "Day of Windows Azure" class and Paul will also be leading some Azure sessions as well.

     

  • I also will be posting a bunch of Windows-Azure focused blog posts (available here) & on-line articles where I'll share tips and techniques with you to hopefully simplify your effort own efforts when working with Azure In addition, I will be hosting a complimentary webinar on March 11th from 12 p.m. – 1 p.m. ET covering Azure Blob Storage. I will be discussing the many features offered by Windows Azure Blob Storage including: accounts, containers, blobs, and blocks/pages, using the storage client library to access blobs, how to conditionally access blobs, blob snapshots, leases, and shared access signatures. You can register for this event here.

     

  • We have also produced a useful class library of helper code for people working with Azure. We call it Wintellect's Power Azure Library. It needs some more testing and documentation but when it is ready, we'll make it freely available from the Wintellect Resource Downloads page.

     

  • Paul and I have also built an Azure diagnostic transfer tool (better name to be created) that can be scripted or run interactively. This tool can force a transfer of Azure diagnostic information from your running instances to Azure storage. Then, the tool can download from storage the Azure diagnostic data creating CSV files which can be loaded into Excel (or other tool) and easily processed including the ability to create charts and graphs. In addition, the tool converts the performance monitor data into a file which can be read by the Windows Performance Monitor tool allowing you to graphically see the values of role instance performance counters over time. This tool will be offered for free and, when available, it can also be downloaded from the Wintellect Resource Downloads page.

     

  • For many, many years, I have been adding little features to my PushPin utility (also freely available from the Wintellect Resource Downloads page). I use this utility throughout every day of my life. It allows me to pin any window on top of other windows, change the opacity of windows, dial phone numbers, rotate the display, touch file timestamps, download files from the web, determine which app(s) have a file in use, navigate to registry keys in RegEdit.exe, and more. The new version of PushPin now periodically checks your Azure subscription and informs you if you have any deployed services running in the cloud allowing you to delete the deployments in order to avoid racking up charges. This utility is great for presenters, experimenters, or testers who deploy services to Azure and do not want to leave the deployment running indefinitely.

     

  • At Wintellect, we offer consulting services on many various technologies and, for some time now, we have been helping various companies migrate their existing applications to Windows Azure. The results of this real-world experience can be seen in everything we do: courses, conference sessions, blog posts, articles, class libraries, and tools.

And, before anyone asks: At this time, I do not plan on writing a book about Windows Azure development due to the time commitment involved in producing a brand new book. But, hopefully, I can get relevant information out to you sooner (and more cheaply) via all the avenues mentioned above. Also stay-tuned as I will be announcing the release of our new online (premium) content, you must sign up with Wintellect (please note that signing up is free). I will release more details in the coming weeks, so stay tuned.

Many developers are familiar with Thread Local Storage (TLS) as a mechanism allowing you to associate a piece of data with a thread. I usually discourage people from using TLS because I recommend architecting applications to perform their operations using thread pool threads. TLS doesn't work with the thread pool because different thread pool threads all take part in a since workflow or operation sequence. However, sometimes people would like to associate some data with a workflow that multiple threads participate in. The .NET Framework has a little-known facility that allows you to associate data with a "logical" thread-of-execution. This facility is called logical call context and it allows data to flow to other threads, AppDomains, and even to threads in other processes.

While the logical call context facility was originally created for use by the .NET Framework's remoting infrastructure it can certainly be used without using remoting. Here's how it works, every managed thread has a hashtable object associated with it. For this hastable, the keys are String objects and the values are can refer to any object whose type is marked with the [Serializable] custom attribute. The content of this hashtable is automatically serialized/deserialized when a logical thread of execution crosses a physical thread, appdomain, or process boundary.

To manipulate a thread's logical call context hashtable, you call the static LogicalSetData and LogicalGetData methods defined on the CallContext class (defined in the System.Runtime.Remoting.Messaging namespace). You delete a key from the hashtable by calling FreeNamedDataSlot. The class looks like this:

[Serializable]
public sealed class CallContext : ISerializable {
public static void LogicalSetData(String name, Object data);
public static Object LogicalGetData(String name);
public static void FreeNamedDataSlot(String name);

// For remoting only
public static void SetHeaders(Header[] headers);
public static Header[] GetHeaders();
}

Here is a small sample application that demonstrates the call context mechanism:

public static class Program {
   private const String c_CCDataName = "CCData";

   private static void Main() {
      // Set an item in the thread's call context
      CallContext.LogicalSetData(c_CCDataName, "Data=" + DateTime.Now);

      // Get the item in the thread's call context
      GetCallContext();

      // Show that call context flows to another thread
      WaitCallback wc = na => GetCallContext();
      wc.EndInvoke(wc.BeginInvoke(nullnullnull));

      // Show that call context flows to another AppDomain
      AppDomain ad = AppDomain.CreateDomain("Other AppDomain");
      ad.DoCallBack(GetCallContext);
      AppDomain.Unload(ad);

// Remove the key to prevent (de)serialization of its value
// from this point on improving performance

      CallContext.FreeNamedDataSlot(c_CCDataName);

      // Show no data due to the key being removed from the hashtable
      GetCallContext(); 
   }

   private static void GetCallContext() {
      // Get the item in the thread's call context
      Console.WriteLine("AppDomain={0}, Thread ID={1}, Data={2}",
         AppDomain.CurrentDomain.FriendlyName,
         Thread.CurrentThread.ManagedThreadId,
         CallContext.LogicalGetData(c_CCDataName));
   }

}

 

When I compile and run this code, I get the following output:

AppDomain=04a-Contexts.exe, Thread ID=1, Data=Data=9/27/2010 2:47:55 PM
AppDomain=04a-Contexts.exe, Thread ID=3, Data=Data=9/27/2010 2:47:55 PM
AppDomain=Other AppDomain, Thread ID=1, Data=Data=9/27/2010 2:47:55 PM
AppDomain=04a-Contexts.exe, Thread ID=1, Data=

Since the logical call context mechanism serializes and deserializes objects in a hashtable, it is a pretty expensive mechanism. That is, it takes time to serialize & deserialize objects and, of course, deserializing objects creates objects in the managed heap which must ultimately be garbage collected. So, in my own applications, I try to avoid the call context mechanism just like I try to avoid TLS. However, there are occasions where call context can fill a need and save the day.

In version 2.0 of the .NET Framework, Microsoft introduced the System.Threading. SynchronizationContext class. Simply stated, a SynchronizationContext-derived object connects an application model to its threading model. The FCL defines several classes derived from SynchronizationContext, but usually you will not deal directly with these classes; in fact, many of them are not publicly exposed or documented. Here is what the SynchronizationContext class looks like (I show only the members relevant to this discussion):

public class SynchronizationContext {
// Gets the SynchronizationContext-derived object
// associated with the calling thread
public static SynchronizationContext Current { get; }

// Invokes d asynchronously
public virtual void Post(SendOrPostCallback d, object state);

// Invokes d synchronously
public virtual void Send(SendOrPostCallback d, object state);
}

// SendOrPostCallback is a delegate defined like this:
public delegate void SendOrPostCallback(Object state);

Console and NT service applications have no threading model and therefore calling SynchronizationContext.Current will return null. For GUI applications such as Windows Forms, Windows Presentation Foundation, and Silverlight, the threading model dictates that all UI components must be updated by the thread that created them. So, when a GUI thread calls SynchronizationContext.Current, a reference to an object that knows how to invoke the d delegate on the calling GUI thread is returned. For ASP.NET applications, calling SynchronizationContext.Current returns a reference to an object that knows how to associates the original client request's identity and culture with the calling thread before invoke the d delegate (which will be invoked on the same thread that calls SynchronizationContext's Post or Send methods. In fact, for an ASP.NET SynchronizationContext object, the Post and Send methods do the exact same thing: they call the d delegate synchronously.

When working with the .NET Framework's Asynchronous Programming Model (APM), understanding the SynchronizationContext is extremely important as it allows the callback method to be invoked using your application's thread model. To simplify this, I wrote the following little method:

private static AsyncCallback SyncContextCallback(AsyncCallback callback) {
// Capture the calling thread's SynchronizationContext-derived object
SynchronizationContext sc = SynchronizationContext.Current;

// If there is no SC, just return what was passed in
if (sc == null) return callback;

// Return a delegate that, when invoked, posts to the captured SC a method that
// calls the original AsyncCallback passing it the IAsyncResult argument
return asyncResult => sc.Post(
result => callback((IAsyncResult)result), asyncResult);
}

This method turns a normal AsyncCallback method into an AsyncCallback method that is invoked via the SynchronizationContext-derived object associated with the calling thread.

Recently, I was involved in a Wintellect consulting engagement where a customer had some class library code that was created years ago. The code in this class library was not designed to work well in a multithreaded environment. Specifically, this means that if two or more threads called into the class library code at the same time, the data got corrupted and the results could not be trusted. Non-concurrent-ready code is easy to obtain with frequent use of mutable static fields. But, there are other common coding practices which can result in code that is not safe with multiple threads passing through it at the same time.

This customer wanted to increase the performance of their code and the best way to accomplish this is to have multiple threads processing their own data independently of each other. But, again, the class library code base would produce errant results if we did this. To demonstrate the problem, imagine this very simple static class which is indicative of the non-thread safe class library that I'm referring to:

internal static class NonConcurrentAlgorithm {

private static List<String> s_items = new List<String>();

 

public static void Add(String item) { s_items.Add(item); }

public static String[] GetItems() { return s_items.ToArray(); }

}

 

If we have two threads using this class simultaneously, the results are unpredictable. For example, let's say we have this code:

ThreadPool.QueueUserWorkItem(o => NonConcurrentAlgorithm.Add("Item 1"), null);
NonConcurrentAlgorithm.Add("Item 2");
Thread.Sleep(1000);  // To demonstrate the problem consistently
foreach (var i in NonConcurrentAlgorithm.GetItems())
   Console.WriteLine(i);

 

When this code runs, the console could show:

  • "Item 2" by itself
  • "Item 2" followed by "Item 1"
  • "Item 1" followed by "Item 2"

Clearly, this is not desireable and the problem all stems from the threads sharing the one List<String> object. In fact, the List<T> class is not itself thread-safe and so it is even possible that having multiple threads accessing it simultaneously could result in items disappearing or a single item being inserted multiple times, or worse. It depends on how the List<T> class is internally implemented which is not documented and is subject to change.

Now, one way to improve performance for the customer would be for Wintellect to take the non-concurrent code base and make it thread safe. This is the best thing to do; however, the code base was very large, the changes to the code base would have been substantial and a lot of testing would have had to be done. The customer was not too excited by this recommendation. So, what we did instead was use the CLR's AppDomain feature. This works out great because an AppDomain's state is completely isolated from all other AppDomains. To communicate across AppDomains, you must create a class derived from MarshalByRefObject. So, I created a NonConcurrentAlgorithmProxy class that wraps the methods of the static class. The NonConcurrentAlgorithmProxy class looks like this:

internal sealed class NonConcurrentAlgorithmProxy : MarshalByRefObject {

   public void Add(String item) { NonConcurrentAlgorithm.Add(item); }
   public String[] GetItems()  { return NonConcurrentAlgorithm.GetItems(); }
}

 

Then we modified the code that uses this class library code so that each thread creates its own AppDomain and creates an instance of the NonConcurrentAlgorithmProxy class in each AppDomain. The static field in the NonConcurrentAlgorithm class is now one-per-AppDomain and since each thread gets its own AppDomain, there is now one List<String> object per thread. Here is the new code that uses the class library code via the proxy class:

// Create Thread 1's AppDomain & proxy
var thread1AppDomain = AppDomain.CreateDomain(String.Empty);
var thread1Proxy = (NonConcurrentAlgorithmProxy)

   thread1AppDomain.CreateInstanceAndUnwrap(

      typeof(NonConcurrentAlgorithmProxy).Assembly.FullName,

      typeof(NonConcurrentAlgorithmProxy).FullName);

// Create Thread 2's AppDomain & proxy
var thread2AppDomain = AppDomain.CreateDomain(String.Empty);
var thread2Proxy = (NonConcurrentAlgorithmProxy

   thread2AppDomain.CreateInstanceAndUnwrap(


					typeof(NonConcurrentAlgorithmProxy).Assembly.FullName, 


					typeof(NonConcurrentAlgorithmProxy).FullName);

// Have 2 threads execute the same code at the same time but in different AppDomains
ThreadPool.QueueUserWorkItem(o => thread2Proxy.Add("Item 1"), null);
thread1Proxy.Add("Item 2");
Thread.Sleep(1000);  // To demonstrate the problem has been fixed

// Show Thread 1's list of items; guaranteed to be "Item 2"
foreach (var i in thread1Proxy.GetItems())
   Console.WriteLine(i);

// Show Thread 2's list of items; guaranteed to be "Item 1"
foreach (var i in thread2Proxy.GetItems())
   Console.WriteLine(i);

// Cleanup each thread's AppDomain
AppDomain.Unload(thread1AppDomain);
AppDomain.Unload(thread2AppDomain);

 

This is substantially less coding, testing, and effort than what would have been involved with making the customer's current code base thread safe! And, this technique can scale very nicely for many threads as well. Of course, there is a slight performance penalty when creating/destroying AppDomains and calling methods through the proxy. This is why it would be ideal to make the existing code base thread safe. But, this is a great compromise and the customer was quite happy with the results and the time/cost it required to improve their application's performance substantially.

More Posts Next page »