Dot Net Core 6 - Progress

by samantha copeland on July 5, 2023

So far, I'm a month in on progress. I've got a couple of widgets as well as basic CMS functionality working. It's still very much a work in progress, consider the code pre-beta.

Even though I've been using .Net Core for a few years (.Net Core 3.1), it's been for APIs, so I haven't really encountered a lot of the things that are dramatically different between .Net 4.5 and the .Net Core variants of C#.

Since this is MVC, there are more blatant differences, such as IHtmlContent vs IHtmlString - each has ToString() available to them - IHtmlContent uses the default object implementation which is to produce the class name and not return the HTML content, which is what an IHtmlString implementation would do. Writing a custom extension method with a StringWriter fixes the issue, but it's a pain when this is the behavior of TagBuilder output.

Due to the nature of a CMS, it is frequently common to have two or more forms (ex a contact form and a search form) or even a model on a page, and due to this, it is frequently easier to use a typed HtmlHelper (HtmlHelper<TModel>) so you can create a one-off form with strongly typed form fields, this was pretty trivial in .Net 4.5, create a new instance and pass in a new context, and you're gold. In .Net Core, it's all tangled up in the new DI nature of .Net Core, I managed to do it, though. It involved studying the source code and unit tests provided for .Net 6, and basically it was a hack: create a Generic subclass of RazorPage<TModel>, have a property (IHtmlHelper<TModel> Html) in that sub class, tag it with the RazorInject attribute, and not only instantiate the class, but then pull IRazorPageActivator and IRazorViewEngine out of the RequestServices collection and run this instance through activation. Get this: it required a view, and guess, what, it could be any view, even an empty embedded partial view (which made life easier) which did not actually impact the ability for the desired markup to appear when used.

Another change from the prior versions: no more Linq-to-SQL. Due to some of the bulk operations, and performance concerns, I did make an attempt to port the existing extension library I had used over for Entity Framework, but got nowhere. Then I tried looking at nuget packages, but they generally had restrictive licenses, ex MIT if you were open source, but "pay me" if you had more than X revenue - I was not going to tie users of the CMS to having to check their revenue stream to verify if they could use this CMS. Then I found a Microsoft article: EF 7 targets .Net Core 6 (not .Net 7 like the name might make you think) - and now has batch operations (ExecuteUpdate and ExecuteDelete)! So now I've got a nice out of the box conversion for those batch operations.

There are also what amounts to two root folders, ContentRootPath and WebRootPath, and if you are trying to concatenate either of these with an absolute web path to a file (ex "/views/something.cshtml") and use Path.Combine, it will re-root the result, and you won't get back "c:\website\www\views\something.cshml" as you might expect, so when you do a File.Exists on the result, it will say False as the Combine will return "/views/something.cshtml". You'll need to use Path.Join, which will concatenate with the right folder delimiter, but it won't catch duplicate slashes, so you'll have to scrub those yourself.

There is no more Ajax helper, so no more Ajax.BeginForm - so I reverse engineered the resulting HTML markup to roll my own to continue with easy partial postbacks.

SQL 2008 is not supported by EF Core 6 or 7, I had tried using an existing MVC database to test migrated data, but once I attempted some reflection based dynamic sorting, it errored out. I then did some research, and apparently, baring use of some special packages, 2008 is not supported, so the minimum version of SQL Server is now 2012.