2005 2006 2007 2008 2009 2010 2011 2015 2016 2017 2018 aspnet azure csharp debugging docker elasticsearch exceptions firefox javascriptajax linux llblgen mongodb powershell projects python security services silverlight training videos wcf wpf xag xhtmlcss

Tip: Quick Reflector Loading for .NET and Silverlight



In my daily development there are three tools that I keep open almost constantly:  Visual Studio 2008, Windows Debugger, and Reflector.  The first is obvious, the second is for extreme-debugging, and the third so I can have a clue what I’m working with (…I have NO idea how people do .NET or Silverlight development without reflector!)  The first two I access with icons, while the third is one that I open and close at least 10 times a day.

To quickly access reflector (as well as Notepad2 and a whole host of sysinternals apps!) I throw it in my Windows folder so I can access it from the Run box.  Not only that, but I typically rename tools I throw in there to have only one letter.  Reflector is “r”.  So, I hit Win-R and type “r”.  Up comes reflector.  Here’s the thing though: I work in both .NET and Silverlight equally.  Yet, Reflector only loads ONE of them.  What to do?

The fix is simple: copy r.exe to rs.exe.  When I load r.exe, I select .NET.  When I load rs.exe, I select Silverlight.  Now I when I hit Win-R, I can type either “r” or “rs” depending on what framework I want to inspect.  You could even take the concept further by making a “rf.exe” for the compact framework”  Each “x.exe” will have it’s own “x.cfg” so the configurations won’t bleed over each other.

Adding XmlNode to Silverlight



Of the many types of data I work with, XML shows up all the time.  However, when working in Silverlight, your XML options are dramatically limited.  For example, for some reason Microsoft totally forgot to add a simple XmlNode class.  Microsoft seems to think that using LINQ for XML will solve all our XML problems.  Well, most of the stuff that I do on a daily basis has nothing to do with extensive querying XML.  I just need something simple to pull quick data.  Not only that, but LINQ for XML is in the System.Xml.Linq assembly, which is not a native Silverlight assembly.  I’m not going to bloat my XAP file for a single dependency.

So, in my internal build of Themelia for Silverlight, you will find the Themelia.Xml.XmlNode class.  I use this all over the build entire XML trees and to search the same tree for elements I need.  All this in one small discrete class that doesn’t require you to bloat your XAP file.  Here’s a sample of how to use my XmlNode class:

XmlReader reader = XmlReader.Create(new StringReader(@"<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">
    <s:Body>
    <s:Fault>
      <faultcode>s:Client</faultcode>
      <faultstring xml:lang=""en-US"">This is the fault reason.</faultstring>
      <detail>
        <FaultDetail xmlns=""http://schemas.datacontract.org/2004/07/Sample.Service"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
          <Reason>This is the fault reason.</Reason>
          <Source>GetPersonData</Source>
        </FaultDetail>
      </detail>
    </s:Fault>
    </s:Body>
    </s:Envelope>"));
XmlNode node = new XmlNode(reader);
XmlNode faultDetailNode = node.FindDescendant("faultDetail");
stackpanel01.Children.Add(new TextBlock
{
    Text = faultDetailNode.FirstChild.TextContent
});
stackpanel01.Children.Add(new TextBlock
{
    Text = faultDetailNode.AttributeDictionary["xmlns"]
});
stackpanel01.Children.Add(new TextBlock
{
    Text = faultDetailNode.AttributeDictionary["xmlns:i"]
});

It does a few more things that you can see by looking at the source for it, but this is essentially all I need in for XML processing on most days.  Here’s the source for XmlNode.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
//+
namespace Themelia.Xml
{
    public class XmlNode
    {
        //- @Name -//
        public String Name { get; set; }


        //- @TextContent -//
        public String TextContent { get; set; }


        //- @Children -//
        public List<XmlNode> NodeList { get; set; }


        //- @AttributeMap -//
        public Dictionary<String, String> AttributeDictionary { get; set; }


        //- @FirstChild -//
        public XmlNode FirstChild
        {
            get
            {
                if (NodeList.Count > 0)
                {
                    return NodeList[0];
                }
                //+
                return null;
            }
        }


        //+
        //- @Ctor -//
        private XmlNode()
        {
            NodeList = new List<XmlNode>();
            AttributeDictionary = new Dictionary<String, String>();
        }
        public XmlNode(XmlReader xmlReader)
            : this()
        {
            Initialize(xmlReader);
        }
        public XmlNode(Stream xmlStream)
            : this(XmlReader.Create(xmlStream))
        {
        }
        public XmlNode(String name)
            : this()
        {
            Name = name;
        }


        //- $Initialize -//
        private void Initialize(XmlReader reader)
        {
            reader.Read();
            this.Name = reader.Name;
            //+ attribute
            reader.MoveToElement();
            if (reader.HasAttributes)
            {
                reader.MoveToFirstAttribute();
                AttributeDictionary.Add(reader.Name, reader.Value);
                while (reader.MoveToNextAttribute())
                {
                    AttributeDictionary.Add(reader.Name, reader.Value);
                }
            }
            //+ node
            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element)
                {
                    NodeList.Add(new XmlNode(reader.ReadSubtree()));
                }
                else if (reader.NodeType == XmlNodeType.Text)
                {
                    TextContent = reader.ReadContentAsString();
                }
            }
        }


        //- @FindDescendant -//
        public XmlNode FindDescendant(String name)
        {
            XmlNode foundNode = NodeList.FirstOrDefault(p => p.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
            if (foundNode != null)
            {
                return foundNode;
            }
            foreach (XmlNode node in NodeList)
            {
                foundNode = node.FindDescendant(name);
                if (foundNode != null)
                {
                    return foundNode;
                }
            }
            //+
            return foundNode;
        }


        //- @FindDescendantList -//
        public List<XmlNode> FindDescendantList(String name)
        {
            List<XmlNode> nodeList = new List<XmlNode>();
            XmlNode foundNode = NodeList.FirstOrDefault(p => p.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
            if (foundNode != null)
            {
                nodeList.Add(foundNode);
                foundNode = null;
            }
            foreach (XmlNode node in NodeList)
            {
                foundNode = node.FindDescendant(name);
                if (foundNode != null)
                {
                    nodeList.Add(foundNode);
                    foundNode = null;
                }
            }
            //+
            return nodeList;
        }


        //- @GetChildDictionary -//
        public Dictionary<String, String> GetChildDictionary()
        {
            Dictionary<String, String> map = new Dictionary<String, String>();
            foreach (XmlNode node in NodeList)
            {
                if (!String.IsNullOrEmpty(node.TextContent))
                {
                    map.Add(node.Name, node.TextContent);
                }
            }
            //+
            return map;
        }
    }
}

Yeah, there’s more it could probably do and I’ll probably add more to it in the future, but this little class has worked in all my XML scenarios so far.

Obtaining Enumeration Names and Values in Silverlight 2.0



In .NET, when you are dealing with singular enumerations (the ones singular names) or flags enumerations (the ones with plural names), you have the ability to access the names and values of each of the items in the enumeration.  For example, the below code iterates through and prints out both the values and names of the enumeration items:

using System;
//+
namespace Sample
{
    public enum Component
    {
        Keyboard,
        Mouse,
        Display,
        Disk,
        Memory,
        Network
    }

<span style="color: blue">public class </span><span style="color: #2b91af">Program
</span>{
    <span style="color: green">//- $Main -//
    </span><span style="color: blue">private static void </span>Main(<span style="color: #2b91af">String</span>[] args)
    {
        <span style="color: green">//+ name
        </span><span style="color: blue">foreach </span>(<span style="color: #2b91af">String </span>name <span style="color: blue">in </span><span style="color: #2b91af">Enum</span>.GetNames(<span style="color: blue">typeof</span>(<span style="color: #2b91af">Component</span>)))
        {
            <span style="color: #2b91af">Console</span>.WriteLine(name);
        }
        <span style="color: green">//+ value
        </span><span style="color: blue">foreach </span>(<span style="color: #2b91af">Object </span>value <span style="color: blue">in </span><span style="color: #2b91af">Enum</span>.GetValues(<span style="color: blue">typeof</span>(<span style="color: #2b91af">Component</span>)))
        {
            <span style="color: #2b91af">Console</span>.WriteLine((<span style="color: #2b91af">Int32</span>)value);
        }
    }
}

}

Now let’s go to do the same thing in Silverlight 2.0.

image

Err... wait a minute.  Where’s GetNames and GetValues?  Well, they don’t exist.  Fortunately, we have the ability to access these via reflection.  To obtain the names, we just need to obtain the Type object of our enumeration and call GetFields with the Public and Static binding flags set, and look in the resulting FieldInfo array.  Each FieldInfo object will have a Name property without item name.  For the values, we simply use Enum.Parse to turn that name into the actual value.  For the underlying value, we can just cast that to the underlying type of the enumeration.  In the example above, that would be System.Int32.  Here’s all that in action:

 

//- $OnLoaded -//
private void OnLoaded(Object sender, System.Windows.RoutedEventArgs e)
{
    Type enumType = typeof(Component);
    System.Reflection.FieldInfo[] fiArray = enumType.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
    foreach (System.Reflection.FieldInfo fi in fiArray)
    {
        //+ name
        sp01.Children.Add(new TextBlock
        {
             Text = fi.Name
        });
    }
    foreach (System.Reflection.FieldInfo fi in fiArray)
    {
        //+ value
        sp01.Children.Add(new TextBlock
        {
            Text = ((Int32)Enum.Parse(enumType, fi.Name, false)).ToString()
        });
    }
}

I’ve left the namespaces of the items in the System.Reflection namespace in place so you can see exactly what types were working with here.

Of course, you can always wrap this up into it’s own class so you can reuse this logic all over:

namespace Themelia
{
    public class EnumReader
    {
        /// <summary>
        /// Gets the names of an enumeration type.
        /// </summary>
        /// <param name="enumerationType">Type of enumeration.</param>
        /// <returns>List of names of the enumeration.</returns>
        public static List<String> GetNameList(Type enumType)
        {
            if (!enumType.IsEnum)
            {
                throw new InvalidOperationException("Specified generic parameter must be an enumeration.");
            }
            List<String> nameList = new List<String>();
            //+ type
            FieldInfo[] fiArray = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
            foreach (FieldInfo fi in fiArray)
            {
                nameList.Add(fi.Name);
            }
            //+
            return nameList;
        }


        //- @GetNameList -//
        /// <summary>
        /// Gets the names of an enumeration type.
        /// </summary>
        /// <typeparam name="T">Type of enumeration.</typeparam>
        /// <returns>List of names of the enumeration.</returns>
        public static List<String> GetNameList<T>() where T : struct
        {
            return GetNameList(typeof(T));
        }


        //- @GetValueList -//
        /// <summary>
        /// Gets the values of an enumeration type.
        /// </summary>
        /// <typeparam name="T">Type of enumeration.</typeparam>
        /// <returns>List of values of the enumeration.</returns>
        public static List<T> GetValueList<T>() where T : struct
        {
            Type enumType = typeof(T);
            if (!enumType.IsEnum)
            {
                throw new InvalidOperationException("Specified generic parameter must be an enumeration.");
            }
            List<T> valueList = new List<T>();
            FieldInfo[] fiArray = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
            foreach (FieldInfo fi in fiArray)
            {
                valueList.Add((T)Enum.Parse(enumType, fi.Name, false));
            }
            //+
            return valueList;
        }
    }
}

In this example class, you can see that two of the methods are actually declared as generic.  So, to use them like this:

//- $OnLoaded -//
private void OnLoaded(Object sender, System.Windows.RoutedEventArgs e)
{
    foreach (String name in EnumReader.GetNameList<Component>())
    {
        //+ name
        sp01.Children.Add(new TextBlock
        {
            Text = name
        });
    }
    foreach (Component component in EnumReader.GetValueList<Component>())
    {
        //+ value
        sp01.Children.Add(new TextBlock
        {
            Text = ((Int32)component).ToString()
        });
    }
}

One thing to keep in mind is that reflection does have a performance hit.  However, given that most of WPF, Silverlight, and WCF are all about constant reflection, you can rest comfortably that it’s not nearly as bad as some people would say.  Having said that, if your application profiling does say that you are reflecting too much, you can always cache the data returned from these method and access the cache instead.  Don’t however, cache for the sake of caching.  Saying “We’re always going to cache, just to be consistent” is as stupid as saying “We’re always going to drive 45mph, just to be consistent.”  This kills people on both the interstate and in school zones.  Make your caching decisions (and ALL other decisions!) based upon your current situation never upon dangerous mindless consistency.

Silverlight Feature Requests



Silverlight is probably the most important technology to be released since Firefox 1.0 and that since .NET 1.0.  However, as with most early-edition pieces of software, there are some major things missing.  Below is a list of things that I request that Microsoft add with a quick note on each.  It ranges from a few UI things to the more hardcore mechanical things (…things that many developers will say are meaningless until they learn how to spell C-L-R).

  • GIF Support - Obvious.  It's very odd that some manager somewhere said "no one ever uses GIF anymore".
  • Style Inheritance - Another obvious one.  We who knew WPF long before Silverlight was around THRIVE on this.
  • DockPanel - COME ON! You MUST be joking! I shouldn't have to use a third party CodePlex control for this.
  • VisualBrush - The ability to paint controls on a background and in other places will go a long way in helping people creating more interactive help files and training software.
  • RelativeSource - The ability to bind one element's property to another is EXTREMELY important (i.e. my height == my parent's height).
  • MultiView - It takes almost no code to write this; just make it native so we don't have dozens of versions all over.
  • WebHttpBinding for JSON - POX is less important, but would be nice; JSON is the de facto web standard.
  • System.Security.Cryptography.RSA with providers - This would greatly increase the security of client-server communication.
  • Workflow Foundation - Even a light version with only the basic activities (for, if, while, etc…) would be nice.
  • SVG Viewer - This should shut up the anti-Microsoft cult.
  • Better font rendering - It's HORRIBLE in 2.0.
  • iPhone Support - I think this may take a miracle.
  • MultiTouch - Need this for iPhone support.
  • CSS3 DOM Selector (http://www.w3.org/TR/selectors-api/) - So we use it instead of jQuery's version for closer-to-native speed on EVERY browser without even needing JQuery.
  • A XMLHttpRequest object - This would allow us to use Silverlight's CrossDomainPolicy.xml stuff for cross domain stuff instead of playing games with browser detection nonsense and adding hacks for browsers which don't support it.
  • API for browser abstraction - Web developers HATE having to do lame detection to figure out if we are on IE so we can talk to it like a child.  Give us the ability to create managed extensions to Silverlight so we can add in our pain-in-the-butt browser differences in Silverlight instead of relying on painfully slow JScript rendering and browser detection.
  • Service for extensions - This goes with the last one.  We should have the ability to 1) extend the hardcore functionality of Silverlight and 2) have a centralize service that Silverlight calls to download our functionality when our application requests it.  This would be very just like what Firefox does when it needs a plugin.  It would also do auto-updating like with Firefox extensions.
  • JSON deserializer that actually works to deserialize data serialized by the JSON serializer - JSON is critically important to the web; it should be supported better.
  • The ability to get 500 HTTP status codes from Firefox, Chrome, and IE - This would allow us to use fault contracts in WCF.  This would have to be a pain to implement, though. So, I wouldn't expect it for a while.
  • The ability for NPCTRL to communicate CLR configuration information to the CoreCLR to tweak GC things that are normally in configuration - If the hosting NPCTRL control would just allow us to give it configuration parameters to send to the CoreCLR, that would RULE (like we can already do in .NET with configuration).
  • Hosting documentation that doesn't SUCK - Using Win32/ATL to host a Silverlight control is insane right now.  The documentation is very incomplete and there are NO samples (and the IDL is wrong!)
  • Background GC on Windows - I suspect that this would increase performance in many scenarios.
  • The missing GC methods - The System.GC class is missing a PUBLICLY ACCESSIBLE GetCollectionCount.  This will help us with profiling.  It's marked as internal now and if you try to access it via reflection or other fancy tricks you get security errors.
  • ICorProfilerCallback interface - This is my NUMBER ONE FEATURE REQUEST!  This is REQUIRED to create a Silverlight profiler.  Silverlight will NOT be a technology ready for enterprise usage without this.  PERIOD.
  • Documentation on Silverlight's ETW - it's there and it's working in SL2, but I see absolutely zero docs on how to access it.
  • The native AGCORE and NPCTRL source code - This will aide in performance and feature creation
  • COM interface for hosting the CoreCLR - not really a Silverlight feature, but this would be REALLY nice.

Project Sneak Peek



Today I thought I would give a teaser of my latest side project (I'm about a month into it).

Since I'm not a general "business application" developer, but am a specialist in various areas of technology, most of the projects I work on are awesome.  Two of my favorite projects are the Brainbench C# 2.0 exam and the Brainbench C# 2.0 Fundamentals exam, both as the author.  Immediately after finishing the later project, I ended my 2 year long on-and-off consultancy with Brainbench as author and technical editor.

Now, nearly a year later, I've gone on my own (more teasers in Q2 2009):

Which of the following statements regarding a .NET object's sync block index are true?
 
When an ephemeral segment GC occurs, the synch block index contains a pointer to the next object.
If a root is found by a GC, a bit will be enabled in the synch block index.
Constructed objects have the sync block index initialized to a negative value.
Value types have their synch block index set to the value of their location on the stack.
When a monitor lock is entered, the index of a free sync block is recorded in the synch block index.

Setting a Silverlight 2 Startup Breakpoint using WinDBG



As I've mentioned on a previous occasion, hardcore debugging is done with WinDBG and SOS.  Visual Studio's debugger just isn't enough for the super interesting scenarios.  I've also mentioned that I have no intention of giving a step-by-step introduction into how to use SOS.  However, given that debugging is directly related to internals and that most people with advanced Silverlight issues will search for "advanced Silverlight debugging" or the like, I'll provide a little information here and there to help people find what they are looking for quicker.

Here I would like to explain how you can set a break point very early in the Silverlight load process, before your application even loads.  This technique will give you a glimpse into the internals of Silverlight to see how things work.  It will also help you to step through your method calls from the very beginning in WinDBG.

First, however, understand that Silverlight has three major components that you need to be aware of:

  • NpCtrl.dll
  • AgCore.dll
  • CoreCLR.dll

Each of these components is critical to loading and running a Silverlight application.  NpCtrl.dll is a browser plugin which follows the Netscape Plugin API (NPAPI).  When your browser sees that you are trying to load Silverlight 2, it will call the NPInitialize export (a public DLL function).  Later, this plug-in will load the AgCore.dll and create a instance of the COM class XcpControl2 to allow NpCtrl to interact with Silverlight (you too can use XcpControl in your COM development).  AgCore is the unmanaged part of Silverlight 2.  It handles everything from DOM interaction, to rendering, to media play.

At this point you will see the spinning XAP-loading progress bar.  When this is complete, NpCtrl will finally load CoreCLR.dll.  Upon load, the DllMain function for this DLL is called.  This function will start up the CoreCLR, the CLR that Silverlight 2 uses.  Upon completion, NpCtrl then calls the GetCLRRuntimeHost DLL export to get the loaded instance of the CLR.  The rest of your application is ready to run (as a side note, the order of a few of these things changes under certain circumstances, so you may actually see CoreCLR load AgCore.)

With this information you're ready to start a fresh instance of a web browser (it's crucial that Silverlight 2 isn't already loaded) and attach WinDBG to your browser's process.  Upon attach you are given control to the command interface.  To set a breakpoint when Silverlight 2 starts, you set a breakpoint when a specific DLL is loaded.  Depending on your needs this may be the npctrl.dll, agcore.dll, or coreclr.dll.

You set a breakpoint for a DLL load in WinDBG by using the following command:

sxe ld:DLLNAME

Thus, if you wanted to break at a specific point in the Silverlight loading procedure, you use one of the following commands:

sxe ld:npctrl

sxe ld:agcore

sxe ld:coreclr

If you want to remove these breakpoints, just type the the following:

sxr

Once you have one or more DLL load breakpoints these and resume your application (the 'g' command or F5 in WinDBG) you can test it our by going to http://themelia.netfxharmonics.com/. If successful, WinDBG will break when your DLL loads.  In the call stack window (or when you type the 'k' command), you will see a call stack that looks something like the following:

kernel32!LoadLibraryW+0x11
npctrl!GetCLRRuntimeHost+0x112
npctrl!CWindowsServices::CreateCLRRuntimeHost+0x19
agcore!CCLRHost::Initialize+0x12a
agcore!CRuntimeHost::Initialize+0x60
agcore!CCoreServices::CLR
Startup+0x95
agcore!CDeployment::Start+0x27
agcore!CCoreServices::StartDeploymentTree+0x53
npctrl!CXcpBrowserHost::put_Source+0x10f
npctrl!CommonBrowserHost::OnGotSourceDownloadResponse+0x4b
npctrl!CXcpDispatcher::OnReentrancyProtectedWindowMessage+0x284
npctrl!CXcpDispatcher::WindowProc+0x51 ¨C11CUSER32!InternalCallWinProc+0x28 ¨C12CUSER32!UserCallWinProcCheckWow+0x150

Chances are, though, that you won't see this information like this at first.  Instead, you will probably see a series of memory addresses.  To view the actual function names, you must configure your symbol paths in WinDBG.  These symbols, often called PDBs, will relate the machine information with information from the original source.  In our case, we need them to view the function names.

To setup symbols, use the following command, replacing C:_SYMBOL with a symbol location of your choice (symbols are very important and, therefore, should not be thrown into a "temp" folder):

. symfix SRVC:_SYMBOLhttp://msdl.microsoft.com/download/symbols;SRVC:_SYMBOLhttp://symbols.mozilla.org/firefox

You may also enter this information in the window that is shown when you hit Ctrl-S.  Either way, this will configure the symbols for both Microsoft's symbol server and Mozilla's.  The latter will help you view exactly how far the loading processing has gone while in Firefox.

With the symbols configured, you will then be able see something like the above call stack.  If you set the symbols after you had already loaded Silverlight 2 in your browser, then you need to exit the browser, start a new instance, and reattach WinDBG.  Regardless, every time a DLL is loaded, WinDBG will automatically access the appropriate Microsoft and Mozilla and download the symbol file for that DLL.  This will take time for every DLL that is to be loaded.  Expect the WinDBG status bar to read BUSY for a long time.  It will only load the symbol for each DLL once.

The method I've just described works perfectly for breaking in WinDBG Firefox and IE.  But, what about Chrome?  Depending on settings, Google Chrome uses either a process-per-tab model or a process-per-site model.  While this flexibility is great for daily use, for debugging we can't have processes bouncing around like jack rabbits on cocaine.  You need a process that you can attach to that won't run away as soon as you use it.  So, to successfully attach WinDBG to Chrome, you should start Chrome up in single process mode.  You do this as follows:

chrome.exe --single-process

At this point, you can attach to Firefox, IE, and Chrome for Silverlight 2 debugging in Silverlight.

Silverlight SOS Commands



Today I became rather curious of what commands Silverlight's version of SOS provided (see my Learning WinDBG/SOS and Advanced Debugging post for more information on SOS).  I didn't really have any guess to whether there would be more, less, or the same.  So I ran Silverlight's SOS.dll through .NET's dumpbin.exe application with the /exports switch to get a list of what you can do with it.  In this case, the lower case DLL exports are the actual SOS commands you can use.  I did dumpbin.exe on the .NET 2.0 version and did a diff between them.  The results?  The Silverlight version of SOS actually has more commands than the .NET version.

Here is a list of SOS commands that aren't in the .NET version:

analyzeoom histobj vh
ao histobjfind vo
dumpsigelem histroot  
findroots histstats  
fq hof  
gcheapstat listnearobj  
gcwhere lno  
heapstat t  
histclear tp  
histinit verifyobj  

You can type these into your debugger to see the specific syntax for each of these.  For detailed information on most of these, you'll have to wait until something gets posted on MSDN or one of the SOS developers post something.  For a few, however, Sasha Goldshtein has provided some information and examples.  Here are some posts from this person's web site where you can find information no some of these new commands:

In case you're wondering, the .NET version has a few commands that the Silverlight version didn't have too.  This isn't a big deal as the commands that are missing don't really have much meaning for Silverlight (or have an alternative).  Here's a list of these:

comstate
dumpmethodsig
rcwcleanuplist
tst

Also, for the sake of completeness, below is the completely list of all Silverlight commands.  Just type then into WinDBG with the ! prefix to play with each of them.  For many of them you can type "!sos.help COMMANDNAME" to get help for a specific COMMANDNAME.

analyzeoom dumpsigelem histclear syncblk
ao dumpstack histinit t
bpmd dumpstackobjects histobj threadpool
clrstack dumpvc histobjfind threads
da eeheap histroot token2ee
do eestack histstats tp
dso eeversion hof traverseheap
dumparray ehinfo ip2md u
dumpassembly finalizequeue listnearobj verifyheap
dumpclass findappdomain lno verifyobj
dumpdomain findroots minidumpmode vh
dumpheap fq name2ee vmmap
dumpil gchandleleaks objsize vmstat
dumplog gchandles pe vo
dumpmd gcheapstat printexception  
dumpmodule gcinfo procinfo  
dumpmt gcroot savemodule  
dumpobj gcwhere soe  
dumpruntimetypes heapstat sosflush  
dumpsig help stoponexception  

Then there's the complete list of .NET SOS commands:

bpmd dumpstack procinfo
clrstack dumpstackobjects rcwcleanuplist
comstate dumpvc savemodule
da eeheap soe
do eestack sosflush
dso eeversion stoponexception
dumparray ehinfo syncblk
dumpassembly finalizequeue threadpool
dumpclass findappdomain threads
dumpdomain gchandleleaks token2ee
dumpheap gchandles traverseheap
dumpil gcinfo tst
dumplog gcroot u
dumpmd help verifyheap
dumpmethodsig ip2md vmmap
dumpmodule minidumpmode vmstat
dumpmt name2ee  
dumpobj objsize  
dumpruntimetypes pe  
dumpsig printexception  

If you haven't noticed yet, most of these aren't even documented commands. However, if you type them into SOS, you will not only see that they exist, you will be given the syntax for how to use them (and, then, there's !sos.help).

kick it on DotNetKicks.com

Learning WinDBG/SOS and Advanced Debugging



In my daily R&D work as well as in my general development, I always keep WinDBG open so I can quickly debug major problems in a system or just to take a look under the covers. WinDBG is short for Windows Debugger and it's what you would use if you were to debug a Windows driver or figure out why your system blue screened.  It's an advanced unmanaged debugger.  If you're into internals and eat up books like Windows Internals and Windows via C/C++, then you will or probably already do love Windows Debugger.

You can use it for more than unmanaged debugging though.  The .NET framework ships with a product called SOS, which you can load into WinDBG to enable advanced managed debugging.  Actually, with the proper settings ("Enable unmanaged code debugging" to true) you can sometimes load SOS in Visual Studio.  Using either, you can do anything from break when a particular method is called, dump out the IL at a particular place in your call stack (yes, this means you can view the code at runtime without needing the code!), view the methods of a type, or even break when the CLR first loads.  It's incredibly powerful.  You don't even need to be at the system to use it.  Just have someone send you a memory dump and you can use that just as easily as if you were physically at the system.

You can even use it to debug .NET applications inside of unmanaged applications.  For example, WinDBG is the tool I used to figure out why Visual Studio 2008 didn't allow .NET assemblies to be referenced in Silverlight.  Visual Studio was simply loading a managed assembly to do all of its assembly reference dirty work.  Since .NET has this awesome thing called the CTS (Common Type System), types are actual types instead of just chunks of memory.  So when you pause a process and walk through memory, you don't just see memory addresses like 0x018271927, but you see things like System.String with a value of "ctl02".

In addition to being able to debug unmanaged code, .NET code, and .NET code in unmanaged code, you can also use WinDBG to debug Silverlight code.  As it turns out, when you install Silverlight, sos.dll is installed in your %ProgramFiles%\Microsoft Silverlight\2.0.31005.0\sos.dll folder (or on a 64-bit system, %ProgramFiles(x86)%\Microsoft Silverlight\2.0.31005.0\sos.dll).  Just attach your debugger to the unmanaged browser to debug the managed Silverlight application.

At this point you might expect me to announce that I'm going to do some long series on how to effectively use SOS, but that's not the case for two reasons: first, I'm not going to dump out a series of screen shots when many others have done this already.  Second, 90%+ of advanced debugging is all about understanding internals; something that takes many hours of study over many months.  Don't think that learning some tool will help you to effectively debug serious problems.

Thus, remember this: your ability to debug something is directly proportional to your knowledge of the system.  As I say regularly, if you ever try to fix something without understanding it, you are, at best, doing little more than hacking.  Therefore, instead of writing a series, I'm going to refer you to a series of places where you can easily learn all about WinDBG and, more importantly, advanced debugging and system internals.

Before you go diving into a list of resources, though, you need to realize that WinDBG, like Visual Studio's built-in, toned-down debugger, is only a tool.  As I've already mentioned, no tool will ever replace the need for the human to know how to use the tool or how to interpret the information provided by the tool.  Knowledge of debugging is required before you can use a debugging tool effectively.  Logic is also always required when debugging any issue.  Not only that, but as previously mentioned, deep knowledge of the internals of the system you are debugging is non-negotiable.  If you don't know what a MethodDesc, what a method table, or even what a module is, then your debugging abilities will be severely limited.  You won't have a clue how to find or interpret your debug output.

The more you know about the CLR, memory management, threading, garbage collection, the CLR's type system, and Windows the better off you are.  If you understand why .NET finalizers should only be used once every 10 years, you're on the right track.  If you don't even know how many generations are in .NET's garbage collector, you have some serious research ahead of you.  The more you know, the better off you are.  This applies to the whole of the system.  I hear people all the time talking about the "stack" and the "heap" as if they are some ethereal concept beyond human grasp.  These people typically have no idea that these are concepts that predate .NET by decades.  If you can't explain the stack and heap from a C/C++ perspective, then you don't truly understand the concepts.

Also, if you understand memory management in C/C++, you're way ahead of the game.  Even though you don't normally see them in a typical ASP.NET web form, you should know your pointers as they are the foundation of all memory management.  Without awareness of pointers, the entire concept of "passing by reference" is little more than magic.  You need to know why something is a value type and why something is a reference type.  If you don't understand the concept of a sync block index, then you're always wonder why you can't lock on a value type and why you can lock on a value type cast to an interface.  This type of information will go a long way to help you not only debug a system, but, equally important, to make sure it has optimal performance.

You should also not be afraid of IL.  This is the language of .NET.  You don't need to care about becoming fluent in writing in IL.  I promise you that you won't be required by any fascist employer to write a full-scale WPF system in IL.  However, if you don't even know what boxing, you need to hit the books.  Knowledge of IL dramatically aides in your understanding of both the framework class library and the CLR.  You should be aware of what is actually happening under the covers.  Don't simply assume that the csc.exe or vbc.exe compilers will fix your coding flaws.  Some times the code created by these compilers isn't optimal.  You should also understand what the evaluation stack is and how stack-based programming works as this is the foundation for IL development.

Fortunately, there are resources for these prerequisites of advanced debugging in addition to the following debugging resources.  Not only that, but there's two books that explains just about every thing I've just mentioned!  It's Jeffery Richter's CLR via C# and Joe Duffy's .NET Framework 2.0.  Buy these books and a stack of highlighters and study until every page has marks, notes, and coffee stains on them.  In addition to this, you should probably also drop by your local book store, grab a book on C/C++ and read a chapter or two on memory management so you can see the types of things the CLR has to deal with so you don't have to.

For even deeper debugging, though, you may want to study the "Processor Architecture" section of the WinDBG help files, get the aforementioned Windows/C++ books, and buy Advanced Windows Debugging as well.  Everything you study is just "code", so the more you know, the deeper you can debug.  Not just debugging though, but knowledge of internals help you get more knowledge of internals.  By understanding C++, assembly language, and Windows internals, you already have just about everything you need to do effective reverse engineering.  This will help you to understand the undocumented internals and features of various technologies.

These things will help further your knowledge of what's actually going on in .NET's brain.  It's also important to remember that you won't learns this stuff over night.  As I said, your debugging skills are directly related to your knowledge of internals.  Therefore, as pick up more prerequisites in your career, you will become better at debugging (and performance optimization).  Every few months I take some time to further my understanding of the internals of new (and even sometimes old) technologies for these specific reasons.  For example, in Q1 and Q2 of 2009, I'm spending the bulk of my time studying assembly language and Windows architecture to further my own understanding.

Now on to the resources (which will be updated every now and again):

Advanced Debugging Resources

Reusing .NET Assemblies in Silverlight



Table of Contents

Introduction

Long before Silverlight 1.0 was released, it was actually called WPF/E or WPF Everywhere.  The idea was to allow you to create WPF like interfaces in your web browser.  This can be seen in a very small way in Silverlight 1.0.  All it provided was very basic primitive objects with the ability for interact with client-side technologies like JavaScript.  However, with Silverlight 2.0, Silverlight is actually more than what was originally promised with the term "WPF/E".  Silverlight is now far much more than a graphical technology.  All this stuff about Silverlight being "WPF for the Web" is more to make the marketing folks happy than anything else.

As a technology parallel to .NET, Silverlight is not part of the .NET family.  Rather, it essentially mirrors the .NET platform to create a new platform inside of a web browser where you have a mini-CLR and mini-Framework Class Library (FCL).  However, even though they are parallel technologies, you would suspect that Microsoft would allow some level of reuse between the two.  As it turns out, most topics are completely reusable.  Among other things, Silverlight has delegates, reference types, value types, a System namespace, and the ability to write code in both C# and VB.

Furthermore, despite the rumors, Silverlight also shares the exact same module and assembly format as .NET.  This may seem completely shocking to some people given the fact that Visual Studio 2008 doesn't allow you to reference a .NET assembly in a Silverlight project.  In reality, however, there's no technical reason for this prohibition.  There isn't a single byte difference between a Silverlight and .NET assembly.  One way to see this is by referencing a Silverlight assembly in a .NET project.  Just try it.  It works great.  So, why doesn't Visual Studio allow .NET assemblies in Silverlight projects?

To answer this, we need to understand that just because an optional helper tool (i.e. Visual Studio) doesn't allow something, that doesn't mean the technology itself doesn't.  In this case, the reason why Visual Studio allows a .NET project to reference Silverlight assemblies, but not the other way around is probably because .NET assemblies can normally do more.  For example, .NET has all kinds of XML related entities in its System.Xml assembly.  If Silverlight were to try to use this, it would blow up at runtime.  However, both Silverlight and .NET have an mscorlib assembly thus giving them a sense of brotherhood.  Having said that, Silverlight has the System.Windows.Browser assembly which, upon access in .NET, would make your .NET application explode!  Thus, the Visual Studio restriction laws are flawed.

Fortunately, there are ways around Visual Studio's fascist regime.  I'm going to talk about two different ways of reusing .NET assemblies and code in Silverlight.  The first technique is the more powerful assembly-level technique, while the second is more flexible file-level technique.  Each technique is useful for its own particular scenarios.  Please keep naive comments of "I'm ALWAYS going to…" and "I'm NEVER going to…" to yourself.  You need to make decisions of which of these techniques or possibly another technique to use on a case by case basis.

The Assembly-Level Technique

For this technique, you need to understand what's going on under the covers when you try to add a .NET reference to your Silverlight application in Visual Studio.  It's actually incredibly simple.  Visual Studio isn't a monolith that controls all your code from a centralized location; sometimes it uses plug-ins to do it's dirty work.

In this case, Visual Studio 2008 uses the Microsoft.VisualStudio.Silverlight .NET assembly.  In this assembly is the Microsoft.VisualStudio.Silverlight.SLUtil class which contains the IsSilverlightAssembly method.  When you add an assembly to a Silverlight Project, this method is called internally to see if your assembly is Silverlight.  If it is, it will add it.  If not, it won't.  It's just that simple.  But, given that the Silverlight and .NET assembly format is the same, how can it know?

You may be shocked to find out that the reason behind this is completely artificial: if the assembly references the 2.0.5.X version of the mscorlib assembly, then Visual Studio says that it's a Silverlight assembly!  This test is essentially all the IsSilverlightAssembly does.  Therefore, if you take your .NET 2.x/3.x assembly and change the version of mscorlib that your assembly references from 2.0.0.0 to 2.0.5.0, you may then add the assembly as a reference.  Now let's talk about this with a more hands on approach.

Below is the sample code we will be working with for this part of the discussion.  Say this code is placed in an empty .NET project.  When it is compiled, we will have an assembly.  Let's call it DotNet.dll.

using System;
//+
namespace DotNet
{
    public class Test
    {
        public String GetText()
        {
            return String.Format("{0} {1} {2} {3}", "This", "is", "a", "test");
        }
    }
}

Before we go any further, lets' discuss the state of the universe at this point.  If you ever try to solve a problem without understanding how the system works, you will at best be hacking the system.  Professionals don't do this.   Therefore, let's try to understand what's going on. 

The first thing you need to know is that when you add an assembly to a project in Visual Studio, you are simply telling Visual Studio to tell the compiler what reference you have so that when the compiler translates your code into IL, it knows what assemblies to include as "extern assembly" sections.  Even then, only the assemblies that are actually used in your code will have "extern assembly" sections.  Thus, even if you added reference every single assembly in your entire system but only use two, the IL will only have two extern sections (i.e. references assemblies).  The second thing you need to know is that no matter what, your assemblies will always have a reference to mscorlib.  This is the root of all things and is where System.Object is stored.

To help you understand this, let's take a look at the IL produced by this class.  To look at this IL, we are going to use .NET's ILDasm utility.  Reflector will not be your tool of choice here.  Reflector is awesome for referencing code, but not for working with it.  It's more about form than function.  With ILDasm we are going to run the below command:

ILDasm DotNet.dll /out:DotNet.il

For the sake of your sanity, use the Visual Studio command prompt for this.  Otherwise you will need to either state the absolute path of ILDasm or set the path.

This command will produce two files: DotNet.il and DotNet.res.  The res file is completely meaningless for our discussion and, therefore, will be ignored.  Here is the IL code in DotNet.il:

.assembly extern mscorlib
{
    .publickeytoken = (B7 7A 5C 56 19 34 E0 89)
    .ver 2:0:0:0
}
.assembly DotNet
{
    /** a lot of assembly level attributes have been left out **/


    .hash algorithm 0x00008004
    .ver 1:0:0:0
}
.module DotNet.dll
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 
.corflags 0x00000001     


.class public auto ansi beforefieldinit DotNet.Test extends [mscorlib]System.Object
{
    .method public hidebysig instance string GetText() cil managed
    {
        .maxstack    4
        .locals init ([0] object[] CS$0$0000)
        IL_0000:    ldstr "{0} {1} {2} {3}"
        IL_0005:    ldc.i4.4
        IL_0006:    newarr [mscorlib]System.Object
        IL_000b:    stloc.0
        IL_000c:    ldloc.0
        IL_000d:    ldc.i4.0
        IL_000e:    ldstr "This"
        IL_0013:    stelem.ref
        IL_0014:    ldloc.0
        IL_0015:    ldc.i4.1
        IL_0016:    ldstr "is"
        IL_001b:    stelem.ref
        IL_001c:    ldloc.0
        IL_001d:    ldc.i4.2
        IL_001e:    ldstr "a"
        IL_0023:    stelem.ref
        IL_0024:    ldloc.0
        IL_0025:    ldc.i4.3
        IL_0026:    ldstr "test"
        IL_002b:    stelem.ref
        IL_002c:    ldloc.0
        IL_002d:    call  string [mscorlib]System.String::Format(string, object[])
        IL_0032:    ret
    }


    .method public hidebysig specialname rtspecialname 
         instance void    .ctor() cil managed
    {
        .maxstack    8
        IL_0000:    ldarg.0
        IL_0001:    call  instance void [mscorlib]System.Object::.ctor()
        IL_0006:    ret
    }
}

Right now we only care about the first section:

.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
  .ver 2:0:0:0
}

This ".assembly extern ASSEMBLYNAME" pattern is how your assembly references are stored in your assembly.  In this case, you can see that mscorlib is referenced using both it's version and it's public key.  For our current mission, all we need to do is change the second 0 to a 5.  The public key tokens used in Silverlight are completely different from the ones in .NET, but we are trying to fool Visual Studio, not Silverlight.  This is a compile-time issue, not a runtime-issue.  Speaking more technically, we don't care about the public key token because this information is only used when an assembly is to be loaded.  The correct mscorlib assembly will have already loaded by the Silverlight application itself long before our assembly comes on the scene.  So, in our case, this entire mscorlib reference is really just to make the assembly legal and to fool Visual Studio.

Once you make the change from 2:0:0:0 to 2:0:5:0, all you need to do is use ILAsm to restore the state of the universe (unlike Reflector with C#, ILAsm can put humpty dumpty back together again).  Here's our command for doing this (in this case the resource part is completely optional, but let's add it for completeness):

ilasm DotNet.il /dll /resource:DotNet.res /out:DotNet2.dll

You are now free to reference your .NET assembly in your Silverlight project or application.  As I've already mentioned, Silverlight and .NET have the same assembly format.  There's nothing in Silverlight that stops us from referencing .NET assemblies, it was only Visual Studio stopping us.

At this point you have just the basics of this topic.  However, it's not the end of the story.  As you should be aware, .NET's core assemblies use four-part names.  That is, they have a strong name.  This is used to disambiguate them from other assemblies.  That is, instead of the System assembly being called merely "System", which can easily conflict with other assemblies (obviously written by non-.NET developers who don't realize that System should be reserved), it's actually named "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089".  When you reference an assembly, you need to make sure to match the name, version, culture, and public key token.  When it comes to using .NET assemblies in Silverlight, this is critically important.

Let's say, for instance, that you created a .NET project which referenced and used entities from the System, System.ServiceModel, and System.Runtime.Serialization assemblies.  In this case, the IL produced by the .NET compiler will create the following three extern assembly sections:

.assembly extern System
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89)
  .ver 2:0:0:0
}
.assembly extern System.ServiceModel
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89)
  .ver 3:0:0:0
}
.assembly extern System.Runtime.Serialization
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89)
  .ver 3:0:0:0
}

Notice the public key token on each.  Here all three are the same, but for other .NET assemblies they may be different.  What's important here, though, is that the keys are used to identity the assemblies for .NET, not Silverlight.  Thus, even though you did add your .NET assembly to your Silverlight application, an exception would be thrown in runtime at the point where your application tries to access something in one of these assemblies.

The following shows you what would happen in the extreme case of trying to use the System.Web assembly in your Silverlight.  You would get the same error if you tried to access something in one of the above assemblies as well.

AssemblyException

As it stands, though, we can fix this just as easily as we fixed the mscorlib problem in Visual Studio.  All we need to do is open our IL and change the public keys and versions to the Silverlight versions.  Below is a list of the common Silverlight assemblies each with their public key token and version:

.assembly extern mscorlib
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}
.assembly extern System
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}
.assembly extern System.Core
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}
.assembly extern System.Net
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}
.assembly extern System.Runtime.Serialization
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}
.assembly extern System.Windows
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}
.assembly extern System.Windows.Browser
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}


//+ note the different public key token in the following
.assembly extern System.ServiceModel
{
  .publickeytoken = (31 BF 38 56 AD 36 4E 35)
  .ver 2:0:5:0
}
.assembly extern System.Json
{
  .publickeytoken = (31 BF 38 56 AD 36 4E 35)
  .ver 2:0:5:0
}

Just use the same ILDasm/Edit/ILAsm procedure already mentioned to tell the assembly to use the appropriate Silverlight assemblies instead of the .NET assemblies.  This is an extremely simple procedure consisting of nothing more than a replace, a procedure that could easily be automated with very minimal effort.  It shouldn't take you much time at all to write a simple .NET application to do this for you.  It would just be a simple .NET to Silverlight converter and validator (to test for assemblies not supported in Silverlight).  Put that application in your Post Build Events (one of the top 5 greatest features of Visual Studio!) and you're done.  No special binary hex value searching necessary.  All you're doing is changing two well documented settings (the public key token and version).

For certain assemblies, this isn't the end of the story.  If your .NET assembly has a strong name, then by modifying it's IL, you have effectively rendered it useless.  Aside from disambiguation, strong names are also used for tamper protection.  You can sort of think of them as a CRC32 in this sense.  If you were to modify the IL of an assembly with a strong name, you would get a compile-time error like the following:

StrongNameException 

However, as you know by the fact that we have looked at the raw text of the source code with our own eyes, the strong name does absolutely no encryption of the IL.  That's one of the most common misconceptions of strong names.  They are not used as for public key encryption of the assembly.  Therefore, we are able to get around this by removing the public key from our assembly before using ILAsm.  Below is what the public key will look like in your IL file.  Just delete this section and run ILAsm.

.publickey = (00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00
              00 24 00 00 52 53 41 31 00 04 00 00 01 00 01 00
              37 3C 5A 7F 6D B6 3F 30 D8 3F DE E3 17 FE E5 2E
              68 43 16 A9 7C 42 69 5A 05 52 E6 73 C5 AC 58 7E
              B0 00 9F DC 1B 0A 78 57 79 12 79 53 E1 60 EB C9
              ED 49 7C 8C 73 1B 01 A7 BA 57 79 B5 53 83 8B CA
              8D F8 6F 3B BD A5 E4 BA 6A 12 B9 52 F2 E9 A3 FC
              42 17 E4 33 97 92 DC 21 30 57 B9 D3 63 7A F2 43
              73 42 70 18 89 8B 44 B9 D4 5A BA A9 21 A3 D9 E0
              86 20 3C 30 01 A9 B9 BB F4 D8 79 B7 7D 56 5A A9)

Upon using ILAsm to create the binary version of the same IL, you will be able to add your assembly, compile and run your application without a problem.  However, you can take this one step further by telling ILAsm to sign the assembly using your original strong name key.  To do this, just use the key command line option to specify the strong name key you would like to use.  Below is the new syntax for re-signing your assembly:

ILAsm DotNet.il /dll /resource:DotNet.res /out:DotNet11.dll /key=..\..\MyStrongNameKey.snk

At this point you have a strongly-named Silverlight assembly createdrom your existing .NET assembly.

Now, before moving on to explain a more flexible method of reuse, I want to cover a few miscellaneous topics.  First, for those of you who know some IL and are trying to be clever to make this process even simpler, you may think you could just do the following:

.assembly extern mscorlib { auto }

This won't work as ILAsm will look for "auto" and place the 2.0.0.0 version in it's place, thus leaving you right where you started.  Also, don't even think about leaving the entire mscorlib part off either.  That won't fool anyone since ILAsm will detect that it's missing and add it before continuing the assembly process.  You need to explicitly state that you want assembly version 2.0.5.0.

Second, you need to think twice before you add a Silverlight assembly to a .NET application.  In the Visual Studio world, if you add a .NET assembly, you add only that assembly. But, in the that assembly is a Silverlgiht assembly, then you will see all of the associated Silverlight assemblies added for each culture you have.  When I did this on my system, exactly 100 extra files were added to my Bin folder!  That's insane.  So, perhaps the Visual Studio team put a "Add Reference" block in the wrong place!

The File-Level Technique

Now all of this is great.  You can easily access your .NET assemblies in Silverlight.  But, many times this isn't even what you need.  You need to remember that every time you reference an assembly in Silverlight, you increase the size of your Silverlight XAP package.  Whereas .NET and Silverlight will only register assembly references in IL when they are actually used, Silverlight will package referenced assemblies in the XAP file regardless of use.  They assemblies will also be registered in the AppManifest.xaml file as an assembly part.  Though the XAP file is nothing more than a ZIP file, thereby shrinking the size of the assembly, this still spells "bloat" if all you need is just a few basic types from an assembly that's within your control.  For situations like this, there's a much simpler and much more flexible solution.

The solution to this again deals with understanding the internals of your system: whenever you add a file to your project in Visual Studio, all you are really doing is adding a file to an ItemGroup XML section in the .NET project file.  This is just a basic text file that describes the project.  As you may have guessed, the ItemGroup section simply contains groups of items.  In the case of compilation files (i.e. classes, structs, enums, etc...), they are Compile items.  Here's an example of a snippet from a .NET project:

<ItemGroup>
  <Compile Include="Client\PersonClient.cs" />
  <Compile Include="Agent\PersonAgent.cs" />
  <Compile Include="Properties\AssemblyInfo.cs" />
  <Compile Include="Configuration.cs" />
  <Compile Include="Information.cs" />
  <Compile Include="_DataContract\Person.cs" />
  <Compile Include="_ServiceContract\IPersonService.cs" />
</ItemGroup>

Given this information, all you need to do is (1) create a Silverlight version of this assembly, (2) open the project file and (3) copy/paste in the parts you want to use in your Silverlight project with the appropriate relative paths changed.  This will create a link from the Silverlight project's items to the physical items.  No copying is done.  They are pointing to the exact same file.  When they are compiled, there is no need to do any IL changes in your assemblies at all since the Silverlight assembly will be Silverlight and the .NET assembly will be .NET.

Now that you know about this under-the-covers approach, you should be aware that this is actually a fully supported option in Visual Studio.  Just go to add an existing item to your project and instead of clicking add or just hitting enter, hit the little arrow next to add and select "Add As Link".  This will do the exact same thing as what we did in our bulk copy/paste method in the project file.  Here's a screen shot of the option in Visual Studio:

AddAsLink

What may be more interesting to you is that this feature may be used anywhere in .NET.  You can use this to reuse any files in your entire system.  It's a very powerful technique to reuse specific items in assemblies.  It comes it very handy when two assemblies need to share classes and creating a third assembly which both may access leads to needless complexity.

Conclusion

Given these two techniques, you should be able to effectively architect a solution that scales to virtually any number of developers.  The first technique is easy to deploy using a custom utility and post build events, while the second is natively supported by any good version control systems.  Keep in mind though, that when using the first technique you may not always need to do this on every build.  The best approach I've seen for this is to have a centralized location on a network share that contains nightly (or whatever) builds of core assemblies.  Then, a login script will copy each of the assemblies to each developers machine.  This will cut down on the complexity of compilation and dramatically lower the time to compile any solution.

Regardless of which technique you use, you should feel a sense of freedom knowing of their existence.  This is especially true if all you are doing is trying to share data contracts between .NET and Silverlight.  As I've mentioned in my popular 70+ page "Understanding WCF in Silverlight 2" document, the "Add Service Reference" feature is not something that should be used in production.  In fact, it's painful in development as well.  Using the techniques described here, you can easily share your data contracts between your .NET server and the Silverlight client without the FrontPage/Word 95 style code generation.  For more information on this specific topics, see the aforementioned document.

Links

kick it on DotNetKicks.com

FREE Silverlight Training on the Web



In case you didn't know it, knowledge is free.  In fact, it always has been.  Some cultures make it hard to obtain, but it's free nonetheless.  The Internet gives you extremely close access this knowledge.  You can randomly choose just about any topic in the world and find at least one article, blog posting, or Wikipedia entry on the topic.  In fact, when I was in college I only showed up once to my Kansas State University Physics II class.  Instead I kepted up with the class from home by watching the MIT OpenCourseWare video courses.  When it comes to Internet-related technologies like Silverlight, knowledge is even easier to find.

I see all kinds of courses by some of the biggest training companies offering all sort of great Silverlight courses.  However, these are extremely pricey.  There are also many books on Silverlight coming out.  Again, not free.  But think about it, how do you think the trainers and authors get their information?  When I was offered my Silverlight 2 book deal (since being on a deadline sucks, I turned it down), where do you think I would get my information?  It's all free online.  Here in December 2008, there are all kinds of amazing free resource for learning Silverlight.  You do not need training.  You do not need to buy a book.  Here are some of these resources that I've found this year to help bring you from ground zero to being a Silverlight master:

First, there's the 53-part video series at Silverlight.net.  This series just about every single topic you will ever see in your Silverlight career.  However, I would consider these to be at the basic level.  They cover the fundamentals of each topic, give great tips, and progressively give more interesting examples as the videos progress.  If all you are going to be doing is under-using Silverlight 2 as an RIA platform and for general [boring] UI development, then this series may be 90% of what you need.  Link: http://silverlight.net/Learn/videocat.aspx?cat=2

Second, there's the 44-part video series from Mike Taulty.  This is the guy behind the MSDN Nuggets videos.  These videos are more at the intermediate-advanced level.  It's also somewhat focused at "under-the-covers" development.  Mike doesn't do drag-n-drop videos.  He teaches real technology.  Whereas the previous series will discuss concepts and how to do things "out of the box", Mike's videos show you how to work with things at a more mechanical level, thus giving you a much greater level of control.  If you don't know the topics he's discussing in the videos, you don't know Silverlight.  Link: http://channel9.msdn.com/posts/Dan/Mike-Taulty-44-Silverlight-20-Screencasts/

Third, let's not forget that Microsoft has its annual Mix and PDC conferences.  Microsoft makes sure that the content for these conferences are freely available online.  The Mix videos are very specific and, therefore, should probably be watched on an as-needed basis.   You can just follow the link to see the wide variety of topics.  Since it's at a conference, however, some of the information will be marketing-speaking, but there's a lot of good stuff in the videos as well.  The PDC however is much less marketing-ish and there were a few Silverlight 2 sessions.  Links: http://silverlight.net/learn/videocat.aspx?cat=8 and https://sessions.microsoftpdc.com/public/timeline.aspx.

Fourth, if you're the reading-type, then you may prefer the Silverlight 2 e-book at learn-silverlight-tutorial.com.  This e-book covers a ton of information.  Much like the 53-part series, I would mark this down as basic-level.  It covers a touches on a wide variety of topics.  However, much of the information is just that: "a touch".  It's not very deep, but it's rather wide.  Link: http://www.learn-silverlight-tutorial.com/

Fifth, Microsoft has always been good about providing QuickStarts.  These are kind of a cross between visual, text, and hands-on learning.  These are also the typical go to card for any one new to anything.  The ASP.NET quick starts are still incredibly popular these many years later.  The Silverlight ones are quite well done as well.  The topics are basic-intermediate and range from topics like general UI controls to cooler stuff like JavaScript/DOM interop.  However, you may feel completely free to absolutely ignore the completely worthless "web services" section.  Whoever wrote that thought he or she was writing about the hopelessly-flawed ASMX, not the image-of-beauty WCF and, therefore, didn't even remotely bother to obey the most fundamental of WCF purposes and practices (i.e. keep your address, binding, and contract away from your implementation!) Link: http://silverlight.net/quickstarts/

Speaking of WCF, the last resource I want to mention is my document entitled "Understanding WCF in Silverlight 2".  This one has received a lot of attention since I wrote it in November 2008.  In fact, it's now listed on the WCF MSDN home page.  It's there because I cover WCF from the ground up for both .NET and Silverlight in a very deep manner.  If you are new to WCF, SOA, or Silverlight, then this is a good place to start (of course, no bias here.)  I wrote this document to help both people new to WCF and Silverlight as well as those who have been working either either for a while.  Even if you're not too serious about Silverlight, you should still read this detailed document to understand WCF better.  I don't play around with introductory nonsense, I hit the ground running with best-practices and proper architectural principles.  Link: http://www.netfxharmonics.com/2008/11/Understanding-WCF-Services-in-Silverlight-2

Though it's not a straight learning resource, I support I would also like to mention that you can always check out the Silverlight tag in my Delicous account: http://delicious.com/quantum00/silverlight.  However, keep in mind that just because I bookmark something, it doesn't mean I'm recommending the resource.  It just means it was interesting and/or provided some value to me.  You can expect this to be updated for the months to come.  I live off of my delicious account.

Another thing I would like to mention is that if you know WPF and web development, then you almost get Silverlight knowledge naturally.  Silverlight is essential a subset of WPF for the web.  You just take WPF, rip out a bunch of features, add just a handful of topics, move it to the web, and you have Silverlight.  Much of your skills are reusable if you already know WPF.  Actually, a lot of your skills are reusable if you're a .NET developer in general.  Just whip open Reflector and start looking through the framework, you'll see that there's a lot less than what's in the .NET framework, thus requiring much less learning time.

So, don't waste your money on books.  The blog is the new book.  Don't bother asking your employer for Silverlight training.  OK, well, if you just want some time off from work, sure, go ahead and ask.  Really, though, these resources will give you what you need for your Silverlight development.  In fact, if you were to compare the syllabus for an expensive course with the topics found in the first two sections of videos mentioned (97 of them!), you will see that the ROI for the course is virtually non-existent.

Links Summary