January 7, 2015

Reading Xml Using XDocument

The ideas behind this blog are revealed here
Wanted to read some objects in using XDocument.

Found that the best was to use the explicit cast operators exposed by XDocument. These can be used to protect against attributes and elements that are missing

Also found that the XDocument.Parse() method was an excellent way to use raw XML strings to test the parsing
Consider this class:
internal class Base 
{
 public int Id { get; set; }
 public string Name { get; set; }
 public string Faction { get; set; }
}
Here is some small test XML to parse:
string rawTestXml = @"
<Bases>
  <Base ID=""1""><NAME>Freeport 2</NAME><FACTION>Zoners</FACTION></Base>
  <Base ><NAME>Pacifica</NAME></Base>
</Bases>";
Here is a method to test parsing this XML:
public void TestXDocumentParseUnprotected()
{
    FreelancerData freelancerData = new FreelancerData();

    var xmlDoc = XDocument.Parse(rawTestXml);
    var basesTableRaw = new Dictionary<int, Base>();

    foreach (var bas in xmlDoc.Descendants("Base"))
    {
        var b = new Base()
        {
            Id = Convert.ToInt32(bas.Attribute("ID").Value),
            Name = bas.Element("NAME").Value,
            Faction = bas.Element("FACTION").Value,
        };

        basesTableRaw.Add(b.Id, b);
    }

    Debug.Assert(basesTableRaw.Count == 2);

}
This will throw an exception when parsing the second "Base" element in the Xml string, as this second object is missing an "ID" attribute a NullReferenceException will be thrown by the line to extract it. If the XML data can be guaranteed then this is not a problem. A more robust way to read in the XML is to use the XElement/Xattribute explicit conversion operators:
public void TestXDocumentParseProtected()
{
  var xmlDoc = XDocument.Parse(rawTestXml);
  var basesTableRaw = new Dictionary<int, Base>();

  foreach (var bas in xmlDoc.Descendants("Base"))
  {
    var b = new Base()
    {
      Id = (int?)bas.Attribute("ID") ?? 0,  // 0 when the attribute "ID" is not present
      Name = (string)bas.Element("NAME") ?? "",  // "" when the element "NAME" is not present
      Faction = (string)bas.Element("FACTION"), // null when the element "FACTION" is not present
    };

    basesTableRaw.Add(b.Id, b);
  }

  Debug.Assert(basesTableRaw.Count == 2);
}
However this is allowing malformed objects to be allowed as input. The developer must detect these and decide what to do with them.

Note that the XDocument.Load() method can be used to load a document from a local file system file or from a Url. So this method
public void LoadBases(string rootPath)
{
  string xmlFileName = "Bases.xml";
  string basesPath = Path.Combine(rootPath, xmlFileName);
  var xmlDoc = XDocument.Load(basesPath);
  
  ...
}
can work with a local file:
LoadBases(@"X:\Backup\Documents\flasp\");
or a url:
LoadBases(@"http://www.somewebserver.com/flasp/");

December 21, 2014

Weak References with Compiled Transforms

There is a good description of this generic WeakReference<> class here.
Here is an example of using WeakReferences for caching XslCompiledTransform's:
private static Dictionary<string, WeakReference<XslCompiledTransform>> xsltLookupTable = 
  new Dictionary<string, WeakReference<XslCompiledTransform>>();

public XslCompiledTransform GetCompiledTransform(string xslFileName)
{
    XslCompiledTransform xct = null;
    bool found = xsltLookupTable.ContainsKey(xslFileName);
    if (found) // IF the transform is already cached
    {   // Try and get it
        WeakReference<XslCompiledTransform> xctWr = xsltLookupTable[xslFileName] 
           as WeakReference<XslCompiledTransform>;
        xctWr.TryGetTarget(out xct); // Try and get it from the WeakReference
        m_logger.WriteTrace("Found XslCompiledTransform entry for \'" + 
           xslFileName + "\' in the cache");
        // Note the entry maybe null (if the weak reference expired)
    }
        
    if (xct == null) // IF the compiled transform was not already cached
    {
        // Create it
        xct = new XslCompiledTransform();
        xct.Load(xslFileName, 
          new XsltSettings { EnableDocumentFunction = true }, 
          new XmlUrlResolver());
        // Insert it into a WeakReference
        WeakReference<XslCompiledTransform> wr = new 
          WeakReference<XslCompiledTransform>(xct);
        if (found)
        {
          m_logger.WriteTrace("Removing XslCompiledTransform entry for \'" + 
              xslFileName + "\' as it was null in the cache");
          xsltLookupTable.Remove(xslFileName);
        }
        xsltLookupTable.Add(xslFileName, wr); // Add the WeakReference to the cache
        m_logger.WriteTrace("Adding XslCompiledTransform entry for \'" + 
          xslFileName + "\'");
    }
    return xct;
}
It uses the new generic WeakReference<> class (available in .NET 4.5?). This class could be further refactored into a generic caching class if it was required.

December 12, 2014

Configuring log4net for specific classes or namespaces

Here is some sample xml that goes in the application config file.
<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
    ...
  </configSections>
  <log4net>
    <appender name="ConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
      <mapping>
        <level value="ERROR" />
        <foreColor value="Red, HighIntensity" />
      </mapping>
      <mapping>
        <level value="WARN" />
        <foreColor value="Yellow" />
      </mapping>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%utcdate [%t] %-5p [] - %m%n"/>
      </layout>
    </appender>
    <appender name="OutputDebugStringAppender" type="log4net.Appender.OutputDebugStringAppender">
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%utcdate [%t] %-5p %c [] - %m%n"/>
      </layout>
    </appender>
    <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
      <file value="FilePath.txt" />
      <appendToFile value="true" />
      <maximumFileSize value="1000KB" />
      <maxSizeRollBackups value="20" />
      <param name="RollingStyle" value="Size" />
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%utcdate [%t] %-5p %c [] - %m%n" />
      </layout>
    </appender>
    <root>
      <level value="INFO"/>
      <appender-ref ref="RollingFile"/>
      <appender-ref ref="ConsoleAppender"/>
      <appender-ref ref="OutputDebugStringAppender"/>
    </root>
    <!--Level values are DEBUG, INFO, WARN, ERROR -->
    <!--Entries for "top level" server module classes, to allow tracing of method calls -->
    <logger name="Some.Name.Space.ClassA.">
      <level value="INFO"/>
    </logger>
    ...
    <!--Entries for namespaces, to allow full tracing inside modules -->
    <logger name="Some.Particular.Namespace">
      <level value="INFO"/>
    </logger>
    ...
    <!--Entries for certain individual classes -->
    <logger name="Some.Deep.Level.NameSpace.SpecificClass.">
      <level value="DEBUG"/>
    </logger>
    ...
  </log4net>
...  
</configuration>

December 5, 2014

Simple Logger using Caller Info Attributes

Since .NET 4.5 There are 3 caller info attributes that are filled in at compile time by the compiler CallerMemberName, CallerFilePath, and CallerLineNumber These strings are inserted at compile time so they are much faster than using reflection.

Here is an example of how to use it to make the simplest logger (only 1 method + 1 property):
using System.Runtime.CompilerServices;

public enum LoggingLevelEnum
{
    Debug = 1,
    Info = 2,
    Warning = 3,
    Error = 4,
    Fatal = 5
}

public interface ISimpleLogger
{
    LoggingLevelEnum LoggingLevel { get; set; }

    void Log(
        Func<string> message,
        LoggingLevelEnum level = LoggingLevelEnum.Debug,
        [CallerMemberName] string member = "",
        [CallerFilePath] string file = "",
        [CallerLineNumber] int line = -1)
}

public class SimpleLogger : ISimpleLogger
{
    public LoggingLevelEnum LoggingLevel { get; set; } = 
        LoggingLevelEnum.Debug;

    public void Log(
        Func<string> message,
        LoggingLevelEnum level = LoggingLevelEnum.Debug,
        [CallerMemberName] string member = "",
        [CallerFilePath] string file = "",
        [CallerLineNumber] int line = -1)
    {
        if (level >= LoggingLevel)
        {
            Trace.WriteLine($"{level.ToString().ToUpper()} Member: {member}, File: {file}, Line: {line} - {message()}");
        }
    }
}
and invoking it:
ISimpleLogger logger = new SimpleLogger();
...
catch(Exception ex)
{
  // The attributed parameters are inserted by the compiler at compile time
  logger.Log(() => { return " Exception caught " + ex.ToString(); }, LogLevelEnum.Error); 
}

Note: Why log using a function returning a string? So that if you have a complex expression for creating the message, it only gets evaluated if the logging level is sufficient. If there is a lot of logging and the logging level is high, it saves a lot of unecessary string concatenation occurring.


November 18, 2014

When is a Hyphen not a Hyphen?

Take a look at these 2 command line strings:
CASE 1:
"%windir%\Microsoft.NET\Framework\v2.0.50727\caspol.exe" -machine -addgroup All_Code 
-site 192.168.45.111 FullTrust -name "XXX : 192.168.45.111" -description 
"Allows full trust privileges to XXX Public Safety Applications"
CASE 2:
"%windir%\Microsoft.NET\Framework\v2.0.50727\caspol.exe" -machine -addgroup All_Code 
-site 192.168.45.111 FullTrust –name "XXX : 192.168.45.111" –description 
"Allows full trust privileges to XXX Public Safety Applications"

While the first one succeds the 2nd one fails. When we converted the "-name" in the first one to hex we got
2D6E616D65
Whereas in the second we got
966E616D65

The hyphen in the first is a hyphen but in the second one it is in fact a "non-breaking hyphen". This is just visible in this email but in a notepad editor they may look exactly the same.
The morale of the story is: Beware of command line arguments copied from 3rd party sources

November 6, 2014

Debug with an IntegerOptionFile

Sometimes it is useful when debugging within an application to change the logic using an external influence, for example, using a value in a file. I have made the class as small as possible so that it can be copied and pasted anywhere for temporary debugging help Something that can be used like this:
...
int myOption = IntegerOptionFile.WriteValue(1)
...
int myOption = IntegerOptionFile.ReadValue()
if (myOption == 1)
{
    PerformSomeOptionalCode()
}
...
Here we can change a special option file and have the code change behaviour:
using System.IO;
...
// Use this to help debug an application by writing code
// that can be switched by reading a value from a text file
internal static class IntegerOptionFile
{
    private static readonly string optionFilePath = Path.Combine(
        Path.GetTempPath(), "intoption.txt");

    public static void WriteValue(int option)
    {
        File.WriteAllText(optionFilePath, option.ToString());
    }

    // Consider defining a suitable default value
    public static int ReadValue(int def = default(int))
    {
        int option = def;
        bool res = File.Exists(optionFilePath);
        if (!res)
        {
            WriteValue(def);
        }
        res = File.Exists(optionFilePath);
        if (res)
        {
            string tmp = File.ReadAllText(optionFilePath);
            if (tmp.Length > 0)
            {
                int.TryParse(tmp, out option);
            }
        }
        return option;
    }
}
By using a text file we can change the value from a simple notepad editor and have the running program change behaviour immediately. Note that this is only temporary code used for debugging/investigating a problem, not for release code.

October 30, 2014

Using Linq To Sql

To use LinqToSql in a project:
First add "System.Data.Linq" reference to the project
Map the Entity Classes to Tables. Need a "[Table]XxxTable" class per table with appropriate properties for each column. Note that the columns names have to match the property names. Although this table class maps to the Db table an instance of it represents a row in the table. For example:
// Table mapping entity for the MyTableRow table row
[Table(Name = "MyTable")]
internal class MyTableRow
{
    // Default constructor is Required for Linq to Sql
    public MyTableRow()
    {
    }

    /////////////////////////////////
    // Database columns defined here

    [Column(IsPrimaryKey = true, IsDbGenerated = true)]
    public int Id { get; set; }

    [Column(CanBeNull = false)]
    public string Name { get; set; }

    [Column(DbType = "Bit NOT NULL")]
    public bool IsMandatory { get; set; }
}
This maps to a row in the SQL table "MyTable". Need a "DataContext" derived class to access these tables, call it xxxDataContext. Mark it with the "[Database]" attribute. For example:
// Linq to SQL data context for accessing the DB 
[Database]
internal class MyDataContext : DataContext
{
    // Constructor
    public MyDataContext(string connectionString)
        : base(connectionString)
    {
    }
}
Found that making the correct key definitions (including foreign keys) on the SQL tables was critical to getting the Linq to Sql working. With those definitions we can start to query the DB using Linq.
Querying SQL with LINQ
LINQ to SQL: .NET Language-Integrated Query for Relational Data
private void CreatePattern(
    MyDataContext dbAccess, 
    MyTableRow[] toCreate)
{
    var table = dbAccess.GetTable<MyTableRow>();
    table.InsertAllOnSubmit(toCreate);
    dbAccess.SubmitChanges();
}

private MyTableRow[] ReadPattern()
{
    var allRows = new MyTableRow[0];
    using (var dbAccess = new MyDataContext(GetDatabaseConnectionString()))
    {
        var table = dbAccess.GetTable<MyTableRow>();
        allRows = table.ToArray();
    }
    return allRows.ToArray();
}

private void UpdatePattern(
    MyAdminContext dbAccess, 
    MyTableRow[] changed)
{
    var table = dbAccess.GetTable<MyTableRow>();
    foreach (var target in changed)
    {
        // Find row to update in the table
        var id = target.Id;
        var row = table.FirstOrDefault(rowx => rowx.Id == id);
        if (row != null) // IF it was found
        {
            // Copy the changes from target into the row
            UpdateRow(row, target); 
        }
    }
    dbAccess.SubmitChanges(); 
}

private void DeletePattern(
    MyDataContext dbAccess, 
    MyTableRow[] deleted)
{
    var table = dbAccess.GetTable<MyTableRow>();

    foreach (var target in deleted)
    {
        // Find row to delete in the table
        var id = target.Id;
        var row = table.FirstOrDefault(ipdx => ipdx.Id == id);
        if (row != null) // Was it found?
        {
            table.DeleteOnSubmit(row);
        }
    }
    dbAccess.SubmitChanges();
}
There are 2 ways to create transactions; using the TransactionScope class and using the standard DbTransaction class.
Using new TransactionScope() Considered Harmful
All About TransactionScope
Using Transaction Scope (need to add the System.Transactions assembly in the references)
using System.Transactions;
...
using (var scope = TransactionScopeFactory.CreateTransactionScope()) // Asscociate all the changes with 1 transaction
{
    // Use 1 data context for all operations, in this case MS DTC will not be used
    // See http://weblog.west-wind.com/posts/2009/Jul/14/LINQ-to-SQL-and-Transactions 
    // paragraph 'TransactionScope DTC Requirements'
    using (var dbAccess = new MyDataContext (GetDatabaseConnectionString()))
    {
        MakeDbChangesUsingLinqToSql(dbAccess);

        scope.Complete();
        log.WriteInfo("Transaction completed, the database changes are committed.");
    }
}
Using a DbTransaction
using (var dbAccess = new MyDataContext(GetDatabaseConnectionString()))
{
    dbAccess.Connection.Open();
    // To absolutely guarantee that the MS DTC will not be used (which can occur when using TransactionScope) 
    // we will use a standard DB transaction here
    dbAccess.Transaction = dbAccess.Connection.BeginTransaction();
    
    try
    {
        MakeDbChangesUsingLinqToSql(dbAccess);
    
        dbAccess.Transaction.Commit(); // No exceptions so commit the changes
        log.WriteInfo("Transaction completed, the database changes are committed.");
    }
    catch (Exception) // Rollback if any exception is encountered
    {
        dbAccess.Transaction.Rollback();
        throw;
    }
}