There are some fancy tools/add-ons for Visual Studio that are huge productivity boosters. But for the poor man, purchasing an add-on is sometimes not an option.
Often, I review others' code (or perhaps my own code from a few years back), and think "What a newb! This junk is spaghetti code!". It is in situations like this where I find myself dying for the ability to collapse if blocks, while statements, etc. in C#.
As I mentioned there add ons that solve this quite eloquently. But, if you're just looking for a quick and dirty way to collapse those curly brackets, I have a macro for you! :)
In visual studio press the ALT key, followed by F8. This opens the macro pane. Most likely, there is already a macro project named my macros. Right click the module underneath that in the tree, and select "Edit". Now, blast this code into the editor:
'Add regions, by curly brackets. Put cursor on the first curly bracket of a pair, and run the macro.
Sub Regionify()
'region-ify
DTE.ActiveDocument.Selection.EndOfLine()
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.Text = "#region"
DTE.ActiveDocument.Selection.LineUp()
DTE.ExecuteCommand("Edit.GotoBrace")
DTE.ActiveDocument.Selection.LineUp()
DTE.ActiveDocument.Selection.EndOfLine()
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.Text = "#endregion"
'return to where I was
DTE.ActiveDocument.Selection.LineDown()
DTE.ExecuteCommand("Edit.GotoBrace")
End Sub
Another developer named Roland has a great post on how to assign hot keys to macros like this one. You can read about that here:
http://weblogs.asp.net/rweigelt/archive/2006/05/15/446536.aspx
Tuesday, August 31, 2010
Wednesday, March 24, 2010
Sorting any XML
I wrote this because I deal with a tool that treats XML as unsorted data. At the same time, it generates an XSD schema that enforces order. So, to solve the problem, I wrote a transform to take XML and alphabetize it by element name. This will work for any XML without namespaces, and will probably work for XML with namespaces by putting a declaration at the top of the transform.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="*" mode="Sorting">
<xsl:sort select="local-name()" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*" mode="Sorting">
<xsl:copy>
<xsl:choose>
<xsl:when test="./*">
<xsl:apply-templates select="@*" mode="AttSorting" />
<xsl:apply-templates select="./*" mode="Sorting">
<xsl:sort select="local-name()" />
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="@*" mode="AttSorting" />
<xsl:value-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
<xsl:template match="@*" mode="AttSorting">
<xsl:copy>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="*" mode="Sorting">
<xsl:sort select="local-name()" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*" mode="Sorting">
<xsl:copy>
<xsl:choose>
<xsl:when test="./*">
<xsl:apply-templates select="@*" mode="AttSorting" />
<xsl:apply-templates select="./*" mode="Sorting">
<xsl:sort select="local-name()" />
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="@*" mode="AttSorting" />
<xsl:value-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
<xsl:template match="@*" mode="AttSorting">
<xsl:copy>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Monday, January 12, 2009
Assembly Resolution - How AppDomains Change from Desktop to Web
So, for our build wizard, I needed to load some DLLs into a child app domain that could orchestrate all of our build script work, then unload the domain. Freeing up the .NET Assemblies in this way lets us always run off the latest/greatest of the DLL without the need to reset IIS.
I put some significant effort into getting the child AppDomain code to work from a mock command line app before plunging into the web world. This was my first exposure to a non-academic use of AppDomains, so I wanted to have a playground to get comfortable and prototype some code. It didn't take long to get something that was working. So, I imported the classes from my command line app into my web app I had been working on.
In the command line app, I had been initializing the AppDomain like so:
//setup a child appdomain
string appDomainUniqueNamePerUser = string.Format("WF Child Domain", Guid.NewGuid().ToString("D"));
AppDomain childAD = AppDomain.CreateDomain(appDomainUniqueNamePerUser);
assemblyResolvePath = appDomainBaseDir + @"\BuildScripts";
childAD.AssemblyResolve += new ResolveEventHandler(childAD_AssemblyResolve);
//get my proxy class for crossing the appdomain boundary
WFWP remoteWorker =
(WFWP)childAD.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "FE.BuildControl.WFWP");
Suddently, I was getting strange error "Type is not resolved for member 'FE.BuildControl.WFWP'". What?! The exact same code just worked from the command line.
After much painful troubleshooting, I discovered this error is more of a red herring than anything. It points to assembly loading problems (imagine that!). So, I discovered through the Fusion log and FileMon that my assembly resolution for the WFWP class was interrogating my C:\windows\Microsoft.NET\Framework\v2.0.... folder. "Why there?", you ask....
Well, it turns out that AppDomains by default will assume the same base directory as the .exe they are running from. Yes...the .EXE they are running from. :) So, when I was running as a command line app, it was probing for assemblies in the same folder I was executing from. Naturally, my referenced DLLs existed there and all was well. When in a web app, your .EXE is aspnet_wp.exe (Windows XP) or W3WP.exe (Win 2003). So, those reside in the .NET 2.0 framework folder, mentioned above. So, it was doing exactly what I told it to do, but that's not what I meant.
Enter the AppDomainSetup class:
string appDomainUniqueNamePerUser = string.Format("WF Child Domain", Guid.NewGuid().ToString("D"));
AppDomainSetup ads = new AppDomainSetup();
ads.ApplicationBase = appDomainBaseDir;
ads.DisallowBindingRedirects = false;
ads.DisallowCodeDownload = true;
ads.PrivateBinPath = "Bin";
AppDomain childAD = AppDomain.CreateDomain(appDomainUniqueNamePerUser, null, ads);
By specifying my physical folder that I'm using as a virtual directory in IIS as my "ApplicationBase" above, I can cause the assembly resolution logic in .NET to look for my DLLs there instead. The "PrivateBinPath" just helps it along and says, "DLLs in this application will be in this folder". Now, my child appdomain executes like a champ!
Moral of the story: .NET simplifies/standardizes a lot of things compared to prior languages, but one cannot assume that a class will behave identically when put in a different context (such as another hosted process).
That's all for now. Take care,
I put some significant effort into getting the child AppDomain code to work from a mock command line app before plunging into the web world. This was my first exposure to a non-academic use of AppDomains, so I wanted to have a playground to get comfortable and prototype some code. It didn't take long to get something that was working. So, I imported the classes from my command line app into my web app I had been working on.
In the command line app, I had been initializing the AppDomain like so:
//setup a child appdomain
string appDomainUniqueNamePerUser = string.Format("WF Child Domain", Guid.NewGuid().ToString("D"));
AppDomain childAD = AppDomain.CreateDomain(appDomainUniqueNamePerUser);
assemblyResolvePath = appDomainBaseDir + @"\BuildScripts";
childAD.AssemblyResolve += new ResolveEventHandler(childAD_AssemblyResolve);
//get my proxy class for crossing the appdomain boundary
WFWP remoteWorker =
(WFWP)childAD.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "FE.BuildControl.WFWP");
Suddently, I was getting strange error "Type is not resolved for member 'FE.BuildControl.WFWP'". What?! The exact same code just worked from the command line.
After much painful troubleshooting, I discovered this error is more of a red herring than anything. It points to assembly loading problems (imagine that!). So, I discovered through the Fusion log and FileMon that my assembly resolution for the WFWP class was interrogating my C:\windows\Microsoft.NET\Framework\v2.0.... folder. "Why there?", you ask....
Well, it turns out that AppDomains by default will assume the same base directory as the .exe they are running from. Yes...the .EXE they are running from. :) So, when I was running as a command line app, it was probing for assemblies in the same folder I was executing from. Naturally, my referenced DLLs existed there and all was well. When in a web app, your .EXE is aspnet_wp.exe (Windows XP) or W3WP.exe (Win 2003). So, those reside in the .NET 2.0 framework folder, mentioned above. So, it was doing exactly what I told it to do, but that's not what I meant.
Enter the AppDomainSetup class:
string appDomainUniqueNamePerUser = string.Format("WF Child Domain", Guid.NewGuid().ToString("D"));
AppDomainSetup ads = new AppDomainSetup();
ads.ApplicationBase = appDomainBaseDir;
ads.DisallowBindingRedirects = false;
ads.DisallowCodeDownload = true;
ads.PrivateBinPath = "Bin";
AppDomain childAD = AppDomain.CreateDomain(appDomainUniqueNamePerUser, null, ads);
By specifying my physical folder that I'm using as a virtual directory in IIS as my "ApplicationBase" above, I can cause the assembly resolution logic in .NET to look for my DLLs there instead. The "PrivateBinPath" just helps it along and says, "DLLs in this application will be in this folder". Now, my child appdomain executes like a champ!
Moral of the story: .NET simplifies/standardizes a lot of things compared to prior languages, but one cannot assume that a class will behave identically when put in a different context (such as another hosted process).
That's all for now. Take care,
Subscribe to:
Posts (Atom)