Nancy and the issue with Enums as strings

enum_as_string

Bakground

The other day I was trying to show an enum property as a string in an Nancy based API.

And I just couldn’t do it at first but later on I found a way. Just so I remember until next time I thought I’d write a step by step instruction.

The initial Code

I’ve created an Empty ASP.Net project and added Nancy.Hosting.Aspnet Nuget package with the following command:

Install-Package Nancy.Hosting.Aspnet

In this project I’ve created a very simple NancyModule that returns a list of a class called TeamMember. Each TeamMember has a Name and an Avatar property that is an enum.

public class Index : NancyModule
{
    public Index()
    {
        Get["/"] = _ =>
        {
            var teamMembers = new List()
            {
                new TeamMember { Name = "Marcus", Avatar = StarWarsCharacter.Luke  },
                new TeamMember { Name = "Hugo", Avatar = StarWarsCharacter.Chewbacca }
            };
 
            return Response.AsJson(teamMembers);
        };
    }
}

Above shows my very basic NancyModule. And the code below shows the TeamMember class and the enum called StarWarsCharacter.

public class TeamMember
{
    public string Name { get; set; }
    public StarWarsCharacter Avatar { get; set; }
}
public enum StarWarsCharacter
{
    Leia,
    Luke,
    Chewbacca
}

Above the enum used in my example. This generates the output as shown below.

 
[ 
 { 
   name: "Marcus", 
   avatar: 2 
 }, 
 { 
   name: "Hugo", 
   avatar: 6 
 } 
] 

As you can see the enum is represented by an integer in the json-output.

First solution

If you do a google search for Enum as string then you probably will find people mentioning that you need to decorate your enum properties with the [JsonConverter(typeof(StringEnumConverter))] attribute:

    [JsonConverter(typeof(StringEnumConverter))]
    public StarWarsCharacter Avatar { get; set; }

So now I can’t build because I’m missing some references. I Install the Newtonsoft.Json Nuget package with this command:
Install-Package Newtonsoft.Json

and I hit the rebuild.

Still the json-output is representing the enum as an integer.

Why? I still haven’t figured out that part yet but if you install the Nuget package called Nancy.Serialization.JsonNet with this command:

Install-Package Nancy.Serialization.JsonNet

Shabaam, presto!

[
 {
  Name: "Marcus",
  Avatar: "Luke"
 },
 {
  Name: "Hugo",
  Avatar: "Chewbacca"
 }
]

Next challange

This is awesome! But wait a minute, now my json properties aren’t formatted as I like. The properties start with a capital letter, not like I want.

Solution continued

Don’t panic Hugo, you’ll only need to add a CustomSerializer and a Bootstraper and then it will be alright.

Below is the CustomSerializer class.

public class CustomSerializer : JsonSerializer
{
    public CustomSerializer()
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver();
    }
}

And below you can see the BootStraper.

public class BootStraper : DefaultNancyBootstrapper
{
    protected override void ConfigureApplicationContainer(TinyIoCContainer container)
    {
        base.ConfigureApplicationContainer(container);
        container.Register(typeof(JsonSerializer), typeof(CustomSerializer));
    }
}

The final solution

For a final touch you can remove the attribute JsonConverter all together and configure everything in the CustomSerializer by adding a StringEnumConverter to the Converters.

public class CustomSerializer : JsonSerializer
{
    public CustomSerializer()
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver();
        Converters.Add(new StringEnumConverter
        {
            CamelCaseText = false
        });
    }
}

And lastly remove the attribute from the TeamMember class as all enums will be converted to strings as defined in the BootStraper above.

public class TeamMember
{
    public string Name { get; set; }
    public StarWarsCharacter Avatar { get; set; }
}

Conclusion

It’s always easy when you know how to solve issues, so here goes the perfect recipe for solving the enum as string issue on Nancy.

The code is as always here. You can find the different solutions as different branches.

Cheers,

Hugo

Moles issue when multiple projects reference the same moles assembly and the assembly version changes

Background

The other day I had one of the teams at my current customer report a strange build error in TFS build. They could tell that it had something to do with Moles but they couldn’t solve it.

The solution they were trying to build was pretty simple and consisted of on Class Library project and two Test projects, one for unit testing and the second for integration testing. It looked something like the picture below:
image

Challenge

I noticed right away that both test projects had moles references to the library which doesn’t have to be a bad thing. But then I also noticed that one of the test projects had a reference to the other test project as well. Could this result in a conflict resolving the correct Moles assembly?

Well if you DO NOT change the assembly version of the library project then you WILL NOT have a problem. But if you’re like us and like to sync your AssemblyVersion and AssemblyFileVersion with the build in TFS then you will run into this trouble. You’ll probably get an error message like:

The type or namespace name ‘Moles’ does not exist in the namespace (are you missing an assembly reference?)

Mind you that this error message is a common compile error in Moles but does also appear in this case. I’ve attached a small solution that mimics this behavior here. (you will need VS2010 and Moles installed to build the zipped solution)

Solution

You get this error because when you add a Moles reference in your test project it adds a reference to a specific version of the Moled assembly (this is of course the default behavior you want in most cases) but when two assemblies have the same Mole reference and they reference each other we get a copy conflict.

To solve this I’ve come up with these solutions:

  1. First of all you should probably break the project reference between the two test projects and then your problems will automatically go away.
  2. When you add a Moles Reference from within Visual Studio you’ll get a reference to a specific version like so:
    <Reference Include=Type.Moles, Version=1.0.0.0, Culture=neutral
    , processorArchitecture=MSIL
    />
    If you change the property Specific Version on the Moles reference to False then that will solve this issue as well.
    image

I wish that the command “Upgrade .Moles files..” on the solution level would automatically update the project references with the new versions of the Mole References. But I believe I have to file that request to Microsoft.
image

Enjoy,

Hugo

Do you get a Login dialog from your client machine when connecting to SSRS using all but the IP-address?

Background

I’ll be leaving my current client soon after been there for more then a year. As a final test the person at the customer that shadowed me during all this time had to install a complete TFS environment including build server without my help.

And he did it, which I personally take as the best compliment as a coach and consultant leaving the assignment. Anyway my job in this final test was to verify that everything was working as expected.

Challenge

When I reached the verification part in my tests where I finally tried to connect to SSRS from my client machine I got an Login Dialog every time except when I used the IP-address of the SSRS machine.

As a seasoned installer of TFS and SSRS I thought I had seen all the silly errors you can get configuring SSRS so instantly I got the feeling that something was rotten outside the SSRS box. And there was some issues with the DNS that were outside the control of the SSRS box. After almost 1½ days (I kid you not) I stumbled upon the solution…

Solution

Someone had added a <RSWindowsNegotiate/> tag to the authentication types section in the rsreportserver.config file (located in your SSRS installation path). As we’re not using kerberos in this installation a quick delete of the <RSWindowsNegotiate/> tag fixed our issue. This is how our authentication types section looked like after the change.

<AuthenticationTypes>
  <RSWindowsNTLM/>
</AuthenticationTypes>

Now this configuration was probably done by the IT-ops that delivered the machine in the first place but investigation will continue to exclude my fellow shadower from blame.

Cheers,

Hugo