Want to build a .NET Application? Check SSW's Web Application / API consulting page.
It's common for .NET solutions to have multiple projects, for example an API and a UI. Did you know Microsoft Visual Studio and Jetbrains Rider allow you to start as many projects as you want with a single click?
When developing software, we implement a dependency injection centric architecture.
All the DLL references and files needed to create a setup.exe should be included in your solution. However, just including them as solution items is not enough, they will look very disordered (especially when you have a lot of solution items). And from the screenshot below, you might be wondering what the _Instructions.docx is used for...
The traditional .sln format has served developers well for years, but it comes with significant limitations that impact productivity and collaboration, especially as projects grow larger and teams expand. The modern SLNX format solves these problems with a clean XML-based structure.
When programming in a Dot Net environment it is a good practice to remove the default imports that aren't used frequently in your code.
This is because IntelliSense lists will be harder to use and navigate with too many imports. For example if in VB.NET, Microsoft.VisualBasic would be a good item to have in the imports list, because it will be used in most areas of your application.
The designer should be used for all GUI design. Controls will be dragged and dropped onto the form and all properties should be set in the designer, e.g.
There are many ways to reference images in ASP.NET. There are 2 different situations commonly encountered by developers when working with images:
Incrementally as we do more and more .NET projects, we discover that we are re-doing a lot of things we've done in other projects. How do I get a value from the config file? How do I write it back? How do I handle all my uncaught exceptions globally and what do I do with them?
Figure: Keep these two versions consistent If you are not using the GAC, it is important to keep AssemblyVersion, AssemblyFileVersion and AssemblyInformationalVersionAttribute the same, otherwise it can lead to support and maintenance nightmares. By default these version values are defined in the AssemblyInfo file. In the following examples, the first line is the version of the assembly and the second line is the actual version display in file properties.
How do you get a setting from a configuration file? What do you do when you want to get a setting from a registry, or a database? Everyone faces these problems, and most people come up with their own solution. We used to have a few different standards, but when Microsoft released the Configuration Application Blocks, we have found that working to extend it and use it in all our projects saves us a lot of time! Use a local configuration file for machine and/or user specific settings (such as a connection string), and use a database for any shared values such as Tax Rates.
See how we configured this reset default settings functionality with the Configuration Block in the .NET Toolkit
In almost every application we have a user settings file to store the state of the application. We want to be able to reset the settings if anything goes wrong.
See how we configured this reset default settings functionality with the Configuration Block in the .NET Toolkit
There are 2 type of connection strings. The first contains only address type information without authorization secrets. These can use all of the simpler methods of storing configuration as none of this data is secret.
When deploying an Azure hosted application we can use Azure Managed Identities to avoid having to include a password or key inside our connection string. This means we really just need to keep the address or url to the service in our application configuration. Because our application has a Managed Identity, this can be treated in the same way as a user's Azure AD identity and specific roles can be assigned to grant the application access to required services.
This is the preferred method wherever possible, because it eliminates the need for any secrets to be stored. The other advantage is that for many services the level of access control available using Managed Identities is much more granular making it much easier to follow the Principle of Least Privilege.
If you have to use some sort of secret or key to login to the service being referenced, then some thought needs to be given to how those secrets can be secured. Take a look at Do you store your secrets securely to learn how to keep your secrets secure.
In .NET 5 we can use Azure Key Vault to securely store our connection strings away from prying eyes.
Azure Key Vault is great for keeping your secrets secret because you can control access to the vault via Access Policies. The access policies allows you to add Users and Applications with customized permissions. Make sure you enable the System assigned identity for your App Service, this is required for adding it to Key Vault via Access Policies.
You can integrate Key Vault directly into your ASP.NET Core application configuration. This allows you to access Key Vault secrets via IConfiguration.
public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>{webBuilder.UseStartup<Startup>().ConfigureAppConfiguration((context, config) =>{// To run the "Production" app locally, modify your launchSettings.json file// -> set ASPNETCORE_ENVIRONMENT value as "Production"if (context.HostingEnvironment.IsProduction()){IConfigurationRoot builtConfig = config.Build();// ATTENTION://// If running the app from your local dev machine (not in Azure AppService),// -> use the AzureCliCredential provider.// -> This means you have to log in locally via `az login` before running the app on your local machine.//// If running the app from Azure AppService// -> use the DefaultAzureCredential provider//TokenCredential cred = context.HostingEnvironment.IsAzureAppService() ?new DefaultAzureCredential(false) : new AzureCliCredential();var keyvaultUri = new Uri($"https://{builtConfig["KeyVaultName"]}.vault.azure.net/");var secretClient = new SecretClient(keyvaultUri, cred);config.AddAzureKeyVault(secretClient, new KeyVaultSecretManager());}});});
✅ Good example - For a complete example, refer to this sample application
Tip: You can detect if your application is running on your local machine or on an Azure AppService by looking for the WEBSITE_SITE_NAME environment variable. If null or empty, then you are NOT running on an Azure AppService.
public static class IWebHostEnvironmentExtensions{public static bool IsAzureAppService(this IWebHostEnvironment env){var websiteName = Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME");return string.IsNullOrEmpty(websiteName) is not true;}}
In order to access the secrets in Key Vault, you (as User) or an Application must have been granted permission via a Key Vault Access Policy.
Applications require at least the LIST and GET permissions, otherwise the Key Vault integration will fail to retrieve secrets.
Figure: Key Vault Access Policies - Setting permissions for Applications and/or Users
Azure Key Vault and App Services can easily trust each other by making use of System assigned Managed Identities. Azure takes care of all the complicated logic behind the scenes for these two services to communicate with each other - reducing the complexity for application developers.
So, make sure that your Azure App Service has the System assigned identity enabled.
Once enabled, you can create a Key Vault Access policy to give your App Service permission to retrieve secrets from the Key Vault.
Figure: Enabling the System assigned identity for your App Service - this is required for adding it to Key Vault via Access Policies
Adding secrets into Key Vault is easy.
Figure: Creating the SqlConnectionString secret in Key Vault.
Figure: SqlConnectionString stored in Key Vault
Note: The ApplicationSecrets section is indicated by "ApplicationSecrets--" instead of "ApplicationSecrets:".
As a result of storing secrets in Key Vault, your Azure App Service configuration (app settings) will be nice and clean. You should not see any fields that contain passwords or keys. Only basic configuration values.
Figure: Your WebApp Configuration - No passwords or secrets, just a name of the Key vault that it needs to access
In .NET 1.1 we used to store our connection string in a configuration file like this:
<configuration><appSettings><add key="ConnectionString" value ="integrated security=true;data source=(local);initial catalog=Northwind"/></appSettings></configuration>
...and access this connection string in code like this:
SqlConnection sqlConn =new SqlConnection(System.Configuration.ConfigurationSettings.AppSettings["ConnectionString"]);
❌ Historical example - Old ASP.NET 1.1 way, untyped and prone to error
In .NET 2.0 we used strongly typed settings classes:
Step 1: Setup your settings in your common project. E.g. Northwind.Common
Figure: Settings in Project Properties
Step 2: Open up the generated App.config under your common project. E.g. Northwind.Common/App.config
Step 3: Copy the content into your entry applications app.config. E.g. Northwind.WindowsUI/App.config The new setting has been updated to app.config automatically in .NET 2.0
<configuration><connectionStrings><add name="Common.Properties.Settings.NorthwindConnectionString"connectionString="Data Source=(local);Initial Catalog=Northwind;Integrated Security=True"providerName="System.Data.SqlClient" /></connectionStrings></configuration>
...then you can access the connection string like this in C#:
SqlConnection sqlConn =new SqlConnection(Common.Properties.Settings.Default.NorthwindConnectionString);
❌ Historical example - Access our connection string by strongly typed generated settings class...this is no longer the best way to do it
It is good to store program settings in an .xml file. But developers rarely worry about future schema changes and how they will inform the user it is an old schema.
What is wrong with this?
Both controls can represent XML hierarchical data and support Extensible Stylesheet Language (XSL) templates, which can be used to transform an XML file into a the correct format and structure. While TreeView can apply Styles more easily, provide special properties that simplify the customization of the appearance of elements based on their current state.
There are three types of settings files that we may need to use in .NET :
Windows Communication Foundation (WCF) extends .NET Framework to enable building secure, reliable & interoperable Web Services.
WCF demonstrated interoperability with using the Web Services Security (WSS) including UsernameToken over SSL, UsernameToken for X509 Certificate and X509 Mutual Certificate profiles.
Did you know if you are using DataSets throughout your application (not data readers) then you don't need to have any code about connection opening or closing.
Some say it is better to be explicit. However the bottom line is less code is less bugs.
Each class definition should live in its own file. This ensures it's easy to locate class definitions outside the Visual Studio IDE (e.g. SourceSafe, Windows Explorer)
EF Core provides a powerful way to interact with databases using .NET, but poor query optimization can lead to significant performance issues. Developers often fall into common pitfalls like inserting data in a loop, running excessive queries, or keeping track of too many entities. By following these best practices, you can improve performance and reduce database load.
Instead of images sitting all around the solution, we put all the images in the same folder.