Optimize Images for Your Website

by Oliver 17. June 2013 13:59

This is just a short post to draw your attention to a sweet tool I've just discovered: PNGGauntlet. It runs on Windows using the .NET 4 framework and is as easy to use as you could possibly wish. Also: it's completely free to use. Convert Your Existing PNGs For starters, we'll just convert some existing PNGs – can't really do any harm with that. In the Open File dialog, there's an option to filter for only .png files. You can choose many of them at once: If you provide an Output directory, the optimized files will be written to that destination. But: the tool also has the option to overwrite the original files, which is awesome if you use some kind of source control (and thus have a backup) and just want to get the job done. During my first run, using the 8 processing threads my CPU has to offer, … … I got savings from 3% to 27%: PNGGauntlet also tells me, that in total I saved 4,52 KB. If those were all images on your web site, that would be a not so bad improvement, especially when you get it investing about 2 min of your time and no extra expenses! Real Savings Running PNGGauntlet on the sprites that we use for Camping.Info, we were really surprised: out of 172 KB it saved us over 31%, a whole 54 KB! Now that's an improvement that on a slightly slower connection will already be noticeable. We'll definitely check the rest of our images for more savings. Convert Other Image Formats You can also choose to change your images format to PNG if you're in the mood. I tried converting all GIFs in the Orchard CMS Admin theme to PNGs and went from a total of 24 KB for 20 files to less than 17 KB with no loss of quality – an over 30% saving! Just beware that you'll need to change the file references in your project to pick up the new PNGs. Roundup Easy, fast and cheap (as in free) image optimization doesn't have to be magic anymore – today anyone can do it. Check out PNGGauntlet to try for yourself. There's really no excuse not to!

SpecFlow Step Definition with Optional Parameter

by Oliver 13. May 2013 11:41

Today, this question came up on the SpecFlow Google Group: Assuming I would like to define in Gherkin the following: 1. When I send some argument xxx with parameter aaa and another parameter bbb 2. When I send some argument xxx with parameter aaa And I would like to have only one reusable function, something like this: [When(@"I send some argument (.*) with parameter (.*) and another parameter (.*)")] public void foo(string arg, string paramA, string paramB) {   // check if paramB is null and do something } I am aware of the table feature (pipe separated values) but I would like to stick with this text-alike syntax. We've encountered this use case several times in the past (also avoiding the table syntax) and used to solve it by delegating the shorter version to the longer one but I decided to go see if I can find a more elegant solution. Matching the steps The first step at matching both steps was to simply match the first step. Since version 1.9 SpecFlow has this wonderful syntax highlighting in .feature files which helps identify unbound steps: We can see, that our first pattern is too greedy and matches the second step but not the way we need. Changing the regular expression for the first parameter to something more restrictive, allows us to restrict the match to only the first step (notice that the second step has been colored purple to notify us of the fact that there is no matching step definition, yet): The regex ([^ ]*) we use here means that we match all characters that are not spaces 0 to n times, thus denying the match of the second step because of the space character following the argument aaa. Sometimes, though, you also need to match spaces in arguments and that's when we use a slightly modified version like this:  "([^"]*)"  which means: match a quote, then match everything but a quote 0 to n times and save this match as a reference, and then match another quote. In a verbatim string (prefixed by the @ sign) this will look like this: Note, that now you'll have to enclose your spaced string value in quotes, though, but you can still use the same method to put that step attribute on. Now, let's go for the second argument. Using a .NET Optional Parameter My first try was to add an optional parameter to the method we already have and provide it with a default argument like this: Unfortunately, SpecFlow complains that for the first step with only one argument the matching method needs to have only one parameter. I thought that the compiler would generate two methods here, one with and one without the optional parameter so that at runtime it could pick the right one depending on which parameters were provided with a  value. It turns out that this is not so. Seems that IL code for a method with optional parameters contains only one method, as well, as per this article: Intermediate language for optional parameter method: IL .method private hidebysig static void Method([opt] int32 'value', [opt] string name) cil managed { .param [1] = int32(1) .param [2] = string('Perl') .maxstack 8 L_0000: ldstr "value = {0}, name = {1}" L_0005: ldarg.0 L_0006: box int32 L_000b: ldarg.1 L_000c: call void [mscorlib]System.Console::WriteLine(string, object, object) L_0011: ret } That's why SpecFlow complains. Solution: Use Two Methods It looks like there is not direct solution to the problem that would require only a single method. The solution we employ seems to be all you can do about it, at least right now with SpecFlow 1.9. Which would be to use (at least) two separate methods, one of which delegates its execution to the other, more general one: Happy spec'ing!

Test Driving AppHarbor – A Walkthrough and Review

by Oliver 15. March 2013 20:50

For some time now, I've wanted to check out AppHarbor, a cloud service to host .NET applications that includes a build environment, executes tests and deploys successful builds to one or more app servers. They use Amazon's cloud computing infrastructure as their backend. The smallest package is free so there's no good reason not to check it out. Getting my first application up and running First, you need to Sign up, confirm the link in the confirmation email, and log in. This part took about 2 minutes. (Created a new KeePass entry with an uncrackable password on the way.) Then, create an application, entering a name and the geographical region you want your application to be hosted at: Once you're done with that, you can choose where your code is hosted – this assumes you version control your source code using e.g. BitBucket, CodePlex, or Git. They also have a solution for the situation where you don't host your code anywhere, using a built-in Git repository. I didn't use that option, though, since I have an account at GitHub. Clicking on "Configure GitHub to deploy to AppHarbor" directs you to the GitHub logon screen (if you're logged out) where you simply sign in. Now, the following dialog was a bit spooky: What I read between the lines is something like: all your base are belong to us! I mean, it basically says that they can do to all of my projects … well, anything, really. Since I didn't want to create a new account just to try out AppHarbor and, honestly, because I somehow felt that they wouldn't destroy all of my work, I clicked "Authorize app". Phew! Remark: You might choose to use a different GitHub account for your deployments, using e.g. copies of your repositories locally where you just copy everything you need from your dev repo. Then you can grand AppHarbor access to that account without much ado. Now, the AppHarbor app took over and I chose a repository for the application I created earlier: Once I chose a repo for my first app, I got to see the first Build status message – here AppHarbor is building my app for the first time: A few seconds after AppHarbor was done building, and testing, and deploying my app after I had clicked the Deploy button, my app was ACTIVE :-) Under the Hostnames link I found that they had given it http://mathie.apphb.com/ and after a couple of seconds I saw my app online on AppHarbor. That was easy – how about deploying a new version? I'm quite surprised at how easy (and fast!) it was to get my first app up and running. For completeness, I wanted to check how AppHarbor would handle my pushing some changes to the master branch of my repo. Here we go: The commit was picked up within seconds! Another click on Deploy gets the new version out there. Remark: On their homepage they say that apps get automatically deployed once build and test runner finish successfully. This was not the case here, and I didn't find any setting to enable this. If you know how that works, please leave a comment. Update: Looks like this works out of the box, you just need to wait a minute or two for their deployment agent to pick up the new version. I updated my app just now and it got deployed by itself :-) Go back in time – it's easy, too Now, this is a nice feature: you can deploy any version of your application with a click of a button! So, if for some reason, you discover that the new version has some flaw, go back to an older one: What else do they offer? AppHarbor contains an add-on infrastructure and already offers several add-ons that you can install with your application. Most of them charge an extra monthly fee, some of them also offer a free plan. There are mostly analytics add-ons and DB engines, including dedicated MS SQL Server, RavenDB, MySQL, a PostgrSQL flavor, and a few more. Interesting platform with big ease of setup and a free plan Should be good for any smallish app that you just want to set up and forget about! For $10/month you can also assign your own host names which makes this a viable solution. It saves you from installing and maintaining a separate build server with something like TeamCity or CruiseControl running and is also almost easier to set up. Where are you gonna host your next app?

Test Driving AppHarbor – A Walkthrough and Review

by Oliver 15. March 2013 20:50

For some time now, I've wanted to check out AppHarbor, a cloud service to host .NET applications that includes a build environment, executes tests and deploys successful builds to one or more app servers. They use Amazon's cloud computing infrastructure as their backend. The smallest package is free so there's no good reason not to check it out. Getting my first application up and running First, you need to Sign up, confirm the link in the confirmation email, and log in. This part took about 2 minutes. (Created a new KeePass entry with an uncrackable password on the way.) Then, create an application, entering a name and the geographical region you want your application to be hosted at: Once you're done with that, you can choose where your code is hosted – this assumes you version control your source code using e.g. BitBucket, CodePlex, or Git. They also have a solution for the situation where you don't host your code anywhere, using a built-in Git repository. I didn't use that option, though, since I have an account at GitHub. Clicking on "Configure GitHub to deploy to AppHarbor" directs you to the GitHub logon screen (if you're logged out) where you simply sign in. Now, the following dialog was a bit spooky: What I read between the lines is something like: all your base are belong to us! I mean, it basically says that they can do to all of my projects … well, anything, really. Since I didn't want to create a new account just to try out AppHarbor and, honestly, because I somehow felt that they wouldn't destroy all of my work, I clicked "Authorize app". Phew! Remark: You might choose to use a different GitHub account for your deployments, using e.g. copies of your repositories locally where you just copy everything you need from your dev repo. Then you can grand AppHarbor access to that account without much ado. Now, the AppHarbor app took over and I chose a repository for the application I created earlier: Once I chose a repo for my first app, I got to see the first Build status message – here AppHarbor is building my app for the first time: A few seconds after AppHarbor was done building, and testing, and deploying my app after I had clicked the Deploy button, my app was ACTIVE :-) Under the Hostnames link I found that they had given it http://mathie.apphb.com/ and after a couple of seconds I saw my app online on AppHarbor. That was easy – how about deploying a new version? I'm quite surprised at how easy (and fast!) it was to get my first app up and running. For completeness, I wanted to check how AppHarbor would handle my pushing some changes to the master branch of my repo. Here we go: The commit was picked up within seconds! Another click on Deploy gets the new version out there. Remark: On their homepage they say that apps get automatically deployed once build and test runner finish successfully. This was not the case here, and I didn't find any setting to enable this. If you know how that works, please leave a comment. Update: Looks like this works out of the box, you just need to wait a minute or two for their deployment agent to pick up the new version. I updated my app just now and it got deployed by itself :-) Go back in time – it's easy, too Now, this is a nice feature: you can deploy any version of your application with a click of a button! So, if for some reason, you discover that the new version has some flaw, go back to an older one: What else do they offer? AppHarbor contains an add-on infrastructure and already offers several add-ons that you can install with your application. Most of them charge an extra monthly fee, some of them also offer a free plan. There are mostly analytics add-ons and DB engines, including dedicated MS SQL Server, RavenDB, MySQL, a PostgrSQL flavor, and a few more. Interesting platform with big ease of setup and a free plan Should be good for any smallish app that you just want to set up and forget about! For $10/month you can also assign your own host names which makes this a viable solution. It saves you from installing and maintaining a separate build server with something like TeamCity or CruiseControl running and is also almost easier to set up. Where are you gonna host your next app?

Automatic Deployment of a New Discoverize Portal

by Oliver 11. March 2013 15:02

This is a technical post about how we automatically deploy new portals that will be run by our own portal software discoverize. After filling in and submitting our portal creation form we do the following: Save the entered information into /App_Data/<PortalName>/portal.xml Trigger the TeamCity build through a web request to a specific URL Send an email with the request status or any errors that occurred Display a Thank You page. Now, the TeamCity build configuration that was triggered under 2. does the following: Execute the Powershell script create-portal.ps1 in c:\projects\discoverize create the AppPool Discoverize-Portals if it doesn't exist yet (all our portals run within it) iterate over all folders inside wwwroot\discoverize.com\App_Data if a folder with the same name exists under wwwroot\discoverize-portals, skip it else move the current folder from wwwroot\discoverize.com\App_Data to wwwroot\discoverize-portals add a line with the full path to the new portal folder to newportals.txt (e.g. C:\inetpub\wwwroot\discoverize-portals\<PortalName>) add a new site to IIS and set its AppPool to Discoverize-Portals start the new site in IIS (needs Admin privileges, that's why we use a parameterized task scheduler task for that) Build the source code from the repository Execute the Deploy-NewPortals target from deploy.proj using MSBuild in c:\projects\discoverize Iterate over the entries in newportals.txt, for each entry do: Copy the build output from step 2. to wwwroot\discoverize-portals\<PortalName> Run the site setup (this uses Orchard's setup method) with our own recipe (using Orchard.exe) Call an action (SetupComplete) on the new site to mark deployment as done Create a default entry so there's something to look at (using Orchard.exe) The SetupComplete action then finishes doing this: save the information of the portal.xml into an application specific configuration file create new user "portal-owner" for content management send an email about the successful installation of the new portal Quite complex, if I look at it now, but it works!

SQL Server Compact timed out waiting for a lock

by Oliver 28. January 2013 14:26

Today, I faced the exception mentioned in the post title: SQL Server Compact timed out waiting for a lock. The default lock time is 2000ms for devices and 5000ms for desktops. The default lock timeout can be increased in the connection string using the ssce: default lock timeout property. (Plus some session details). Circumstances The exception was thrown in my local dev environment while working on our Orchard CMS based portal software discoverize, calling any page in the portal. Obviously, something was wrong not with a single page but rather with a piece of infrastructure. Interestingly enough, only a few moments before trying to open the web site I had done some database manipulation using SqlCeCmd deleting some unneeded columns from one of our tables. It seems that after that the site broke. Solutions tried I tried to get hold of the DB like this: stop and start the web site in IIS (using appcmd stop site "discoverize" and appcmd stop site "discoverize") – no change take DB offline by renaming the file – waited a few moments, renamed it back – no change! Here I started wondering where the lock is saved – is it inside the DB? took the whole application pool offline and restarted it – bang! That helped. I now have my site back up and running and can continue develepment. Conclusion If you encounter the SQL CE timeout error during development inside a web application, restarting the app's app pool will probably get you back to work. Happy coding!

SQL Server Compact timed out waiting for a lock

by Oliver 28. January 2013 14:26

Today, I faced the exception mentioned in the post title: SQL Server Compact timed out waiting for a lock. The default lock time is 2000ms for devices and 5000ms for desktops. The default lock timeout can be increased in the connection string using the ssce: default lock timeout property. (Plus some session details). Circumstances The exception was thrown in my local dev environment while working on our Orchard CMS based portal software discoverize, calling any page in the portal. Obviously, something was wrong not with a single page but rather with a piece of infrastructure. Interestingly enough, only a few moments before trying to open the web site I had done some database manipulation using SqlCeCmd deleting some unneeded columns from one of our tables. It seems that after that the site broke. Solutions tried I tried to get hold of the DB like this: stop and start the web site in IIS (using appcmd stop site "discoverize" and appcmd stop site "discoverize") – no change take DB offline by renaming the file – waited a few moments, renamed it back – no change! Here I started wondering where the lock is saved – is it inside the DB? took the whole application pool offline and restarted it – bang! That helped. I now have my site back up and running and can continue develepment. Conclusion If you encounter the SQL CE timeout error during development inside a web application, restarting the app's app pool will probably get you back to work. Happy coding!

Writing Acceptance Tests for an Orchard / ASP.NET MVC Application – using SpecFlow, Coypu (Selenium) and the MvcIntegrationTestFramework

by Oliver 22. August 2012 13:48

When we started development on Marinas.info, we decided to write acceptance tests for all important features of our application. This decision was even more justified by the fact that a bunch of similar platforms are to follow using the same codebase. We wanted an application with less bugs and easier maintenance. Writing good, automated acceptance tests is not easy and it’s not fast, either. For some time now, we’ve been trying to get the first set of our tests run green, which proved especially tricky on our TeamCity continuous integration server. This post investigates a working solution. The ingredients: SpecFlow, Coypu (Selenium), Browser, Web Server, and MvcIntegrationTestFramework SpecFlow In .NET world, using SpecFlow to write acceptance tests is nothing new and has recently become, yet again, more appealing after its update to version 1.9. One of our scenarios for verifying image upload functionality looks like this: It’s simple to write, easy to read and great living documentation. For Browser based tests you need: Coypu (Selenium) Everyone who has written tests for Selenium for even a mildly ajax-y site knows how painful it can be to create reliably working tests. Coypu alleviates the pain and makes test creation as straight-forward as it should be in the first place. Coypu is: A robust wrapper for browser automation tools on .Net, such as Selenium WebDriver that eases automating ajax-heavy websites and reduces coupling to the HTML, CSS & JS A more intuitive DSL for interacting with the browser in the way a human being would A few examples of Coypu’s clean API can be seen here in one of the step definitions for the above scenario (Browser is an instance of the BrowserSession class from Coypu): A web browser To run browser based tests you, of course, need … a browser! Coypu offers support for quite a bunch of them, including the usual suspects Internet Explorer, Chrome, and Firefox. A web server You need to host your application in some web server or another to process requests. Well, this statement turns out to be only partially true, as you will see with the MvcIntegrationTestFramework. But at least for browser based test you need a web server, and you basically have the choice between IIS and IIS Express (if you don’t want to write your own or use someone else’s implementation). We chose IIS Express as it is manageable through a non-administrator account, but it needs to be installed on all machines that will execute the tests. For non-browser based tests: MvcIntegrationTestFramework Introduced by Steven Sanderson in 2009, this small framework allows to write integration tests for ASP.NET MVC applications and execute them without a browser! It empowers you to make assertions on your controllers’ actions’ results rather than on the rendered html output by injecting some clever hooks into your MVC application under test. An example of how a test would look can be found in the above mentioned post. The “magic” of this framework lies in the use of ApplicationHost.CreateApplicationHost() which creates an application domain for hosting your ASP.NET application. Check out this screenshot of part of the source code: How to put the pieces together After a quite radical evolution of our test code (which you can read up on in my follow-up post The Long Road to Browser Based Acceptance Testing), we finally settled for the following: Before the first test starts, setup an instance of the AUT (application under test). This includes: deploying the AUT as we do for our staging environment, but to a temp folder initialize an AppHost instance à la MvcIntegrationTestFramework, i.e. an ASP.NET enabled application domain that hosts the AUT execute the Orchard setup command via the AppHost instance (instead of running the setup through a browser, which we used to do but was a lot slower) Before each test run (SpecFlow scenario) we then execute various commands to setup the environment for the concrete test, e.g.: clean the database simply by overwriting it with a copy we saved after the initial setup create Marina entries that will be displayed and searchable on the site, again, using the AppHost instance Once we want to execute steps in the browser, we do the following: start an instance of IIS Express pointing to the deployed application (we used the wrapper code from Spinning up IISExpress for integration testing) initiate a Coypu BrowserSession which under the hood creates an instance of the browser you choose after battling with Internet Explorer, Chrome, and Firefox Portable, we now use Firefox 10.0.6 ESR (Extended Support Release) because version 10 is of now the highest version supported by Selenium (2.1.25) and the ESR doesn’t ask to be updated all the time After each test run (SpecFlow scenario) we do this: close the browser shut down the IIS Express instance (we slightly modified the above mentioned wrapper code calling Kill() on the process instance after the call to CloseMainWindow() so that it reliably terminates even on TeamCity) Conclusion Setting up a reliable environment for automatically executing acceptance tests has not been a walk through the park but we finally have a solution that basically “just works”. Hopefully, our experience will help you save a couple of hours and also some headache along the way Happy coding!

ToDebugString() – give me some debug info about my object, e.g. Request.Url

by Oliver 16. September 2011 20:06

Lately, I was having trouble debugging certain parts of my code in Visual Studio, and all I wanted to know was the value of some variable at some point in time. Well, I’d use some logging if I could just get at that value easily. But for some objects I don’t really know what I’m looking for or where I should be looking for it. So just give me the values of all the members of that object, will ya? And could you recurse that? But no deeper than 3 levels, alright? Or let’s say… 5? public static string ToDebugString(this object obj, int maxdepth, int depth=0) { if (obj == null) return "null";   if (obj is IConvertible) return obj.ToString();   if (depth >= maxdepth) return "...";   var sb = new StringBuilder();   if (depth > 0) sb.AppendLine();   foreach (var propertyInfo in obj.GetType().GetProperties(BindingFlags.Public|BindingFlags.Instance)) { sb.Append(new string(' ', 2*depth)).Append(propertyInfo.Name).Append(": "); try { var value = propertyInfo.GetValue(obj, new object[0]); sb.AppendLine(ToDebugString(value, maxdepth, depth + 1)); } catch (Exception ex) { sb.AppendLine(string.Format("[{0}]", ex.Message)); } }   // remove newline from end of string var newLine = Environment.NewLine; if (sb.Length >= newLine.Length) sb.Replace(newLine, "", sb.Length - newLine.Length, newLine.Length);   return sb.ToString(); } With this little helper I can now simply call anyobject.ToDebugString(4 /* maxdepth */) and I get a nicely formatted debug view of that object; e.g. Request.Url.ToDebugString(3) gives me: AbsolutePath: /logg.aspxAbsoluteUri: http://localhost:55235/logg.aspxAuthority: localhost:55235Host: localhostHostNameType: DnsIsDefaultPort: FalseIsFile: FalseIsLoopback: TrueIsUnc: FalseLocalPath: /logg.aspxPathAndQuery: /logg.aspxPort: 55235Query: Fragment: Scheme: httpOriginalString: http://localhost:55235/logg.aspxDnsSafeHost: localhostIsAbsoluteUri: TrueSegments: Length: 2 LongLength: 2 Rank: 1 SyncRoot: Length: 2 LongLength: 2 Rank: 1 SyncRoot: ... IsReadOnly: False IsFixedSize: True IsSynchronized: False IsReadOnly: False IsFixedSize: True IsSynchronized: FalseUserEscaped: FalseUserInfo: Nice Right now this method chokes on indexed properties but once I’ll need it I’ll go and look for a way to include them. It also chokes any exceptions on the way to just get the job done. Happy coding!

JSON Import In .NET

by Anton 22. July 2011 13:37

Bantam Is Quitting Services We as teamaton were using bantam for all of our todos. At the beginning of this year bantam was bought by ConstantContact, and they announced that bantam will cease services as of July 1. Since we are developing our own todo management tool (see our blog), we decided to push the development and use it instead of bantam. Of course we wanted to take all of our todos with us. We used bantams export feature which gave us a JSON-file with all our tasks (closed and open ones). So I took on the task to write an JSON import feature into our tool. Json.NET After a bit of researching, I found that the library Json.NET would suit our import needs perfectly. Applying the deserialization was pretty straightforward – the documentation helped a lot. Here is the code from the Import controller: [HttpPost] public ActionResult Import(HttpPostedFileBase file) { var todos = new List<Todo>(); if (file != null && file.ContentLength > 0) { var streamReader = new StreamReader(file.InputStream); string text = streamReader.ReadToEnd(); streamReader.Close(); var bantamTodos = JsonConvert.DeserializeObject<IList<BantamTodo>>(text) as List<BantamTodo>; todos = bantamTodos.Select(bantamTodo => bantamTodo.ConvertToTodo()).ToList(); _todoRepository.SaveImport(todos); } return RedirectToAction("List"); } It just opens the file, extracts the content as a string, deserializes the string into a list of bantam todos, and then converts these bantam todos into our “normal” todos. Indirection Via BantamTodo-Class As you can see, I did not convert the JSON directly into our Todo-class. You can use attributes and the converter class to deserialize JSON into a class of your liking. There are two reasons, why I did not choose to do so: I did not want to load the Todo-class with attributes and converters, and I thought it would be easier to introduce a middle class (BantamTodo), which poses as a container and converter. I used a nice tool, to take a good look into the original JSON-file: JSON Viewer. With the information about the structure of the JSON file I started implementing via the TDD pattern. Here is my test class, which tests the deserialization of the the bantam todos and the conversion from the class BantamTodo to Todo: [Test] public void Should_Import_BantamToDo_FromJson() { var jsonToDo = ArrangeTaskAsJson(); var bantamToDo = JsonConvert.DeserializeObject<BantamTodo>(jsonToDo); bantamToDo.Categoy.Should().Be.EqualTo("Organisation"); bantamToDo.Complete.Should().Be.EqualTo(true); bantamToDo.Created_At.Should().Be.EqualTo(new DateTime(2011, 6, 30, 0, 41, 57)); bantamToDo.Due.Should().Be.EqualTo(new DateTime(2011, 7, 1)); bantamToDo.Author.Name.Should().Be.EqualTo("Anton"); bantamToDo.Assigned_To.Name.Should().Be.EqualTo("Oliver"); bantamToDo.Related_To[0].Name.Should().Be.EqualTo("ToDo-Management Tool"); bantamToDo.Name.Should().Be.EqualTo("Entwicklung nach Gebieten Personen zuordnen - Verantwortliche, Blogs, etc."); bantamToDo.Description.Should().Be.EqualTo("some good description"); bantamToDo.Flagged.Should().Be.EqualTo(true); } [Test] public void Should_Convert_BantamToDo_ToTodo() { var jsonToDo = ArrangeTaskAsJson(); var bantamToDo = JsonConvert.DeserializeObject<BantamTodo>(jsonToDo); var todo = bantamToDo.ConvertToTodo(); todo.Status.Should().Be.EqualTo(bantamToDo.Complete ? Status.Closed : Status.Open); todo.Description.Should().Contain(bantamToDo.Name); todo.Description.Should().Contain(bantamToDo.Description); todo.Tags.Select(t => t.Name).Should().Contain(bantamToDo.Categoy); foreach (var bantamProject in bantamToDo.Related_To) todo.Tags.Select(t => t.Name).Should().Contain(bantamProject.Name); todo.DateCreated.Should().Be.EqualTo(bantamToDo.Created_At); todo.DateCompleted.Value.Date.Should().Be.EqualTo(bantamToDo.Due); todo.DateDue.Should().Be.EqualTo(bantamToDo.Due); todo.Creator.Name.Should().Be.EqualTo(bantamToDo.Author.Name); todo.Assignee.Name.Should().Be.EqualTo(bantamToDo.Assigned_To.Name); todo.Priority.Value.Should().Be.EqualTo(bantamToDo.Flagged ? 2 : 0); } The implementation was pretty straightforward. Since it was my first time working with MVC, and also my first time working with JSON, it took me some time. All in all – research, export and meetings included – it took me about 12 hours. If you have any suggestions as to improvement I would appreciate them. If you are trying to import JSON into .NET yourself, I hope that this article helps.

About Oliver

shades-of-orange.com code blog logo I build web applications using ASP.NET and have a passion for javascript. Enjoy MVC 4 and Orchard CMS, and I do TDD whenever I can. I like clean code. Love to spend time with my wife and our children. My profile on Stack Exchange, a network of free, community-driven Q&A sites

About Anton

shades-of-orange.com code blog logo I'm a software developer at teamaton. I code in C# and work with MVC, Orchard, SpecFlow, Coypu and NHibernate. I enjoy beach volleyball, board games and Coke.