During the time of this writing, at work, I am currently in the process of migrating some .NET Framework Web Applications to .NET Core.
You might ask "But, Why?!" ...
and you are right to ask. We just migrated everything from SCCM to Intune in the cloud and I am planning to move those web apps, where we migrated the user base, to Azure as well. But that will be another Blog Post.
Before moving everything to the cloud, I want to make these very apps ready for the future. Microsoft just announced .NET 5 and will cut of some legacy stuff from .NET Framework. I don't know exactly what will be cut, but I really think that .NET Core will be the future of .NET.
But there is another reason as well, which is kind of personal. We host these web apps in IIS and therefore the whole async-await isn't working as expected due to IIS running in STA. Maybe I am doing something wrong, but I always had to execute async-awaits or even some ".GetAsync().Result" in a separate thread. So I had to work around it and wrote a little "Helper" that took a Function and executed it on a separate thread with manual synchronisation by a Barrier. It worked pretty well, but it was like that little spot on your back, that always itches but you cannot reach. It worked, it was kind of elegant, but it just did not feel right to me and I wanted to get rid of it.
ASP.NET Core solves this for me. Also I just want to try out something I didn't work with before. Curiosity may kill the cat, but it is what pushes us developers forward.
So here are some topics I encountered during the migration:
NuGet and indirect dependencies
The first I encountered was, that NuGet now resolves indirect dependencies and loads them for you, which I really love. I don't know, why it is not doing the same with .NET Framework. Still love it.
We used a lot of Linq2Sql in our code, which is just no longer available in .NET Core anymore. So I decided to at have look at EntityFramework. Using the DB-First Approach. "DB-Scaffold" created all the Entities in just a matter of seconds. So all that was left, was to replace all the Database Calls with Entity Framework Calls, which fortunately were not that much. The Linq2Sqls ".Where(x => x...)"-Expressions could still be used. So it was not that much effort.
Basically it boiled down to replacing the "DbContext.GetTable<TItem>()." with "EFContext.Items.".
It's no longer available, which you only get to know through an exception during runtime. So keep it in mind. You can Replace it with Task.Run().
The old application was using a federated authentication via Azure. So I was having a look into it and luckily this is already implemented in .NET Core. Even more so, it works better, than the previous solution, IF YOU stick to some rules, which I learned by not following them and then trying to figuring out for about 4h, why it did not work.
- DO NOT CHANGE THE CALLBACK PATH!
- DO NOT CHANGE THE CALLBACK PATH!
Why shouldn't I change the Callback Path?
I took a look inside the dependency assemblies and found a controller, that is spun up during authentication and listens to "/signin-oidc".
There is no ignoring of routes anymore. This was not a problem for me, but maybe some of you need this?
Also the MVC Routing is now done in the Startup.cs, but if you copied the Routing Class from your ASP.NET MVC Framework Application, then you can make it work, by just giving the static method, that was executed before to the routing setup in the Startup.cs. Some very little modification was necessary, but since my routing table there a quite big, I expected it to take a lot more time, than it took.
One of the main reasons for me personally was to make Async/Await work as it is intended to. Which it just does. So I can use this from now on.
Previously ASP.CORE web applications were hosted in a separate process, which now (with .NET Core 2.2) is no longer the case.
Make sure to give every .NET Core App its own ApplicationPool, otherwise you will get an error message "HTTP Error 500.0 - ANCM In-Process Handler Load Failure".
MVC Views are precompiled
Maybe this is not relevant to the most you, but I had built kind of a very specific CMS, which was using the availability of View-Files in different Folders to show you options to click on and navigate through the site.
With ASP.NET Core, the Views are precompiled and shipped in a "<Your-Project-Name>.Views.dll" containing types of your Views. Everything worked on my machine, because the files were there, but on the server after deploying, there was only one page with no options to click on.
Another problem then was, that the assembly is built AFTER your project-assembly and "linked" at runtime and it curiously is still a .NET Framework Assembly (or the tool i used to look into it, just does not know of .NET Core yet). Nevertheless, you will need to use "Assembly.LoadUnsafe()" if you want to take a look into it during runtime, which I needed.
Edit: as @eddyhaigh pointed out you can turn off pre-compilation for views.
PowerShell Remote Sessions
Since there is always confusion which NuGet-Package to take, I used "Microsoft.PowerShell.SDK".
The Powershell works fine out-of-the-box as long as you execute locally. But when you use it for remoting, it did not work initially. So after some debugging and googling I found a page, stating that on importing the session, the remotesigning needs to be active. It states, that you must have admin rights, which was not necessary in my case. I added the "Set-ExecutionPolicy RemoteSigned" before "New-PSSession ... " and it worked.
Also you will have to adjust the RuntimeIdentifier in the publishing profile to either "win10-x64" for Windows Server 2016+ or "win81-x64" for Windows Server 2012R2 (as of 2019-06-13, using .NET Core 2.2 and Microsoft.Management.Infrastructure 1.0.0 as Dependency).
So to make a long story short. It was quite a bit of work, but really far less than expected.
Has any of you ever done something similar and want to share some experience?
Top comments (3)
As of .Net Core 3 there are additional changes, wich are written here.
Mostly it is about ASP.Net Core but don‘t forget some breaking changes in Azure Functions, wich have cost today.
You can turn off precompiling of views in the csproj stackoverflow.com/questions/507785...
I already worked around that, but thanks a lot. If I would have known it before ... 👍
Actually I have gotten to like the Compiler to check my views before they are published.
Less runtime errors 💪