Build a CRUD App with ASP.NET MVC and Entity Framework

avatar-quorralyne.jpg Heather Downing

Interested in building a secure ASP.NET MVC website that allows users to handle their own data with ease? Let’s walk through creating a basic application that allows the creation, reading, updating, and deletion of data (CRUD) with Entity Framework by your users while managing them easily with Okta. For a fun example, we will create a web application that lists upcoming rocket launches for space enthusiasts! You will have everything you need to get up and running by the end of this post.

What Does Your ASP.NET MVC + Entity Framework App Need to Do?

For the purposes of this tutorial, here are the requirements you’ll need to fulfill:

  • Users must sign in to see a specific page (i.e. a gated flow)
  • Users must be able to create and read data
  • The app should display user-specific data, i.e. name

Be sure to have Visual Studio and the latest ASP.NET Framework (4.x) version installed on your development machine before you continue. We will walk through installing the other dependencies together. Let’s get started!

Okta Rocket

Create Sample Users for Your ASP.NET MVC App

For this tutorial, you’ll use Okta for user creation and authentication.

Why use Okta for authentication? Okta makes identity management easier, more secure, and more scalable than what you’re used to. Okta is an API service that allows you to create, edit, and securely store user accounts and user account data, and connect them with one or more applications.

If you haven’t already, go to developer.okta.com and create an account to get started, then continue with the following steps.

Visit the Users tab and click Add Person. Fill out the form and be sure to set the Password drop down to “Set by Admin”, and fill in a temporary password for the user. Click Save and Add Another and continue adding a couple more users.

Add person

Once you have the users added, you’ll notice the status for your newly created users is set to “Password expired”. This is expected for admin-created users and will guide them through their reset password flow during the first login to your site - without any additional work on your part.

User dashboard

Set Up Your ASP.NET MVC Application in Okta

Now that you have your users set up in your database, set up this specific application within Okta. On the Dashboard, click Applications in the main menu and on the Application screen, click Add Application. Select Web and then click Next.

User dashboard

Name the application “Okta MVC CRUD App”. Select Implicit (Hybrid) in addition to the pre-selected Authorization Code, and click Done.

App settings

Your application has been created, but you still need to add the logout redirect now that the field is available. Select Edit, add the URI http://localhost:8080/Account/PostLogout, and click Save.

General settings

Scroll down and you’ll have access to the ClientID and Client Secret. Keep these on hand to add to your application’s Web.config file later on. Now your app is good to go for Okta auth!

App dashboard

Create an ASP.NET MVC Application with Entity Framework using a LocalDB Connection

Click File > New > Project. Select Visual C# then select ASP.NET Application. Choose MVC and name it “CrudMVCCodeFirst”.

Right-click on the project and select Properties. Go to the Web tab and set the project URL to reflect the application settings in Okta’s portal https://localhost:8080.

Visual Studio project settings URL

Right-click on the project and select Manage NuGet Packages. Tap on Browse and search for Entity Framework. Install version 6.2.0.

Visual Studio NuGet Entity Framework

Open the Web.config and add your connection string inside the configuration element to use LocalDB using the code below.

<connectionStrings>
    <add name="LaunchContext" 
	connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial 
        Catalog=RocketLaunch1;Integrated Security=SSPI;" 
	providerName="System.Data.SqlClient" />
  </connectionStrings>

You will be using Entity Framework to create database entities. This code first approach eliminates the need for you to define a database. Instead, the first time you access your data by running the app, Entity Framework will create your database for you using LocalDB as your database engine.

Create a class in the Models folder called LaunchEntry.cs and add the properties below.

public class LaunchEntry
{
    public int Id { get; set; }
    public string LaunchInfo { get; set; }
    public string PostedByUserName { get; set; }
}

Create a folder at the project level called Data and add a class inside of it called LaunchContext.cs Add System.Data.Entity, CrudMVCCodeFirst.Models and System.Data.Entity.ModelConfiguration.Conventions to the usings at the top of the file and extend the class with DBContext. Now you can add your DbSets. The name of the connection string in your Web.config is passed into the constructor. Add the code below.

public class LaunchContext : DbContext
{
    public LaunchContext() : base("LaunchContext")
    {
    }

    public DbSet<LaunchEntry> Launches { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
}

The code in the OnModelCreating() method prevents table names from being pluralized. If you didn’t do this, the generated tables in the database would be named LaunchEntries. Instead, the table name will be LaunchEntry. This tutorial utilizes singular form, but you can select whichever form you prefer by including or omitting this overridden method.

Right-click on the Controller folder and add a new scaffolded item.

Visual Studio add a new scaffold item

Select MVC 5 Controller with views, using Entity Framework and click Add.

Visual Studio add MVC EF controller

Select “LaunchEntry” as the Model class and “LaunchContext” as the Data context class. Set the controller name to “LaunchController”, leave the other default values and click Add.

Visual Studio add controller

The scaffolder will create a LaunchController.cs file and a set of views for it (.cshtml files)

Because this is a claims-aware application, we need to indicate where to get user identity information from. Open your Global.asax.cs file. Add System.Web.Helpers to the usings group. Replace the Application_Start() method with the code below to match the name of claim type - “name” in this case - from the JsonWebToken (JWT) you are receiving from Okta to set your user’s identifier.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
            
    AntiForgeryConfig.UniqueClaimTypeIdentifier = "name";
}

Go into Views/Shared and open _Layout.cshtml. Add a link to your Launch controller’s newly generated Index page by replacing the unordered list with the class nav navbar-nav with the code below. This will allow you to navigate to the launch controller from the home page of the site.

<ul class="nav navbar-nav">
    <li>@Html.ActionLink("Launches", "Index", "Launch")</li>
    <li>@Html.ActionLink("Home", "Index", "Home")</li>
    <li>@Html.ActionLink("About", "About", "Home")</li>
    <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Run the project in the browser. You should see your Launches link in the navigation bar. Select it to access the Index page, and add a launch or two, adding your name and editing a bit.

ASP.NET site default page

Create page

Index page

Add the Okta .NET SDK to your ASP.NET MVC App

Congrats, you have a working CRUD application that lets you keep track of rocket launches! However - right now anyone can access the Launch page. Let’s add functionality to authenticate users to give only specific people access to that and hide it from public view.

Right-click on the project and select Manage NuGet Packages. Tap on Browse and search for Okta.AspNet. This is the .NET 4.x framework version of the SDK. Find version 1.1.4 and click Install.

Visual Studio NuGet install Okta.AspNet

Additionally, you need to install Microsoft.Owin.Host.SystemWeb version 4.0.1 and Microsoft.Owin.Security.Cookies version 4.0.1. These libraries will assist us in accessing the token data in our code.

Add the Okta account access to your Web.config file under the appSettings section. Use the code below, replacing the Okta client ID and secret with your specific app’s Okta credentials you generated in the portal earlier.

<!-- 1. Replace these values with your Okta configuration -->
    <add key="okta:ClientId" value="{clientId}" />
    <add key="okta:ClientSecret" value="{clientSecret}" />
    <add key="okta:OktaDomain" value="https://{yourOktaDomain}" />

    <add key="okta:RedirectUri" value="http://localhost:8080/authorization-code/callback" />
    <add key="okta:PostLogoutRedirectUri" value="http://localhost:8080/Account/PostLogout" />

In order to handle OWIN, we need to do that from a Startup class. Right-click on the project and select Add OWIN Startup class. Call it “Startup” and click OK.

Visual Studio Add OWIN Startup file

Add the following to your usings section.

using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Okta.AspNet;
using System.Collections.Generic;
using System.Configuration;

Replace the Configuration() method with the code below.

public void Configuration(IAppBuilder app)
{
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

    app.UseCookieAuthentication(new CookieAuthenticationOptions());

    app.UseOktaMvc(new OktaMvcOptions()
    {
        OktaDomain = ConfigurationManager.AppSettings["okta:OktaDomain"],
        ClientId = ConfigurationManager.AppSettings["okta:ClientId"],
        ClientSecret = ConfigurationManager.AppSettings["okta:ClientSecret"],
        RedirectUri = ConfigurationManager.AppSettings["okta:RedirectUri"],
        PostLogoutRedirectUri = ConfigurationManager.AppSettings["okta:PostLogoutRedirectUri"],
        GetClaimsFromUserInfoEndpoint = true,
        Scope = new List<string> { "openid", "profile", "email" },
    });
}

Now you need to handle the login and logout functionality. Right-click on the Controllers folder and add a new MVC 5 empty controller called AccountController. Add Okta.AspNet and Microsoft.Owin.Security.Cookies to the usings section. Add the code below inside of the AccountController class to handle the Action Results for this controller.

public ActionResult Login()
{
    if (!HttpContext.User.Identity.IsAuthenticated)
    {
        HttpContext.GetOwinContext().Authentication.Challenge(
            OktaDefaults.MvcAuthenticationType);
        return new HttpUnauthorizedResult();
    }

    return RedirectToAction("Index", "Home");
}

[HttpPost]
public ActionResult Logout()
{
    if (HttpContext.User.Identity.IsAuthenticated)
    {
        HttpContext.GetOwinContext().Authentication.SignOut(
            CookieAuthenticationDefaults.AuthenticationType,
            OktaDefaults.MvcAuthenticationType);
    }

    return RedirectToAction("Index", "Home");
}

public ActionResult PostLogout()
{
    return RedirectToAction("Index", "Home");
}

Open the LaunchController and add the Authorize attribute at the top of any actions you don’t want public access to. Leaving the attribute off of the Index action will allow anyone to view the list of upcoming launches - just not edit them. Add Authorize to the top of GET actions for Create, Edit, Delete, and their corresponding POST endpoints. This will ensure those function will be accessed by authenticated users only and will redirect to the Okta login process if they are not authenticated.

//// GET: Launch/Create
[Authorize]
public ActionResult Create()
// POST: Launch/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize]
public ActionResult Create([Bind(Include = "Id,LaunchInfo,PostedByUserName")] LaunchEntry launchEntry)

Run the project in a browser and use a different one then what you are logged into the Okta portal with (or log out of your admin account first). Use one of your newly created user credentials and try it out. Click on Launches and you should be taken through the Okta generated authentication flow before landing on the Index page.

Track Users In Your Entity Framework CRUD Actions

You’ve successfully gated the Launches section! However, you might want to know which specific user would be doing the CRUD operations from here - and perhaps display the name of the currently logged in user. Let’s add that functionality now.

Go to Views/Shared and open _Layout.cshtml. Beneath the <ul> list of ActionLinks add the code below to display the user’s name and toggle the Login/Logout link button.

@if (Context.User.Identity.IsAuthenticated)
{
    <ul class="nav navbar-nav navbar-right">
        <li>
            <p class="navbar-text">Hello, <b>@Context.User.Identity.Name</b></p>
        </li>
        <li>
            <a onclick="document.getElementById('logout_form').submit();" 
                style="cursor: pointer;">Log out</a>
        </li>
    </ul>
    <form action="/Account/Logout" method="post" id="logout_form"></form>
}
else
{
    <ul class="nav navbar-nav navbar-right">
        <li>@Html.ActionLink("Log in", "Login", "Account")</li>
    </ul>
}

Go to Views/Launch and open Create.cshtml. Locate the form-group div that specifies the PostedByUserName field and delete it. Locate and remove in the Edit.cshtml as well.

Open the LaunchController. Replace your Create() method with the code below to automatically assign the logged in user to the PostedByUserName property which is called upon saving the form in each case.

// POST: Launch/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize]
public ActionResult Create([Bind(Include = "Id,LaunchInfo,PostedByUserName")] LaunchEntry launchEntry)
{
    launchEntry.PostedByUserName = this.User.Identity.Name;

    if (ModelState.IsValid)
    {
        db.Launches.Add(launchEntry);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(launchEntry);
}

Now replace the Edit() method as well with the code below.

// POST: Launch/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize]
public ActionResult Edit([Bind(Include = "Id,LaunchInfo,PostedByUserName")] LaunchEntry launchEntry)
{
    launchEntry.PostedByUserName = this.User.Identity.Name;

    if (ModelState.IsValid)
    {
        db.Entry(launchEntry).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(launchEntry);
}

Launch the application in the browser and log in as one of your created users. Play around with creating new launches, editing a few that already exist and even delete one. You will notice the Posted By field is gone since we automatically assign it to the logged in user now.

Create page final

That’s it! Your users can now create, edit and delete the launch entries after being signed in, and without typing their name for the changes they produce. You’ve taken a journey from the basics of a CRUD app and transformed it into something that can be done by the users on your site in a secure fashion. Pretty slick!

How have you used this approach in your projects? Leave a comment below and tell me what you’ve used this for.

In the meantime… I have a couple of space rockets to check out.

Learn More About ASP.NET

As always if you have any questions, comments, or concerns about this post feel free to leave a comment below. For other great content from the Okta Dev Team, follow us on Twitter and Facebook!