Update: Due to new personal commitments and more work commitments in 2021, I wasn’t able to make much progress with my weekly C# A-Z series on dev.to/shahedc. For now, I’ll focus on some new content for my regular blog (this blog, WakeUpAndCode.com) and hope to revisit the A-Z series with .NET 6.
Original Post:
I published my first ASP .NET Core A-Z series on WakeUpAndCode.com back in 2019, from January to June 2019. I followed this with a new A-Z series in 2020, simultaneously mirroring the posts on dev.to as well.
Going forward, my next A-Z series will cover 26 topics covering various C# language features. The C# A-Z series will be featured exclusively on my dev.to site under the .NET org:
Meanwhile, this site (WakeUpAndCode.com) will continue to feature new ASP .NET Core content based on .NET 5, Blazor and more! To get a sneak peak of what’s to come, check out my guest appearance on the .NET Docs Show (livestreamed Dec 7, 2020). You may jump ahead to 58:05 in the video for the sneak peek:
The above video teases my upcoming cinematic visualizer app, which will allow the end user to connect the dots within a cinematic universe, e.g. the Marvel Cinematic Universe. The source code will allow any .NET developer to learn more about C# and .NET 5, ASP .NET Core, Entity Framework, Azure App Service, Bot Framework, Azure Functions, and more!
The goal of the web app is to make use of all 3 project styles available in ASP .NET Core:
MVC (Model View Controller)
Razor Pages
Blazor
Developers frequently ask the developer community (and Microsoft) whether a particular web project type is preferred over the other. Last year’s blog series built upon the NetLearner web app by duplicating identical functionality across all three project types. This year, the cinematic visualizer app will attempt to use each project type of something specific.
MVC for data entry
Razor Pages for the Portal site
Blazor for the highly interactive portion
The above choices aren’t necessarily prescriptive for the type of web apps they will demonstrate. However, they should provide a starting point when developing ASP .NET Core web applications.
As promised, below is the initial release of the ASP .NET Core 3.1 A-Z ebook. This combines the 26 blog posts from the series of ASP .NET Core articles on this website.
You can find the complete ebook on GitHub using one of the links below:
The cover image was generated using the Canva mobile app
The 2020 eBook is still a work in progress 🙂
I’m using my Worker Service sample to auto-generate Word documents from each blog post by converting each article’s HTML into Word format using MariGold.OpenXHTML
After some tweaking, images have been manually resized using a Macro in the Word document. Automatic resizing doesn’t seem to work between HTML to Word conversions, but feel free to submit a Pull Request if you have suggestions on how to fix it.
Animated GIF images don’t work in the ebook, so a link to each original source has been included where they appear in a few chapters.
This is the twenty-sixth of a new series of posts on ASP .NET Core 3.1 for 2020. In this series, we’ve covered 26 topics over a span of 26 weeks from January through June 2020, titled ASP .NET Core A-Z! To differentiate from the 2019 series, the 2020 series mostly focused on a growing single codebase (NetLearner!) instead of new unrelated code snippets week.
Z is for Zero-Downtime* Web Apps for ASP .NET Core
If you’ve made it this far in this ASP .NET Core A-Z series, hopefully you’ve learned about many important topics related to ASP .NET Core web application development. As we wrap up this series with a look at tips and tricks to attempt zero-downtime, this last post itself has its own lettered A-F mini-series: Availability, Backup & Restore, CI/CD, Deployment Slots, EF Core Migrations and Feature Flags.
NOTE: While it may not be possible to get 100% availability 24/7/365, you can ensure a user-friendly experience free from (or at least with minimal) interruptions, by following a combination of the tips and tricks outlined below. This write-up is not meant to be a comprehensive guide. Rather, it is more of an outline with references that you can follow up on, for next steps.
Availability
To improve the availability of your ASP .NET Core web app running on Azure, consider running your app in multiple regions for HA (High Availability). To control traffic to/from your website, you may use Traffic Manager to direct web traffic to a standby/secondary region, in case the primary region is unavailable.
Consider the following 3 options when running a web app in multiple Azure regions. In these scenarios, the primary region is always active and the secondary region may be passive (as a hot or cold standby) or active. When both are active, web requests are load-balanced between the two regions.
Options
Primary Region
Secondary Region
A
Active
Passive, Hot Standby
B
Active
Passive, Cold Standby
C
Active
Active
For more information on achieving High Availability (HA) in multiple regions, check out the official docs at:
If you’re running your web app in a Virtual Machine (VM) instead of Azure App Service, you may also consider Availability Sets. This helps build redundancy in your Web App’s architecture, when you have 2 or more VMs in an Availability Set. For added resiliency, use Azure Load Balancer with your VMs to load-balance incoming traffic. As an alternative to Availability Sets, you may also use Availability Zones to counter any failures within a datacenter.
Backup & Restore
Azure’s App Service lets you back up and restore your web application, using the Azure Portal or with Azure CLI commands. Note that this requires your App Service to be in at least the Standard or Premium tier, as it is not available in the Free/Shared tiers. You can create backups on demand when you wish, or schedule your backups as needed. If your site goes down, you can quickly restore your last good backup to minimize downtime.
NOTE: You may use the new Snapshots feature to “automatically create perioidic restore points of your app”. However, this feature is only available in a Premium App Service Plan.
In addition to the app itself, the backup process also backs up the Web App’s configuration, file contents and the database connected to your app. Database types include SQL DB (aka SQL Server PaaS), MySQL and PostgreSQL. Note that these backups include a complete backup, and not incremental/delta backups.
Continuous Integration & Continuous Deployment
In the previous post, we covered CI/CD with YAML pipelines. Whether you have to fix an urgent bug quickly or just deploy a planned release, it’s important to have a proper CI/CD pipeline. This allows you to deploy new features and fixes quickly with minimal downtime.
Whether you’re deploying your Web App to App Service for the first time or the 100th time, it helps to test out your app before releasing to the public. Deployment slots make it easy to set up a Staging Slot, warm it up and swap it immediately with a Production Slot. Swapping a slot that has already been warmed up ahead of time will allow you to deploy the latest version of your Web App almost immediately.
Note that Deployment Slots are only available in Standard, Premium or Isolated App Service tiers, not in the Free/Shared tiers. You can combine Deployment Slots with your CI/CD pipelines to ensure that your automated deployments end up in the intended slots.
EF Core Migrations in Production
We covered EF Core Migrations in a previous post, which is one way of upgrading your database in various environments (including production). But wait, is it safe to run EF Core Migrations in a production environment? Even though you can use auto-generated EF Core migrations (written in C# or outputted as SQL Scripts), you may also modify your migrations for your needs.
I would highly recommend reading Jon P Smith‘s two-part series on “Handling Entity Framework Core database migrations in production”:
What you decide to do is up to you (and your team). I would suggest exploring the different options available to you, to ensure that you minimize any downtime for your users. For any non-breaking DB changes, you should be able to migrate your DB easily. However, your site may be down for maintenance for any breaking DB changes.
Feature Flags
Introduced by the Azure team, the Microsoft.FeatureManagement package allows you to add Feature Flags to your .NET application. This enables your web app to include new features that can easily be toggled for various audiences. This means that you could potentially test out new features by deploying them during off-peak times, but toggling them to become available via app configuration.
To install the package, you may use the following dotnet command:
By combining many/all of the above features, tips and tricks for your Web App deployments, you can release new features while minimizing/eliminating downtime. If you have any new suggestions, feel free to leave your comments.
This is the seventeenth of a new series of posts on ASP .NET Core 3.1 for 2020. In this series, we’ll cover 26 topics over a span of 26 weeks from January through June 2020, titled ASP .NET Core A-Z! To differentiate from the 2019 series, the 2020 series will mostly focus on a growing single codebase (NetLearner!) instead of new unrelated code snippets week.
Query Tags were introduced in Entity Framework (EF) Core 2.2, as a way to associate your LINQ Queries with SQL Queries. This can be useful when browsing log files during debugging and troubleshooting. This article explains how Query Tags work, how to find the output and how to format the text strings before displaying them.
NOTE: You may have read that Query Types have been renamed to entities without keys, but please note that Query Types (introduced in EF Core 2.1) are not the same thing as Query Tags.
As of ASP .NET Core 3.0 Preview 1, EF Core must be installed separately via NuGet (e.g. v3.0.0-preview4.19216.3), as it is no longer included with the ASP .NET Core shared framework. Also, the dotnet ef tool has to be installed as a global/local tool, as it is no longer part of the .NET Core SDK. For more information, see the official announcement for Preview 4, where it was first mentioned:
The NetLearner source code includes a C# model called LearningResource, with a few basic fields:
public class LearningResource
{
public int Id { get; set; }
[DisplayName("Resource")]
public string Name { get; set; }
[DisplayName("URL")]
[DataType(DataType.Url)]
public string Url { get; set; }
public int ResourceListId { get; set; }
[DisplayName("In List")]
public ResourceList ResourceList { get; set; }
[DisplayName("Feed Url")]
public string ContentFeedUrl { get; set; }
public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; }
}
A collection of LearningResource objects are defined as a DbSet in the LibDbContext database context class:
public DbSet<LearningResource> LearningResources { get; set; }
The GetTop() service method in the LearningResourceService class defines a Query Tag with the TagWith() method, as shown below:
public async Task<List<LearningResource>> GetTop(int topX)
{
var myItems =
(from m in _context.LearningResources
.Include(r => r.ResourceList)
.TagWith($"This retrieves top {topX} Items!")
orderby m.Id ascending
select m)
.Take(topX);
return (await myItems.ToListAsync());
}
In the above query, the TagWith() method takes a single string value that can they be stored along with wherever the resultant SQL Queries are logged. This may include your persistent SQL Server database logs or Profiler logs that can be observed in real-time. It doesn’t affect what gets displayed in your browser.
This can be triggered by visiting the LearningResourcesController’s GetTop method, while passing in an integer value for topX. This causes the Index view to return the top “X” learning resources in a list. For example: if topX is set to 5, the resulting view will display 5 items in the displayed list.
Observing Query Tags in Logs
Using the SQL Server Profiler tool, the screenshot below shows how the Query Tag string defined in the code is outputted along with the SQL Query. Since topX is set to 5 in this example, the final string includes the value of topX inline within the logged text (more on formatting later).
From the code documentation, the TagWith() method “adds a tag to the collection of tags associated with an EF LINQ query. Tags are query annotations that can provide contextual tracing information at different points in the query pipeline.”
Wait a minute… does it say “collection of tags”…? Yes, you can add a collection of tags! You can call the method multiple times within the same query. In your code, you could call a string of methods to trigger cumulative calls to TagWith(), which results in multiple tags being stored in the logs.
Formatting Query Tag Strings
You may have noticed that I used the $ (dollar sign) symbol in my Query Tag samples to include variables inline within the string. In case you’re not familiar with this language feature, the string interpolation feature was introduced in C# 6.
$"This retrieves top {topX} Items!"
You may also have noticed that the profiler is showing the first comment in the same line as the leading text “exec sp_executesql” in the Profiler screenshot. If you want to add some better formatting (e.g. newline characters), you can use the so-called verbatim identifier, which is essentially the @ symbol ahead of the string.
@"This string has more
than 1 line!"
While this is commonly used in C# to allow newlines and unescaped characters (e.g. backslashes in file paths), some people may not be aware that you can use it in Query Tags for formatting. This operator allows you to add multiple newlines in the Query Tag’s string value. You can combine both operators together as well.
@$"This string has more than 1 line
and includes the {topX} items!"
In an actual example, a newline produces the following results:
The above screenshot now shows multiline text from a Query Tag using newlines within the text string.
This is the fifth of a new series of posts on ASP .NET Core 3.1 for 2020. In this series, we’ll cover 26 topics over a span of 26 weeks from January through June 2020, titled ASP .NET Core A-Z! To differentiate from the 2019 series, the 2020 series will mostly focus on a growing single codebase (NetLearner!) instead of new unrelated code snippets week.
In my 2018 series, we covered EF Core Migrations to explain how to add, remove and apply Entity Framework Core Migrations in an ASP .NET Core web application project. In this article, we’ll continue to look at the newer 2020 NetLearner project, to identify entities represented by C# model classes and the relationships between them.
NOTE: Please note that NetLearner is a work in progress as of this writing, so its code is subject to change. The UI web apps still needs work (and will be updated at a later date) but the current version has the following models with the relationships shown below:
Classes and Relationships
The heart of the application is the LearningResource class. This represents any online learning resource, such as a blog post, single video, podcast episode, ebook, etc that can be accessed with a unique URL.
public class LearningResource
{
public int Id { get; set; }
[DisplayName("Resource")]
public string Name { get; set; }
[DisplayName("URL")]
[DataType(DataType.Url)]
public string Url { get; set; }
public int ResourceListId { get; set; }
[DisplayName("In List")]
public ResourceList ResourceList { get; set; }
public ContentFeed ContentFeed { get; set; }
public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; }
}
The ContentFeed class represents the RSS Feed (or channel information) for an online resource, a URL that can be used to retrieve more information about the online resource, if available.
public class ContentFeed
{
public int Id { get; set; }
[DisplayName("Feed URL")]
public string FeedUrl { get; set; }
public int LearningResourceId { get; set; }
public LearningResource LearningResource { get; set; }
}
The ResourceList class represents a logical container for learning resources in the system. It is literally a list of items, where the items are your learning resources.
public class ResourceList
{
public int Id { get; set; }
public string Name { get; set; }
public List<LearningResource> LearningResources { get; set; }
}
The TopicTag class represents a single “tag” value that can be used to categorize online resources. Possibly values could be “.NET Core”, “ASP.NET Core” and so on.
public class TopicTag
{
public int Id { get; set; }
[DisplayName("Tag")]
public string TagValue { get; set; }
public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; }
}
At this point, you may have noticed both the LearningResource and TopicTag classes contain a List<T> property of LearningResourceTopicTag. If you browse the database diagram, you will notice that this table appears as a connection between the two aforementioned tables, to establish a many-to-many relationship. (more on this later)
The following diagram shows an example of how the a LearningResource (e.g. link to a doc/video) is a part of a ResourceList, while each LearningResource also has a link back to its root site, channel or RSS feed (via ContentFeed).
One to One
Having looked through the above entities and relationships, we can see that each LearningResource has a ContentFeed. This is an example of a 1-to-1 relationship. For example:
Learning Resource = Wake Up and Code! blog site
Content Feed = RSS Feed for blog site
In the two classes, we see the following code:
public class LearningResource { public int Id { get; set; }
[DisplayName("Resource")] public string Name { get; set; }
[DisplayName("URL")] [DataType(DataType.Url)] public string Url { get; set; }
public int ResourceListId { get; set; } [DisplayName("In List")] public ResourceList ResourceList { get; set; }
public ContentFeed ContentFeed { get; set; }
public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; } }
public class ContentFeed { public int Id { get; set; }
[DisplayName("Feed URL")] public string FeedUrl { get; set; }
public int LearningResourceId { get; set; } public LearningResource LearningResource { get; set; } }
Each Learning Resource has a corresponding Content Feed, so the LearningResource class has a property for ContentFeed. That’s pretty simple. But in the ContentFeed class, you don’t necessarily need a property pointing back to the LearningResource . In fact, all you need is a LearningResourceId property. EF Core will ensure that LearningResource.Id points to ContentFeed.LearningResourceId in the database. But to help with object-property navigation in your code, it is useful to include an actual LearningResource object in the ContentFeed class to point back to LearningResource.
Another way of looking at the One-to-One relationship is to view the constraints of each database entity in the visuals below. Note that both tables have an Id field that is a Primary Key (inferred by EF Core) while the ContentFeeds table also has a Foreign Key for the LearningResourceId field used for the constraint in the relationship.
One to Many
Next, let’s take a look at the One-to-Many relationship for each ResourceList that has zero or more LearningResources. For example:
Resource List = ASP .NET Core Blogs (parent container)
Learning Resource = ASP .NET Core A-Z Blog Series (single URL)
In the two classes, we see the following code:
public class ResourceList { public int Id { get; set; }
public string Name { get; set; }
public List<LearningResource> LearningResources { get; set; } }
public class LearningResource { public int Id { get; set; }
[DisplayName("Resource")] public string Name { get; set; }
[DisplayName("URL")] [DataType(DataType.Url)] public string Url { get; set; }
public int ResourceListId { get; set; } [DisplayName("In List")] public ResourceList ResourceList { get; set; }
public ContentFeed ContentFeed { get; set; }
public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; } }
Each Resource List has zero or more Learning Resources, so the ResourceList class has a List<T> property for LearningResources. This is even simpler than the previously described 1-to-1 relationship. In the LearningResource class, you don’t necessarily need a property pointing back to the ResourceList. But once again, to help with object-property navigation in your code, it is useful to include an actual ResourceList object in the LearningResource class to point back to ResourceList.
Another way of looking at the One-to-Many relationship is to view the constraints of each database entity in the visuals below. Note that both tables have an Id field that is a Primary Key (once again, inferred by EF Core) while the ResourceLists table also has a Foreign Key for the ResourceListsId field used for the constraint in the relationship.
Many to Many
Finally, let’s also take a look at a Many-to-Many relationship, for each TopicTag and LearningResource, either of which can have many of the other. For example:
Topic Tag = “ASP .NET Core” (tag as a text description)
Learning Resource = Specific blog post on site (single URL)
This relationship is a little more complicated than all of the above, as we will need a “join table” to connect the two tables in question. Not only that, we will have to describe the entity in the C# code with connections to both tables we would like to connect with this relationship.
In the two classes we would like to connect, we see the following code:
public class TopicTag
{
public int Id { get; set; }
[DisplayName("Tag")]
public string TagValue { get; set; }
public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; }
}
public class LearningResource { public int Id { get; set; }
[DisplayName("Resource")] public string Name { get; set; }
[DisplayName("URL")] [DataType(DataType.Url)] public string Url { get; set; }
public int ResourceListId { get; set; } [DisplayName("In List")] public ResourceList ResourceList { get; set; }
public ContentFeed ContentFeed { get; set; }
public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; } }
public class LearningResourceTopicTag
{
public int LearningResourceId { get; set; }
public LearningResource LearningResource { get; set; }
public int TopicTagId { get; set; }
public TopicTag TopicTag { get; set; }
}
This special class has the following properties:
LearningResourceId: integer value, pointing back to LearningResource.Id
LearningResource: optional “navigation” property, reference back to connected LearningResource entity
TopicTagId: integer value, pointing back to TopicTag.Id
TopicTag: optional “navigation” property, reference back to connected TopicTag entity
To learn more about navigation properties, check out the official docs at:
Another way of looking at the Many-to-Many relationship is to view the constraints of each database entity in the visuals below. Note that the two connected tables both have an Id field that is a Primary Key (yes, inferred by EF Core!) while the LearningResourceTopicTag table has a Composite Key for the TopicTagId and LearningResourceId fields used for the constraints in the relationship.
The composite key is described in the LibDbContext class inside the OnModelCreating() method:
public class LibDbContext : IdentityDbContext
{
...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
...
modelBuilder.Entity<LearningResourceTopicTag>()
.HasKey(lrtt => new { lrtt.LearningResourceId, lrtt.TopicTagId });
}
}
Here, the HasKey() method informs EF Core that the entity LearningResourceTopicTag has a composite key defined by both LearningResourceId and TopicTagId.
References
For more information, check out the list of references below.