ASCII vs ISO-8859-1

Note to self:

var ascii7BitEncoding = Encoding.ASCII; // ASCII
var ascii8BitEncodingIsh = Encoding.GetEncoding("iso-8859-1"); // Extended ASCII for almost all practical purposes

Where Extended ASCII differs from ISO-8859-*, according to Wikipedia:

One notable way in which ISO character sets differ from code pages is that the character positions 128 to 159, corresponding to ASCII control characters with the high-order bit set, are specifically unused and undefined in the ISO standards, though they had often been used for printable characters in proprietary code pages, a breaking of ISO standards that was almost universal.

Enabling Web Transforms when debugging ASP.NET apps

Web Transformations is a great feature. When a web application is packaged or published, the Web.config file is transformed dependent on which Visual Studio / MSBuild configuration you are running, enabling environment-specific settings to change accordingly.

However, to my mind there is a shortcoming. Since the transformation happens during packaging or publishing of the application, transformation rules do not take effect when debugging a web application (typically by hitting F5 in Visual Studio) because the application is served from the project directory. Here’s how to solve this: essentially, we can change the the project setup so that the transformation happens right after the project build step. Here’s how:

Step 1: Unload the project in Visual Studio

In the Solution Explorer in Visual Studio, right-click on the project and select Unload project from the context menu:

Step 2: Rename Web.config on the file system

In the Windows Explorer, browse to the project directory, and rename Web.config to Web.template.config:

Step 3: Rename Web.config in the project file

What we will do here, is to rename the existing Web.config to Web.template.config in the project file (.csproj or .vbproj). This will be the file that we keep in the version control system, and the final Web.config will instead be generated for us when building the application.

In the Solutuion Explorer in Visual Studio, right-click on the project and select Edit <project name>:

Search for “web.config” in the project file to locate where the Web.config and transformation files definitions. It looks something like so:

<Content Include="Web.config" />
<Content Include="Web.Debug.config">
   <DependentUpon>Web.config</DependentUpon>
</Content>
<Content Include="Web.Release.config">
   <DependentUpon>Web.config</DependentUpon>
</Content>

In the project file, for instance on the line after the one with Web.config, add the following:

<None Include="Web.template.config" />

Then, change the text of the DependentUpon element to read Web.template.config instead of Web.config. Finally, change the Content elements for for Web.Debug.config and Web.Release.config to None elements. This prevents these files from being included in the deployment package. They don’t need to be, as the transformations have already been run. All in all, the snippet from above should now read:

<Content Include="Web.config" />
<None Include="Web.template.config" />
<None Include="Web.Debug.config">
   <DependentUpon>Web.template.config</DependentUpon>
</None>
<None Include="Web.Release.config">
   <DependentUpon>Web.template.config</DependentUpon>
</None>

Step 4: Running transformation when building

Now that we have a reference to Web.template.config in the project file, the next step is to run the transformation during the build step. Add a custom target that runs the transformation and then include it at the begining of the build task using the {{BuildDependsOn}} property. The resulting XML snippet looks like so:

<PropertyGroup>
  <BuildDependsOn>
    CustomWebConfigTransform;
    $(BuildDependsOn);
  </BuildDependsOn>
</PropertyGroup>
<Target Name="CustomWebConfigTransform">
   <TransformXml> source="Web.template.config"
      transform="Web.$(Configuration).config"
      destination="Web.config" />
</Target>

Save the file and reload the project into the Visual Studio solution. Then, in the Solution Explorer, observe that the Web.config file now is denoted as missing, and that the Web.template.config is present with the two transformation files beneath it in the file tree:

Step 5: Test running transformations during build

In this step, we will test that the transformations will be run when launching the application by hitting F5 in Visual Studio. First, we need to create a configuration example in Web.Debug.config. Remove all the gunk that Microsoft so helpfully has filled the file with during project creation, and insert one simple appSettings entry, making the Web.Debug.config look like this:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <appSettings>
    <add key="Configuration" value="Debug" xdt:Transform="Insert"/>
  </appSettings>
</configuration>

Take care to include the xdt XML namespace definition. Without it, the transformations will not be run.

Open up an ASPX page, for instance Default.aspx, and enter a label that will display the value of our confiugration setting:

<

pre class=”xml” name=”code”>
<p>
Configuration: <asp:Label ID=”Configuration” runat=”server” />
</p>

Next, enter this in the code behind:

protected void Page_Load(object sender, EventArgs e)
{
   Configuration.Text = ConfigurationManager.AppSettings["Configuration"];
}

Hit F5 to run the application and verify that it in fact is able to read from the transformed Web.config:

Step 6: Disable transformations during packaging and publishing

Since msbuild by default runs the transformations, we need to disable this to prevent the transformations to be applied twice. To do this, unload the project from the solution as we did in step 1, and then edit the project file in Visual Studio. For each of the configurations that you have in your solution, disable the built-in transformation runs by adding the TransformWebConfigEnabled element and setting it to false. Like so:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
   <TransformWebConfigEnabled>False</TransformWebConfigEnabled>
   ...
</PropertyGroup>

Summary / other tweaks

What we have achieved, is that the transformations are applied when building the application, making the transformed file available when running the application locally from Visual Studio. Another tip with regards to Web Transformations is to use the SlowCheetah Visual Studio Add-in that Scott Hanselman has described very well here. It will give you a nice transformation preview on the context menu in Visual Studio which is extremely helpful.

NLog: writing log entries to Azure Table Storage

In August last year, I blogged about how to get Log4Net log entries written to Azure Table Storage. In this article, I will show how the same thing can be easily achieved using NLog.

The concepts in NLog is very similar to Log4Net. More or less, replace the word “appender” in Log4Net lingo with “target”, and you’re game.

First, let’s create a class for log entries:

public class LogEntry : TableServiceEntity
{
    public LogEntry()
    {
        var now = DateTime.UtcNow;
        PartitionKey = string.Format("{0:yyyy-MM}", now);
        RowKey = string.Format("{0:dd HH:mm:ss.fff}-{1}", now, Guid.NewGuid());
    }
    #region Table columns
    public string Message { get; set; }
    public string Level { get; set; }
    public string LoggerName { get; set; }
    public string RoleInstance { get; set; }
    public string DeploymentId { get; set; }
    public string StackTrace { get; set; }
    #endregion
}

Next, we need to do is to create a class that represents the table storage service. It needs to inherit from TableServiceContext:

public class LogServiceContext : TableServiceContext
{
    public LogServiceContext(string baseAddress, StorageCredentials credentials) : base(baseAddress, credentials) { }
    internal void Log(LogEntry logEntry)
    {
        AddObject("LogEntries", logEntry);
        SaveChanges();
    }
    public IQueryable<LogEntry> LogEntries
    {
        get
        {
            return CreateQuery<LogEntry>("LogEntries");
        }
    }
}

Finally, as far as code is concerned, a class that is a custom NLog target that gets called when the NLog framework needs to log something:

[Target("AzureStorage")]
public class AzureStorageTarget : Target
{
    private LogServiceContext _ctx;
    private string _tableEndpoint;
    [Required]
    public string TableStorageConnectionStringName { get; set; }
    protected override void InitializeTarget()
    {
        base.InitializeTarget();
        var cloudStorageAccount =
            CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue(TableStorageConnectionStringName));
        _tableEndpoint = cloudStorageAccount.TableEndpoint.AbsoluteUri;
        CloudTableClient.CreateTablesFromModel(typeof(LogServiceContext), _tableEndpoint, cloudStorageAccount.Credentials);
        _ctx = new LogServiceContext(cloudStorageAccount.TableEndpoint.AbsoluteUri, cloudStorageAccount.Credentials);
    }
    protected override void Write(LogEventInfo loggingEvent)
    {
        Action doWriteToLog = () =>
        {
            try
            {
                _ctx.Log(new LogEntry
                {
                    RoleInstance = RoleEnvironment.CurrentRoleInstance.Id,
                    DeploymentId = RoleEnvironment.DeploymentId,
                    Timestamp = loggingEvent.TimeStamp,
                    Message = loggingEvent.FormattedMessage,
                    Level = loggingEvent.Level.Name,
                    LoggerName = loggingEvent.LoggerName,
                    StackTrace = loggingEvent.StackTrace != null ? loggingEvent.StackTrace.ToString() : null
                });
            }
            catch (DataServiceRequestException e)
            {
                InternalLogger.Error(string.Format("{0}: Could not write log entry to {1}: {2}",
                    GetType().AssemblyQualifiedName, _tableEndpoint, e.Message), e);
            }
        };
        doWriteToLog.BeginInvoke(null, null);
    }
}

So, to make it work, we need to register the target with the NLog framework. This is done in the NLog.config file:

<?xml version="1.0"?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <extensions>
    <add assembly="Demo.NLog.Azure" />
  </extensions>
  <targets>
    <target name="azure" type="AzureStorage" tableStorageConnectionStringName="Log4Net.ConenctionString" />
  </targets>
  <rules>
    <logger name="*" minlevel="Info" writeTo="azure" />
  </rules>
</nlog>

For information about how to set your ServiceDefinition.csdef and ServiceConfiguration.cscfg files, see my previous post.You can find the code for this example on GitHub. Suggestions for improvement are very welcome.