<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.inetium.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Mike Hodnick</title><link>http://blogs.inetium.com/blogs/mhodnick/default.aspx</link><description>Inetium Consultant</description><dc:language>en</dc:language><generator>CommunityServer 2008 (Build: 30417.1769)</generator><item><title>Updated Content</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2008/03/26/this-blog-has-moved.aspx</link><pubDate>Wed, 26 Mar 2008 17:14:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:16797</guid><dc:creator>mhodnick</dc:creator><slash:comments>0</slash:comments><description>&lt;P&gt;Please point your feed reader to  &lt;A href="http://www.kindohm.com"&gt;http://www.kindohm.com&lt;/A&gt; for my latests posts and updates. &lt;/P&gt;&lt;BR&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=16797" width="1" height="1"&gt;</description></item><item><title>Enumerate SharePoint 2007 Site Definitions and Templates with PowerShell</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/12/11/611.aspx</link><pubDate>Mon, 11 Dec 2006 13:00:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:611</guid><dc:creator>mhodnick</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.inetium.com/blogs/mhodnick/rsscomments.aspx?PostID=611</wfw:commentRss><comments>http://blogs.inetium.com/blogs/mhodnick/archive/2006/12/11/611.aspx#comments</comments><description>&lt;P&gt;Here's a quick script for enumerating all of the available site definitions, their configurations, and any site templates installed on a SharePoint Server. If you're creating sites programmatically, this comes in handy as you'll likely rely on these values in a configuration document somewhere:&lt;/P&gt;&lt;CODE&gt;&lt;PRE&gt;[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

$url = "http://MySite"

$site= new-Object Microsoft.SharePoint.SPSite($url )
$web= $site.OpenWeb()

$loc= [System.Int32]::Parse(1033)

$templates= $site.GetWebTemplates($loc)

foreach ($child in $templates)
{
	write-host $child.Name $child.Title $child.ID
}

write-host done
&lt;/CODE&gt;&lt;/PRE&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=611" width="1" height="1"&gt;</description><category domain="http://blogs.inetium.com/blogs/mhodnick/archive/tags/Office+_2F00_+SharePoint+2007/default.aspx">Office / SharePoint 2007</category><category domain="http://blogs.inetium.com/blogs/mhodnick/archive/tags/Powershell/default.aspx">Powershell</category></item><item><title>Use of configuration data when using STSADM.EXE to activate custom Features in SharePoint 2007</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/12/09/604.aspx</link><pubDate>Sun, 10 Dec 2006 00:59:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:604</guid><dc:creator>mhodnick</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.inetium.com/blogs/mhodnick/rsscomments.aspx?PostID=604</wfw:commentRss><comments>http://blogs.inetium.com/blogs/mhodnick/archive/2006/12/09/604.aspx#comments</comments><description>&lt;p&gt;When implementing a custom Feature in SharePoint 2007, you may rely on custom configuration data (in a custom configuration section) stored in a SharePoint site's web.config file.  When activating and deactivating your feature through the SharePoint site settings user interface, this works just fine.  However when using the STSADM.EXE command-line tool to activate and deactivate features, there is no web context and the tool does not run within the context of a SharePoint site.  Thus if your feature relies on custom configuration data in a config file, the configuration data will not be available when using STSADM.EXE.&lt;/p&gt;

&lt;p&gt;You can address this problem by creating (or modifying) a file named STSADM.EXE.config that resides in the same folder as STSADM.EXE (c:\program files\common files\microsoft shared\web server extensions\12\bin).  This file is just an application configuration file (e.g. app.config), and you can add custom configuration data to it like any other web.config or app.config file.  Keep in mind that this is a server-wide config file.  Any customizations or changes you make will affect all uses of STSADM.EXE on all sites on the server.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=604" width="1" height="1"&gt;</description><category domain="http://blogs.inetium.com/blogs/mhodnick/archive/tags/.Net+Development/default.aspx">.Net Development</category><category domain="http://blogs.inetium.com/blogs/mhodnick/archive/tags/Office+_2F00_+SharePoint+2007/default.aspx">Office / SharePoint 2007</category></item><item><title>PowerShell: Zip up a folder and email it</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/11/29/powershell-zip-up-a-folder-and-email-it.aspx</link><pubDate>Wed, 29 Nov 2006 17:46:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:564</guid><dc:creator>mhodnick</dc:creator><slash:comments>8</slash:comments><description>&lt;P&gt;Here's a quick little PowerShell script you can use in conjunction with &lt;A href="http://blogs.inetium.com/blogs/mhodnick/archive/2006/08/07/295.aspx"&gt;Out-Zip&lt;/A&gt; to zip up a folder on your hard drive and email it:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;$sender = sender@host.com
$recipient = recipient@host.com
$server = mail.host.com
$targetFolder = c:\MyFolder
$file = c:\MyZipFile.zip

if ( [System.IO.File]::Exists($file) )
{
  remove-item -force $file
}

gi $targetFolder | out-zip $file $_
$subject = "Sending a File " + [System.DateTime]::Now
$body = "I'm sending a file!"
$msg = new-object System.Net.Mail.MailMessage $sender, $recipient, $subject, $body
$attachment = new-object System.Net.Mail.Attachment $file
$msg.Attachments.Add($attachment)
$client = new-object System.Net.Mail.SmtpClient $server
$client.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
$client.Send($msg)&lt;/CODE&gt;&lt;/PRE&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=564" width="1" height="1"&gt;</description><category domain="http://blogs.inetium.com/blogs/mhodnick/archive/tags/Powershell/default.aspx">Powershell</category></item><item><title>Incorrectly documented delimiters for custom multi-column field classes</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/10/24/421.aspx</link><pubDate>Tue, 24 Oct 2006 14:23:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:421</guid><dc:creator>mhodnick</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.inetium.com/blogs/mhodnick/rsscomments.aspx?PostID=421</wfw:commentRss><comments>http://blogs.inetium.com/blogs/mhodnick/archive/2006/10/24/421.aspx#comments</comments><description>&lt;P&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms454556.aspx" target="_blank"&gt;This MSDN article&lt;/a&gt; on creating custom multi-column field classes in WSS lists incorrectly specifies the string delimiter used to construct a new &lt;A href="http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.spfieldmulticolumnvalue.spfieldmulticolumnvalue.aspx" target=_blank&gt;SPFieldMultiColumnValue&lt;/A&gt; object. Microsoft says that the delimiter is "#;" when in fact it is ";#" (the semi-colon and pound sign are swapped). I discovered this while writing unit tests and referring to the article.&lt;/P&gt;
&lt;P&gt;I have to cut Microsoft some slack because the documentation is "pre-release". It's one of the pains of developing against Beta software. &lt;/P&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=421" width="1" height="1"&gt;</description><category domain="http://blogs.inetium.com/blogs/mhodnick/archive/tags/Office+_2F00_+SharePoint+2007/default.aspx">Office / SharePoint 2007</category></item><item><title>VS .Net Solution Size and ReSharper</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/09/29/385.aspx</link><pubDate>Fri, 29 Sep 2006 12:16:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:385</guid><dc:creator>mhodnick</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.inetium.com/blogs/mhodnick/rsscomments.aspx?PostID=385</wfw:commentRss><comments>http://blogs.inetium.com/blogs/mhodnick/archive/2006/09/29/385.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://www.hanselman.com/blog/WhatsTheUpperLimitOnTheNumberOfProjectsWithinVS2005.aspx" target="_blank"&gt;Hanselman recently posted&lt;/a&gt; about the "upper limit" of the number of projects in VS 2005.  It's a good post because it's true that too many projects just bog down Visual Studio.  Consider refactoring your VS .Net solution to decrease the number of projects if you're having performance problems.  &lt;/p&gt;

&lt;p&gt;I'm currently working with a VS 2003 project where there are 26 projects.  We really don't need 26 projects.  But for right now, the size is borderline unmanageable.  VS 2003 crashes often and it takes a long time for the solution to load.  &lt;/p&gt;

&lt;p&gt;What makes matters worse (as Hanselman also notes) is the JetBrains ReSharper add-in.  ReSharper by itself is an awesome tool, but not so much with very large VS 2003/2005 solutions.  ReSharper constantly searches your projects as you type and perform tasks in Visual Studio, so the more projects you have the slower it goes.  &lt;/p&gt;

&lt;p&gt;Still even worse is that ReSharper will re-enable itself if you disable it as an add-in.  Normally in Visual Studio, you can press the Ctrl+Space keyboard combination to enable Intellisense/auto-complete.  This key combination will &lt;strong&gt;enable&lt;/strong&gt; ReSharper if it is disabled.  This is at least true for VS 2003.  &lt;/p&gt;

&lt;p&gt;I've resorted to completely uninstalling ReSharper for VS 2003 from my system.  I use the Ctrl+Space combo pretty often by habit, and I don't want ReSharper enabled.  My only option was to completely get rid of it until I move on to another project.&lt;/p&gt;

&lt;p&gt;In the meantime, my team will look in to shrinking the number of projects in our solution to make it more manageable.  Then we'll reap the benefits of a leaner solution and add-ins like ReSharper.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=385" width="1" height="1"&gt;</description></item><item><title>Create zip/compressed folders with Powershell</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/08/07/295.aspx</link><pubDate>Mon, 07 Aug 2006 19:59:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:295</guid><dc:creator>mhodnick</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.inetium.com/blogs/mhodnick/rsscomments.aspx?PostID=295</wfw:commentRss><comments>http://blogs.inetium.com/blogs/mhodnick/archive/2006/08/07/295.aspx#comments</comments><description>&lt;P&gt;I came across this &lt;a href="http://mow001.blogspot.com/2006/01/msh-out-zip-function.html" target="_blank"&gt;Powershell blog post&lt;/a&gt; about adding folders and files to a zip archive, but it wasn't exactly 100% usable out of the box.&amp;nbsp; Here's a slight re-work of the script that will have you zipping files from a prompt all day and all night:&lt;/P&gt;
&lt;pre&gt;&lt;code&gt;
########################################################
#
# out-zip.ps1
#
# Usage:
# 
# To zip up some files:
# ls c:\source\*.txt | out-zip c:\target\archive.zip $_
#
# To zip up a folder:
# gi c:\source | out-zip c:\target\archive.zip $_
########################################################

$path = $args[0]
$files = $input
  
if (-not $path.EndsWith('.zip')) {$path += '.zip'} 

if (-not (test-path $path)) { 
  set-content $path ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18)) 
} 

$ZipFile = (new-object -com shell.application).NameSpace($path) 
$files | foreach {$zipfile.CopyHere($_.fullname)} &lt;/code&gt;&lt;/pre&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=295" width="1" height="1"&gt;</description><category domain="http://blogs.inetium.com/blogs/mhodnick/archive/tags/Powershell/default.aspx">Powershell</category></item><item><title>I like pair programming, just not with you (know your text editor)</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/08/04/PairProgrammingTextEditor.aspx</link><pubDate>Fri, 04 Aug 2006 13:16:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:289</guid><dc:creator>mhodnick</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.inetium.com/blogs/mhodnick/rsscomments.aspx?PostID=289</wfw:commentRss><comments>http://blogs.inetium.com/blogs/mhodnick/archive/2006/08/04/PairProgrammingTextEditor.aspx#comments</comments><description>&lt;P&gt;&lt;A href="http://en.wikipedia.org/wiki/Pair_programming" target=_blank&gt;Pair programming&lt;/A&gt; is an important part of modern-day, agile software development processes. It helps developers write better software. Pair programming is a good thing. &lt;/P&gt;
&lt;P&gt;However, I usually can't stand watching someone else write code, or watch someone else do anything on a keyboard for that matter. It's like getting teeth pulled. No, it's like getting teeth pulled while walking on hot coals and self-inflicting paper cuts. &lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.amazon.com/gp/product/020161622X/sr=8-1/qid=1154694739/ref=pd_bbs_1/103-0220614-9539844?ie=UTF8" target=_blank&gt;&lt;IMG alt=Book src="http://a1204.g.akamai.net/7/1204/1401/05041516011/images.barnesandnoble.com/images/9440000/9443648.jpg" width=100 align=right&gt;&lt;/A&gt; A few of us at work are reading &lt;A href="http://www.amazon.com/gp/product/020161622X/sr=8-1/qid=1154694739/ref=pd_bbs_1/103-0220614-9539844?ie=UTF8" target=_blank&gt;The Pragmatic Programmer&lt;/A&gt;, which stresses knowing how to squeeze every drop of coding power out of a text editor. A developer's text editor (or IDE) is to code as a woodworker's saw is to wood. I couldn't agree more. The better you know how to work the keyboard the faster (and easier) you will be able to write code. And I'm not even talking about editors like VI and Emacs - I'm even just talking about basic Notepad operations (although I hope you're not using Notepad to write your apps). &lt;/P&gt;
&lt;P&gt;So, here are some basics (at least on a Windows OS) that will leave your mouse-wielding co-workers in the dust, and will make me pleased to pair-program with you: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Ctrl+X, Ctrl+C, Ctrl+V&lt;/STRONG&gt; &lt;EM&gt;Cut, Copy and Paste&lt;/EM&gt;&lt;BR&gt;95% of developer already know these, but they save you the hassle of choosing the cut, copy, and paste commands from a toolbar or menu. 
&lt;LI&gt;&lt;STRONG&gt;Ctrl+[right/left arrow]&lt;/STRONG&gt; &lt;EM&gt;Move word to word&lt;/EM&gt;&lt;BR&gt;This will move your cursor to the next "non-alphanumeric" character in a file. Meaning, if you have spaces between words it will stop at each space. Handy for moving quickly down a line of text rather than just the arrow keys alone. 
&lt;LI&gt;&lt;STRONG&gt;Shift+[arrow keys]&lt;/STRONG&gt; &lt;EM&gt;Select text&lt;/EM&gt;&lt;BR&gt;Allows you to select (e.g. highlight) text without using the mouse. Use the left and right arrows to select adjacent text, or the up and down arrows to select entire lines of text. 
&lt;LI&gt;&lt;STRONG&gt;Ctrl+Shift+[right/left arrow]&lt;/STRONG&gt; &lt;EM&gt;Select text word to word&lt;/EM&gt;&lt;BR&gt;This is like the Ctrl+[right/left arrow] and Shift+[arrow keys] commands combined together. You can select words while moving your cursor rather than single characters at a time. 
&lt;LI&gt;&lt;STRONG&gt;Home and End keys&lt;/STRONG&gt; &lt;EM&gt;Go to the beginning or the end of a line&lt;/EM&gt;&lt;BR&gt;These are arguably two of the least-utilized keys by developers. 
&lt;LI&gt;&lt;STRONG&gt;Ctrl+Home and Ctrl+End&lt;/STRONG&gt; &lt;EM&gt;Go to the beginning or the end of a document&lt;/EM&gt;&lt;BR&gt;It's like the Home and End key behavior on steroids. 
&lt;LI&gt;&lt;STRONG&gt;Ctrl+s&lt;/STRONG&gt; &lt;EM&gt;Saves the file&lt;/EM&gt;&lt;BR&gt;I'm surprised at how many people still use the mouse to move their pointer to the Save button a toolbar. This shortcut will prolong carpal tunnel syndrome by 0.01% each time you use it. All major Windows text editors support this. 
&lt;LI&gt;&lt;STRONG&gt;Alt, with arrows&lt;/STRONG&gt; &lt;EM&gt;Navigates menu bars&lt;/EM&gt;&lt;BR&gt;You should know keyboard bindings for commands specific to your favorite text editor. For example: closing the text editor, code indenting/formatting, etc. But if you don't, you can use alt key to enable keyboard command of the menu bar and then use the arrow keys to navigate it. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Once you've gotten the hang of these, using them in combination with each other gives you more power. For example, if you want to delete the line that your cursor is on, use the End key, then Shift+[down arrow] to select the line, then delete.&lt;/P&gt;
&lt;P&gt;As I already mentioned, you'll need to go beyond the basic text editing commands to harness all the power of your text editor. Get to know the keyboard bindings that your editor supports to complete certain tasks and operations. You should also be able to set up custom bindings to perform commands. For example, if you really want to use the Ctrl+U, Shift+X sequence to auto-indent and format your code, then you should be able to set up that binding in your editor. If you can't do that with your text editor or IDE, then you might want to try a different one. Being able to set up a Rebuild All command in Visual Studio .Net from the keyboard is one of my first tasks after a fresh install.&lt;/P&gt;
&lt;P&gt;Take all this only as a suggestion. I don't think you &lt;EM&gt;have&lt;/EM&gt; to use keyboard shortcuts to be a good developer, and there's probably somebody out there who is faster than me by using a mouse. However I've never met such a person, and their right wrist is probably throbbing right about now. You need to do what is comfortable to you so that you like your development environment and can get your job done. But if I'm pair programming with you and you see me falling asleep as you use the mouse to select some text, now you'll know why. &lt;/P&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=289" width="1" height="1"&gt;</description><category domain="http://blogs.inetium.com/blogs/mhodnick/archive/tags/.Net+Development/default.aspx">.Net Development</category></item><item><title>MAPI32.dll wrong version error after uninstalling Office 2007</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/07/18/257.aspx</link><pubDate>Tue, 18 Jul 2006 17:33:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:257</guid><dc:creator>mhodnick</dc:creator><slash:comments>56</slash:comments><description>&lt;P&gt;A while back I installed Office 2007 Beta 2, but today I wanted to uninstall it as there were a few quirks of Outlook 2007 that were starting to bug me. Back when I installed Office 2007 Beta 2, I installed it over Office 2003. After uninstalling Office 2007 I attempted to open Outlook 2003 and received this error message:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;Cannot start Microsoft Outlook. MAPI32.DLL is 
corrupt or the wrong version.  This could have 
been caused by installing other messaging system. 
Please reinstall Outlook.&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;I repaired the Office 2003 installation but that did not help. I also reinstalled Office 2003 but that did not help either.&lt;/P&gt;
&lt;P&gt;Then I came across &lt;A href="http://forums.microsoft.com/TechNet/ShowPost.aspx?PostID=438256&amp;amp;SiteID=17" target=_blank&gt;this forum post&lt;/A&gt; that had something that worked (the solution is the last reply in the post). Mapi32.dll is obviously located at &lt;CODE&gt;c:\windows\system32\Mapi32.dll&lt;/CODE&gt; right? Well, yes, but unfortunately the error message is not specifying the correct file name of the dll in question.&lt;/P&gt;
&lt;P&gt;The actual dll that is causing the problem is MSMAPI32.dll, which is located at &lt;CODE&gt;C:\Program Files\Common Files\System\MSMAPI\1033&lt;/CODE&gt;. Simply rename this file to something else (e.g. MSMAPI32_OLD.dll), reinstall Office 2003, and Outlook 2003 should work perfectly after that.&lt;/P&gt;
&lt;P&gt;I'm not sure if this solution will have any effect on other permutations of how Office 2003 and Office 2007 are installed. e.g. if you get the error about MAPI32.dll if you uninstalled Office 2003 before installing Office 2007 Beta, I don't know if this solution will help you.&lt;/P&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=257" width="1" height="1"&gt;</description><category domain="http://blogs.inetium.com/blogs/mhodnick/archive/tags/Office+_2F00_+SharePoint+2007/default.aspx">Office / SharePoint 2007</category></item><item><title>Concurrent Deserialization and Preventing File Locks</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/06/26/247.aspx</link><pubDate>Mon, 26 Jun 2006 16:29:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:247</guid><dc:creator>mhodnick</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.inetium.com/blogs/mhodnick/rsscomments.aspx?PostID=247</wfw:commentRss><comments>http://blogs.inetium.com/blogs/mhodnick/archive/2006/06/26/247.aspx#comments</comments><description>		&lt;p&gt;
			I recently maintained an ASP .Net application where Xml Serialization was used 
			to read and persist configuration data during page requests. When site traffic 
			increased, users encountered &lt;code&gt;System.IO.IOExceptions&lt;/code&gt; with the 
			message "The process cannot access the file "c:\SomeFolder\SomeFile.xml" 
			because it is being used by another process. The exception was not always 
			encountered 100% of the time. The problem could be easily reproduced by opening 
			two browser windows, opening the page in each browser, and quickly refreshing 
			each browser side by side.
		&lt;/p&gt;
		&lt;p&gt;I was able to narrow down the problem to a method in a class where 
			deserialization takes place on each page request. The following code was used:&lt;/p&gt;
		&lt;pre&gt;&lt;code&gt;XmlSerializer serializer = new XmlSerializer(typeof(Foo));
TextReader reader = new StreamReader(serializedFooPath);
myFoo = (Foo)serializer.Deserialize(reader);
reader.Close();
&lt;/code&gt;&lt;/pre&gt;
		&lt;p&gt;Basically the &lt;code&gt;TextReader&lt;/code&gt; locks the file until it is done using 
			it.&amp;nbsp; You can easily avoid locking&amp;nbsp;a file by changing how it is 
			accessed. Simply introduce a &lt;code&gt;FileStream&lt;/code&gt; object that can control 
			how the file is accessed rather than allowing the &lt;code&gt;TextReader&lt;/code&gt; to 
			control it for you. The &lt;code&gt;FileStream&lt;/code&gt; object can accomplish this by 
			using the &lt;code&gt;FileShare.Read&lt;/code&gt; enumeration value:&lt;/p&gt;
		&lt;pre&gt;&lt;code&gt;XmlSerializer serializer = new XmlSerializer(typeof(Foo));
FileStream fs = new FileStream(serializedFooPath, FileMode.Open, FileAccess.Read, FileShare.Read);
TextReader reader = new StreamReader(fs);
myFoo = (Foo)serializer.Deserialize(reader);
reader.Close();
fs.Close();
&lt;/code&gt;&lt;/pre&gt;
		&lt;p&gt;According to MSDN, any request to open the file will fail until the file is 
			closed if &lt;code&gt;FileShare.Read&lt;/code&gt; is not specified [1].&lt;/p&gt;
		&lt;p&gt;Making this change eliminated the problem and the IOException no longer 
			occurred.  It was an easy quick fix - perhaps a better deserialization strategy would come in handy but this fix was able to fix the bug quickly.  Thanks to &lt;a HREF="/blogs/jgood"&gt;Jake&lt;/a&gt; for 
			helping out by supplying the MSDN reference.&lt;/p&gt;
		&lt;p&gt;[1] Refer to &lt;a href="http://msdn2.microsoft.com/en-us/library/system.io.fileshare.aspx" target="_blank"&gt;
				http://msdn2.microsoft.com/en-us/library/system.io.fileshare.aspx&lt;/a&gt; for 
			full documentation of the &lt;code&gt;FileShare&lt;/code&gt; enumeration and &lt;a href="http://msdn2.microsoft.com/en-us/library/system.io.filestream.aspx" target="_blank"&gt;
				http://msdn2.microsoft.com/en-us/library/system.io.filestream.aspx&lt;/a&gt; for 
			full documentation of the &lt;code&gt;FileStream&lt;/code&gt; class.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=247" width="1" height="1"&gt;</description><category domain="http://blogs.inetium.com/blogs/mhodnick/archive/tags/.Net+Development/default.aspx">.Net Development</category></item><item><title>ASP .Net Caching API Tips</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/06/26/246.aspx</link><pubDate>Mon, 26 Jun 2006 14:46:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:246</guid><dc:creator>mhodnick</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.inetium.com/blogs/mhodnick/rsscomments.aspx?PostID=246</wfw:commentRss><comments>http://blogs.inetium.com/blogs/mhodnick/archive/2006/06/26/246.aspx#comments</comments><description> &lt;p&gt;
        The ASP .Net web caching API is a powerful and useful tool at your disposal. Here
        are a few tips and suggestions that will help make your code more flexible and
        maintainable when using the caching API:&lt;/p&gt;
    &lt;ul&gt;
        &lt;li&gt;Define unique keys for cached items in your domain&lt;/li&gt;
        &lt;li&gt;Store expiration durations or times in a configuration file (web.config)&lt;/li&gt;
        &lt;li&gt;Include a configuration setting for enabling and disabling caching&lt;/li&gt;
        &lt;li&gt;Encapsulate caching behavior in a class&lt;/li&gt;
    &lt;/ul&gt;
    &lt;h3&gt;
        Define Unique Keys&lt;/h3&gt;
    &lt;p&gt;
        You can get or insert items from and into the cache using a key. A key is a &lt;code&gt;String&lt;/code&gt;
        value that uniquely identifies an item stored in the cache. Normally you will want
        to use a key based on the unique identifier of some domain object you are working
        with. For example, you may have a &lt;code&gt;Customer&lt;/code&gt; class with an &lt;code&gt;Integer&lt;/code&gt;
        property named &lt;code&gt;CustomerId&lt;/code&gt; that uniquely identifies the customer in
        your domain. Using the &lt;code&gt;CustomerId&lt;/code&gt; as the basis for the cache key would
        be a good choice.  However, the unique identifier of the domain object alone is not
        a good, complete choice for the cache key.  Consider this example:
    &lt;/p&gt;
    &lt;pre&gt;&lt;code&gt;//Bad example.  Non-unique keys are used.
Customer customer = GetCustomerById(100);
Employee employee = GetEmployeeById(100);
double customerValue = 10;
double employeeValue = 100;
Cache.Insert(customer.CustomerID.ToString(), customerValue);
Cache.Insert(employee.EmployeeID.ToString(), employeeValue);
&lt;/code&gt;&lt;/pre&gt;
    &lt;p&gt;The same cache key ("100") is being used to store two different values for two different types of objects, 
    and the employee's value will overwrite the customer's value.  In real life you wouldn't do anything like the
    example above on purpose, but when dealing with the cache across many web forms or web controls in a
    web application, you may not know or remember what other keys are being used to cache values.&lt;/p&gt;
    &lt;p&gt;A better approach would be to qualify the cache key with something that describes the data being stored:&lt;/p&gt;
    &lt;pre&gt;&lt;code&gt;//Better example.  Unique keys are used.
Customer customer = GetCustomerById(100);
Employee employee = GetEmployeeById(100);
double customerValue = 10;
double employeeValue = 100;
Cache.Insert("Customer" + customer.CustomerID.ToString(), customerValue);
Cache.Insert("Employee" + employee.EmployeeID.ToString(), employeeValue);
&lt;/code&gt;&lt;/pre&gt;
    &lt;h3&gt;Make Sliding and Absolute Expirations Configurable&lt;/h3&gt;
    &lt;p&gt;Don't hard-code expiration times in your caching code.  Someone (either you or a user) will probably
    change their mind in the future about how long to store data in the cache.  Use a customer configuration
    section or the &lt;code&gt;AppSettings&lt;/code&gt; section in &lt;code&gt;web.config&lt;/code&gt; to store cache expiration values, as this
    will allow you to change cache times without re-compiling the application.&lt;/p&gt;
    &lt;p&gt;The &lt;code&gt;web.config&lt;/code&gt; file could use an &lt;code&gt;appSettings&lt;/code&gt; section as simple as the 
    example below to configure the number of minutes to store an item in the cache:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;appSettings&amp;gt;
  &amp;lt;add key="customerYtdSalesCacheMinutes" value="30"/&amp;gt;
&amp;lt;/appSettings&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Insert items into the cache using the app setting value:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;...
//calculate the absolute expiration DateTime
DateTime absoluteExp =
    DateTime.Now.AddMinutes(YtdSalesCacheMinutes);
//Use a sliding expiration of zero
TimeSpan slidingExp = TimeSpan.Zero;
Cache.Insert(
    someKey, someValue, null, absoluteExp, slidingExp);
...

public int YtdSalesCacheMinutes
{
  get 
  { 
    return Convert.ToInt32(
      ConfigurationManager.AppSettings["customerYtdSalesCacheMinutes"]); 
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Enable and Disable Caching Through Configuration&lt;/h3&gt;

&lt;p&gt;There may be times when you'll want to disable caching within your app (e.g. during development or debugging).  
Use a configuration setting and add some simple logic to your code to handle this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;!-- web.config --&amp;gt;
&amp;lt;appSettings&amp;gt;
  &amp;lt;add key="customerYtdSalesCacheEnabled" value="true"/&amp;gt;
&amp;lt;/appSettings&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;
// C# code //
...
if (YtdSalesCacheEnabled)
    Cache.Insert(key, myValue, null, absoluteExpiration, slidingExpiration, CacheItemPriority.Normal, null);
...

public bool YtdSalesCacheEnabled
{
    get
    {
        string setting = 
            ConfigurationManager.AppSettings["customerYtdSalesCacheEnabled"];
        if (string.Compare(setting, "true", true) == 0)
            return true;
        return false;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Encapsulate Caching Behavior in a Class&lt;/h3&gt;

&lt;p&gt;Insert and obtain cached values to and from the ASP .Net cache with
a class designated for that behavior.  This will provide the full benefit of an 
object-oriented approach.  The most obvious and immediate benefits are that caching can 
be re-used from anywhere within the application, cache keys can be generated 
consistently, and configuration settings can be obtained in a single place.  The design
of such a class could take on many different forms to suit the needs of different
applications, but here is one example:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;using System;
using System.Web.Caching;
using System.Configuration;

namespace MJH.Caching
{
    public class CustomerCacheManager
    {
        private const string CUST_YTD_SALES_KEY = "CustomerYTDSales-{0}";

        /// &amp;lt;summary&amp;gt;
        /// Obtains a customer's YTD sales value.
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name="cache"&gt;&amp;lt;/param&amp;gt;
        /// &amp;lt;param name="customer"&gt;&amp;lt;/param&amp;gt;
        /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
        public double GetCustomerYtdSales(Cache cache, Customer customer)
        {
            //get the cache key
            string key = GetCustYtdKey(customer.CustomerID);
            
            //return the value from the cache if it exists
            if (cache[key] != null)
                return (double)cache[key];

            //calculate the (time consuming) YTD sales value
            double ytdSalesValue = customer.GetYtdSalesValue();

            //if caching is enabled, store the calculated
            //value in the cache
            if (YtdSalesCacheEnabled)
            {
                DateTime absoluteExp = 
                    DateTime.Now.AddMinutes(YtdSalesCacheMinutes);
                TimeSpan slidingExp = TimeSpan.Zero;
                cache.Insert(
                    key,                        //item key
                    ytdSalesValue,              //item value
                    null,                       //dependencies
                    absoluteExp,                //absolute expiration
                    slidingExp);                //sliding expiration
            }
            return ytdSalesValue;
        }

        /// &amp;lt;summary&amp;gt;
        /// Generates a cache key for a customer
        /// YTD sales value.
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name="customerId"&gt;&amp;lt;/param&amp;gt;
        /// &amp;lt;returns&gt;&amp;lt;/returns&amp;gt;
        private string GetCustYtdKey(int customerId)
        {
            return string.Format(CUST_YTD_SALES_KEY, customerId.ToString());
        }

        /// &amp;lt;summary&amp;gt;
        /// Gets the nubmer of minutes that YTD sales
        /// values should be cached.
        /// &amp;lt;/summary&amp;gt;
        public int YtdSalesCacheMinutes
        {
            get { 
                return Convert.ToInt32(
                    ConfigurationManager.AppSettings["customerYtdSalesCacheMinutes"]); 
            }
        }

        /// &amp;lt;summary&amp;gt;
        /// Gets whether caching is enabled.
        /// &amp;lt;/summary&amp;gt;
        public bool YtdSalesCacheEnabled
        {
            get
            {
                string setting = ConfigurationManager.AppSettings["customerYtdSalesCacheEnabled"];
                if (string.Compare(setting, "true", true) == 0)
                    return true;
                return false;
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=246" width="1" height="1"&gt;</description><category domain="http://blogs.inetium.com/blogs/mhodnick/archive/tags/.Net+Development/default.aspx">.Net Development</category></item><item><title>See Windows Vista</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/06/06/161.aspx</link><pubDate>Tue, 06 Jun 2006 12:15:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:161</guid><dc:creator>mhodnick</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.inetium.com/blogs/mhodnick/rsscomments.aspx?PostID=161</wfw:commentRss><comments>http://blogs.inetium.com/blogs/mhodnick/archive/2006/06/06/161.aspx#comments</comments><description>&lt;p&gt;Make sure you check out &lt;a href="http://www.seewindowsvista.com/" target="_blank"&gt;SeeWindowsVista.com&lt;/a&gt; to see a lot of cool things you can do with WPF.  Lots of examples of 2D and 3D, including the earlier demos/proof-of-concepts (e.g. NASCAR, North Face, etc).  &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=161" width="1" height="1"&gt;</description><category domain="http://blogs.inetium.com/blogs/mhodnick/archive/tags/WPF/default.aspx">WPF</category></item><item><title>A comment on interviewing</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/05/31/147.aspx</link><pubDate>Wed, 31 May 2006 16:20:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:147</guid><dc:creator>mhodnick</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.inetium.com/blogs/mhodnick/rsscomments.aspx?PostID=147</wfw:commentRss><comments>http://blogs.inetium.com/blogs/mhodnick/archive/2006/05/31/147.aspx#comments</comments><description>&lt;P&gt;"Tell me about yourself".&lt;/P&gt;
&lt;P&gt;This is the first item I ask of interview candidates, and I'm suprised at how often it completely catches them by suprise or how they don't know how to answer the question. I've gotten responses from "what do you mean" to an entire detailed work history. &lt;/P&gt;
&lt;P&gt;It is a tough question, but I think candidates have to know how to answer it. It's their 60-second chance to tell me what's important and relevant about their personality and their professional work history. It forces the candidate to have their thoughts organized and to be concise. Unfortunately most of the time their response results in train wreck of technical project details.&lt;/P&gt;
&lt;P&gt;I don't expect a response that's perfect, but I'm looking to hear the candidate tell me about:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Professional interests. e.g. hard-core programmer, .Net development, WinFX/WPF, Ajax, Agile Development, and Perl. 
&lt;LI&gt;Personality traits. e.g. enjoy working with people, have fun at work while being professional, refuse to work with end users. 
&lt;LI&gt;Work history. e.g. I was a Code Monkey and developed a Widget and a Thingamabob at Acme. I led a team of developers at Intertrode and successfully rolled out 4 large web apps. 
&lt;LI&gt;A few personal things. e.g. camping, hiking, playing drums, and watching kung fu &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;This topic in an interview isn't a make-or-break item, but it sets the stage for the rest of the interview. It gives the candidate a chance to shine and to let me know that they're serious about wanting to talk with me, about wanting the job, and that they've put some thought into what they want to tell me.&lt;/P&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=147" width="1" height="1"&gt;</description></item><item><title>I've lost control of my wallpaper</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/05/17/129.aspx</link><pubDate>Wed, 17 May 2006 14:01:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:129</guid><dc:creator>mhodnick</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.inetium.com/blogs/mhodnick/rsscomments.aspx?PostID=129</wfw:commentRss><comments>http://blogs.inetium.com/blogs/mhodnick/archive/2006/05/17/129.aspx#comments</comments><description>&lt;p&gt;Someone in the Inetium office is messing with me.  One day last week, and again yesterday, my Windows desktop wallpaper was automatically changed to this image:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.flickr.com/photos/kindohm/148169510/" target="_blank"&gt;&lt;img src="http://static.flickr.com/52/148169510_738c1867a9.jpg?v=0" border="0" width="400" alt="hods" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I went to my Desktop properties to change it back to something else, but my wallpaper controls were disabled.  What's also weird is that the image is "doctored".  Most of the image is real - that is really me behind a goalie prop at the XCel Energy Center - but that flaming flag thing is not a part of the original image.  Thus my research began...&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;In the registry, my desktop wallpaper was pointing to an image named "hods.jpg" out on a share of our domain controller.&lt;/li&gt;
  &lt;li&gt;I changed the registry value, but when I rebooted the setting was overwritten.&lt;/li&gt;
  &lt;li&gt;Very few people in the office call me "hods".  I have a lousy poker face, but did the best I could yesterday to try and snuff out the person that did this.  Nobody fessed up.&lt;/li&gt;

&lt;li&gt;I talked to a couple of our domain admins and they couldn't figure out how the setting was being written, nor could they identify the the individual who put the image out on the share.  The owner was only shown as "Administrator".  &lt;/li&gt;

&lt;li&gt;I checked out the other profile folders under my Documents and Settings folder, and there was only one other one besides myself.  That folder is the name of one of our old domain admins and it was created back in January 2005.  I didn't see any evidence in there that he had logged in recently.&lt;/li&gt;

&lt;li&gt;I verified in my startup settings (using msconfig) that no special batch file or script is being run on startup.&lt;/li&gt;

&lt;li&gt;In the meantime I've eliminated all shared folders and have removed all known "extra" permissions to folders on my machine.&lt;/li&gt;

&lt;li&gt;I now have successful security events logged to my security log, so I can now find out if someone else is logging in to my machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Late yesterday after rebooting another time, my wallpaper settings were unlocked and I could change the wallpaper.  I was never able to track down the perpetrator.  &lt;/p&gt;

&lt;p&gt;What's a bit annoying about all this is that I do demos and use my laptop with client users pretty often, so to unexpectedly see that image stretched across my screen when I log in at a client is a little awkward.  But overall, I'd rather find out who is doing it than solve the problem.  I guess I'll just see if the problem happens again.  &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=129" width="1" height="1"&gt;</description></item><item><title>Update on the consulting front</title><link>http://blogs.inetium.com/blogs/mhodnick/archive/2006/05/17/128.aspx</link><pubDate>Wed, 17 May 2006 13:34:00 GMT</pubDate><guid isPermaLink="false">7346ef18-9fb1-4a4e-be41-9add5078176c:128</guid><dc:creator>mhodnick</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.inetium.com/blogs/mhodnick/rsscomments.aspx?PostID=128</wfw:commentRss><comments>http://blogs.inetium.com/blogs/mhodnick/archive/2006/05/17/128.aspx#comments</comments><description>&lt;p&gt;I haven't posted in a while because things have been pretty busy in the office.  I haven't had much time at all to continue my WPF research, but there are some other interesting things happening that I hope to write about in the near future.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VS .Net Solution Re-structuring&lt;/strong&gt; - My development team that works on .Net apps for one of our clients is looking into restructuring the primary Visual Studio .Net solution that holds most of the app code.  The way it is currently structured makes it difficult to develop, maintain, and deploy the applications.  There are 24 projects in the solution, including web applications and shared assemblies.  A new strategy for versioning and deployment is also in the works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not-so-shared web controls&lt;/strong&gt; - I now have ownership of a common web controls project that is a part of the bigger solution named above.  It was developed using web user controls but is being deployed for use by multiple web applications.  Some trickery with virtual directories is used in an attempt to try and make these web controls "shared", but because of how ASP .Net caches assemblies, it causes many problems during deployment over the different web applications.  Ideally I'd like to convert this project into a custom web server control library so that they can be truly shared, but there are over 75 web user controls that would need to be converted.  I'm not sure if it will make sense to literally convert everything to custom web server controls, but what we're doing now doesn't work so well either.
&lt;/p&gt;

&lt;p&gt;Perhaps the biggest challenge will be to justify the time needed to work on these issues.  Arguably, fixing these issues will result in much higher development productivity and smoother deployments in the future.  Short term, the gains may not be noticeable - and will likely slow down any immediate development.  Building up the case to work on these issues shouldn't be too difficult, but it will be necessary in order to justify working on them.&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.inetium.com/aggbug.aspx?PostID=128" width="1" height="1"&gt;</description><category domain="http://blogs.inetium.com/blogs/mhodnick/archive/tags/.Net+Development/default.aspx">.Net Development</category></item></channel></rss>