New Nuget Package for Neo4j Users - Neo4jClient.Extension

The defacto standard for .net users of Neo4j is the Neo4jClient nuget package, if you don’t have that, you’re basically rolling your own connection code, in some cases you might need to, but most of the time, the client will work well.

Today I was adding Neo4jClient to a new project, and searched via the Nuget package UI and up popped Neo4jClient.Extension, so, I went to the github repo, read the .md file and thought - I’ll download that bad boy and give it a go.

The general gist is to be able to pass things like your actual entities to the client without needing to write the Cypher, thereby adding even more type safety to your code, so instead of:

Client.Cypher.Merge(string.Format("(n:Label {{item}}.Id = {0})", entity.Id));

You can now just put in:

Client.Cypher.MergeEntity(entity);

Which certainly prevents typos. I’ll describe a bit more about it below, but the TL:DR of it is, whilst it’s in it’s early stages, it’s worth looking at for a .net developer, in particular with a new project. There are some issues to be aware of (see the bottom of the post) but all in all I look forward to seeing how this progresses.

Attributes Everywhere!

Neo4jClient.Extension uses attributes for most of it’s core functionality.

[CypherLabel]

I like the [CypherLabel] attribute a lot, it works well for simple cases, and is a neat way of putting labels in the code, the downside would come from wanting to add extra more dynamic labels, so you might have a class called Location looking something like this:

[CypherLabel(Name="Location")]
class Location {
    public string Name { get; set; }
}

But you couldn’t subsequently put something in the DB with (n:Location:USA) as there is no way to add the ‘USA’ label.

[CypherMatch]

Here we can do searches in a simpler fashion to the old way, so instead of:

Client.Match("(n:Model {Id:{myParam}.Id})").Return(n => n.As<MyObj>());

we instead just do:

Client.Cypher.MatchEntity(model, "n").Return(n => n.As<MyObj>());

Note, I’ve defined the ‘n’ parameter name in the MatchEntity call, if I left that out, the param name would (at present) be the lowercased name of the label.

[CypherMerge/MergeOnCreate/MergeOnMatch]

These are the main guts and where the work is really showing, the cool thing here is it removing the complexity and nightmare of curly brace nesting. Basically, the CypherMerge attribute defines the ‘key’ the Merge will work from, generally this will be the ‘Id’ property. The MergeOnCreate attribute is applied to all the attributes you would want to be created as part of the ‘ON CREATE’ bit of a MERGE query, and quite obviously the MergeOnMatch attribute is for the ON MATCH bit.

One thing to consider with the use of these attributes (and it affects the ‘CypherMatch’ one as well) is that you can only have one Merge/Create version, so if you decide you want to merge properties 1,2,3 one time and 4,5,6 another, you’re going to have to revert to the old .Merge technique for at least one of those cases. It’s not a huge issue because in at least one of the cases you’ve saved a bucket load of curly brace potential problems.

Some issues

It’s early days, and only version 0.1.0.1 but these are worth noting in case you want to use the package.

Case changing of Property names

For some reason the case of the properties in my classes is changed so the first character is lowercase, which is not something I’m overly pleased with, it’s not ‘end of the world’ type stuff, but I’m wary of code that doesn’t do what I expect, and I expect if I have a property called ‘Name’ that it will be stored as ‘Name’ in the DB.

Labelling

If you use any special characters in your labels, such as ‘/’, ‘ ‘ (space) or just the ` character you’ll run into issues, there is a pull request to fix this, so hopefully not an issue for long

AttributeUsage

You can apply the CypherLabel attribute to a property (and a CypherMerge* attribute to a class) but in both cases they won’t do anything.

Install Cypher Highlighting into Sublime Text 3

I’ve had Sublime Text (ST) 2 installed now for quite a while, purely because I use the Cypher highlighting package, and whilst I waited for ST3 to have it in the Package manager, it didn’t matter that I had both for a while. But I finally decided to bite the bullet and install Cypher manually into ST3.

Step 1.

Go to https://github.com/kollhof/sublime-cypher and Download ZIP of the repo.

Step 2.

Open ST3, and go to ‘Browse Packages’ (CTRL+SHIFT+P then type ‘browse’)

Step 3.

In the Explorer window, add a new folder called ‘Cypher’

Step 4.

Extract the contents of the ZIP you downloaded in Step 1 into the folder you created in Step 3

Step 5.

Restart ST3.

Step 6.

Switch to Cypher mode (CTRL+SHIFT+P then ‘Cypher’)

Step 7.

image

Ha! We all know that won’t work :)

CdnFallbackExpression for JQuery, JQuery.UI, Modernizr and Bootstrap

So, like a total chump, I didn’t really understand what the CdnFallbackExpression on a Bundle actually meant. It didn’t help that pretty much every example you find online shows you what to write for jQuery, but nothing else.

With Tournr, I want to use CDN’s where I can for obvious reasons – and so I dutifully tried the jQuery example:

var bundle = new Bundle("~/Scripts/jQuery").Includes("~/Scripts/jQuery-2.1.1.js");
bundle.CdnFallbackExpression = "window.jQuery";
bundle.CdnPath = "https://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.1.min.js";
bundles.Add(bundle);

Works just fine.

And this is the point things start to go awry. In my naivety I didn’t really understand what was happening. I didn’t twig that the CdnFallbackExpression has to be window.jQuery. It won’t work otherwise. Being a developer, I took it upon myself to wrap up the above into a method, something like:

private static Bundle GetBundle(string name, string cdnPath, params string[] includes){ /**/ }

Being snazzy and using the ‘name’ as a fallback expression.

That’s right, the name, (actually “window.{0}” where {0} was the name), which as you can imagine worked great for jQuery, not so for anything else. I believed that what I wanted was something like:

<script>(window.bootstrap) || document.write('<script src="~/Scripts/bootstrap.min.js><\/script>')</script>

I imagine you looking at this, perhaps with your palm attached to your forehead. You are right to do so.

So, I test tournr, hmmm bootstrap is no longer working. If I remove the CDN stuff, it’s all good, so I guess bundling must be b0rked?? I spent ages looking for errors in the Console windows of IE and Chrome Developer Tools – nada. Network was showing the files downloading, but curiously I noticed 2 copies downloading, so my local and my CDN loading. Odd. One or the other please, not both. This led to my eureka moment!

The CdnFallbackExpression has to be set CORRECTLY. No amount of time saving auto setting was gonna save me, so now the GetBundle  looks more like this:

private static Bundle GetBundle(string name, string cdnPath, string fallbackExpression, params string[] includes){ /**/ }

So, the fallback expressions for jQuery, UI, etc are listed below:

Library

Expression

jQuery window.jQuery
jQuery.UI window.jQuery.ui
Modernizr window.Modernizr
Bootstrap $.fn.modal

Tournr

A little while ago (2 months and 12 days to be precise) I launched my project I’ve been making for a while now: Tournr. I have the usual Facebook page (please like!), twitter account and even a blog for the features / tips etc. So this post is really to first introduce the readers of this blog to Tournr, but also as I’d like to post about the design decisions I’ve made here, anyhews, I’ll get on to that later.

Briefly Tournr is a site to help organisers run competitions, long term it’ll do loads, short term it helps with registration, providing one point for a competition entry and results recording so if you have a competition to run, please try it and let me know if there is something you want / need to help you!

Much more later!

BrowserStack Visual Studio 2013 Extension

So, if you download the extension from Visual Studio Gallery (here) you’ll find it won’t install into VS 2013, but it’s easy to fix.

Open up your downloaded file using your preferred zip solution (7zip in my case), edit the extension.vsixmanifest file, and change the following lines from:

<Installation InstalledByMsi="false" AllUsers="true">
  <InstallationTarget Version="11.0" Id="Microsoft.VisualStudio.Pro" />
  <InstallationTarget Version="11.0" Id="Microsoft.VisualStudio.Premium" />
  <InstallationTarget Version="11.0" Id="Microsoft.VisualStudio.Ultimate" />
</Installation>

to:

<Installation InstalledByMsi="false" AllUsers="true">
  <InstallationTarget Version="12.0" Id="Microsoft.VisualStudio.Pro" />
  <InstallationTarget Version="12.0" Id="Microsoft.VisualStudio.Premium" />
  <InstallationTarget Version="12.0" Id="Microsoft.VisualStudio.Ultimate" />
</Installation>

Save the file and make sure the archive is updated. Then double click and install the extension.

Neo4jClient with LinqPad

Quite often I want to just try out some code, usually useful when answering a question on StackOverflow, but typically these don’t require a full solution, and it’s a bit heavy handed to whip out Visual Studio for a simple create / match query, so what about LinqPad? One of the most awesome tools for a .NET developer (if you haven’t got it, you should get it).

I’m going to assume a few things here:

  1. You have got Neo4j running and know the url (if you’ve changed it)
  2. You have downloaded and installed / have LinqPad > 4.51.01 (at the time of writing at the beta page: http://www.linqpad.net/beta.aspx) running

Set up LinqPad

You need to have version 4.51.01 or greater to be able to download the nuget packages (as this version uses the latest Nuget Client)

With LinqPad open, press F4 (or go to Query, Query Properties):

image

In the query properties window, press the ‘Add NuGet…’ button:

image

Search for ‘Neo4jClient

image

Press ‘Add to Query’, and it’ll start downloading:

image

Accept the license message that pops up:

image

Now you should have the Neo4jClient package added to your local cache:

image

Lastly, we can add the namespaces we’ll want:

image

Select ‘Neo4jClient’ and ‘Neo4jClient.Cypher’:

image

Then press OK

Our query properties should now contain the Neo4jClient nuget package:

image

and the namespaces:

image

You can just press OK now, and it’ll be set up for this query, or press the ‘Set as default for new queries’ button to always have Neo4jClient goodness available.

Querying

Every query will need to begin with the same bit of code, which we’re familiar with:

var client = new GraphClient(new Uri("http://localhost:7474/db/data"));
client.Connect();

After that, you can do what you want:

client.Cypher
        .Create("(n:Test {user})")
        .WithParam("user", new {Name = "Chris"})
        .ExecuteWithoutResults();

var results = client.Cypher
                .Match("(n:Test)")
                .Return(n => new {NameReturned = Return.As<string>("n.Name")})
                .Results;
                

And because we’re in LinqPad world, we can just call ‘Dump()’ to get the results:

foreach (var result in results)
    result.Dump();

image

Awesome!

Notes

One thing to note is that the ‘Language’ choice is important, if you’re wanting to use actual classes (so for example, to do ‘n.As<T>()’ instead) you’ll need to have language set to: ‘C# Program’ (or VB, or even F# if you’re up for it!), for all other queries (like the one above) you’ll need to be on ‘C#/VB Statements(s)’ as you need to initialise the client first. ‘C#/VB Expression’ won’t work.

Ninjecting Neo4jClient into MVC5/4/3

First, create your new MVC project (or load your existing one!)

Then add the Ninject.MVC nuget package:

image

We’ll also want the Neo4jClient package

image

Now we have those two, we can hook it up, first off we need to tell Ninject how to bind to Neo4jClient, I use a Module for this, so add this class to your project (usually I have them in a sub-folder called ‘Modules’ in the App_Start folder – but it can be anywhere):

public class Neo4jModule : NinjectModule
{
    /// <summary>Loads the module into the kernel.</summary>
    public override void Load()
    {
        Bind<IGraphClient>().ToMethod(InitNeo4JClient).InSingletonScope();
    }

    private static IGraphClient InitNeo4JClient(IContext context)
    {
        var neo4JUri = new Uri(ConfigurationManager.ConnectionStrings["Neo4j"].ConnectionString);
        var graphClient = new GraphClient(neo4JUri);
        graphClient.Connect();

        return graphClient;
    }
}

Now we just need to tell Ninject to load the module, so in the NinjectWebCommon.cs file (in the App_Start folder) edit the ‘RegisterServices’ method (at the bottom of the file) so it looks like:
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
    kernel.Load<Neo4jModule>();
} 

Lastly, we just need to inject into our controller, which is a case of adding a constructor (or modifying an existing one) to take an ‘IGraphClient’ instance:

private readonly IGraphClient _graphClient;
public HomeController(IGraphClient graphClient)
{
    _graphClient = graphClient;
}
 

Now the controller has an instance of the graphclient to use as and when it pleases:

public ActionResult Index()
{
    ViewBag.NodeCount =  _graphClient.Cypher.Match("n").Return(n => n.Count()).Results.Single();

    return View();
}
image

Obviously extending this, you could add a base ‘Neo4jController’ which any controllers requiring Neo4j override.

Using BeyondCompare 4 with Tortoise HG 2.11.1 (and possibly all 2.x previous)

So, I started off following the Using Beyond Compare with Version Control Systems knowledge base article on Scooter Software’s pages, and all seemed to be going well, but unfortunately it didn’t stay that way. In effect whenever I did a diff it would open Beyond Compare 4 (BC4) and not show the diff.

Not good.

So I did what we’d all do – raised a question on their support forums, which went well, fast responses, but didn’t fix it. Which is unfortunate, so I started reading up about how HG knows about diff tools etc, and was eventually led to the solution, which is:

  1. Go to: C:\Program Files\TortoiseHg\hgrc.d\
  2. Open up ‘MergeTools.rc’ (you might want to open it with administrator privileges)
  3. Paste the following in below the [merge-tools] header:
    ; Windows version of BeyondCompare 4
    beyondcompare4.priority=-1
    beyondcompare4.args=$local $other $base /mergeoutput=$output /ro /lefttitle=parent1 /centertitle=base /righttitle=parent2 /outputtitle=merged /automerge /reviewconflicts /solo
    beyondcompare4.premerge=False
    beyondcompare4.regkey=Software\Scooter Software\Beyond Compare 4
    beyondcompare4.regkeyalt=Software\Wow6432Node\Scooter Software\Beyond Compare 4
    beyondcompare4.regname=ExePath
    beyondcompare4.gui=True
    beyondcompare4.diffargs=/lro /lefttitle='$plabel1' /righttitle='$clabel' /solo /expandall $parent $child
    beyondcompare4.diff3args=$parent1 $parent2 $child /lefttitle='$plabel1' /centertitle='$clabel' /righttitle='$plabel2' /solo /ro
    beyondcompare4.dirdiff=True
  4. Save the file (I had to save as MergeTools.rc1 then rename in the folder itself)
  5. Restart TortoiseHG (the most successful way I’ve done this is to signout/in or restart the PC)
  6. Try a diff

Microsoft Word, Comments and Sorting by Date

I don’t know if you use Word on a daily basis, and even if you do – whether you use the ‘Revisions’ features which allow you to comment on the document and then comment on those comments and then … well you get the idea.

I do, and it’s becoming increasingly frustrating that I can’t order those comments by the date they were entered (or at least I can’t find how) and I have browsed for quite some time online trying Macro solutions (which create another document), even just reading the ‘comments’ tool window in word to try to see the most recent comment.

Either ways – it’s rubbish.

But.

I’m a developer, specifically a Microsoft .net developer. I casually note that Visual Studio has templates for developing Office 2013 addins – so – how hard can it be?

Turns out - not very.

The Addin:

To get the addin go to: http://sdrv.ms/1hOdoQ3 which gets you to my public SkyDrive folder where you can download it (you want ‘Word_2013_RevisionsByDateAddin.zip’)

Once it’s installed, you can enable / disable it via the ‘Add-ins’ menu on the ribbon:

image

(Sorry for the UI, I only spent about an hour on the code – it’s functional – not pretty :) )

That will show the pane (which will be on the right hand side, you can drag it around wherever you so please):

image

and you can click on the headers to sort by the various columns.

Double clicking on a row will take you to that part of the document, due to the implementation of this, it may not be obvious where it is as it scrolls to the first point – i.e. it might be at the bottom of the page. The addin will select the text on the page that was commented on, so you can use that as a guide.

Known Issues:

1. If a comment is really long, you can’t really see it all in the tool window (you can just double click on it and it’ll take you there though)

2. Not really an issue as such – but it will ask you to install the VSTO (Visual Studio Tools for Office) Runtime on your machine when you install – which does mean downloading it from Microsoft directly. This is handled in the installer, and it’s a whopping 38Mb :( – you can get it directly from MS if you want (http://www.microsoft.com/en-gb/download/details.aspx?id=40790)

Potential Issues:

1. I don’t know if it works on Word 2010 – please try it and let me know!

The Code

You can get the code and tinker with it as you will here (https://bitbucket.org/cskardon/office-addins) I will put it somewhere where it can be installed from better at some point.. probably.. maybe..

Let me know any problems (particularly install ones – please send a picture of an issue to me and I can try to fix it easier!!)

Error: Unable to access jarfile d:\Databases\Neo4j

Cryptic. I’ve spent a large proportion of time on this, and straight off the bat – NO this is not the ‘windows-jarfile’ error of the old skool days. No, this is a pretty simple issue, my folder structure was:

d:\Databases\Neo4j
d:\Databases\Neo4j Trie

Inside each a copy of the the ‘zip’ contents, with different configuration properties for the various things (ports etc) so I could run multiple copies of Neo4j at the same time.

All good.

EXCEPT I get this error from the “Neo4j Trie” folder when I try to run Neo4j.bat:

Error: Unable to access jarfile d:\Databases\Neo4j

I looked through the bat files, to no avail, then – a moment of inspiration! I rename the folder to:

d:\Databases\Neo4j-Trie

And HUZZAH! We’re back in business.

Update: I'm pleased to say that this is fixed in the bat file so from the next release on, it shouldn't be a problem.