Tuesday, March 9, 2010

Visual Studio 2008 text-encoding iso-8859-1 versus UTF-8

I ran into an issue with ASP.NET pages coming back with the wrong character encoding for text processed through controls.
In the code I specified UTF-8, but when I checked the properties in Firefox the encoding was ISO-8859-1 (Western European (ISO) 28591).
One result of this was that a   that had been encoded through a control, such as a LinkButton, was appearing as  (U+00C2 Latin Capital Letter A With Circumflex Alt+0194) followed by the actual non-breaking space.

  • non-breaking space character in ISO-8859-1 is byte 0xA0
  • non-breaking space character in UTF-8 is byte 0xC2,0xA0
  • character bytes 0xC2,0xA0 viewed as ISO-8859-1 comes out as " " (where the second character is a non-breaking space).
<%@ Page Language="C#" AutoEventWireup="true" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title> 
    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            HttpContext.Current.Response.ContentType = "Content-Type: text/html; charset=UTF-8";
            lnkTest.Text += "1";
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <p>Before&nbsp;After</p>
        <asp:LinkButton ID="lnkTest" runat="server" Text="Before&nbsp;After" />
    </div>
    </form>
</body>
</html>

Try changing the content type line as follows:

HttpContext.Current.Response.ContentType = "text/html; charset=UTF-8";

See Also:

Wednesday, March 3, 2010

Setting properties from a dictionary of strings

A code snippet that can be used to set an objects properties via reflection.

See Also:

using System.ComponentModel;
using System.Collections.Generic;

///...

/// 
/// Set Properties on this instance using key value pairs from a dictionary
/// 
/// Dictionary of keys (property names) and values (value to set property to)
public void FromTemplateData(Dictionary<string, string> templateData)
        {
            PropertyDescriptorCollection propertyDescriptors = TypeDescriptor.GetProperties(this);

            foreach (string key in templateData.Keys)
            {

                //Find the property, ignore case.
                PropertyDescriptor propertyDescriptor = propertyDescriptors.Find(key, true);//propertyDescriptors[nodeName];
                if (propertyDescriptor != null)
                {
                    propertyDescriptor.SetValue(this, propertyDescriptor.Converter.ConvertFromInvariantString(templateData[key]));
                }
                else
                {
                    throw new ApplicationException("No property matching name: " + key);
                }
            }
        }

Tuesday, February 23, 2010

DropDownList Extension method for selecting by value

    /// 
    /// Extension methods for the ASP.NET DropDownList control.
    /// 
    public static class DropDownListExtension
    {
        /// 
        /// Select an item in the DropDownList based on the value
        /// 
        /// The DropDownList to select from
        /// The value to select
        public static void SelectItemByValue(this System.Web.UI.WebControls.DropDownList dropDownList, string valueToSelect)
        {
            try
            {
                dropDownList.SelectedIndex = dropDownList.Items.IndexOf(dropDownList.Items.FindByValue(valueToSelect));
            }
            catch (Exception ex)
            {
                throw new ApplicationException("Unable to set value to " + valueToSelect, ex);
            }
        }

        /// 
        /// Select an item in the DropDownList based on the value after the drop down list has been data bound.
        /// 
        /// The DropDownList to select from
        /// The value to select
        public static void SelectItemByValueAfterDataBound(this System.Web.UI.WebControls.DropDownList dropDownList, string valueToSelect)
        {
            dropDownList.DataBound += delegate(object sender, EventArgs e) { dropDownList.SelectItemByValue(valueToSelect); };
        }
    }

Friday, February 12, 2010

Running a class in a seperate AppDomain without loading the assembly into the default AppDomain

Project 1 - AppDomain (Console Application)

Program.cs

This project has no reference to Project 3 (FileLockFail). FileLockFail will not appear in the list of assemblies.
Unloading the created appDomain will release the file lock.

using System;
using System.Reflection;
using Interfaces;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        private const string targetDllName = "FileLockFail.dll";

        static void Main(string[] args)
        {
            string testFileFullPath = CreateTestFile();

#if(DEBUG)
            //Copy the DDL that will be loaded into the AppDomain into the working directory.
            DirectoryInfo dllDir = new DirectoryInfo(Environment.CurrentDirectory);
            string source = Path.Combine(dllDir.Parent.Parent.Parent.FullName, @"FileLockFail\bin\Debug\" + targetDllName);
            string destination = Path.Combine(dllDir.FullName, targetDllName);
            File.Copy(source, destination, true);
#endif

            AppDomainSetup domainSetup = new AppDomainSetup();
            domainSetup.ApplicationName = "appDomain";
            domainSetup.ApplicationBase = Environment.CurrentDirectory;

            AppDomain appDomain = AppDomain.CreateDomain("appDomain", null, domainSetup);

            ITestMethod otherDomainTestClass = (ITestMethod)appDomain.CreateInstanceAndUnwrap(
                targetDllName.Replace(".dll", ""),
                "FileLockFail.FailToCloseFileStream");

            otherDomainTestClass.TestMethod(testFileFullPath);

            try
            {
                //This should fail due to the file lock still being open.
                System.IO.File.Delete(testFileFullPath);
                System.Diagnostics.Debug.Fail("Exception expected");
            }
            catch (IOException)
            {
                AppDomain.Unload(appDomain);
            }

            System.IO.File.Delete(testFileFullPath);

            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            Console.WriteLine("Assembly: {0}", AppDomain.CurrentDomain.FriendlyName);
            foreach (Assembly assembly in assemblies)
            {
                Console.WriteLine("Loaded:  {0}.", assembly.ManifestModule.Name);
            }

            Console.WriteLine("Press enter");
            Console.ReadLine();
        }

        private static string CreateTestFile()
        {
            string filePath = Path.Combine(Environment.CurrentDirectory, "TestFile.txt");
            using (FileStream fileStream = File.Create(filePath))
            {
                using (System.IO.StreamWriter fileWriter = new StreamWriter(fileStream))
                {
                    fileWriter.Write("Hello World " + DateTime.Now);
                }
            }
            return filePath;
        }

    }

}

Project 2 - Interfaces (Class Library)

ITestMethod.cs

Shared interface between both DLL's.

namespace Interfaces
{
    public interface ITestMethod
    {
        void TestMethod(string message);
    }
}

Project 3 - FileLockFail (Class Library)

FailToCloseFileStream.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace FileLockFail
{
    [Serializable]
    public class FailToCloseFileStream : MarshalByRefObject, Interfaces.ITestMethod
    {
        private static System.IO.FileStream _fileStream = null;

        public void TestMethod(string message)
        {
            Console.WriteLine("Host domain: {0} Message: {1}", AppDomain.CurrentDomain.FriendlyName, message);

            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            Console.WriteLine("Assembly: {0}", AppDomain.CurrentDomain.FriendlyName);
            foreach (Assembly assembly in assemblies)
            {
                Console.WriteLine("Loaded:  {0}.", assembly.ManifestModule.Name);
            }

            _fileStream = System.IO.File.OpenWrite(message);

            //Don't close the file stream
        }
    }
}

Thursday, February 11, 2010

Running a class in a seperate AppDomain

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            TestClass currentDomainTestClass = new TestClass();
            currentDomainTestClass.TestMethod("From current domain");

            AppDomain appDomain = AppDomain.CreateDomain("appDomain");
            TestClass otherDomainTestClass = (TestClass)appDomain.CreateInstanceAndUnwrap(
                typeof(TestClass).Assembly.FullName,
                typeof(TestClass).FullName);

            otherDomainTestClass.TestMethod("Seperate domain");

            Console.ReadLine();
        }
    }

    public class TestClass : MarshalByRefObject
    {
        public void TestMethod(string message)
        {
            Console.WriteLine("Host domain: {0} Message: {1}",
                AppDomain.CurrentDomain.FriendlyName,
                message);

        }
    }
}

MSDN: Using Application Domains

Wednesday, February 10, 2010

Filtering a log4net appender to exclude a logger

<filter type="log4net.Filter.LoggerMatchFilter">
  <loggerToMatch value="Logger.To.Filter.Out" />
  <acceptOnMatch value="false" />
</filter>

From ILoggable: Log4Net filtering by logger

Tuesday, January 26, 2010

TypeCode enumeration for creating switch statements with

You can use the TypeCode enumeration to create switch statements for built-in types.

switch (Type.GetTypeCode(myObj.GetType())) {
    case TypeCode.Boolean: ...
    case TypeCode.Char: ...
    case TypeCode.String: ...
    case TypeCode.Object: ...
    default: ...
}