My Experience With .NET Core
I have been playing around with .NET core after having experience with regular old ASP.NET for years. While its a cool technology, its not without its thorns.
March 17th, 2017 in Emerging Technology
For the past three weeks, I have been using .NET Core. Before this, I have had about 3 years experience building applications in ASP.NET and writing Unity3D games in C# for about the same out of time. Although it wouldn’t be my first choice for a project, that honor goes to Python, I actually enjoy using C#.
Up until this point, ASP.NET was for windows development only. True, C# was available for on Linux and Mac OSX through various technologies, like Mono or Unity3D (Unity on my Mac is what introduced me to C# actually). But anyone who has used those technologies can probably attest that these technologies weren’t as good as their Microsoft counterparts. So when I heard about Microsoft’s intent to open source .NET Core and make it cross platform, I pledged to try it.
Fast forward a year, I have finally decided to try .NET Core. I’ll admit I was excited. None of the computers I own are Windows machines, although my work machine has a Windows 7 VM. So I set about installing .NET on my on Linux Mint laptop, My Macbook Pro, and my iMac. Surprisingly, the Linux install was the smoothest install in the bunch. I ran the commands and it just worked. On Mac, however, there was one extra step you have to run, which is outlined in Known Problems under Users of zsh, though that could be because of I am using Mac OSX 10.10.
After getting everything installed, I obviously started playing around with the technology. It was decent. Out of the box, they give you plenty of commands to get started quickly. I didn’t like the way they laid out a web project, but again, I prefer Flask for my web development needs. I felt that the base project was too large and bloated, which is an obvious concussion if you ever used and enjoyed Flask. I don’t like how opaque passing data from the view to the controller was, and how ASP.NET selected the Template file. I like explicitly passing parameters to a function. It just makes me feel like I have more control. These annoyances are nothing compared to the other issues I faced, however.
The next problem I faced was how to add a library to the project, AKA linking a library to the project. The documentation on this is lacking to say the least. Most .NET packages will tell you to install packages via NuGet. However, NuGet doesn’t work very well with .NET Core. Firstly, it throws up packages that you install via nuget install into your current directory, causing a nightmare for git. I actually had to close a teammate’s Pull Request because he mistakenly ran NuGet several times. In order to install a package, you must put the package and version in the dependencies section of your project.json and then run dotnet restore,which actually uses NuGet under the hood. Nowhere does the documentation make this readily apparent.
With that sorted, I moved on to attempting to share a library that my team built to facilitate a micro-services architecture we are developing. This library is basically our data access layer for our various services. Words can not convey how frustrating this process was. You can not just build your project as a library, share the build and then pass a flag to link the library like you can in C/C++. Or at least the documentation doesn’t describe a way to do this. In order to achieve this, you must build your library as a NuGet package, deploy the package to a NuGet server, and then follow the same process as any other package. Usually, you could simply have a local directory with NuGet packages in it and point NuGet’s sources to the directory. But this package needed to be shared with my team across multiple computers (I myself have 4 computers that I cycle between), and this package couldn’t be public. So I decided to roll our own NuGet Server. I used this Simple-Nuget-Server, which came with its own can of worms. With that done, I just had to point the NuGet sources to the server, which was the easiest part of the process.
When I had all of these systems in place, I decided to tackle Continuous integration for our project. Initially, this was simple to do. I just wrote makefiles to get everything automated on all of our computers and just invoked those in our continuous integration scripts. This worked fine, until Monday. To set the stage, I must disclose that we are using GitLab (self hosted, thank god) and the built in GitLab CI tools. The CI runner we are using is based off of docker so that we get a clean environment for our builds. The docker image that we used was microsoft/dotnet:latest. I mistakenly believed that Microsoft wouldn’t release a change that breaks the underlying build system of .NET. But alas, they did. On Monday, they released a new Docker Image that removed support for project.json and replaced it with MSBuild, which depends on .csproj files. This of course was an easy fix. I simply changed the image back and that was that. The infuriating part is that they decided to scrap project.json and move back to the .csproj files, which existed before .NET core. Which, many would tell me isn’t that big of a deal.
But what infuriates me is this reliance on these settings file. Don’t get me wrong, I love files that hold my settings or automate building. All of my deployed Python apps rely on an ini file to initialize the WSGI server, all of my C++ projects have a makefile that hold all of the commands I need. In a way, I rely on these build systems and settings files. But what the major difference between make files or ini files and project.json files is that they aren’t needed. The ini files I use for my wsgi apps are simply stand-ins for arguments for command line arguments. For example I can replace this wsgi invocation:
wsgi -protocol=http -port=5000 -workers=22 -listen=0.0.0.0 -vacuum=true with wsgi -ini=settings.ini. I’ll be honest, I’m not even certain that the first invocation of wsgi is valid because I use the second one so often. It is very similar to my C++ files.
The reliance on those files honestly make the .NET Core Command Line Interface feel hacked together. It is almost like Microsoft took the build system from Visual Studio and simply wrapped it in a command line interface. This is especially true now that they are moving back to .csproj files. In fact the reason they gave for the change is because they want to make it easier to port existing .NET projects to .NET core. This isn’t helped by the fact that there is little to no documentation from Microsoft on how to do a lot of operations through the command line interface. Most of the documentation explains how to perform the action through the Visual Studio Interface, which I don’t have access to on Linux, and it doesn’t work on my Mac computers. And the documentation that describes what you need to do, doesn’t feel very complete.
.NET Core is definitely not as mature as many other platforms out there. Core is in this weird limbo where it has a very mature community and a good echo system but it doesn’t feel like it is mature because of this transition to Mac and Linux. It feels like Microsoft moved this platform to a new paradigm without properly adjusting to this new paradigm. Perhaps I expected to much from a language that is not even out of beta yet (all though I believe that they are testing rc4), but it really feels like a Windows product on a Unix system, which is less than ideal.
Despite its numerous kinks, Core is still a cool platform. It has potential to be a pleasure to develop with. In my opinion, the biggest issue is the lackluster documentation, although that is a problem for Microsoft in general. I think with better documentation and nicer to work with command line tools for Unix, Core has great potential to be a great platform. I look forward to see where Core goes.
I recently played around with .NET Core again and a lot of the issues I spoke about here are seemingly resolved. I haven’t run into these problems. While I still don’t like the the strong opinions, I wouldn’t mind using it again.