.NETowo


.NET Core, web development with React and other JavaScript Frameworks

React with ECMAScript 6 in ASP.NET Core – Part I

tags: .NETCore, C#, dotnet, JavaScript, React

Hi everyone. This time I would like to introduce you to my tutorial about ReactJS with using ASP.NET Core.

A few weeks ago, I’ve started a project which uses .NET Core. There was required a simple UI in the application. In case like this I’ve always used AngularJS, but this time I thought it’s good opportunity to learn something new and I’ve chosen React.

There are a lot of tutorials about this framework in Internet, but a lot of these are created with ES5. I’m .NET developer so I like if my code is least little like C#. So, I’ve used ES6. I know there is template available in .NET core CLI which was created by Microsoft but it’s in TypeScript. You can ask me why I didn’t use it? .NET developers love TypeScript – yes, but in my opinion React community not, and I want to extend my knowledge about ES6.

What I’ll show you in this article?

  • Creating of a simple ASP.NET Core Web API application.
    If you just start your adventure with .NET Core please check my first post about this
    http://dotnetowo.pl/en/dotnet-core-on-no-windows-systems-net-core-cli/
  • Node.js and gulp configuration and first React application
  • Necessary knowledge about React – props, state, componentDidMount, componentWillMount, componentWillUnmount

If you don’t want to start from beginning you can find every part on github in own branch. Let’s start!

ASP.NET Core Web API project

  • Application creation
    Command:
    dotnet new webapi –n ReactWithDotnet
    (-n – application name)
    
  • Adding references to Static Files
    (https://www.nuget.org/packages/Microsoft.AspNetCore.StaticFiles/).In .csproj location execute below command

    Command:
    dotnet add package Microsoft.AspNetCore.StaticFiles
    
  • Packages restore
    Command:
    dotnet restore
    
  • Setting static and default filesOpen Startup.cs file and on the bottom of Configure method add two below code lines

    app.UseDefaultFiles();
    app.UseStaticFiles();
    

  • Add index.html file in wwwroot directory
    
    Dotnetowo.pl
    
     
    <div id="app-root"></div>
    <script src="index.js"></script>
    
    

Create a simple API

  • There is the ValuesController class in Controllers directory. We use it in our application. As I said I would like to focus on ReactJS so I will not make implementation of data saving to database and data will be keep in static object. My class look like in this way:
    [Route("api/people")]
    public class ValuesController : Controller
    {
    protected static List people = new List {
    new Person
    {
    Id = 1,
    FirstName = "Artur",
    LastName = "Ziemianski",
    PhoneNumber = "+48 712311231"
    }
    };
    
    // GET api/values
    [HttpGet]
    public IEnumerable Get()
    {
    return people;
    }
    
    // GET api/values/5
    [HttpGet("{id}")]
    public Person Get(int id)
    {
    return people.FirstOrDefault(w=>w.Id == id);
    }
    
    // POST api/values
    [HttpPost]
    public void Post([FromBody]Person value)
    {
    people.Add(value);
    }
    
    // PUT api/values/5
    [HttpPut("{id}")]
    public void Put(int id, [FromBody]Person value)
    {
    var person = people.First(w=>w.Id == id);
    person.FirstName = value.FirstName;
    person.LastName = value.LastName;
    person.PhoneNumber = value.PhoneNumber;
    }
    
    // DELETE api/values/5
    [HttpDelete("{id}")]
    public void Delete(int id)
    {
    var person = people.First(w=>w.Id==id);
    people.Remove(person);
    }
    }
    
    public class Person
    {
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }
    }
    
  • Expected result if you invoke localhost:5000/api/people

    If you want to skip the step you can download it on:
    https://github.com/artzie92/dotnetowo_react_dotnetcore/tree/clear_api

Configuration prepare

  • Package.json file initialization (be sure there is installed node.js on your pc)There are two ways to create this file. You can get it from below listing:

    {
    "name": "react-with-dotnet",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
    },
    "repository": {
    "type": "git",
    "url": "git+https://github.com/artzie92/dotnetowo_react_dotnetcore.git"
    },
    "author": "artur ziemianski",
    "license": "ISC",
    "bugs": {
    "url": "https://github.com/artzie92/dotnetowo_react_dotnetcore/issues"
    },
    "homepage": "https://github.com/artzie92/dotnetowo_react_dotnetcore#readme",
    "dependencies": {
    "classnames": "^2.2.3",
    "immutable": "^3.8.0",
    "react": "^15.0.2",
    "react-dom": "^15.0.1"
    },
    "devDependencies": {
    "babel-core": "^6.7.6",
    "babel-loader": "^6.2.4",
    "babel-plugin-syntax-async-functions": "^6.5.0",
    "babel-plugin-syntax-flow": "^6.5.0",
    "babel-plugin-syntax-jsx": "^6.5.0",
    "babel-plugin-syntax-object-rest-spread": "^6.5.0",
    "babel-plugin-syntax-trailing-function-commas": "^6.5.0",
    "babel-plugin-transform-flow-strip-types": "^6.5.0",
    "babel-plugin-transform-object-rest-spread": "^6.6.5",
    "babel-plugin-transform-react-jsx": "^6.7.5",
    "babel-plugin-transform-regenerator": "^6.5.2",
    "babel-plugin-transform-runtime": "^6.5.2",
    "babel-preset-es2015": "^6.5.0",
    "babel-preset-react": "^6.22.0",
    "babelify": "^7.3.0",
    "browserify": "^14.0.0",
    "events": "^1.1.1",
    "flux": "^3.1.2",
    "flux-utils": "^1.0.2-stop",
    "gulp": "^3.9.1",
    "vinyl-source-stream": "^1.1.0",
    "webpack":"2.5.1"
    }
    }
    

    Or you can use npm-init command in main application directory and fill base data yourself, like on screen below.

    As you can see I used in this example terminal integrated with Visual Studio Code. I recommend this feature because it speeds up our work and we have everything in one window.

    Let’s move to package.json file now which has been generated and will add required packages.

  • Gulp configurationAs I said before there will be used ES6 in our application. EXMAScript 6 is not supported by browsers. It’s reason why we need tool which will convert our code to ES5 and will move it to one file. The file will be added to our website.
    First let’s install gulp
    – npm install gulp -g
    

    Thanks for this gulp command should be available in whole system scope.

    Next, we need to create gulpfile.js. Please fill it like on below listing

    //gulpfile.js
    var gulp = require('gulp');
    var browserify = require('browserify');
    var babelify = require('babelify');
    var source = require('vinyl-source-stream');
    
    gulp.task('build', function () {
    return browserify({entries: './clientapp/root', extensions: ['.jsx', '.js'], debug: true})
    .transform('babelify', { presets: ['es2015', 'react'] })
    .bundle()
    .pipe(source('index.js'))
    .pipe(gulp.dest('./wwwroot/'));
    });
    
    gulp.task('watch', function () {
    gulp.watch('./clientapp/**/*{.js,.jsx}', ['build']);
    });
    
    gulp.task('default', ['watch']);
    

As you can see there are three tasks in the configuration

  1. ‘build’ – the task will build our application and will create index.js file. The fill will be placed in wwwroot director and we will attach it in index.html file
  2. ‘watch’ – the task follows files with .js and .jsx extensions. If one of them did change, build will execute
  3. ‘default’ – there is list of default tasks

A simple application in ReactJS

We have everything what we need to start working with React. Let’s start!

  • First of all, create children of clientapp directory like on below screen. There will be created whole front-end side

    This article is about react fundaments so we will not use whole structure but it will be necessary in the next parts.

  • app.container.js file modificationsIn the file we’ll create our first component which will be entry point of a whole application.

    //app.container.js
    import React, { Component } from 'react'
    
    class AppContainer extends Component{
    constructor(props){
    super(props);
    }
    
    render(){
    return(
    <div>Welcome on dotnetowo.pl</div>
    );
    }
    }
    
    export default AppContainer;
    
    

    A first code line is import from react module. Next there has been created AppContainer component. There is nothing special in constructor,
    we’ll back here again later. Last element it’s a render function. The function is responsible for HTML rendering.

  • root.js file modificationsThere will be initialized our component and will be showed in index.html.

    //root.js
    'use strict';
    
    import AppContainer from './containers/app.container';
    import React from 'react';
    import ReactDOM from 'react-dom';
    
    ReactDOM.render(
    ,
    document.getElementById('app-root')
    );

    First argument of ReactDOM object’s method is element which will be add to DOM. Second argument it’s container where our element should be rendered.

  • Node.js packages installation and application buildIt’s time to create our index.js file which will be saved in wwwroot directory and loaded on a website.
    1. Node.js packagesIn directory with package.json file please execute below command

      npm install
      
    2. Application buildIn directory with gulpfile.js file please execute below command

      gulp build
      

    3. Application runIf everything was finished successful in wwwroote directory has been generated index.js file. You can execute below command in directory with ReactWithDotnet.csproj file

      dotnet run
      

      The application is available on localhost:5000 and should looks like on below screen

    The code for above steps you can find on
    https://github.com/artzie92/dotnetowo_react_dotnetcore/tree/base_react_structure

Components

Bravo! You’ve created a first ReactJS application. A react application always contains one or more components. So, when you think about your application you should trying split it on components. Thanks for components there is easy way to a code reusing.

Our application will be simple contact book. So, there is necessary people list and we will create a ‘people-list-component.js’ for this. Please add below file in components directory

//people-list.component.js
import React, { Component } from 'react';

class PeopleListComponent extends Component {
constructor(props) {
super(props);
}

render() {
return (
<div>
<h2>People list component</h2>
{this.props.name}

</div>
);
}
}

export default PeopleListComponent;

Next please modify app.container.js

//app.container.js
import React, { Component } from 'react'
import PeopleListComponent from '../components/people-list.component';

class AppContainer extends Component{
constructor(props){
super(props);
}

render(){
return(
<div>Welcome on dotnetowo.pl</div>
);
}
}

export default AppContainer;

I used props object which was transferred in component’s constructor. The value was set up in ‘app.container.js’. You screen should looks like on the screen

About props object you will read in next chapter.

Necessary knowledge: props, state, componentDidMount, componentWillMount, componentWillUnmount

There are two data types for component control – props and state. First of these is constant during whole component lifecycle and it’s set up by parent. In above example in AppContainer component we assigned a value to ‘name’ parameter and next we showed the value in PeopleListComponent.

If you want to refresh your data after changes you must use state object. You should set up directly a value to state object only one time – in component constructor. In other places you have to use setState() method, which provides component refreshing. Our application is in early version now but before we go to next more complicated parts please modify PeopleListComponent like below

//people-list.component.js
import React, { Component } from 'react';

class PeopleListComponent extends Component {
constructor(props) {
super(props);

this.incrementer = this.incrementer.bind(this);
this.wrongDecrementer = this.wrongDecrementer.bind(this);

this.counter = 0;
this.wrong = 0;
this.state = {
test: this.counter,
test2: this.wrong
}
}

componentDidMount(){
this.incrementer();
this.wrongDecrementer();
}

wrongDecrementer(){
this.wrong--;
this.state.test2 = this.wrong;

setInterval(this.wrongDecrementer, 2000);
}

incrementer() {
this.counter++;
this.setState({
test: this.counter
})
setInterval(this.incrementer, 5000);
}

render() {
return (
<div>
<h2>People list component</h2>
{this.props.name}

Test variable in state object: {this.state.test}

Test set state in wrong way: {this.state.test2}

</div>
);
}
}

export default PeopleListComponent;

In above code, I added two variables to state object: test and test2. First of these should
be incremented by one in 5 sec intervals. ‘test2’ should be decremented by one in 2 sec intervals.
For ‘test’ I used correctly change value method – setState(). In second case I assigned new value directly to state object.
I believe you saw that ‘test2’ is not updated every 2 secs but after 5 sec.
It works in this way because directly set up doesn’t invoke render method. So it’s is really important to use setState() method because it does it.

For sure you saw to below code lines

this.incrementer = this.incrementer.bind(this);
this.wrongDecrementer = this.wrongDecrementer.bind(this);

Thank for these lines there is possible to refer to component context by ‘this’ key word.

Next new thing is componentDidMount() method

componentDidMount(){
this.incrementer();
this.wrongDecrementer();
}

The method is executed if component has been created. Try invoke content of this method in constructor and look in java script console then you will understand for sure why I used componentDidMount() in this case.

Next two important methods: componentWillMount() and componentWillUnmount(). I think that names of these methods say how they work. We’ll use the methods later but I recommend check it yourself :).

Summary

In the first part of this tutorial I showed you how you can connect in a simple way .NET Core Web API with ReactJS. Now you are ready to test your knowledge. Create a few components and make references between these. Check how work state and props objects. Check 3 new methods. It’s fundamental knowledge and it’s necessary in next steps, so please try to understand as many as possible.

In the next article, we’ll go to Flux concept. The concept is helpful in component lifecycle management.

Thank you very much for you visit. Please feedback and I hope to next time :).

Repozytorium:

https://github.com/artzie92/dotnetowo_react_dotnetcore/tree/base_react_knowledge


Comments

Author: Zosia

2017-06-15 23:52:15 | Szczerze świetny artykuł, wyjątkowo mi się przydał. Będę zaglądał częściej.

Got Something To Say:

Your email address will not be published. Required fields are marked *