Build a Basic FullStack app using C#(.NET Core), MySQL and Webpack/React. (1/3)(Updated)
We will build a basic fullstack web app that will implement webpack, c# and mysql. It would be something you can build off of, to build fullstack app with react and c#.
So we will create an app which will hold our favorite games, which would be retrieved from a database. We will make a crud app, which will create, read, update, and delete data from our mysql database.
Step One: The setup.
We will first install mysql workbench which will hold our database.
MySQL :: Download MySQL Workbench
The following LGPL libraries are used by MySQL Workbench and their sources are provided for download in compliance with…
But we will only create our database using the code-first way. Which means we will create our domain models. Which will be how our table is structured regarding fields and their datatypes based from the domain models created from the project Domain class library which we would get into later in the tutorial. We will just create our server, and our user which would how our backend server will access the data.
Then create the user called root, and give it a easy password since this is for tutorial purposes.
Next we will create a C# solution, and have our first project be a web api from visual studio. Have the Solution be called Games, and have the web project be Games.Web — Then we will add 3 class libraries to the solution.
Games.Data — Responsible for retrieving data from your database via a Context class which will hold your tables, via fields of your class. This class library will hold your Repositories which would be responsible for retrieving data from your Context class.
Games.Domain — Responsible for defining your data you will retrieve, and create.
Games.Services — Responsible for retrieving data from your repositories in your Games.Data, and have it presentable to view via ViewModels we will define in the next tutorial.
Configuring your Database.
We will now setup our database using entity framework core and create our database using the code-first way. So we will first define our entity models in our .Domain class library project.
Add 2 classes to your project. Have one of them being Entity.cs and Game.cs. (NOTE: Our Games class will be in our Games folder.) Now it will create a file with the class being named after the file. Now make your Entity class which will be abstract and all your domain classes will inherit from this class. In our Entity class it will only have properties which all of our domain models will inherit. In this case it is only gonna be a property of id of type Guid which is a unique identifier which will be any table’s primary key.
Abstract classes are classes that can be extended, and are meant to just be base classes. Whenever a class inherits a abstract class it will inherit all its properties, and will implement method if the abstract keyword is used in the methods signature.
public abstract IEnumerable<GameViewModel> GetGames();
NOTE(Right click on any problems and visual studio will auto import for you when you click the light bulb.)
Now lets define our Game domain class which will inherit our Entity abstract class, and will contain a Id property upon being initialized. We will add 4 more properties to our Game class which would be the columns of our Games table in our database.
It will contain 4 properties.
Title — a string with the game’s title.
Genre — a string with the game’s genre.
ReleaseYear — a integer with the games release year.
Company — A string with the gaming company that created the game.
It will also have a private constructor for initializing our Database table upon the first migration, and a public constructor for when we create new data, we would use our ModelFactory class(which we would define later) to create a new domain using this constructor. Then we will add our new data into our context class to the property of that type(which we would define later) which will be inserted it into our database.
NOTE(All of our properties are auto-implemented since we are not implementing logic within our setter. )
Awesome! Now let’s define our context class which would be responsible for bridging our application and our database.
We will define our context class but first make sure your have entity framework core nuget package install for your data project. We will have our Context class named after our solution(Games). It will inherit the DbContext class from EntityFrameworkCore.
All of the properties of our context class would be a type of DbSet with a generic type of the domain we defined earlier(Game). Have the table be named Games, and have a constructor that will take DbContextOptions with a generic type of our context class. We will use the base keyword to alter derived class options with the options defined in our constructor.
Now define your connection string that will be used to connect to the database. Go to your appsettings.Development.json. NOT!! the appsettings.json. Since the appsettings.json is used for production not for development, in our Web project.
We will then add a ConnectionStrings property with a property of DefaultConnection set to our connection string. With our host being localhost or 127.0.0.1, then our database name(which would be called games), and our username and password.
Now go to our startup.cs file, and install needed dependencies.
Import EntityFrameworkCore, and Pomelo to connect to your database. In our ConfigureServices method which will run on runtime. We will assign a connection string to variable from our Configuration property which will be our appsettings.Development.json(or appsettings.json on production). Now add a your DbContext to your services argument, and pass in your context class as a generic type. Then will have a lambda that will return our options, then we will use Pomelo which will connect to our database using the connection string we defined.
Now let’s migrate our schema, which will be code that will be generate. That will be responsible for updating or creating our database. Open your Nuget Packager Console then using the Add-Migration command with the name of the migration afterwards. Your migration will be called initial-migration, and it will migrate in your Data assembly/project.
Which will create a Migrations folder within your Data project.
Then go back to your console, and go to your Web assembly. Then type the Update-Database command which will be used to update your mysql server with your new created database using your context class. Now your MySql server should look like this.
Now our database is created, and based on our domain models using the code-first way. We will now define our repositories in our Data project, which will be our business logic layer over our Context class.
We will define our repositories.
First we will create a Repositories folder, and have a Games folder within your Repositories folder. Have a Impl(short for implementation) folder within your Games folder which will hold a class, and you will have the interface or the signature of the Repository class outside the Impl folder.
Have your all your interfaces named after the class(signature it’s following) with I in the beginning of the name of file, and it being a interface as the differences between the two files.
We will now define our signature for our GamesRepository first, our return type will be consistent through out the entire application until it hits our controller method. So the return type of repository will be the same in our service class.
Then we will define your GamesRepository class which will be responsible for getting, creating, updating, and deleting games from our context class using linq, and it follow our IGamesRepository signature.
Now we will do the last step we will perform dependency injection into our startup file, by adding it to our services argument as scoped. They are 4 types of dependency injection in .Net Core.
Instance -Will have one static instance used through out your application.
Singleton-Will have a single instance used through out your application.
Scoped-Will have a single instance used through out your http request. It will go through controller method, services, and repositories.
Transient-Will have a single instance per method. For example once it goes to the services from the repositories method it will get disposed(deleted), and a completely new instance would be created just for that method.
Awesome!!!! We are now done defining our business logic layer over our context class.
Now lets define our services which would be responsible for converting data to be used for the controller, and for creating or updating data for the repository. First go to your Services project, and create a Services, Factory, and ViewModels folder.
The purpose of these folders are…
Factory-Will hold our static ModelFactory class which will be a static class responsible for converting domain models to view models in the case of displaying data, and view models to domain model in the case of creating or updating data in our repository. Which would make suitable for context, therefore it will also be suitable through our context for our database.
ViewModels-Will be responsible for displaying data, and will passed as an argument for our controller method when creating or updating data. The purpose for it is that to prevent certain properties to be displayed. For example a password or the user’s location. To make our data presentable to the user.
Services-Will be responsible for communicating with our business logic(repositories).In order to present data using our ModelFactory suitable for the user or will be used to create data for our repositories.
We will first define our View Model folder which will hold our GameViewModel class. Our GameViewModel class in this simple case will hold all of the properties that our domain model, but in the future you would definitely want your view models to be different from your domain models.
Great now define your ModelFactory that will be responsible for making data suitable to be displayed or created/updated. In your factory folder create a ModelFactory class which would be static since all the methods would be static.
Awesome! Now lets start configuring our services using the classes we created.
First we will structure our folder in our Services folder similar to that of our Repositories folder(in the data project).It will have our GamesServices class within our Impl folder, and our interface outside of it.
First define your signature for your GamesServices class, with a interface named IGamesService.
We will now create our GamesService class which will have the signature of our repository. Why? Because when we initialize our service we will not initialize a instance of the repository, but it will have the same characteristics based on the signature. We will do the same throughout the application.
Then we will have the methods that follow the signature in the case of the method that are returning data (GetGames, GetGame, CreateGame) we will use model factory to make the data suitable for the user using the CreateViewModel method. Then in the case of void return type we will convert our view model passed as argument into a domain model using the CreateDomainModel method, then passed it to the repository. This is the bridge of where we would make data suitable for the user or the repository.
Now perform dependency injection for our service in our ConfigureServices method, and use Scoped context.
Awesome! Our service is defined.
Now we will define our controller file. Instead of creating a new file, we will just rename the ValuesController to GamesController. Then delete the data annotation on top of the controller. Then just put a Route annotation with a argument of api/games.
Now we will define a private variable which will hold our gamesService, will be type of IGamesService which is the signature of the GamesService, since it won’t be initialize. Then we will pass it as an argument to the Controller constructor method.
We will have 5 methods with each method being decorated based on the type of HttpRequest. Our get methods will return 200 status code, and our post request will return 201 status code. Then our patch and delete request will return 204 status code. All the methods will return a type of IActionResult that will automatically return json and accept json.
Awesome! Our controller is setup. In the next step in the tutorial we will have a basic setup for our react app using webpack.
Here is my github repo for reference.
A Games app implementing .NET Core, Webpack, React, and Redux. - AliA1997/GamesApp
Follow me on medium, instagram and linkedin.