<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Kris' Blog &#187; .net</title>
	<atom:link href="http://krisselden.com/tag/net/feed/" rel="self" type="application/rss+xml" />
	<link>http://krisselden.com</link>
	<description>Focused on software development.</description>
	<lastBuildDate>Thu, 27 Mar 2008 03:06:56 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>The operation completed successfully.</title>
		<link>http://krisselden.com/2007/05/10/the-operation-completed-successfully/</link>
		<comments>http://krisselden.com/2007/05/10/the-operation-completed-successfully/#comments</comments>
		<pubDate>Fri, 11 May 2007 02:14:45 +0000</pubDate>
		<dc:creator>Kris</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[wpf]]></category>

		<guid isPermaLink="false">http://krisselden.com/2007/05/10/the-operation-completed-successfully/</guid>
		<description><![CDATA[The stacktrace says it all.
System.Runtime.InteropServices.COMException (0x80070000): The operation completed successfully. (Exception from HRESULT: 0x80070000)
   at MS.Internal.HRESULT.Check(Int32 hr)
   at System.Windows.Media.SafeProfileHandle.ReleaseHandle()
   at System.Runtime.InteropServices.SafeHandle.InternalFinalize()
   at System.Runtime.InteropServices.SafeHandle.Dispose(Boolean disposing)
   at System.Runtime.InteropServices.SafeHandle.Finalize()
We made this go away by calling GC.WaitForPendingFinalizers() but this can cause deadlocks in WPF since some Finalize() methods use [...]]]></description>
			<content:encoded><![CDATA[<p>The stacktrace says it all.</p>
<pre class="line5"><code>System.Runtime.InteropServices.COMException (0x80070000): The operation completed successfully. (Exception from HRESULT: 0x80070000)
   at MS.Internal.HRESULT.Check(Int32 hr)
   at System.Windows.Media.SafeProfileHandle.ReleaseHandle()
   at System.Runtime.InteropServices.SafeHandle.InternalFinalize()
   at System.Runtime.InteropServices.SafeHandle.Dispose(Boolean disposing)
   at System.Runtime.InteropServices.SafeHandle.Finalize()</code></pre>
<p>We made this go away by calling GC.WaitForPendingFinalizers() but this can cause deadlocks in WPF since some Finalize() methods use Dispatcher.Invoke().</p>
]]></content:encoded>
			<wfw:commentRss>http://krisselden.com/2007/05/10/the-operation-completed-successfully/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Validating fullwidth alphanumeric input in .Net</title>
		<link>http://krisselden.com/2007/02/19/validating-fullwidth-alphanumeric-input-in-net/</link>
		<comments>http://krisselden.com/2007/02/19/validating-fullwidth-alphanumeric-input-in-net/#comments</comments>
		<pubDate>Tue, 20 Feb 2007 03:52:09 +0000</pubDate>
		<dc:creator>Kris</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[ffxi]]></category>
		<category><![CDATA[globalization]]></category>

		<guid isPermaLink="false">http://krisselden.com/2007/02/19/validating-fullwidth-alphanumeric-input-in-net/</guid>
		<description><![CDATA[One of the things that attracted me to playing Final Fantasy XI (a MMORPG) was the opportunity to play on the same server with Japanese players. I’ve been a fan of anime since I was a kid and always curious about Japanese culture.
I noticed that when a Japanese player says 5000 gil (Final Fantasy currency) [...]]]></description>
			<content:encoded><![CDATA[<p>One of the things that attracted me to playing <a href="http://www.playonline.com/ff11us/">Final Fantasy XI</a> (a <a href="http://en.wikipedia.org/wiki/MMORPG">MMORPG</a>) was the opportunity to play on the same server with Japanese players. I’ve been a fan of anime since I was a kid and always curious about Japanese culture.</p>
<p>I noticed that when a Japanese player says 5000 gil (Final Fantasy currency) it looks wide and spaced funny like &#8220;５０００　ｇｉｌ.&#8221; As Japanese players are generally considered to be more <a href="http://en.wikipedia.org/wiki/Leetspeak">l33t</a> by the American players, some even try to mimic this by adding spaces like so &#8220;5 0 0 0  g i l.&#8221; People even <a href="http://www.windower.net/forums/viewtopic.php?t=2050">hack</a> the game to input Japanese text on the American client.</p>
<p>So when my brother called me in a bind about a missed requirement to accept double byte credit card numbers, I knew exactly what he was talking about.<br />
Luckily the web browser deals with the input and on the ASP.NET side it is decoded into a Unicode string. From there it is actually quite simple.</p>
<p>No, int.Parse(string) does not work.</p>
<p>You could loop over each character in the string and use char.IsNumber(char) for validation. You&#8217;d probably want to be more specific char.<a href="http://msdn2.microsoft.com/en-us/library/system.char.getunicodecategory.aspx">GetUnicodeCategory</a>(char) since we don&#8217;t need to support roman numerals.</p>
<pre class="line5"><code>protected void CustomValidator1_ServerValidate(object source, ServerValidateEventArgs args)
{
    foreach (char c in args.Value)
        if (char.GetUnicodeCategory(c) != UnicodeCategory.DecimalDigitNumber)
            args.IsValid = false;
}</code></pre>
<p>You probably want to normalize it before saving it into the database. You could use (int)char.<a href="http://msdn2.microsoft.com/en-us/library/system.char.getnumericvalue.aspx">GetNumericValue</a>(char) but even easier is to use string.<a href="http://msdn2.microsoft.com/en-us/library/ebza6ck1.aspx">Normalize</a>(<a href="http://msdn2.microsoft.com/en-us/library/system.text.normalizationform.aspx">NormalizationForm</a>.FormKD). You could even normalize the string before validation and run your existing validation on the normalized string.</p>
<p>Output from the <a href="http://msdn2.microsoft.com/en-us/library/f177hahy(VS.80).aspx">Immediate Window (Ctrl-Alt-I)</a></p>
<pre class="line9"><code>'\xFF15'
65301 '５'
Char.IsNumber('５')
true
Char.GetUnicodeCategory('５')
DecimalDigitNumber
Char.GetNumericValue('５')
5.0
"５０００　ｇｉｌ".Normalize(System.Text.NormalizationForm.FormKD)
"5000 gil"</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://krisselden.com/2007/02/19/validating-fullwidth-alphanumeric-input-in-net/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Visibility.Visible != IsVisible</title>
		<link>http://krisselden.com/2007/01/31/visibilityvisible-isvisible/</link>
		<comments>http://krisselden.com/2007/01/31/visibilityvisible-isvisible/#comments</comments>
		<pubDate>Wed, 31 Jan 2007 06:33:30 +0000</pubDate>
		<dc:creator>Kris</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[wpf]]></category>

		<guid isPermaLink="false">http://krisselden.com/2007/01/31/visibilityvisible-isvisible/</guid>
		<description><![CDATA[Today, Robert and I spent a while trying to figure out why we couldn&#8217;t give focus to a TextBox we added dynamically. Calling textBox.Focus() was always returning false, yet we could click on it to focus.
Reading the WPF focus overview, Focus() returns false if either IsEnabled, IsVisible or Focusable are false &#8212; well it defaults [...]]]></description>
			<content:encoded><![CDATA[<p>Today, Robert and I spent a while trying to figure out why we couldn&#8217;t give focus to a TextBox we added dynamically. Calling textBox.Focus() was always returning false, yet we could click on it to focus.</p>
<p>Reading the WPF focus overview, Focus() returns false if either IsEnabled, IsVisible or Focusable are false &#8212; well it defaults to being enabled, visible and focusable so why isn&#8217;t it working?</p>
<p>IsVisible is calculated during the Layout pass, which isn&#8217;t going to happen on this dispatcher operation. During this time, textBox.Visibility will return Visibility.Visible and textBox.IsVisible will return false.</p>
<blockquote><p>
Determination of the <a href="http://msdn2.microsoft.com/en-us/library/system.windows.uielement.isvisible.aspx">IsVisible</a> value takes all factors of layout into account. In contrast, Visibility, which is a settable property, only indicates the intention to programmatically make an element visible or invisible.
</p></blockquote>
<pre class="line5"><code>textBox = new TextBox();
AddChild(textBox);
// textBox.IsVisible == false
textBox.UpdateLayout();
// textBox.IsVisible == true
textBox.Focus() // returns true</code></pre>
<p>In general, read-only properties, especially dependency properties registered as read-only, will need an UpdateLayout (I wouldn&#8217;t do that a lot) or you will need to BeginInvoke your work on the Dispatcher to wait for layout.</p>
]]></content:encoded>
			<wfw:commentRss>http://krisselden.com/2007/01/31/visibilityvisible-isvisible/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Adding a Custom Publisher to CruiseControl.NET</title>
		<link>http://krisselden.com/2007/01/29/adding-a-custom-cruisecontrolnet-publisher/</link>
		<comments>http://krisselden.com/2007/01/29/adding-a-custom-cruisecontrolnet-publisher/#comments</comments>
		<pubDate>Mon, 29 Jan 2007 05:55:35 +0000</pubDate>
		<dc:creator>Kris</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[ccnet]]></category>
		<category><![CDATA[nabaztag]]></category>

		<guid isPermaLink="false">http://krisselden.com/2007/01/29/adding-a-custom-cruisecontrolnet-publisher/</guid>
		<description><![CDATA[Now you too can have a funny lookin&#8217; bunny announce whether you broke the build with your last check-in.
The sample code is a Nabaztag publisher for CC.NET which sends the build status as a text to speech message via the Nabaztag API demonstrating a configurable CruiseControl.NET publisher plugin.
NabaztagPublisher.cs
using System;
using System.Net;
using System.Text;
using Exortech.NetReflector;
using ThoughtWorks.CruiseControl.Core;
using ThoughtWorks.CruiseControl.Core.Util;
using ThoughtWorks.CruiseControl.Remote;

namespace [...]]]></description>
			<content:encoded><![CDATA[<p>Now you too can have a funny lookin&#8217; <a href="http://www.nabaztag.com/en/index.html">bunny</a> announce whether you broke the build with your last <a href="http://www.google.com/search?q=continuous+integration">check-in</a>.</p>
<p>The sample code is a Nabaztag publisher for <a href="http://confluence.public.thoughtworks.org/display/CCNET/Welcome+to+CruiseControl.NET">CC.NET</a> which sends the build status as a text to speech message via the <a href="http://help.nabaztag.com/fiche.php?langue=3&#038;fiche=29">Nabaztag API</a> demonstrating a configurable CruiseControl.NET publisher plugin.</p>
<p><a href='http://krisselden.com/wp-content/uploads/nabaztagpublisher.cs' title='NabaztagPublisher.cs'>NabaztagPublisher.cs</a></p>
<pre class="line25"><code>using System;
using System.Net;
using System.Text;
<b>using Exortech.NetReflector;
using ThoughtWorks.CruiseControl.Core;
using ThoughtWorks.CruiseControl.Core.Util;
using ThoughtWorks.CruiseControl.Remote;</b>

namespace NabaztagCruiseControlPlugin
{
    <b>[ReflectorType("nabaztag")]</b>
    public class NabaztagPublisher: <b>ITask</b>
    {
        private const int SuccessEarPosition = 0;
        private const int FailureEarPosition = 9;
        private const string NabaztagUrlFormat =
@"http://api.nabaztag.com/vl/FR/api.jsp?key={0}&amp;sn={1}&amp;token={2}&amp;posleft={3}&amp;posright={3}&amp;ears=ok&amp;voice=graham22s&amp;tts={4}";

        private readonly WebClient _client;

        private string _key;
        private string _token;
        private string _serialNumber;
        private string _pronounceableName;

        public NabaztagPublisher()
        {
            _client = new WebClient();
            _client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(WebClientDownloadStringCompleted);
        }

        <b>[ReflectorProperty("key")]</b>
        public string Key
        {
            get { return _key; }
            set { _key = value; }
        }

        <b>[ReflectorProperty("token")]</b>
        public string Token
        {
            get { return _token; }
            set { _token = value; }
        }

        <b>[ReflectorProperty("serialNumber")]</b>
        public string SerialNumber
        {
            get { return _serialNumber; }
            set { _serialNumber = value; }
        }

        <b>[ReflectorProperty("pronounceableName", Required=false)]</b>
        public string PronounceableName
        {
            get { return _pronounceableName; }
            set { _pronounceableName = value; }
        }

        public void <b>Run(IIntegrationResult result)</b>
        {
            string name = PronounceableName ?? result.ProjectName;
            string message;
            int earPosition;
            switch (result.Status)
            {
                case IntegrationStatus.Success:
                    earPosition = SuccessEarPosition;
                    if (result.LastIntegrationStatus == IntegrationStatus.Success)
                        message = string.Format(
                            "Yet another successful build for {0}.", name);
                    else
                        message = string.Format(
                            "Recent check ins have fixed the build for {0}.", name);
                    break;
                case IntegrationStatus.Failure:
                    earPosition = FailureEarPosition;
                    if (result.LastIntegrationStatus == IntegrationStatus.Success)
                        message = string.Format(
                            "The build has failed for {0}. Oh dear.", name);
                    else
                        message = string.Format(
                            "The build is still broken for {0} people! Get your act together. Deary me.", name);
                    break;
                case IntegrationStatus.Exception:
                    earPosition = FailureEarPosition;
                    message = string.Format(
                        "Oh dear. The build has failed due to an exception for project {0}. This sucks.", name);
                    break;
                case IntegrationStatus.Unknown:
                default:
                    earPosition = FailureEarPosition;
                    message = string.Format(
                        "Oh dear. The build has failed due to an unknown reason for project {0}. This sucks.", name);
                    break;
            }

            Uri uri = new Uri(
                string.Format(NabaztagUrlFormat, Key, SerialNumber, Token, earPosition, Uri.EscapeDataString(message)));
            _client.DownloadStringAsync(uri, uri);
        }

        void WebClientDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            Log.Debug(string.Format("Nabaztag API: {0}", e.UserState));
            if (e.Error != null)
                Log.Error(e.Error);
            else
                Log.Debug(e.Result);
        }
    }
}</code></pre>
<p>I had trouble finding documentation on CC.NET plugins but I found documentation on adding a <a href="http://confluence.public.thoughtworks.org/display/CCNET/Custom+Builder+Plug-in">custom builder plugin</a> and most the info applies to plugins in general.</p>
<p>I had to name the assembly ccnet.nabaztag.plugin.dll (CC.NET expects plugin assembly files to be in the form ccnet.*.plugin.dll) and mark it with NetReflector (part of the CC.NET distribution) attributes that correspond to the XML tags and attributes used to configure the plugin in the ccnet.config file.</p>
<pre class="line7"><code>&lt;project&gt;
...
&lt;publishers&gt;
...
<b>&lt;nabaztag key="111111111" serialNumber="111111111" token="111111111"
pronounceableName="My Project" /&gt;</b>
&lt;/publishers&gt;
&lt;/project&gt;</code></pre>
<p>Another thing to note, CC.NET&#8217;s static Log util is backed by <a href="http://logging.apache.org/log4net/">log4net</a> which is thread safe (in case you were wondering if it was ok for me to log on the async callback, the only drawback is in the log file it will use the thread id and not the name of the project).</p>
<p><img src='http://krisselden.com/wp-content/uploads/bunny.JPG' alt='Bunny' style="float:right; margin-left:10px;" /><br />
Edit:<br />
I wanted to keep the example simple and focused on adding a custom publisher to CC.NET but it seems the bunny is more interesting so I wanted to point out this <a href="http://gk.respin.co.za/default.aspx?SectionID=d662c3da-bebc-4aea-bb85-e203e4c9bea9">C# Nabaztag API</a> wrapper which is also where I got the &#8220;oh deary me&#8221; messages from. And yet another library to control your <a href="http://sourceforge.net/projects/nabazlab">bunny</a>.</p>
<p>Also, for the original <a href="http://freshmeat.net/projects/nabaztagccplugin/">CruiseControl</a>.<br />
<br style="clear:right"/></p>
]]></content:encoded>
			<wfw:commentRss>http://krisselden.com/2007/01/29/adding-a-custom-cruisecontrolnet-publisher/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>
