.NET Core

Azure B2C: Customize Layouts

In the post ASP.NET Core with Azure B2C Auth we did a walkthrough of setting up the basics of Azure B2C and creating a new application that used our new B2C setup for auth. This post is going to be using that same setup to show how to replace the Microsoft provided pages for sign up/sign in with your own custom pages.

Custom Page Hosting

Our custom page needs to be hosted somewhere public with CORS enabled. If the test application was hosted somewhere public we could just us it, but since it is running on localhost that isn’t currently an option. We are going to use Azure Blob storage for hosting in this example.

Create A Storage Account

From the Azure Portal select Storage accounts.

Click the Add button.

Next, on the Create storage account page, I used a new resource group and tried storage accounts names until I found an unused one. For the rest of the fields, I took the defaults and then clicked Review + create.

On the review + create page it takes a few seconds for the account to be validated. After validation click the Create button.

After the storage deployment is complete click the Go to resource button.

Setup Blob storage

The above will land you on the Overview page for the new storage account. Select CORS from the menu.

Since this is just a test I’m allowing everything under the Blob service, for a real deploy I would recommend only allowing the values you expect requests from. After setting your values click the Save button.

Back on the storage menu on the right side of the screen select Blobs.

Click the + Container button to create a new blob storage container.

In the new container, page enter a name and select your public access level. I’m going with the most permissive access level, for a production system you will need to evaluate the appropriate access level for your use case. Click OK when done.

When done you will be returned to your list of containers. Click on the container that was just created to view the details.

Create a custom page

Now that we have our blob storage we need to create the HTML page that we want to to use instead of the default. The following is the code for the page I’m going to use. It is going to be super ugly as I’m not going to use any styling.

<!DOCTYPE html>
<html>
  <head>
    <title>Custom Page!</title>
  </head>
  <body>
    <h1>Custom Page!</h1>
    <div id="api"></div> 
  </body>
</html>

You can make this page look however you want, but it will always need the div with the ID of API as this is where Azure will inject the elements that actually handle the signup/sign in. Save your page.

Upload custom page to blob storage

Back in Azure click the Upload button and then select your file and click the Upload button.

After upload, you will be returned to the list of items in your current container. Click the item you just created. In the details copy the URL as we are going to need it to give B2C the location of our custom page.

B2C use custom page

In your portal head back to your Azure AD B2C page and select User flows.

Select the flow you want to use the custom page for. In our case, we are going to be using the flow for Sign up and sign in.

In the Customize section select Page layouts.

In the bottom of the page select Yes for  Use custom page content and past the link to your blob from above into the Custome page URI field and click Save.

Try it out

With all of the above setup you can now go back to the application using B2C and hit your sign in link and you will see your custom page. Here is what the one in the sample looks like.

Obviously, this example is really ugly and isn’t something you would do to your users, but it gives you the basic idea of how to use a custom page.

Wrapping Up

Hopefully the above will help you get started with customizing you B2C related pages to give your users a more consistent look and feel. The above only uploaded an HTML page to blob storage, but you could also upload a CSS file or any other assets you need. Also, don’t forget if your site is publicly accessible the assets can be stored with the rest of your application in that is appropriate, just remember to configure CORS to allow requests from Azure.

If you want more information on this topic check out the official docs from Microsoft on the subject.

Azure B2C: Customize Layouts Read More »

ASP.NET Core with Azure B2C Auth

I ran into a previous co-work a while back and they were talking about using Azure’s B2C for authentication on their apps. It sounded like a good solution. This blog post is going to cover getting the Azure B2C setup and will cover creating a sample application that will use B2C for authorization.

Create Azure Active Directory B2C

This all assumes you already have an Azure account. If you don’t you can sign up for a free trial (not an affiliate link). After you are signed up head to the Azure Portal.

Note: you can skip this section if you want to use the default Active Directory that is on your Azure account.

In the upper left click the Create a resource link.

In the search box look for Azure Active Directory B2C.

After selecting Azure Active Directory B2C more information will load to the right in a new panel. Click the Create button to continue.

Next, select if you want to create a new B2C tenant or use an existing one. I don’t have an existing one so the following flow will be for creating a new tenant.

On the next panel, you will need to enter an organization name and initial domain name. After entering valid values click the create button.

Switch Active Directory

Now that the new directory has been created we need to switch to the new directory in the Azure Portal. In the left panel click Azure Active Directory.

Click the Switch directory link.

A new panel will show on the right side of the screen with a list of directories you have available. Select the one you created in the steps above or an existing one you would like to use.

Using the search box in the top middle of the portal find Azure AD B2C.

Sample Application

Before moving forward on the Azure side we are going to create our sample client application. This little detour will make it easier for me to point out what values in Azure need to go where in the application configuration.

To create a new web application already set up to use Azure B2C use the following .NET CLI command from a command prompt. There is also a Visual Studio template if you prefer that route.

dotnet new webapp --auth IndividualB2C

In the resulting application, your appsettings.json will have the following section for AzureAdB2C.

"AzureAdB2C": {
  "Instance": "https://login.microsoftonline.com/tfp/",
  "ClientId": "11111111-1111-1111-11111111111111111",
  "CallbackPath": "/signin-oidc",
  "Domain": "qualified.domain.name",
  "SignUpSignInPolicyId": "",
  "ResetPasswordPolicyId": "",
  "EditProfilePolicyId": ""
}

Azure AD B2C Setup

Back to the Azure portal and the Azure AD B2C service page. In the Overview page, the first thing we need to make note of and use to set some configuration values in our application for is the Domain name.

In your appsettings.json file use this value for your Domain value.

"Domain": "TestingOrg3.onmicrosoft.com"

The subdomain is also used to build the Instance like the following.

"Instance": "https://TestingOrg3.b2clogin.com/tfp/"

On the panel that loads hit the Add button. On the new Application panel, we need to give the application a Name, select the type of clients which is Web App / Web API in our case. Next, is the Reply URL which with default setup is your base url/sigin-oidc. I messed this value up in the beginning and got some really strange errors. Finally hit the Create button.

After the creation process is complete copy the value in the Application ID field and use it as ClientId in your appsettings.json file.

Back in Azure select the User flows (policies) option.

At the top of the panel that loads click the New user flow button. The next panel shows a selection of flows that can be added. The application we are making will use both the Sign up and sign in flow and the Password rest flow. I’m only going to walk through the first one, but the second one is very smiliar. Click on the Sign up and sign in like.

In the creation process you will need to set a Name for the flow and select the Identity providers that are valid for the flow. You also have the choice of fields to collect with this flow and which ones should be returned with the claim. After those options are set click the Create button.

The Name form this screen will need to be entered in your appsettings.json file for the SignUpSignInPolicyId value. Here is what I ended up with in my settings file with the Sign Up and Reset Password policies.

"SignUpSignInPolicyId": "B2C_1_SignInOut",
"ResetPasswordPolicyId": "B2C_1_PasswordReset"

Run the sample

At this point, you can run your sample application and click the Sign in link and you will see a page similar to the following which is coming from Azure B2C.

There are ways to customize the pages users will see under the associated flow in Azure.

Wrapping Up

I hit quite a few issues getting Azure B2C setup. I hope this post will help you all bypass some of the issues I hit.

ASP.NET Core with Azure B2C Auth Read More »

ASP.NET Core: Identity Scaffolding

I’m sure we have all started a new web project and then needed to add authentication at a later point. This post is going to cover this process use the Identity Scaffolding feature available in Visual Studio.

Sample

For this example, I’m starting with a new web app created using the following command.

dotnet new webapp

If you have any of the .NET Core 3 previews installed I recommend adding a global.json file in the directory where the application is to be created before running the application creation. I had some issues with the scaffolding in the current preview. The following is the contents of my global.json for an example.

{
  "sdk": {
    "version": "2.2.104"
  }
}

Scaffolding

In Visual Studio right-click on the project and select Add > New Scaffolded Item.

On the Add Scaffold dialog in the left list select Identity in the middle area we want the Identity item and then click the Add button.

Next, on the Add Identity dialog, you get a chance to pick which parts of the provided identity you want to override. I’m going to take the default for all the values. The one exception is the Data context class which I’m using the plus button to the right of the field to add a new one since this project doesn’t currently have any data access in it. When done click the Add button.

After a minute or so identity generation will be complete and a text file will so with some follow up steps. Because of the project type, we started with the only one we need to do anything with is the entity framework migrations. The following are the instructions from the file that will get your database to create/updated with the new data needed to support ASP.NET Core’s Identity.

The generated database code requires Entity Framework Core Migrations. Run the following commands:
1. dotnet ef migrations add CreateIdentitySchema
2. dotnet ef database update
Or from the Visual Studio Package Manager Console:
1. Add-Migration CreateIdentitySchema
2. Update-Database

Finally, in the Pages/Shared directory open the _Layout.cshtml file and add the following to where you want to show the Register and Login links. I added this right after the existing navigation links.

<partial name="_LoginPartial"/>

Wrapping Up

This is a very handle bit of functionality that makes it easy to add Identity for an existing project. You will still be missing some of the nice things provided by creating a project with Identity from the start such as displaying a welcome message with the user’s name, but those bits can be added if it is something you want.

The official docs on this topic cover way more scenarios that this post.

ASP.NET Core: Identity Scaffolding Read More »

Trying Out BenchmarkDotNet

In software, there are tons of different ways to accomplish the same thing and one of the metrics we tend to use to determine a course of action is how we feel that one set of code will perform over another.  The thing is determining which code actually performs better is a bit tricky and I feel like in general people make the choice based on a gut feeling more than actual evidence. Even when evidence a developer has involved if it wasn’t properly collected then it isn’t actually helpful. For example, trying to determine the performance of a set of code when running in debug mode isn’t actually a good indicator of how it is going to perform.

What is a developer to do? Well, this is where BenchmarkDotNet comes in. Here is how the project describes itself.

Benchmarking is really hard (especially microbenchmarking), you can easily make a mistake during performance measurements. BenchmarkDotNet will protect you from the common pitfalls (even for experienced developers) because it does all the dirty work for you: it generates an isolated project per each benchmark method, does several launches of this project, run multiple iterations of the method (include warm-up), and so on. Usually, you even shouldn’t care about a number of iterations because BenchmarkDotNet chooses it automatically to achieve the requested level of precision.

This rest of this post is going to cover creating a sample project using BenchmarkDotNet.

Sample Project

We will be using a new .NET Core console application which can be created using the following .NET CLI command.

dotnet new console

Next, run the following command to add the BenchmarkDotNet NuGet package.

dotnet add package BenchmarkDotNet

Now in the Main function of the Program class, we need to tell the application to run the benchmark we are interested in. In this example, we are telling it to run the benchmarks in the Strings class.

public static void Main(string[] args)
{
    BenchmarkRunner.Run<Strings>();
}

Now in the Strings class, we have two functions marked with the Benchmark attribute which is how the package identifies which functions to measure. For this example, we will be measuring the performance of two different ways to do case insensitive string comparisons.

public class Strings
{
    private readonly Dictionary<string, string> _stringsToTest = 
         new Dictionary<string, string>
         {
             { "Test", "test" },
             { "7", "7" },
             { "A long string", "Does not match" },
             { "Testing", "Testing" },
             { "8", "2" }
         };


    [Benchmark]
    public bool EqualsOperator()
    {
        var result = false;

        foreach (var (key, value) in _stringsToTest)
        {
           result = key.ToLower() == value.ToLower();
        }

        return result;
    }

    [Benchmark]
    public bool EqualsFunction()
    {
        var result = false;

        foreach (var (key, value) in _stringsToTest)
        {
            result = string.Equals(key, value,
                                   StringComparison.OrdinalIgnoreCase);
        }

        return result;
    }
}

I’m sure there is a better way to set up data for test runs, but the above works for my first go at it.

Results

Run the application in release mode and you will see output similar to the following.

Wrapping Up

Having a tool that takes all the guesswork out of how operations perform is going to be very valuable. This is one of those tools I really wish I had found years ago. The project is open source and can be found on GitHub.

Trying Out BenchmarkDotNet Read More »

.NET Core: Windows Compatibility Pack

Windows Compatibility Pack

A little over a year ago Microsoft released the Windows Compatibility Pack for .NET Core that filled in some gaps in .NET Core APIs if your application doesn’t need to run cross-platform. While some of the APIs included in the compatibility pack was added back when support for .NET Standard 2 was released, such as System.Data.SQL client. Some of the APIs will never make it into the .NET Standard because they are Windows only constructs such as registry access.

Since it has been such a long time since the compatibility pack was released I thought this post would be a good reminder. In this post, we will create a new .NET Core application and using the Windows Compatibility Pack to access the registry.

Application Creation

Use the following command from a command prompt to create a new .NET Core console application.

dotnet new console

Use the following command to add a reference to the compatibility pack NuGet package.

dotnet add package Microsoft.Windows.Compatibility

Using the Registry

The following is the full code for the application. This code may not be the best practice, but it does demonstrate the usage of the registry.

class Program
{
    static void Main(string[] args)
    {
        var thing = "World";

        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            using (var regKey = Registry
                                .CurrentUser
                                .CreateSubKey(@"Software\Testing\Test"))
            {
                thing = regKey.GetValue("ThingText")?.ToString() ?? thing;
                regKey.SetValue("ThingText", "Registry");
            }
        }

        Console.WriteLine($"Hello {thing}!");
    }
}

Take special note of the if statement surrounding the registry access as it allows you to check what platform you are running on and vary your implementation, which is very helpful if your application is actually run cross-platform, but you need some slight differences when running on a particular OS.

The application should output “Hellow World!” the first run and “Hello Registry!” the second run.

Wrapping Up

If you were creating a new application it would be best to stay away from platform specific API as much as possible and stick with the APIs defined by the .NET Standard. If you are trying to convert an existing application I could see the compatibility pack speeding your conversion without having to rewrite part of the application that happens to us Windows-based APIs.

.NET Core: Windows Compatibility Pack Read More »

Entity Framework Core: Show Parameter Values in Logging

Back in October, I did a post on Entity Framework Core: Logging which covers enabling logging for Entity Framework Core. This post is going to expand on that previous post and show you how to get the parameter values used in the queries in addition to the SQL statements being used.

Review

This post will not be covering how to set up a logger please see this previous post for those details. The following is the kind of information you get in the log based on the previous post.

Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (41ms) [Parameters=[@__id_0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SELECT TOP(2) [m].[Id], [m].[Address], [m].[City], [m].[Email], [m].[Name], [m].[Phone], [m].[PostalCode], [m].[State]
FROM [Contact] AS [m]
WHERE [m].[Id] = @__id_0

This is helpful when you need to verify the queries Entity Framework is producing, but if you are trying to track down a data related problem not knowing what parameters values are being used can be a pain.

Enable Parameter Values in Logging

Entity Framework Core provides an option to enable sensitive data logging. To enable this option open the Startup class and in the ConfigureServices function make the following change to the AddDbContext call for the DbContext you want the option on for.

Before:
services
  .AddDbContext<ContactsContext>(options => 
     options.UseSqlServer(Configuration["Data:ContactsContext:ConnectionString"]));

After:
services
  .AddDbContext<ContactsContext>(options =>
  {                         
     options.UseSqlServer(Configuration["Data:ContactsContext:ConnectionString"]);
     options.EnableSensitiveDataLogging();
  });

Now running the same query as above you will see the following output.

Microsoft.EntityFrameworkCore.Database.Command[20100]
Executing DbCommand [Parameters=[@__id_0='1' (Nullable = true)], CommandType='Text', CommandTimeout='30']
SELECT TOP(2) [m].[Id], [m].[Address], [m].[City], [m].[Email], [m].[Name], [m].[Phone], [m].[PostalCode], [m].[State]
FROM [Contact] AS [m]
WHERE [m].[Id] = @__id_0

As you can see with enable sensitive data logging we get the value of the ID parameter instead of a question mark.

Before: [Parameters=[@__id_0='?' (DbType = Int32)]
After:  [Parameters=[@__id_0='1' (DbType = Int32)]

Wrapping Up

This is a handy option when you need it. Just use it with care as it could expose data that should be kept private.

Entity Framework Core: Show Parameter Values in Logging Read More »

Creating Desktop Applications in .NET Core 3

In my job, I still do a fair amount of work desktop related work which means when I heard that .NET Core 3 is going to bring support for Winforms and WPF I got pretty excited. This post is going to show you how to installing the preview of .NET Core 3 and then using the .NET CLI to a new Winforms or WPF application.

This information was covered in the .NET Core 3 Preview 1 announcement from December, but I thought I might as well document it here as I was trying it out.

Download and Install

Head over to the .NET Core 3 download  page and select the SDK for your OS. Keep in mind that Winforms and WPF will only run on Windows machines unlike the rest of .NET which is cross-platform. After the download is complete run the installer and follow the prompts.

Project Creation

Using the .NET CLI you can use the following command to create a Winform application.

dotnet new winforms

Of the following to create a WPF application.

dotnet new wpf

After the project is created for either type you can use the following command to run the application.

dotnet run

The following is an example of what you would see for a new WPF application.

Limitations

If you are going to be playing with the desktop-based framework I recommend that you grab the preview of Visual Studio 2019. Even with the preview, there are no designers available Winforms or WPF as of the time of this writing.

Wrapping Up

I know Microsoft has shown some neat demos, but in this first preview doesn’t have much tooling around it so if you are going to do much more than the new applications as I did above you are going to be in for a lot of manual work. Please don’t take this as a dig, as I said above I am very excited about this functionality.

If you are wondering about what versions of Windows .NET Core 3 will be supported on that information can be found here.

Creating Desktop Applications in .NET Core 3 Read More »

ASP.NET Core Configuration Issue with In Process Hosting

Since ASP.NET Core 2.2 was released I have been working on getting all my different applications updated and using in-process hosting. I pretty quickly hit an issue with an application that uses SQLite. As soon as the application tried to access the database I ended up with the following error.

SqliteException: SQLite Error 14: ‘unable to open database file’. Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(int rc, sqlite3 db) Microsoft.Data.Sqlite.SqliteConnection.Open() Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnection(bool errorsExpected)

Issue

After some Googling, I found an issue on GitHub that details the problem. It turns out that when the application gets its current directory it is returning the path to the IIS process that is hosting the application instead of the directory when the application is.

Work Around

On another GitHub issue, I found a link to a recommended workaround. Add the following class somewhere in your application. This code comes here.

internal class CurrentDirectoryHelpers
{
    internal const string AspNetCoreModuleDll = "aspnetcorev2_inprocess.dll";

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern IntPtr GetModuleHandle(string lpModuleName);

    [System.Runtime.InteropServices.DllImport(AspNetCoreModuleDll)]
    private static extern int http_get_application_properties(ref IISConfigurationData iiConfigData);

    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    private struct IISConfigurationData
    {
        public IntPtr pNativeApplication;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.BStr)]
        public string pwzFullApplicationPath;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.BStr)]
        public string pwzVirtualApplicationPath;
        public bool fWindowsAuthEnabled;
        public bool fBasicAuthEnabled;
        public bool fAnonymousAuthEnable;
    }

    public static void SetCurrentDirectory()
    {
        try
        {
            // Check if physical path was provided by ANCM
            var sitePhysicalPath = Environment.GetEnvironmentVariable("ASPNETCORE_IIS_PHYSICAL_PATH");
            if (string.IsNullOrEmpty(sitePhysicalPath))
            {
                // Skip if not running ANCM InProcess
                if (GetModuleHandle(AspNetCoreModuleDll) == IntPtr.Zero)
                {
                    return;
                }

                IISConfigurationData configurationData = default(IISConfigurationData);
                if (http_get_application_properties(ref configurationData) != 0)
                {
                    return;
                }

                sitePhysicalPath = configurationData.pwzFullApplicationPath;
            }

            Environment.CurrentDirectory = sitePhysicalPath;
        }
        catch
        {
            // ignore
        }
    }
}

Finally, in the Main function of the Program class add the following line as the first thing in the function.

CurrentDirectoryHelpers.SetCurrentDirectory();

Wrapping Up

With the above changes, all will work as expected. It is my understanding that this issue will be addressed at some point in the future as a patch so this should just be a temporary fix.

ASP.NET Core Configuration Issue with In Process Hosting Read More »

Dapper Using Lists

Last week’s post on ASP.NET Core with Dapper covered the very basics of using Dapper in an ASP.NET Core project. This week we will be changing up the sample code from last week to show using Dapper to deal with lists instead of just a single object at a time.

This post is going to be pretty short, but I thought it was important to point out that Dapper can execute a single query multiple times by passing it an IEnumerable.

The Sample

The following sample connects to the database, deletes all the existing contacts, seeds the contact table with 3 contacts (this is our list), and then selects all the contacts back out (this comes out as an IEnumerable).

using (var connection = 
           new SqlConnection(_configuration
                             .GetConnectionString("DefaultConnection")))
{
    connection.Open();

    connection.Execute("DELETE Contacts");

    var seedContacts = new List<Contact>
                       {
                           new Contact
                           {
                               Name = "Charlie Plumber",
                               Address = "123 Main St",
                               City = "Nashville",
                               Subregion = "TN",
                               Email = "[email protected]"
                           },
                           new Contact
                           {
                               Name = "Teddy Pierce",
                               Address = "6708 1st St",
                               City = "Nashville",
                               Subregion = "TN",
                               Email = "[email protected]"
                           },
                           new Contact
                           {
                               Name = "Kate Pierce",
                               Address = "6708 1st St",
                               City = "Nashville",
                               Subregion = "TN",
                               Email = "[email protected]"
                           }
                       };

    connection.Execute(@"INSERT INTO Contacts (Name, Address, City, 
                                               Subregion, Email) 
                         VALUES (@Name, @Address, @City, 
                                 @Subregion, @Email)",
                       seedContacts);
    
    var allContacts = connection
                      .Query<Contact>(@"SELECT Id, Name, Address, City, 
                                               Subregion, Email 
                                        FROM Contacts");
}

As expected the end result contains three contact records.

Wrapping Up

Hopefully, this quick little post helps fill in one of the gaps of last week’s post. Make sure and check out the Dapper GitHub page in addition to features I have covered in these two posts it also supports a lot of other functionality such as stored procedures, multiple result sets, etc. The code in its final state can be found here.

Dapper Using Lists Read More »

ASP.NET Core with Dapper

Entity Framework Core has been a the heart of a lot of the post I have done recently. I thought it would be a good change of pace to try out one of the alternatives to Entity Framework Core and give Dapper a try.

I tried to find a good example of the difference between micro ORMs like Dapper and full ORMs like Entity Framework Core, but all the ones I found ended up pushing one option over the other.  I’m not looking to say one is better than the other, but to add a new tool to my toolbelt.

Basically, the differences seem to come down to micro ORMs provide significantly fewer features than a full ORM but come with a higher level of performance. Which is the right choice is going to vary by project.

Sample Project

We will be using a new Razor Pages application as the starting point for the sample application. It currently doesn’t have any database access setup. The code for the starting point of the sample can be found here.

I’m going to be using an existing database created for the SQL Server example in my Entity Framework sample project. Below is a Contacts table generated from that sample project in case you want to manually generate the table.

CREATE TABLE [dbo].[Contacts] (
    [Id]         INT            IDENTITY (1, 1) NOT NULL,
    [Name]       NVARCHAR (MAX) NULL,
    [Address]    NVARCHAR (MAX) NULL,
    [City]       NVARCHAR (MAX) NULL,
    [Subregion]  NVARCHAR (MAX) NULL,
    [PostalCode] NVARCHAR (MAX) NULL,
    [Phone]      NVARCHAR (MAX) NULL,
    [Email]      NVARCHAR (MAX) NULL,
    [Timestamp]  ROWVERSION     NULL
);

Add Dapper Nuget Package

Using your favorite way to add a NuGet package add a reference to the Dapper package. I’m going to do it using Visual Studio by right-clicking on the project and selecting Manage NuGet Packages.

On the next screen, from the Browse tab use the Search Box to search for Dapper. Select the Dapper package and click Install.

Add Connection String Configuration

We are going to store the database connection string in the appsettings.json file. Open the file and add a ConnectionString section with a DefaultConnection that contains the database connection string. This exact setup isn’t required I’m just following the way configuration is set up for Entity Framework base projects. The following is my full configuration file with the new section at the top.

{
  "ConnectionStrings": {
    "DefaultConnection": "Your connection string"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Contact Model

Add a Contact class in a Models folder which will be used to represent our data. The following is the full model class I will be using in this example.

public class Contact
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string Subregion { get; set; }
    public string PostalCode { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
}

Test Setup

To keep things simple I will not be dealing with any UI other than as a way to run the Dapper related code. As such we will be using the Page Modle of the Index page to run the sample code. This is in no way an example of the best practice setup and is only done to demo Dapper in the simplest setup possible.

The following is the full page model with the configuration for the application being injected via the constructor. All the changes passed this point will be in the OnGet function.

public class IndexModel : PageModel
{
    private readonly IConfiguration _configuration;

    public IndexModel(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public void OnGet()
    {

    }
}

Using Dapper

Dapper provides a number of extension methods off of the IDbConnection interface. For this example, we will use these extensions to check to see if a specific contact exists, if it doesn’t then insert it, and finally select the contact back out of the database.

The first step is to open a connection. In this example, we are using SQL Server, but Dapper doesn’t really care and will work with any ADO.NET provider. The following code opens a SQL connection using the connection string from appsettings.json.

using (var connection = new SqlConnection(_configuration.GetConnectionString("DefaultConnection")))
{
    connection.Open();
}

Next, we are going to query the Contacts table for the ID of a specific contact.

if (connection.QueryFirstOrDefault<int?>(@"SELECT Id 
                                           FROM Contacts 
                                           WHERE Name = @Name",
                                         new {Name = "Charlie Plumber"}) == null)
{
}

As you can see from the above you there is nothing special about the SQL being written. For this query, we are using an anonymous type to pass the query a name filter which will be translated to a SqlParameter which ensures the query won’t all things like SQL injection. Note that the parameter name in the SQL string must match the name of the corresponding property on the object being passed to the query.

This next example is the contact insert if the contact wasn’t found in the previous query.

connection.Execute(@"INSERT INTO Contacts (Name, Address, City, Subregion, Email)
                     VALUES (@Name, @Address, @City, @Subregion, @Email)",
                   new Contact
                   {
                       Name = "Charlie Plumber",
                       Address = "123 Main St",
                       City = "Nashville",
                       Subregion = "TN",
                       Email = "[email protected]"
                   });

Again the SQL is exactly what you would expect, which is one of the great parts about Dapper if you are familiar with SQL.

This last example is a combination of all the previous examples with a select to get out the contact details of the contact in question.

using (var connection = new SqlConnection(_configuration.GetConnectionString("DefaultConnection")))
{
    connection.Open();

    if (connection
           .QueryFirstOrDefault<int?>(@"SELECT Id 
                                        FROM Contacts 
                                        WHERE Name = @Name",
                                      new {Name = "Charlie Plumber"}) == null)
    {
        connection.Execute(@"INSERT INTO Contacts (Name, Address, City, 
                                                   Subregion, Email) 
                             VALUES (@Name, @Address, @City, 
                                     @Subregion, @Email)",
                           new Contact
                           {
                               Name = "Charlie Plumber",
                               Address = "123 Main St",
                               City = "Nashville",
                               Subregion = "TN",
                               Email = "[email protected]"
                           });
    }

    var charile = 
      connection.QueryFirstOrDefault<Contact>(@"SELECT Id, Name, Address, 
                                                       City, Subregion, Email 
                                                FROM Contacts 
                                                WHERE Name = @Name",
                                              new {Name = "Charlie Plumber"});
}

Wrapping Up

This first round of playing with Dapper was fun. I write a lot of SQL in my day job so it was kind of nice seeing the explicit SQL vs the magic of a full ORM. I can tell you from doing this sample I would miss Entity Framework’s database creation and migration capabilities.

The code in its final state can be found here.

ASP.NET Core with Dapper Read More »