C# Interactive Shell – Where have you been all my life?

Holy crap. I wish I knew about this before. I used to use LinqPad for these simple tests.

Suppose you want to verify what a certain format of DateTime is. Before LinqPad I would occasionally spin up a new console project to verify.

Turns out Visual Studio has a shortcut for this. It is CTRL + E + E

Enter expression, hit enter, see result. ūüôā

It also works by highlighting a block of code and hitting the key combo. It will auto execute and show you the results.

The shell¬†can even use classes from your project!¬†Just right click on your solution and select “Reset Interactive from Project”.

Filip Ekberg has a more detailed description:¬†Using the C# Interactive Window that comes with Roslyn ‚Äď Part 2

Embedding DLLs in a Compiled Executable

The Problem

For fun I am building a building a multi-platform screen saver in C# that I want to execute as a UWP (Universal Windows Platform) app and as classic screen saver using WPF (Windows Presentation Foundation).

This requires the logic to be left in PCLs (Portable Class Libraries), which results in a bunch of DLLs in the output directory. To build a classic screensaver I need a single EXE. So I went looking for a way to embed all resources in a single EXE.

Stack Overflow to the Rescue

http://stackoverflow.com/questions/189549/embedding-dlls-in-a-compiled-executable

Ok, the fact that this exists and is so easy to use is simply blowing my mind.

  1. Install-Package Costura.Fody
  2. Install-CleanReferencesTarget

Build your project and check the app.publish folder in your output directory (\bin\Debug\app.publish)

For my screen saver project I simply need to rename the extension from exe to scr and I am done. Now to figure out the installer part. ūüôā

Screens Saver Gallery

The UWP¬†is already in the¬†Windows App Store. I must warn you,¬†its not like a classic screen saver that opens after inactivity, that’s not available for UWP (Universal Windows Platform) apps. Its¬†basically a full screen app that shows pretty pictures.

Its free, try it out. ūüôā

https://www.microsoft.com/en-us/store/apps/screen-saver-gallery/9nblggh5j8tx

Xml Polymorphism

In my scenario a policy XML holds a collection of Risk elements. The problem is that each Risk is actually a different type depending on the RiskCode. Each type has different properties, etc. I wanted to use attribute based deserialization without writing a custom parser so I decided to transform the risk element based on the RiskCode.

Here is my approach.

  1. Use Linq To Xml to transform the input document
    • Change the Risk element name based on RiskCode
  2. Use attribute based deserialization
    • All risk nodes map to a class that inherits Risk. Risk contains elements that are common to all classes.

I like this because I think the Linq to Xml transform is much simpler to understand compared to XSLT and the attribute based deserialization should be easier to maintain. We can standardize risk behavior by adding interfaces or virtual methods to the base class.

Input XML

<Policy>
  <PolicyNumber>123</PolicyNumber>
  <Risks>
    <Risk>
      <RiskCode>FOO</RiskCode>
      <Name>Blueberry</Name>
    </Risk>
    <Risk>
      <RiskCode>BAR</RiskCode>
      <Number>2</Number>
    </Risk>
  </Risks>
</Policy>

Transforms To

<Policy>
  <PolicyNumber>123</PolicyNumber>
  <Risks>
    <FooRisk>
      <RiskCode>FOO</RiskCode>
      <Name>Blueberry</Name>
    </FooRisk>
    <BarRisk>
      <RiskCode>BAR</RiskCode>
      <Number>2</Number>
    </BarRisk>
  </Risks>
</Policy>

Class Model

public class Policy
{
    [XmlElement("PolicyNumber")]
    public string PolicyNumber { get; set; }
 
    [XmlArray("Risks")]
    [XmlArrayItem("FooRisk", typeof(FooRisk))]
    [XmlArrayItem("BarRisk", typeof(BarRisk))]
    public Risk[] Risks { get; set; }
}
 
public abstract class Risk
{
    [XmlElement("RiskCode")]
    public string RiskCode { get; set; }
}
 
public class FooRisk : Risk
{
    [XmlElement("Name")]
    public string Name { get; set; }
}
 
public class BarRisk : Risk
{
    [XmlElement("Number")]
    public int Number { get; set; }
}

Transform

public static string TransformXml(string input){       
    var doc = XDocument.Parse(input);
 
    foreach (var risk in doc.Descendants("Risk"))
    {
        switch (risk.Element("RiskCode").Value)
        {
            case "FOO":
                risk.Name = "FooRisk";
                break;
            case "BAR":
                risk.Name = "BarRisk";
                break;
        }
    }
    return doc.ToString();
}

Usage Example

static void Main(string[] args)
{
    var transformed = TransformXml(xmlText);
    var policy = Deserialize<Policy>(transformed);
 
    Console.WriteLine(policy.PolicyNumber);
 
    foreach (var risk in policy.Risks)
    {
        Console.WriteLine(risk.RiskCode);
 
        if (risk is FooRisk)
        {
            var r = risk as FooRisk;
            Console.WriteLine(r.Name);
        }
        else if (risk is BarRisk)
        {
            var r = risk as BarRisk;
            Console.WriteLine(r.Number);
        }
    }            
}

 

System i Navigator Installer Corrupts Db Provider Factories

The IBM System i Navigator installer usually corrupts the DbProviderFactories node in the machine.config file. We have experienced this with both Version 6 and Version 7.

Possible Symptoms

  • Unable to use the¬†IBM.Data.DB2.iSeries driver. Exception mentions DbProviderFactories.
  • Cannot see all of the Data Provider options when selecting a data source in a .NET application. OLE DB and SQL Server is usually available but custom providers such as IBM.Data.DB2.iSeries is not.
  • When connecting to a Team Foundation Server Project in Visual Studio get the following Error:
    • TF31001: Cannot connect to Team Foundation Server at xyz. The server returned the following error: Configuration system failed to initialize. Retry.
  • Any error related to DbProviderFactories

The problem

The installer usually leaves a hanging closing tag in the machine.config file, which corrupts your XML. Since your app.configs/web.configs inherit from this file, your configuration is corrupted also. Re-installing does not work.

The Solution

Check the following files for corrupted XML.

  • C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\Machine.Config
  • C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\Machine.Config

The bad XML usually, but not always, looks like this. Remove the repeating closing tags and re-start your app.

Example of a corrupted machine.config file.
System i Series Navigator installer usually corrupts the machine.config file.