My Journey to Pretzel: Preface

Pretzel, .Text, Community Server Comments

After running my site for more than 12 years, I decided it was time to replace the software behind it with something new.

I started this blog with .Text in August of 2002, which later was merged into CommunityServer. I wrote many extensions for CS, customized it in many ways, and was active in the community. Telligent, the company behind CommunityServer, even awarded me with a MVP status.

However, I lost interest in CS after a while. I started writing my own blog engine (as most developers do I guess). Well, not only once but countless times. Every few months I threw away the current code and started again from scratch. I took the opportunity to play around with the newest stuff, ASP.NET MVC and Nancy, Entity Framework or RavenDb, n-tier architecture or CQRS.

Well, though I learnt a lot about the different technologies, libraries etc, I never got to the point where my software was ready to be published.

Finally I decided to overcome my developer ego and use some existing software. A few month ago I switched to Jekyll, a static site generator written in Ruby. Some weeks later I switched again, this time to Pretzel, which is very similar to Jekyll but written in .NET.

After writing this introduction, I intend to publish a couple of posts about the different stations of my journey to Pretzel in the next few weeks. E.g. I wrote several extensions for Pretzel, and I configured Azure for auto-deployment whenever I push to the git repository of this site.

NuGet package for 7Zip4Powershell

7-zip, Powershell, NuGet Comments

nuget

A few days ago I mentioned 7-Zip for Powershell. I’ve now created a NuGet package and published it at NuGet.org.

It took me a while to figure it out, but finally it’s a “tools only” package, i.e. it adds no references to your project.

To use the new commands just add the package to your solution and import it in your Powershell script:

$SolutionDir = split-path -parent $PSCommandPath
Import-Module (Join-Path $SolutionDir "packages\7Zip4Powershell.1.0\tools\7Zip4Powershell.dll")

Fun with RavenDB and ASP.NET MVC: part I

RavenDB, aspnetmvc Comments

I’m working on a small pet project with ASP.NET MVC, where hierarchical structured documents are stored in RavenDB. These documents can be retrieved by their unique URL, which is also stored in the document. Because there are different kinds of document class, they all derive from the common interface IRoutable. This interface defines a property Path, by which the document can be accessed.

public interface IRoutable {
    string Id { get; set; }
    string Path { get; set; }
}

public class Document : IRoutable {
    public string Id { get; set; }
    public string Path { get; set; }
}

using (var session = _store.OpenSession()) {
    session.Store(new Document { Path = "a" });
    session.Store(new Document { Path = "a/b" });
    session.Store(new Document { Path = "a/b/c" });
    session.Store(new Document { Path = "a/d" });
    session.Store(new Document { Path = "a/d/e" });
    session.Store(new Document { Path = "a/f" });
    session.SaveChanges();
}

Additionally there’s the requirement, that the incoming URL may consist of more parts than the document’s path, carrying some additional information about the request. Here are some examples of possible requests, and which document should match:

Request Found document
a/x a
a/b/c/y/z a/b/c

So, given the path, how can you find the correct document?

The solution to this consists of three parts:

  1. Identify documents in the database which can be accessed via their path
  2. Index those documents
  3. Find the document which matches best a given URL

Marking routable documents

Because there’s not a single class for pages stored in the database, I mark all documents implementing IRoutable by adding a flag IsRoutable to the document’s metadata. This is done by implementing IDocumentStoreListener, so the code is called by RavenDB whenever a document is stored:

public class DocumentStoreListener : IDocumentStoreListener {
    public const string IS_ROUTABLE = "IsRoutable";

    public bool BeforeStore(string key, object entityInstance, RavenJObject metadata, RavenJObject original) {
        var document = entityInstance as IRoutable;
        if (document == null) {
            return false;
        }
        if (metadata.ContainsKey(IS_ROUTABLE) && metadata.Value<bool>(IS_ROUTABLE)) {
            return false;
        }
        metadata.Add(IS_ROUTABLE, true);
        return true;
    }

    public void AfterStore(string key, object entityInstance, RavenJObject metadata) {
    }
}

Indexing routable documents

The next step is to create an index for all documents with the proper flag in their metadata:

public class IRoutable_ByPath : AbstractIndexCreationTask {
    public override IndexDefinition CreateIndexDefinition() {
        return new IndexDefinition {
            Map = @"from doc in docs where doc[""@metadata""][""" + DocumentStoreListener.IS_ROUTABLE + @"""].ToString() == ""True"" select new { doc.Path }"
        };
    }
}

Searching for documents

Ok, so much for the preparation. The interesting part starts when a request comes in. Here RavenDB’s boosting feature is quite handy. The more parts of the path match, the higher score the document will get. E.g. if the requested path is a/b/c/d/e, following RavenDB search will be queried:

search term boost
a/b/c/d/e 5
a/b/c/d 4
a/b/c 3
a/b 2
a 1

The code to create such a query looks like this:

public IRoutable GetRoutable(string path) {
    var query = _documentSession
        .Query<IRoutable, IRoutable_ByPath>();

    if (!String.IsNullOrEmpty(path)) {
        var pathParts = path.Split('/');
        for (var i = 1; i <= pathParts.Length; ++i) {
            var shortenedPath = String.Join("/", pathParts, startIndex: 0, count: i);
            query = query.Search(doc => doc.Path, shortenedPath, boost: i, options: SearchOptions.Or);
        }
    } else {
        query = query.Where(doc => doc.Path == String.Empty);
    }

    var document = query.Take(1).FirstOrDefault();
    return document;
}

This method will finally return the document with the longest matching path.

Based on the incoming request we have found a matching document. What we can do with the remaining part of the URL I’ll leave for the next installment.

I published the complete code with unit tests in this Github repository.

7-Zip for Powershell

7-zip, Powershell Comments

powershell_logo

At work we deal with different big databases, and by big I mean between 3.5 and 8 GB. Those databases are zipped with 7-Zip and stored on a server. Depending on the scenario we unzip one of these databases to a local folder and attach it to the SQL Server. To simplify these steps we have a couple of Powershell scripts, among other things invoking the command line version of 7-Zip.

However, extracting an archive of several gigabytes over the network might take some time, and we’d like to see the progress in the Powershell console. Powershell provides a standard way to report progress by calling Cmdlet.WriteProgress, which then will be displayed by the current host (e.g. command line) appropriately.

Therefore with some support of a co-worker I’ve written two Cmdlets for extracting and compressing archives. The syntax is simple as this:

Expand-7Zip
    [-ArchiveFileName] <string>
    [-TargetPath] <string>
    [<CommonParameters>]

Compress-7Zip 
    [-ArchiveFileName] <string> 
    [-Path] <string>
    [[-Filter] <string>]
    [-Format <OutArchiveFormat> {SevenZip | Zip | GZip | BZip2 | Tar | XZ}]
    [-CompressionLevel <CompressionLevel> {None | Fast | Low | Normal | High | Ultra}]
    [-CompressionMethod <CompressionMethod> {Copy | Deflate | Deflate64 | BZip2 | Lzma | Lzma2 | Ppmd | Default}]
    [<CommonParameters>]

It works with both x86 and x64 and uses SevenZipSharp as a wrapper around 7zip’s API.

7zip4powershell

You can download the cmdlets with the required libraries here or grap the sources at Github.

Don’t copy my referenced assemblies

msbuild Comments

There are cases where you don’t want referenced assemblies to be copied to your output folder.

E.g. you write a plugin for an existing application, which provides a library declaring its contracts. Since the application will load that contract assembly itself, there’s no need for a second copy of the assembly in your plugin folder.

“But you can configure Visual Studio not to copy a reference to the output folder,” you may say. Well, that’s right. In the properties of a referenced assembly you can simply set Copy Local to False.

But…

If you’re an avid user of NuGet like I am, every time you update a package, the old references are removed from your project and the new ones will be added, and Copy Local will be True again. Do you think you will always remember to change that property back to False whenever you update a package? I don’t know about you, but I won’t.

Therefore, here’s a little trick I use in such cases. I have a little MSBuild file which suppresses any referenced assembly to be copied to the output folder:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <!-- make all references non-private, so they won't be copied to the output folder -->
  <Target Name="ClearReferenceCopyLocalPaths" AfterTargets="ResolveAssemblyReferences">
    <ItemGroup>
      <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" />
    </ItemGroup>
  </Target>

</Project>

Save that snippet to a file i.e. PreBuild.targets, and include it in your project file like this:

  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
  <Import Project="PreBuild.targets" />

That’s it. From now on the output folder will only contain your assembly (along with other build artifacts such as the pdb file, of course)