Debugging a WCF service on Windows 7 and IIS 7

I created and deployed a WCF service, created with Microsoft Visual Studio 2008, to IIS 7 on Windows 7 and I got the error message:
Unable to start debugging on the web server. Could not start ASP .NET debugging. More Information may be available by starting the project without debugging.

image

So I did, I started the WCF service without debugging an got the error page:
HTTP Error 404.3 – Not Found
The page you are requesting cannot be served because of the extension configuration. If the page is a script, add a handler. If the file should be downloaded, add a MIME map.

Then I followed the instruction on http://blogs.msdn.com/rjohri/archive/2009/06/29/the-page-you-are-requesting-cannot-be-served-because-of-the-extension-configuration.aspx
, that cleared the error!

  • Run Visual Studio 2008 Command Prompt as “Administrator”.
  • Navigate to C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation.
  • Run this command servicemodelreg –i
  •  

    Installed IIS 7 after installing Visual Studio 2008 and .NET Framework 3.5

    Show all encodings and codepages on a Windows server in C#

    If you want to show all encodings of a Windows server in C# in sorted order, use the code:

        // Get all encodings know on this server
    EncodingInfo[] encodings = Encoding.GetEncodings();
    // Sort EncodingInfo array by Name
    Array.Sort(encodings, new CaseInsensitiveEncodingInfoNameComparer());
    // Show all encodings
    foreach (EncodingInfo encoding in encodings)
    {
    Console.WriteLine(string.Format("{0}", encoding.Name));
    }
        public class CaseInsensitiveEncodingInfoNameComparer : IComparer
    {
    // Compare 2 EncodingInfo objects, by doing a case insensitive compare on there name
    int IComparer.Compare(Object x, Object y)
    {
    int result = 0;
    if (x is EncodingInfo && y is EncodingInfo)
    {
    var xEncodingInfo = x as EncodingInfo;
    var yEncodingInfo = y as EncodingInfo;
    result = ((new CaseInsensitiveComparer()).Compare(xEncodingInfo.Name, yEncodingInfo.Name));
    }
    return result;
    }
    }

     
     

    Result:

    ASMO-708
    big5
    cp1025
    cp866
    cp875
    csISO2022JP
    DOS-720
    DOS-862
    EUC-CN
    EUC-JP
    euc-jp
    euc-kr
    GB18030
    gb2312
    hz-gb-2312
    IBM00858
    IBM00924
    IBM01047
    IBM01140
    IBM01141
    IBM01142
    IBM01143
    IBM01144
    IBM01145
    IBM01146
    IBM01147
    IBM01148
    IBM01149
    IBM037
    IBM1026
    IBM273
    IBM277
    IBM278
    IBM280
    IBM284
    IBM285
    IBM290
    IBM297
    IBM420
    IBM423
    IBM424
    IBM437
    IBM500
    ibm737
    ibm775
    ibm850
    ibm852
    IBM855
    ibm857
    IBM860
    ibm861
    IBM863
    IBM864
    IBM865
    ibm869
    IBM870
    IBM871
    IBM880
    IBM905
    IBM-Thai
    iso-2022-jp
    iso-2022-jp
    iso-2022-kr
    iso-8859-1
    iso-8859-13
    iso-8859-15
    iso-8859-2
    iso-8859-3
    iso-8859-4
    iso-8859-5
    iso-8859-6
    iso-8859-7
    iso-8859-8
    iso-8859-8-i
    iso-8859-9
    Johab
    koi8-r
    koi8-u
    ks_c_5601-1987
    macintosh
    shift_jis
    unicodeFFFE
    us-ascii
    utf-16
    utf-32
    utf-32BE
    utf-7
    utf-8
    windows-1250
    windows-1251
    Windows-1252
    windows-1253
    windows-1254
    windows-1255
    windows-1256
    windows-1257
    windows-1258
    windows-874
    x-Chinese-CNS
    x-Chinese-Eten
    x-cp20001
    x-cp20003
    x-cp20004
    x-cp20005
    x-cp20261
    x-cp20269
    x-cp20936
    x-cp20949
    x-cp50227
    x-EBCDIC-KoreanExtended
    x-Europa
    x-IA5
    x-IA5-German
    x-IA5-Norwegian
    x-IA5-Swedish
    x-iscii-as
    x-iscii-be
    x-iscii-de
    x-iscii-gu
    x-iscii-ka
    x-iscii-ma
    x-iscii-or
    x-iscii-pa
    x-iscii-ta
    x-iscii-te
    x-mac-arabic
    x-mac-ce
    x-mac-chinesesimp
    x-mac-chinesetrad
    x-mac-croatian
    x-mac-cyrillic
    x-mac-greek
    x-mac-hebrew
    x-mac-icelandic
    x-mac-japanese
    x-mac-korean
    x-mac-romanian
    x-mac-thai
    x-mac-turkish
    x-mac-ukrainian

    You should use System.Security.SecurityElement.Escape in C# to escape special characters in XML and not System.Web.HttpUtility.HtmlEncode

    You should use the function System.Security.SecurityElement.Escape and not the function System.Web.HttpUtility.HtmlEncode to escape special characters in XML if you don’t want the characters like éûÉ to be converted to éûÉ which is permit able but not necessary en can result in long xml fields.

    var escapedXml = System.Security.SecurityElement.Escape(@"&<>'""’éûÉغ");
    Console.WriteLine(escapedXml);
    // Result=&amp;&lt;&gt;&apos;&quot;’éûÉغ
    escapedXml = System.Web.HttpUtility.HtmlEncode(@"&<>'""’éûÉغ");
    Console.WriteLine(escapedXml);
    // Result=&amp;&lt;&gt;'&quot;’&#233;&#251;&#201;غ

    To revert the escape process, use:

    SecurityElement securityElement = System.Security.SecurityElement.FromString("<test>H&amp;M</test>");
    string unescapedText = securityElement.Text;
    Console.WriteLine(unescapedText); // Result: H&M
    

    Or

    // Data is the un-escaped text that should be inserted in a XML tag.
    string data = "H&amp;M";
    // A xml tag with the name "test" is used, just for creating the SecurityElement.
    var securityElement = new SecurityElement("test", data);
    // Generate the un-escaped text.
    string unescapedText = securityElement.Text;
    // Result: H&M
    Console.WriteLine(unescapedText);

    Or use the InnerText property of a XmlNode:

    // Data is the un-escaped text that should be inserted in a XML tag.
    string data = "H&amp;M";
    XmlDocument document = new XmlDocument();
    document.LoadXml(string.Format("<test>{0}</test>", data));
    XmlNode node = document.DocumentElement.FirstChild;
    // Generate the un-escaped text.
    string unescapedText = node.InnerText;
    // Result: H&M
    Console.WriteLine(unescapedText);

    Create custom eventlog during setup, by reading log4net configuration file.

    If you want to create a customeventlog during setup, in a custom action. You can open a App.config file containing the log4net configuration and read the settings from that file at runtime.
    You also can add appenders or remove appenders at runtime, but in this case I just wanted to read the configuration and create a custom eventlog:

           private string _productInstallationFolder = null;
    /// <summary>
    /// Returns C:\Program Files\MyCompany\MyProduct or C:\Program Files (x86)\MyCompany\MyProduct depending on the platform.
    /// </summary>
    public string ProductInstallationFolder
    {
    get
    {
    if (string.IsNullOrEmpty(_productInstallationFolder))
    {
    var programFilesFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFiles);
    _productInstallationFolder = Path.Combine(programFilesFolder, @"MyCompany\MyProduct");
    }
    return _productInstallationFolder;
    }
    set
    {
    _productInstallationFolder = value;
    }
    }
    public void CreateCustomEventLog()
    {
    XmlConfigurator.Configure(new FileInfo(string.Format("{0}.config", this.ProductInstallationFolder))); 
    var repository = LogManager.GetRepository() as Hierarchy; if (repository != null) { var appenders = repository.GetAppenders(); if (appenders != null) { foreach (var appender in appenders) { if (appender is EventLogAppender) { var eventLogAppender = appender as EventLogAppender; EventLog.CreateEventSource(eventLogAppender.ApplicationName, eventLogAppender.LogName); // Close application to allow the Windows eventlog service to refresh. // When applcation is restarted the first log event will create the log file. } } } } }

    Adding a folder to the .NET assembly search path, to prevent the error Could not load file or assembly 'log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821' or one of its dependencies. The system cannot find the file specified.

    If you use the XmlConfigurator.Configure() . log4net function in a setup custom action to initialize the log4net logging, you can get the error:

    Could not load file or assembly ‘log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821’ or one of its dependencies. The system cannot find the file specified.

    This is because the msi package installs the assembly containing the custom action that uses the log4net assembly in a folder: C:\Program Files\MyCompany\MyProduct, but when the setup is started from a folder C:\Temp, the current working folder is C:\Windows\SysWOW64 on a x64 windows. The folder C:\Program Files\MyCompany\MyProduct is there for not included in the standard .NET assembly search path. To add the folder C:\Program Files\MyCompany\MyProduct to the .NET assemlby search path use the following class:

    By the way this will also occur when you use custom configuration sections in you’re the App.config of you’re program (exe) and want to use the custom configuration sections during you’re msi installation with a custom setup action.

    public class AssemblyLoader
    {
    private string _productInstallationFolder = null;
    /// <summary>
    /// Returns C:\Program Files\MyCompany\MyProduct or C:\Program Files (x86)\MyCompany\MyProduct depending on the platform.
    /// </summary>
    public string ProductInstallationFolder
    {
    get
    {
    if (string.IsNullOrEmpty(_productInstallationFolder))
    {
    var programFilesFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFiles);
    _productInstallationFolder = Path.Combine(programFilesFolder, @"MyCompany\MyProduct");
    }
    return _productInstallationFolder;
    }
    set
    {
    _productInstallationFolder = value;
    }
    }
    /// <summary>
    /// Add an evenhandler for adding a folder to the .NET assemlby search path.
    /// </summary>
    public void BindAssemblyResolveEventHandler()
    {
    var currentDomain = AppDomain.CurrentDomain;
    currentDomain.AssemblyResolve += this.LoadAssemlbyFromProductInstallationFolder;
    }
    /// <summary>
    /// This function is called when the .NET runtime searches for an assemlby to load and can't find that assembly in the current search path.
    /// The current search path includes "bin folder application", the global assemlby cache, system32 folder etc.
    ///
    /// This function adds a folder to the current search path at runtime.
    ///
    /// An assembly can be a dll or exe, the ResolveEventArgs argument does not cotain this information.
    /// The code will first check if a dll exist in the given folder, if found it loads the dll.
    /// If the dll is not found, the code checks if an executable exists in the given folder, if found it loads the exe.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    /// <returns></returns>
    public Assembly LoadAssemlbyFromProductInstallationFolder(object sender, ResolveEventArgs args)
    {
    Assembly result = null;
    if (args != null && !string.IsNullOrEmpty(args.Name))
    {
    var folderPath = (new FileInfo(this.ProductInstallationFolder)).DirectoryName;
    var assemblyName = args.Name.Split(new string[] { "," }, StringSplitOptions.None)[0];
    var assemblyExtension = "dll";
    var assemblyPath = Path.Combine(folderPath, string.Format("{0}.{1}", assemblyName, assemblyExtension));
    if (!File.Exists(assemblyPath))
    {
    assemblyExtension = "exe";
    assemblyPath = Path.Combine(folderPath, string.Format("{0}.{1}", assemblyName, assemblyExtension));
    }
    result = Assembly.LoadFrom(assemblyPath);
    }
    return result;
    }
    }

    Debug you’re Microsoft Visual Studio 2008 setup project output msi with Debugger.break()

    If you want to start the debugger after installation of you’re product with a Microsoft Visual Studio 2008 setup msi package, use a Installer class and custom actions and then add a Debugger.Break() on the AfterInstall event:

    [RunInstaller(true)]
    public partial class ProjectInstaller : Installer
    {
    public ProjectInstaller()
    {
    InitializeComponent();
    }
    /// <summary>
    /// Event fires after installation
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void AfterInstallation(object sender, InstallEventArgs e)
    {
    Debugger.Break();
    }
    /// <summary>
    /// Event fires before uninstallation
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void BeforeUninstallation(object sender, InstallEventArgs e)
    {
    }
    }

    How to convert a unicode string to an ASCII string

    To convert a unicode string to an ASCII string, use:

            public void ConvertUnicodeStringToAsciiString()
    {
    // Create two different encodings.
    Encoding ascii = Encoding.ASCII;
    Encoding unicode = Encoding.Unicode;
    // Convert the string into a byte[].
    byte[] unicodeBytes = unicode.GetBytes("van ’t huis");
    // Perform the conversion from one encoding to the other.
    byte[] asciiBytes = Encoding.Convert(unicode, ascii, unicodeBytes);
    char[] asciiChars = new char[ascii.GetCharCount(asciiBytes, 0, asciiBytes.Length)];
    ascii.GetChars(asciiBytes, 0, asciiBytes.Length, asciiChars, 0);
    string asciiString = new string(asciiChars);
    Console.WriteLine(asciiString);
    }

    See: http://msdn.microsoft.com/en-us/library/system.text.encoding.convert(VS.71).aspx

    Export images from SQL Server database with C# 3.5

    If you want to export images from a SQL Server database you could use the following code:

            public void ExportImagesFromDatabase()
    {
    var exportPath = @"C:\Temp";
    if (!Directory.Exists(exportPath))
    {
    Directory.CreateDirectory(exportPath);
    }
    var imagesTable = GetImagesFromDatabase("select [ImageColumn] from [ImageTable]");
    var rowCounter = 0;
    foreach (DataRow row in imagesTable.Rows)
    {
    if (row.ItemArray.Length > 0)
    {
    if (row[0] != null)
    {
    var imageBytes = (byte[])row["Image"];
    if (imageBytes.Length > 0)
    {
    using (var convertedImage = new Bitmap(new MemoryStream(imageBytes)))
    {
    var fileName = Path.Combine(exportPath, string.Format("ExportImage_{0}.bmp", rowCounter.ToString().PadLeft(5, '0')));
    if (File.Exists(fileName))
    {
    File.Delete(fileName);
    }
    convertedImage.Save(fileName);
    }
    }
    }
    }
    }
    }
    public DataTable GetImagesFromDatabase(string query)
    {
    if (string.IsNullOrEmpty(query))
    {
    throw new NullReferenceException("Parameter query can't be null or empty");
    }
    var result = new DataTable();
    using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Runner"].ConnectionString))
    {
    using (var command = new SqlCommand(query, connection))
    {
    connection.Open();
    command.CommandTimeout = 0;
    command.CommandType = CommandType.Text;
    using (var adapter = new SqlDataAdapter(command))
    {
    var recordCount = adapter.Fill(result);
    }
    }
    }
    return result;
    }