Migration

Migrating from project.json to csproj using Visual Studio 2017 Moving a real world ASP.NET Core application using VS2015 project.json to VS2017 and csproj

This past weekend I spent a few hours working on migrating the Humanitarian Toolbox allReady project over to the new csproj based Visual Studio 2017 solution format. I’ve written a few times about the plans to retire the project.json file introduced by ASP.NET Core. If you want some background you can read those posts first (don’t worry, I’ll wait)…

The summary is that in Visual Studio 2017 and the final ASP.NET Core SDK tooling, the project.json file was removed in favour of a revised csproj file. This has left some people confused and wondering why project.json is missing in Visual Studio 2017. The decision was mostly made to support customers reliant on using MsBuild and to support migrating larger projects to .NET Core.

Moving from project.json to csproj

In this post I wanted to cover the steps I took to migrate a real ASP.NET Core application to Visual Studio 2017. I’ve recorded the steps that I took and the issues I faced, along with any solutions I was able to find.

TL;DR; It wasn’t as painful as I’d expected it might be, but it also wasn’t entirely automated. There were a few issues along the way, which required some intervention on my part to finally get everything building correctly.

My first trial attempt at this process was actually about 2 weeks ago. At that time I was using the first RTM version of VS 2017 and I started by simply opening our allReady solution file with Visual Studio 2017. 

Visual Studio presents a dialog showing that any project.json projects will be migrated.

Visual Studio 2017 project.json migration dialog

After accepting that message VS will do it’s thing. Under the covers it’s calling the dotnet migrate command which handles the conversion for you. I decided to use Visual Studio 2017 for the migration, rather than the command line as I expect that’s the approach most people will be taking.

During migration; which took only a few seconds for me, you’ll see a progress window from Visual Studio.

ASP.NET Core project.json migration progress

Once the migration is completed you are shown a migration report.

project.json to csproj migration report

This initially led me to believe that things had gone pretty well. In fact, when I tried a restore and build things were not quite so positive. I was shown a staggering 982 errors and 3 warnings. It was late and I was tired, so I decided to abandon attempt one at that point! That was a problem for my future self!

Attempt Two

This weekend I was finally in a position to have another try at the migration. I took the latest version of our code and before starting, updated Visual Studio 2017 because I’d seen that it had some updates pending.

I repeated the initial steps as before and this time, although the result was still not looking great, it was a fair amount improved on attempt 1. Lesson 1 – Always do migrations with the most updated version of the IDE! This time I was at 199 errors and 2 warnings.

project.json Migration Errors

The errors were mostly relating to dependencies so it looked to be a restore issue. I tried cleaning the solution, restarting Visual Studio and even manually deleting the bin and obj folders. Each time I was hit with a wall of red errors when trying to build.

At this point I jumped onto Google and found a suggestion to clear the local nuget cache. I navigated to %USERPROFILE%/.nuget and deleted the contents.

Upon doing that, things were starting to look a little better. The errors cleared but I now had some warnings to deal with and the site would not run.

The second warning was a little strange.

The referenced project ‘..\..\Backup\Web-App\AllReady\AllReady.csproj’ does not exist.

The unit test project was referencing the web project but using the backup folder path. The backup folder is created during migration to hold the original project.json and xproj files in case you need to get back to a prior state. That folder of course didn’t include a csproj file. I removed the reference and re-added it, pointing it to the correct folder.

I also took the chance to move the backup folder so that it was outside of my main solution structure, just in case it was causing or masking any other issues.

Attempting to build at this stage reduced my errors but I still had 29 warnings. To be sure that Visual Studio 2017 wasn’t partly to blame, I also tried using the command line dotnet restore commands directly. However, I was getting warnings there also.

Inside Visual Studio the warning looked like this:

Detected package downgrade: Microsoft.Extensions.Configuration.Abstractions from 1.1.0 to 1.0.2

Trying to run the application at this stage resulted in the following exception:

System.IO.FileLoadException: ‘Could not load file or assembly ‘Microsoft.Extensions.Configuration.Abstractions, Version 1.1.0.0 … The located assembly’s manifest definition does not match the assembly reference.

For some reason the migration had chosen version 1.1.0 for the Microsoft.VisualStudio.Web.BrowserLink dependency when it created the csproj file.

<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.1.0" />

The solution was to change it to 1.0.1 since allReady is targeting the LTS stream of ASP.NET Core currently. All of the other dependencies were registered with their LTS versions. This rouge 1.1.x dependency was therefore causing version conflicts.

<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.0.1" />

At this point, building the solution was getting a bit further. I now had a single warning left for the web project. This warning stated that AddUserSecrets(IConfigurationBuilder) is now an obsolete method.

‘ConfigurationExtensions.AddUserSecrets(IConfigurationBuilder)’ is obselete. ‘This method is obsolete and will be removed in a future version. The recommended alternative is .AddUserSecrets(string userSercretsId) or .AddUserSecrets<TStartup>()..’

The warning explains that we were now expected to pass in the user secrets key as a string to the method or use .AddUserSecrets<TStartup> which is syntactic sugar over AddUserSecrets(this IConfigurationBuilder configuration, Assembly assembly). Previously the storage location for the user secrets ID was the project.json file. It’s now moved to an assembly attribute. The previous overload is not guaranteed to return the correct Assembly so this could produce issues. You can read a fuller explanation from the team on the GitHub repo.

In our case I changed the appropriate line in Startup.cs from

builder.AddUserSecrets();

to

builder.AddUserSecrets("aspnet5-AllReady-468aac76-4430-43e6-848e-f4a3b90d61d0");

Test Project Changes

At this point the web project was building but there were issues inside the test project:

Test project warning after project.json migration

Found conflicts between different versions of the same dependent assembly that could not be resolved. These reference conflicts are listed in the build log when log verbosity is set to detailed.

Some of the dependencies we had been using had newer versions so I took a guess that perhaps I needed to update the Xunit / test related ones. I changed these three dependencies:

<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0-preview-20170106-08" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0-beta5-build1225" />
<PackageReference Include="xunit" Version="2.2.0-beta5-build3474" />

to

<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
<PackageReference Include="xunit" Version="2.2.0" />

Finally the entire solution was building, tests were running and I could start the website locally.

Initial thoughts on csproj and Visual Studio 2017

Generally, everything seems to work once inside Visual Studio 2017. The migration process was a little more effort than I would have liked though.

No auto complete

In Visual Studio 2015 we had version auto complete for the dependencies from NuGet when editing project.json. We’ve lost this in Visual Studio 2017 which is a shame. It now pretty much forces me into the NuGet Package Manager which I find slower. I understand that autocomplete might come back at some point, but it’s a shame we’re lacking it upon release. 

Less easy to scan

Personally, I still prefer the project.json format for readability. There’s still a little more noise in the XML than we had inside the JSON version. That said, the work done to the revised csproj format is great and it’s a vast improvement on the csproj of the past.

Summing Up

Overall the process wasn’t too harrowing. Visual Studio and dotnet migrate handled most of the work for me. It was a shame that I had to resort on a few occasions to Google for manual solutions to solve problems that I’m sure should have been addressed by the tooling. The restore of the dependencies not working without clearing the cache was an unexpected problem.

But with the work of migration behind me I’m ready to move on. I’ve reached the acceptance stage on my project.json grieving process!

Anyone new to ASP.NET Core, using it for the first time in Visual Studio 2017 will probably look at older blog posts and wonder what we were all moaning about. The csproj is a great improvement on what we had in the past, so if you’ve never seen project.json, there’s nothing to miss and only improvements to enjoy.

ASP.NET Core Anatomy (Part 3) – UseMvc Dissecting and understanding the internals of ASP.NET Core

In parts one and two of this series I looked at the two main IServiceCollection extensions (AddMvcCore and AddMvc) in ASP.NET Core. These are used to add in the required MVC services when you plan to use the MVC middleware in your application.

The next thing you are required to do to enable MVC in your ASP.NET Core application is to include the UseMvc IApplicationBuilder extension from the Configure method of your Startup class. This method registers the MVC middleware into your application pipeline so that the MVC framework can handle requests and return the appropriate response (usually a view result or some JSON). In this post I will take a look at what happens when the UseMvc method is called during the application startup.

As with the earlier parts of this series, I’m currently using the rel/1.1.2 codebase from the MVC repository for my investigations. I’m still using the slightly older project.json based code as at the moment there don’t seem to be simple ways to debug into multiple ASP.NET Core source code assemblies in VS2017.

UseMvc is an extension on the IApplicationBuilder which takes an Action delegate of IRouteBuilder. The IRouteBuilder will be used to configure the routing for MVC. There is a more basic variant of the UseMvc method which does not required any parameters. This method simply calls down into the main version, passing in an empty delegate like so…

The main UseMvc method looks like this…

Let’s dissect what this method does. First it does a check to see if the IServiceProvider has an MvcMarkerService service registered in it. To do this it uses the ApplicationServices property which exposes the current IServiceProvider. Calling GetService on the service provider will try to locate a registered implementation for the requested Type. The MvcMarkerService is registered when AddMvcCore executes and as a result, if it is not found, it indicates that either AddMvc or AddMvcCore was not called during ConfigureServices. Marker services like this are used in quite a few places to help calling code verify proper registration of fundamental dependencies before they try to execute. The MvcMarkerService is just an empty class with no actual code.

Next, UseMvc requests a MiddlewareFilterBuilder from the ServiceProvider and sets its ApplicationBuilder using the IApplicationBuilder.New() method. The ApplicationBuilder creates and returns a new instance copy of itself when this method is called.

Next, UseMvc initialises a new RouteBuilder, setting the default handler to the registered MvcRouteHandler. At this point, the DI magic really kicks in and a bunch of dependencies start getting instantiated. MvcRouteHandler is requested and because it has some dependencies in its constructor, various other classes get initialised. Each constructor for these classes can also require additional dependencies which then also get created. This is a great example of how the DI system works. While all of the interfaces and concrete implementations are registered in the container during ConfigureServices, the actual objects are only created at the point they are required to be injected into something. By new-ing up the RouteBuilder, this snowball of object creation begins to occur, until all of the required dependencies have been constructed. Some of these are registered as singletons and will then live for the lifetime of the application, being returned whenever they are requested from the ServiceProvider. Others, might be constructed for each request or in some cases, constructed uniquely every time they are required. Understanding the details of how dependency injection works and specifically the ASP.NET Core ServiceProvider is out of scope for this post.

After creating the RouteBuilder, the Action<IRouteBuilder> delegate action is called which takes the RouteBuilder as its only parameter. In the MvcSandbox sample that I’m using to debug and dissect MVC we call the UseMvc method, passing in a delegate function via a lambda. This function maps a single route named “default” as follows.

This calls the MapRoute method which is an extension on the IRouteBuilder. The main MapRoute method looks like this:

This requests an instance of an IInlineConstraintResolver which is resolved by the ServiceProvider to a DefaultInlineConstraintResolver. This class takes an IOptions<RouteOptions> in its constructor.

The Microsoft.Extensions.Options assembly, as part of its work, calls into the MvcCoreRouteOptionsSetup.Configure method which takes a RouteOptions parameter. This adds a new constraint map of type KnownRouteValueConstraint to the Dictionary of constraint maps. This Dictionary is initialised with a number of default constraints when the RouteOptions is first constructed. I’ll look into the routing code in a little more detail in a future post.

A new Route object is constructed using the name and template provided. In our case this is added the RouteBuilder.Routes List. By this point, running the sample MvcSandbox application, our route builder now has a single route added.

Note that the MvcApplicationBuilderExtensions class also includes an extension method called UseMvcWithDefaultRoute. This method includes a call to UseMvc, passing in a hardcoded default route.

This route is defined with the same name and template as defined in the MvcSandbox application. Therefore it could have been used as a slight code saver within the MvcSandbox Startup class. For the most basic of MVC applications it’s possible that using this helper extension method might be enough for your application routing requirements. In most real-world cases I suspect you’ll end up passing in a more complete customised set of routes. It’s a nice shorthand though if you want to start with the basic routing template. It’s also possible to call UseMvc() without a parameter and instead use the attribute routing approach. 

Next, the static AttributeRouting.CreateAttributeMegaRoute method is called and the resulting route is added to the Routes List (at index zero) on the RouteBuilder. CreateAttributeMegaRoute is documented with the summary “Creates an attribute route using the provided services and provided target router.” and it looks like this:

This method, creates a new AttributeRoute which implements the IRouter interface. Its constructor looks like this:

In its constructor it takes an IActionDescriptorCollectionProvider, an IServiceProvider and a Func which takes an array of ActionDescriptor’s and which returns an IRouter. By default, with the AddMvc registered services, it will get an instance of ActionDescriptorCollectionProvider which is a singleton object registered with the ServiceProvider. ActionDescriptors represent the available MVC actions that have been created and discovered within the application. We’ll look at those another time.

The code (inside the CreateAttributeMegaRoute method) which creates the new AttributeRoute uses a lambda to define the code for the Func<ActionDescriptor[], IRouter>. In this case the delegate function requests an MvcAttributeRouteHandler from the ServiceProvider. Because this is registered as transient, the ServiceProvider will return a new instance of an MvcAttributeRouteHandler each time one is requested. The delegate code then sets the Actions property (an array of ActionDescriptions) on the MvcAttributeRouteHandler using the incoming ActionDescriptions array and finally the new handler is returned.

Back to UseMvc; it finishes by calling the UseRouter extension on the IApplicationBuilder. The object passed into UseRouter is created by calling Build on the RouteBuilder. This method will add the routes into the RouteCollection. Internally the RouteCollection keeps track of which routes are named and which are unnamed. In our MvcSandbox example we end up with a named “default” route and an unnamed AttributeRoute.

UseRouter has two signatures. In this case we’re passing in a IRouter so the following method is called:

This does a check for a RoutingMarkerService within the ServiceProvider. Assuming this is registered as expected  it adds the RouterMiddleware into the middeware pipeline. It is this middleware which will use the IRouter to try and match up requests to the controller and action within MVC which should handle them. The details of this process will feature in a future blog post.

At this point the application pipeline is configured and the application is ready to start receiving requests. That’s a good point to stop for this post.

Summary

In this post we’ve looked at UseMvc and seen that it sets up the MiddlewareFilterBuilder which will be used later. It then also gets an IRouter via a RouteBuilder and much of the work at this stage is around registering routes. Once everything is setup, the routing middleware is registered into the pipeline. It’s this code that knows how to inspect incoming requests and map the paths to the appropriate controllers and actions that can handle them.

Other Posts In This Series

Things I’ve Learnt This Week (19th March)

Week 8 of my series, sharing things I’ve learnt, read, watched and listened to, in the pursuit of expanding my knowledge about software development.

Things I’ve Blogged

ASP.NET Core MVC Anatomy (Part 1) – AddMvcCore – Dissecting and understanding the internals of ASP.NET Core MVC. In this post I looked at what the AddMvcCore extension method to the IServicesCollection does.

ASP.NET Core Anatomy (Part 2) – AddMvc – Dissecting and understanding the internals of ASP.NET Core. In this post I looked at what the AddMvc extension method to the IServicesCollection does.

Things I’ve Learnt

Debugging ASP.NET Core with csproj

This is something I’ve been checking into from time to time. I’ve been a heavy user of the ability global.json gave us in VS 2015 to debug into ASP.NET Core assemblies. Especially to help with my current ASP.NET Core Anatomy series. With the move back to csproj in VS 2017 we no longer have a global.json file to identify the projects we want to load source from. This was touched on in the ASP.NET Community Standup this week. Damian Edwards confirmed they are hopefully working on a solution, but at the moment there is no easy way to do this. With some ceremony it might be possible since the ASP.NET team themselves need to do this to develop the product. I’d love to be able to get my hands on a fairly simple set of instructions to enable this again.

Things I’ve Read

Things I’ve Listened To

Things I’ve Watched

ASP.NET Core Anatomy (Part 2) – AddMvc Dissecting and understanding the internals of ASP.NET Core

Welcome to part 2 of my series where I dissect the internals of the ASP.NET Core source code. Eagle eyed readers will have noticed a slight change to my title for this post. I decided to drop MVC from it. While I’m mostly interested in MVC anatomy at this point, I’ve realised that as I work through the flows, I’m stumbling into features which are part of the main ASP.NET Core framework, such as IRouter. Therefore, it feels sensible to allow myself scope to drift into discussing those parts and as a result, ASP.NET Core Anatomy is a more accurate series title.

If you watched the ASP.NET Community Standup this week, you might have heard Jon Galloway suggesting that these posts be consumed along with a good cup of coffee or tea. So before I begin, I’ll give you time to get yourself a drink!…

Right; all set? In part 1, I looked at what happens inside the AddMvcCore extension method. In this post I want to look at the AddMvc extension method. As in part 1 I am using the rel/1.1.2 tagged code for ASP.NET Core MVC. Things can and will likely change in the code base in the future. Therefore, consider this general guidance which should only be considered current if you are using the same version of the MVC packages. My starting point again is the MvcSandbox project. My ConfigureServices method in Startup.cs looks like this:

This makes a single call the the AddMvc extension method, which looks like this:

This method first calls the AddMvcCore extension method that I looked at in part 1. Therefore all of the same setup and service registration occurs, including the creation of an ApplicationPartManager. The return type from AddMvcCore is an MvcCoreBuilder which AddMvc holds in a variable. As I noted in part 1, this provides access to the the IServiceCollection and ApplicationPartManager generated by AddMvcCore.

AddMvc calls an extension called AddApiExplorer on the IMvcCoreBuilder. This simply adds two service registrations – ApiDescriptionGroupCollectionProvider and DefaultApiDescriptionProvider – to the builder’s IServiceCollection.

Next it calls the AddAuthorization extension on IMvcCoreBuilder. The relevant methods are:

First it calls down to an extension, AddAuthorization in the Microsoft.AspNetCore.Authorization assembly. I won’t go in depth about that in this post, but this adds the core services to enable authorization. After this, AuthorizationApplicationModelProvider is added to the ServicesCollection.

Next, back in AddMvc it uses a private static method AddDefaultFrameworkParts which adds TagHelpers and Razor AssemblyParts.

First this method looks up the Assembly containing the InputTagHelper class which is Microsoft.AspNetCore.Mvc.TagHelpers. It then checks if the ApplicationPartManager.ApplicationParts list already contains a matching assembly. If not, it adds it. This is then repeated for Razor, using the assembly containing UrlResolutionTagHelper which is Microsoft.AspNetCore.Mvc.Razor. This also gets added to ApplicationParts if it is not already there.

Back in AddMvc again, a number of items are added to the ServiceCollection via extension methods. AddMvc calls AddFormatterMappings which registers the FormatFilter class.

Next it calls AddViews which does a few things. First it adds services for DataAnnotations using the AddDataAnnotations extension. Then it adds the ViewComponentFeatureProvider to the ApplicationPartManager.FeatureProviders. Finally it registers a number of view based services, mostly as singletons. I won’t show the whole class here as it’s quite big. The key parts are:

Next, AddMvc calls the AddRazorViewEngine extension method which looks like this:

This calls AddViews again which made me a little curious. It seems to be redundant to call AddViews prior to AddRazorViewEngine, when we can see that AddRazorViewEngine will do that for us and register those services anyway. It’s a safe operation, since all of these extension methods use the TryAdd… style methods. Those prevent duplicate registrations of implementations of services. Despite the safety of this approach, it was still strange to see this. To satisfy my curiosity I opened an issue on the Mvc GitHub repo, to check if this was an issue or actually by design. I got a very quick response from Ryan Nowak at Microsoft confirming that it was a design decision to make the dependencies a little more explicit and easy to see. Thanks Ryan!

AddRazorViewEngine adds three more feature providers to the ApplicationPartManager.FeatureProviders – TagHelperFeatureProvider, MetadataReferenceFeatureProvider and ViewsFeatureProvider. It concludes by registering the services needed for razor views to function.

AddMvc then uses another extension method to add services for the Cache Tag Helper feature. This is a very simple extension method which just registers 5 required services. Then back in AddMvc, AddDataAnnotations is called again. AddViews had already added this previously. This is for the same design decision that I discussed before.

AddMvc then calls the AddJsonFormatters extension method which adds a couple of items to the ServicesCollection.

The final extension method that gets called is AddCors which uses the extension method in the Microsoft.AspNetCore.Cors to add Cors related services.

With the service registrations completed, AddMvc creates a new MvcBuilder, passing in the current ServicesCollection and the ApplicationPartManager which are stored into its properties. Much like the MvcCoreBuilder we looked at in the first post and which we started with at the beginning of AddMvc, the MvcBuilder is described as allowing fine grained configurations of MVC services.

At the end of AddMvc I had 148 registered services in the services collection. 86 additional services are registered above and beyond those that AddMvcCore has added. The ApplicationPartManager had 3 ApplicationParts and 5 FeatureProviders stored in its lists.

Summary

That concludes my dissection of AddMvc. A little less exciting I’m afraid than the AddMvcCore method which laid more groundwork by creating the ApplicationPartManager. Mostly we call extensions to register extra services. As you can see, many of those services are more specific to web applications which need to work with views. For API only applications, it’s possible you won’t need most of these. In the API projects I’ve been working with, we start with AddMvcCore and simply add in the few extra items we need using the builder extension methods. Here is an example of what that looks like in practice:

In the next post I will look at what happens when we call UseMvc in the Startup.cs Configure method. That get’s a little more exciting!

Other Posts In This Series

ASP.NET Core MVC Anatomy (Part 1) – AddMvcCore Dissecting and understanding the internals of ASP.NET Core MVC

Welcome to part 1 of a new series where I will dissect the internals of the MVC source code. I am hoping to learn and demonstrate how it works deep (sometimes very deep) under the hood. In this series I will be studying the guts of MVC. If you’re squeamish, you might want to look away! Personally, I get a lot of value from reading, debugging, reading again, scratching my head, debugging again and eventually understanding (or at least thinking I understand) the source code of ASP.NET MVC. By learning how the framework behaves I can better utilise it and understand why things are happening within my own applications.

As I progress through the series, I will be making my best interpretation of what the code is doing based on what I read and observe. I can’t promise to understand and interpret everything 100% correctly but I will do my best! As I’ll be working my way through it in small chunks, I may learn new things that put earlier posts into more context. If that happens, I’ll try to update those earlier posts. It’s fairly hard to succinctly and coherently explain code in writing. I’ll try to keep the explanation clear and will be dropping in chunks of code from the MVC source to make it a little easier to follow. If it’s still not clear, you can (and in fact I recommend you do) spend time looking at the full code yourself, debugging where necessary. I hope this series will be of interest to some of the ASP.NET community who like me, enjoying understanding how things work. Do let me know your feedback so I know if I’m hitting the right notes.

AddMvcCore

In this post I’ll be dissecting what AddMvcCore is actually doing for us and focusing on classes such as ApplicationPartManager along the way. To do this I’m using the project.json based rel/1.1.2 source code, loading up the included MVC Sandbox project to begin my debugging. As new releases are made it’s possible that some of these classes and methods will change, especially the internal ones. Always refer to GitHub for the latest source! I’ve updated the MvcSandbox ConfigureServices as follows…

AddMvcCore is an extension method on the IServiceCollection. Using extension methods is the common pattern for registering groups of related services into the services collection. AddMvcCore is one of two extension methods which can be used to register the MVC services when building MVC application. AddMvcCore adds a more limited subset of the MVC services than the more commonly used AddMvc method. It’s useful when your application is not taking advantage of all the MVC features. In some simple applications this might be enough. For example, when building REST APIs, where I don’t need the Razor components, I often start with AddMvcCore. You can always add some extra services manually after AddMvcCore, or if you find yourself needing it, move to the more complete AddMvc method instead.

AddMvcCore looks like this:

One of the first things AddMvcCore does is to get an ApplicationPartManager via a static method GetApplicationPartManager which takes in the existing IServiceCollection. This method looks like this:

It first checks in the currently registered services to see if an ApplicationPartManager is already registered. By default this would not be the case. Although unlikely, it is possible that you or a prior service might have registered one before AddMvcCore is called. If an ApplicationPartManager doesn’t already exist, a new one is constructed.

Next the code will try to populate the ApplicationParts property on the ApplicationPartManager. To do this it first asks for an IHostingEnvironment from the services collection. If it can access a matching instance for IHostingEnvironment it uses it to get the application/assembly name. This then gets passed into the static DefaultAssemblyPartDiscoveryProvider.DiscoverAssemblyParts method which will return an IEnumerable<ApplicationPart>.

DiscoverAssemblyParts will first get the Assembly object and a DependencyContext for the supplied assembly name. In my debugging case this was “MvcSandbox”. It then passes these values into GetCandidateAssemblies which calls down into GetCandidateLibraries. Those methods look like this:

The comment above GetCandidateLibraries (stripped in code above) explains what it’s going to do

“Returns a list of libraries that references the assemblies in <see cref=”ReferenceAssemblies”/>. By default it returns all assemblies that reference any of the primary MVC assemblies while ignoring MVC assemblies.”

So to digest that, what we can expect is a list of any assemblies from our solution which reference any of the MVC assemblies.

ReferenceAssemblies is a static HashSet of strings defined at the top of the DefaultAssemblyPartDiscoveryProvider class. It contains the full assembly names for the 13 default MVC related assemblies.

GetCandidateLibraries uses a CandidateResolver class to locate and return the candidates. The CandidateResolver is constructed with the List of RuntimeLibrary objects and the HashSet containing the ReferenceAssemblies. Each of the RuntimeLibrary objects is iterated over and added to a dictionary. During the loop, a check is made to ensure that each depedency name is unique. If not, an exception will be thrown.

Each dependency (RuntimeLibrary) is each stored in the dictionary as a new Dependency object. This object includes a DependencyClassification property that is used to eventually filter out the required libraries (candidates). There are four DependencyClassifications defined in an enum.

When each Dependency is created, it’s initially marked as Unknown unless it is found in the ReferenceAssemblies HashSet. In that case it is instead marked as MvcReference.

The CandidateResolver.GetCandidates method is called which then begins traversing the dictionary of Dependencies. This method combined with ComputeClassification walks the dependency tree. For each Dependency it checks through the child dependencies, breaking out of the loop if any of them is already marked as a Candidate or MvcReference. At this point it will also mark the parent Dependency as a Candidate type. When this process is complete an  IEnumerable<RuntimeLibrary> is returned, containing any identified candidates. In my case, using the sample, it is just the MvcSandbox library which is marked as a Candidate.

DiscoverAssemblyParts converts any returned candidates into a new AssemblyPart. This object simply wraps the Assembly and mainly exposes some of the Assembly properties such as it’s name and types. I’ll probably explore that class in a separate post.

Finally, within GetApplicationPartManager the AssemblyParts are added to the ApplicationPartManager which is then returned. As a reminder, here is the relevant snippet of code that does that…

The returned instance of the ApplicationPartManager is added to the services collection as a Singleton back inside the AddMvcCore extension method.

Following so far? 🙂

The next thing AddMvcCore does is call a static ConfigureDefaultFeatureProviders method which takes in the ApplicationPartManager. This will add a new ControllerFeatureProvider to the FeatureProviders list if one is not already included.

The ControllerFeatureProvider will be used to discover controllers from the list of ApplicationPart instances. I’ll look at the ControllerFeatureProvider in a future post. For now, we’ll continue looking at the final steps inside AddMvcCore now that the ApplicationPartManager has been updated.

First a private ConfigureDefaultServices method is called, which calls the AddRouting extension method from Microsoft.AspNetCore.Routing. I won’t cover this here, but it’ll add all of the necessary services and setup to enable the routing functionality.

AddMvcCore then calls another private method – AddMvcCoreServices – This method registers each of the required core services for MVC to function. This includes things like the options framework, action discovery, action selection, controller factories, action invokers,  model binding and validation.

Finally, AddMvcCore constructs a new MvcCoreBuilder object with the services collection and the ApplicationPartManager as parameters. This class is documented as follows

“Allows fine grained configuration of essential MVC services.”

The MvcCoreBuilder is returned as the result of the AddMvcCore extension method. It exposes the IServiceCollection and ApplicationPartManager as properties. The McCoreBuilder and it’s extension methods are referenced in a few places to allow extra configuration to occur after the initial AddMvcCore call. In fact, the more complete AddMvc extension method calls AddMvcCore first and then uses the MvcCoreBuilder to perform the extra service configuration.

Summary

Explaining the flow above in a way that is reasonably clear is not easy. So, let me wrap up by summarising what we’ve witnessed. This is all very low level MVC code that ultimately adds MVCs required services to the IServiceCollection. Along the way it creates the ApplicationPartManager, which as we’ll look at later is used to start establishing the internal ApplicationModel that MVC uses. We haven’t seen very much direct functionality, but as I follow the startup flow we will get to the more interesting pieces now that the groundwork has been laid.

That completes my initial deep dive into the flow of AddMvcCore. In total it registers 46 additional items into the IServicesCollection. I’ll continue the journey in a future post where I’ll look at the further work that the AddMvc extension method performs.

Other Posts In This Series

Things I’ve Learnt This Week (12th March)

Week 7 of my series, sharing things I’ve learnt, read, watched and listened to, in the pursuit of expanding my knowledge about software development.

Things I’ve Blogged

Things I’ve Learnt

ASP.NET Core MsBuild is Quicker than Project.json

It seems that the build time for the ASP.NET Core framework is nearly halved after moving back to csproj and MsBuild. Reduced down to approx. 28 mins from 52 mins. Read the tweet here

Live Unit Testing in Visual Studio 2017

It was a little disappointing to learn that the new live unit testing feature is not supporting .NET Core projects at launch. Looks like I’ll have to wait a while to try it since most of my projects are .NET Core at the moment.

Registering a Dependency with a non injectable property using Microsoft.Extensions.DependencyInjection

I was looking at an ASP.NET Core project which was using StructureMap to enable some more advanced service registrations that the built in Microsoft DependencyInjection package allowed. However, after looking through, I only found a few that I wasn’t sure how to register with the built in DI container. The project had a StructureMap registration like this:

c.For<DataValidator>().Transient().Use(() => new DataValidator(DataSource.DefaultData));

The DataSource.DefaultData is a static method in this case. After looking at the IServiceCollection methods, it seems the following line works with the default container to achieve the required result:

services.TryAdd(new ServiceDescriptor(typeof(DataValidator), p => new DataValidator(DataSource.DefaultData), ServiceLifetime.Transient)); 

Things I’ve Read

Things I’ve Listened To

Things I’ve Watched

Tools

Visual Studio 2017 is Released Reflecting on the loss of project.json and looking ahead to the new VS 2017 experience

Visual Studio 2017 is released today and I thought it was a good time to reflect on my thoughts about one of the main changes it brings for ASP.NET Core developers. This won’t be a detailed features post, as I’ve only tried the RC a few limited times. Due to some bugs and issues I experienced, I ended up removing the release candidate from my PC and only recently installed the latest more stable version. I plan to begin working with Visual Studio 2017 as soon as possible so I can start to explore the benefits it offers. A few of the new features and tooling enhancements have caught my eye and I’m keen to experience them first hand.

The big change for anyone who has worked on ASP.NET Core projects to date, is the the loss of the project.json format and the move back to a revised and improved csproj format. It’s a decision which caused a lot of reaction when it was first announced and since then has been a common topic of conversation for ASP.NET developers. I’m a fan of project.json format. I found it easy to use, simple to work with and a nice step forward. Personally I would prefer we weren’t loosing it entirely and that the tooling had been developed in a way that could support both formats. Pragmatically I can understand some of the reasons behind the change. Large customers, with heavy reliance on and experience of MsBuild for example, I’m sure would have avoided any use of ASP.NET Core without this compromise being made. Ultimately I am accepting of anything which can allow ASP.NET Core to gain more traction and become the framework of choice for C# based web developers. I do however, find myself a little concerned with the way the news of the change has impacted the first impressions of some people about ASP.NET Core. In a introduction to ASP.NET Core talk I’ve recently presented, it was odd having to avoid too much detail on project.json because I knew it would soon be a thing of the past. Explaining to people that they need to know this now, but don’t get too invested in it as it’s soon obsolete was hard. It was especially confusing for people to be shown the newest version of ASP.NET that already due quite a radical change.

In part due to it’s open development and partly due to this latest change, some people I’ve talked to are left a bit afraid of taking on ASP.NET Core right now. They have the impression it’s not finished, hard work, changing too frequently and ultimately not a safe choice for new projects at the moment. I don’t share these views myself; but I think that it’s partly because that I’ve worked with ASP.NET Core from around the beta 8 time frame. I’ve used it a lot during that time and even have a production system nearly ready for launch which is based around ASP.NET Core API microservices. I’ve seen firsthand the ease of use and enhancements it offers, so I am able to see how those benefits outweigh the bumps along the way. But if new developers are left apprehensive by the strong opinions being shared and the breaking changes, that does worry me a little. I truly hope this is the last of the big forced changes we should expect to the fundamentals of the technology and we can move forward, embracing the future of ASP.NET Core. I certainly wouldn’t and haven’t for the last few weeks promoted starting a new ASP.NET Core project in VS 2015 but at least with today’s launch, we finally have the RTM tooling to be able to move forward with ASP.NET Core and csproj. For any concerned developers reading this post, I think with VS 2017 we should be in the right place to really start making ASP.NET Core the first choice for new projects.

An important fact to state here is that the tooling for ASP.NET Core has always remained in preview. Despite .NET Core and ASP.NET Core being released back in June last year, under full support, we’ve been told that tooling would RTM at a later date. Many of the early adopters to ASP.NET Core would have experienced some pain and glitches with the earlier versions of the preview tooling, although in the latest versions, I’ve had a much more stable experience. My assumption, and I think that of many other developers was that by investing in ASP.NET Core on Visual Studio 2015 early on, we would eventually get some form of RTM tooling in that IDE. However, at the end end of January I picked up on a comment from Damian Edwards during the ASP.NET Community Standup. What I thought I’d heard was that we would never get final supported tooling for Visual Studio 2015.

Puzzled and unsure of my interpretation of his statement, I reached out to Damian on Twitter. Here is the start of the Twitter thread. In summary, I learned that the decision being made was apparently clear. VS 2015 tooling and project.json would never formally RTM and be supported. Anyone with a project.json project would need to upgrade to Visual Studio 2017 at release or use VS code in order to access the supported RTM tooling for ASP.NET Core running on csproj. As Damian explained it, the csproj changes required core IDE changes in Visual Studio 2017 to be possible. These changes would not / could not be brought back into VS 2015. This is where I start to feel a little left out in the cold by Microsoft. Fair enough, the tooling was preview, but we’ve backed the new and supported ASP.NET Core early, with the direct assumption we had a path forwards on the existing IDE version. Would I have started so early with a production system using ASP.NET Core if we had known our team will need to plan and handle a move to VS 2017 to gain tooling support? Perhaps not. I’m still a huge supporter of the new framework and we’re able to run our services inside Docker, on Linux, which has some great advantages for us. The deployment possibilities this has opened up to us is a key advantage of ASP.NET Core and one I hope to explore on this blog soon. Perhaps it’s just me that missed the point until quite late that the csproj change essentially made ASP.NET Core a VS 2017 product only.

A good demonstration of how the change effects early adopters is with open source projects such as the Humanitarian Toolbox allReady project, to which I contribute regularly. Here we have a real-world ASP.NET Core application which started it’s development way back in the early days of ASP.NET Core. allReady has moved through the various beta, release candidate and finally RTM versions of ASP.NET Core. A journey which has been complicated and painful at times due to some breaking changes. It was an accepted journey, given we were working with software still under development, and while I don’t think anyone expected quite so many twists and turns, the team ducked and weaved through them. The issue of the demise of project.json along with the Visual Studio 2017 release, does pose some logistical issues for the project team though. We’re actively discussing in an issue how and when we want to make the switch by migrating to csproj. We’re slightly stuck between a rock and a hard place. On one hand, we’re on unsupported tooling and also run the risk of new contributors opening the solution in VS 2017 and being migrated too early – leaving them unable to commit back to the project. On the other hand, if we migrate now, do we risk loosing contributors who aren’t in a position to, or willing to, upgrade to Visual Studio 2017 at this time? Agreed, they can still use VS Code or a community edition of Visual Studio 2017 if the concern is around licensing, but this still puts constraints on the ease of entry which we very much try to avoid. With allReady we’ll have to migrate fairly soon to avoid contributors who move to VS 2017 and don’t keep VS 2015 installed side-by-side from finding themselves unable to contribute any further. 

I feel slightly aggrieved that despite using the LTS supported version, we’re forced into a full IDE version upgrade in order to continue using that version. It slightly blurs the lines of how I feel a supported product should work. Microsoft have chosen the safer and arguably easier road for themselves which is to avoid putting even a basic and time limited project.json tooling experience into the wild under some form of support. This would have provided greater time for teams to embrace and migrate to csproj at their own speed. The project.json format is a really key part of the structure of ASP.NET Core projects built to date. Simply pulling that piece out from under the earlier adopters doesn’t sit quite right with me. I’m sure many discussions were had, compromises agreed, management decisions made that led to the final agreement to in effect, force the rapid death of project.json. Putting my Microsoft hat on, I can see why this makes things a lot easier for them in the long run. I’ve been fairly accepting of the churn we saw during the final phases leading up to RTM for ASP.NET Core, appreciating that in the end it was to give us a more suitable final product. This has been the one issue that I find myself less able to accept without a little annoyance clouding my thoughts. It’ll be nice to just get it behind us now and move forward without having to consider an impending change around the corner.

One key thing I’m conscious of loosing with the new csproj format is the simplicity of debugging into the ASP.NET source code. Currently a simple addition to the global.json file allows us to include the source into a solution, instead of using the Nuget supplied package. This has been something I’ve taken advantage of many times to learn more about the internal workings of MVC for example or to understand why my application is behaving in a certain way. I believe some level of support is being looked at to keep this functionality and an open and current discussion is ongoing on GitHub to continue to enable a source debugging experience. Initially this doesn’t sound quite a simple and painless as the solution I’ve been able to use to date. I hope we can get to a point where debugging the source is similar to the experience that the current json based format supports.

So, there you have it, my thoughts around project.json laid bare for (probably) a final time as the much loved project.json file moves closer to being a short lived part of .NET history. Visual Studio 2017 is pretty much the final and definitive nail in its coffin. While I have a slightly bitter taste in my mouth, don’t get me wrong, I’m still massively excited by ASP.NET Core in general and thankful that Microsoft are putting great effort into building an open platform for the future. I’m already excited about version 2.0 and I’m also keen to start working with Visual Studio 2017 both at home and at work. I expect to start doing so over the coming weeks and something I’ll be experiencing is how a real-world migration to csproj works.

Looking to end on a more positive note – besides the csproj issue – I am looking forward to VS 2017. Here are just a couple of initial features that I like the look of in Visual Studio 2017 from the information I’ve seen so far.

  1. The new, more rapid installation process does sound nice. Granted, once installed I don’t find myself doing installs too often, but it does seem to simplify the removal footprint as well.
  2. Various other performance related improvements and new configuration options promise to make working with solutions faster and easier than ever before. It’ll be interesting to see if those are noticeable or not.
  3. The new Git integrations within VS 2017 look nice. Any time I can save by not having to switch out of Visual Studio is very welcome.
  4. Live unit testing is a feature which I would like to take advantage of. Limited to the Enterprise license though, this may not be seen by everyone. It offers the continuous running of unit tests in the background, giving instant feedback on breaking changes as code is written. This sounds like it will improve productivity and generally make working on complex projects an easier experience.
  5. Finally I like the concept of the Code Style feature, which looks to allow a project level specification of coding standards that should be applied. Any deviance from the standards will result in compiler warnings to help developers quickly remain consistent. This feels like a nice enhancement to keep teams using a common structure in their code which can only help readability between team members. It’ll be interesting if this can assist with open-source projects like allReady as well.

Over the coming weeks I’ll be trying out the features that are available to me, and hopefully reaping the benefits they bring. After reading this post you could be forgiven for thinking I’m against VS 2017 or raining on it’s parade, but that’s not the case. I am always excited about new versions of products like this, and Visual Studio 2017 is no different. It promises to bring some great new features to developers everywhere. For me, my excitement is only slightly reduced by the gripes I have with the ASP.NET Core tooling but I’m hoping this is the final large piece of pain developers can expect on the early ASP.NET Core adoption path. I guess to end this post I’ll simply say – thank you project.json, you’ve been great!