Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to Implement CRUD forms with React and ASP.NET Core

0.00/5 (No votes)
7 Nov 2017 8  
In this tutorial, I'll be building a high performance ASP.NET Core 2.0 React.js Single Page Application that implements CRUD forms with validation without using Redux or JQuery.

Introduction

In recent years, a number of competing Single Page Application (SPA) frameworks like Angular, Vue, and React have surfaced. One of those, React - a product of Facebook - has runaway from the pack and has remained strides ahead of it. In this tutorial, I will show you how to write a data driven ASP.NET Core 2.0 SPA that includes CRUD operations (create, read, update and delete) using React. Our data will be stored in a SQL Server database, but beyond that, we will not be using any other third party technologies, such as Redux or even JQuery. Stick around and you'll see what makes React so great, and how it makes JQuery virtually obsolete.

Background

React provides many benefits, the most important of which (in my opinion) is components. React components are simple. They simplify your application architecture, they are encapsulated and they can be reused, and styling components is greatly simplified (say goodbye to your global style sheet). In this tutorial, we'll be writing JSX using TypeScript so we will also be utilizing ES6 JavaScript enhancements, which offer more benefits. I decided to write this tutorial because I could not find a comprehensive tutorial that dealt with using React in a data driven ASP.NET Core 2.0 application. What follows is part one of a three part series.

Using the Code

You can use the code in this tutorial in your own applications by simply changing the model names, i.e., changing the data type of the model data passed to each component. That may not make sense to you now, but it will make perfect sense by the time you get to the end of this tutorial. Also by that time, you will understand how React fits within the ASP.NET Core framework. Let's begin, shall we!

Building Our React Application

In this tutorial, we'll be building a movie database application. Visual Studio 2017 includes a basic React project template, so we'll be starting with that. Let's create our project...

  1. Open Visual Studio and select New Project.
  2. From the New Project dialog box, select .NET Core and then ASP.NET Core Web Application (figure 1):

    fig 1: New Project dialog

  3. From the ASP.NET Core Web Application dialog box, select React.js (figure 2)

    fig 2: New ASP.NET Core Web Application dialog

  4. Name the application 'TestReactMovieApplication'.

Building Our Models

Our models consists of three classes: Actor, Movie, and MovieActor, which simply defines the relationship between movies and actors. Let's start by creating a new Class. In Visual Studio, right-click on the project, select Add, then New Class. Call the new class models.cs (figure 2.1).

fig 2.1: Add New Item dialog

Next open the models.cs file and paste the Actor class as shown below (fig 2.2). Then do the same for the Movie and MovieActor classes shown below that (figures 2.3 and 2.4). Note our models.cs file will contain all three classes in order to reduce file-sprawl.

[Table("Actor")]
public class Actor
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key, Column(Order = 0)]
    [Required]
    [DisplayName("Id")]
    public int Id { get; set; }

    [Required]
    [MaxLength(50)]
    [DisplayName("Name")]
    public string Name { get; set; }

    [MaxLength(10)]
    [DisplayName("Gender")]
    public string Gender { get; set; }

    [DisplayName("Age")]
    public int? Age { get; set; }

    [MaxLength(255)]
    [DisplayName("Picture")]
    public string Picture { get; set; }
}
Figure 2.2
[Table("Movie")]
public class Movie
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key, Column(Order = 0)]// check order #
    [Required]
    [DisplayName("Id")]
    public int Id { get; set; }

    [Required]
    [MaxLength(100)]
    [DisplayName("Title")]
    public string Title { get; set; }

    [Required]
    [MaxLength(100)]
    [DisplayName("Director")]
    public string Director { get; set; }

    [Required]
    [DisplayName("DateReleased")]
    public DateTime DateReleased { get; set; }

    [MaxLength(50)]
    [DisplayName("ReleasedBy")]
    public string ReleasedBy { get; set; }

    [MaxLength(10)]
    [DisplayName("Rating")]
    public string Rating { get; set; }

    [MaxLength(50)]
    [DisplayName("Genre")]
    public string Genre { get; set; }

    [DisplayName("GrossRevenue")]
    public decimal? GrossRevenue { get; set; }
}  
Figure 2.3
[Table("MovieActor")]
public class MovieActor
{
    [Key, Column(Order = 0)]
    [Required]
    [DisplayName("MovieId")]
    public int MovieId { get; set; }

    [Key, Column(Order = 1)]
    [Required]
    [DisplayName("ActorId")]
    public int ActorId { get; set; }
}
Figure 2.4

Next, we'll need to create a database context for EntityFramework. Right click on your project, select Add, then Class. Give the file the name AppDbContext.cs. Then open the new file and paste the following code (figure 2.5). Note that we have pluralized the names of the DBSets. This helps us easily differentiate the models from the datasets. Also since our MovieActor table has a compound primary key, we need to specify that in the OnModelCreating() method.

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<appdbcontext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        /* Define any composite PKs here*/
        modelBuilder.Entity<movieactor>()
            .HasKey(m => new {m.MovieId,m.ActorId}); 
    }

    public DbSet<actor> Actors {get; set;}
    public DbSet<movie> Movies {get; set;}
    public DbSet<movieactor> MovieActors {get; set;}
}
Figure 2.5

We'll need to add the DbContext to the project services. We're also going to specify a JSON option that will maintain the case of our field names rather than changing them to camelCase, which is the default. (This will break the Microsoft Fetch Data example - don't be alarmed.) Open startup.cs in your project root and make sure the ConfigureServices() method looks like the following (figure 2.5.1).

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<appdbcontext>(options =>
    {
        options.UseSqlServer(Configuration.GetConnectionString("AppDbContext"));
        options.ConfigureWarnings(x => x.Ignore(RelationalEventId.AmbientTransactionWarning));
    });

    services.AddMvc().AddJsonOptions(options =>
    {
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    });
}
Figure 2.5.1

Configuring the Application

tsconfig.json

Since we'll be writing a bit of TypeScript, we're going to turn TypeScript's 'strict' mode off to make our life easier. In tsconfig.json, which lives in the root of your application, let's set 'strict' to false as shown below:

"compilerOptions": { "strict": false

Connection String

We'll set our connection string in appsettings.json, also in the root of our application (figure 2.6). Your connection string should look similar to the one shown, however your server name may be different depending on what you specified when you installed SQL Server. Enter it just before the "Logging" settings.

{
  "ConnectionStrings": {
    "AppDbContext": "server=localhost\\SQL2012;Database=Movies;Integrated Security=True;
                    MultipleActiveResultSets=true"
  },
  "Logging": {

Anatomy of a React TS Application

At this point, I'd like to digress and talk about the anatomy of our React.js application. This tutorial will follow an MVC (model, view, controller) methodology except that instead of server-side views, we will have client side React components acting as our views. I also want to talk about the structure of our React application in a bit more detail.

The Project

When you create an ASP.NET Core React application, you'll find the following project items (figure 7). The most important things to know are: that we no longer user server-side views (instead, we have React components under the ClientApp folder); that the client script must be "compiled" (performed by webpack); that the client script is "transpiled" (converted from TypeScript to ES5 or ES6 per your tsconfig.json file); that all server to client communication happens using AJAX and JSON.

The React Application

Figure 7

Models

As well as the server side models that we created above (models.cs in figure 7), React requires client-side models. We'll be creating a client-side models file with essentially the same structure except for the datatypes (TypeScript datatypes are simpler and fewer) and without any of the ASP.NET data attributes.

Components (Views)

In our React application, we'll be building client-side components (in ClientApp\components) to act as the "views" of our application (fig 10). As in traditional ASP.NET MVC applications, we will create a folder for each component (model). However, rather than creating five views, we will perform all of our CRUD operations with just three, which will simplify maintenance of our views.

React Views

Figure 10

Also, each component will have its own .css file. This is a big improvement over a global styles.css file in which everything affects everything else. The only thing to know about the component css file is that it will only ever affect itself and any children that it contains.

Controllers

As in traditional ASP.NET MVC applications, our React application will have one controller for each model, i.e., we will have three separate controllers (figure 11).

Controllers

Figure 11

There will be a few differences in our controllers compared to a traditional MVC controller. All of our controllers will be WebAPI controllers and all methods will return JSON data. This has the advantage of allowing us to leverage our application to also serve mobile applications. Secondly, in following many WebAPI practices, we will use the HTTP methods PUT and POST for edit and create respectively. So instead of a Create method, we will have a POST method, and instead of an Edit method, we will have a PUT method.

That concludes Part 1 of this tutorial. Stick around. In Part 2, we'll be creating our components.

History

  • 11/7/2017: Original article

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here