Full-Stack MVC Application with Redux

This post covers the end-to-end process (wiring MVC and React) of creating a brand new ASP.NET MVC website and adding a React component in it. We will start from scratch and end with a fully functioning component.

We can use .NET Framework, but you can instead use .NET Core if you want to be able to run your site on Linux or Mac OS. Currently .NET Core is missing some of the functionality provided by .NET Framework, so it is recommended to use .NET Framework unless you have a reason to use .NET Core specifically (eg. cross-platform support).

Start by creating a new ASP.NET Core MVC project:

  1. File → New → Project
  2. Ensure “.NET Framework 4.6” is selected in the dropdown list at the top
  3. Go to Templates → Visual C# → Web and select the “ASP.NET Core Web Application (.NET Framework)” template. 

We need to install ReactJS.NET to the newly-created project. This is accomplished using NuGet, a package manager for .NET. Right-click on your project in the Solution Explorer and select “Manage NuGet Packages”. Click the “Browse” tab, search for “React.AspNet”, and install the React.AspNet package.

We also need to modify the Startup.cs file to initialize ReactJS.NET. Open Startup.cs and perform the following changes:

At the top of the file, add:

<code class="csharp language-csharp" data-lang="csharp"><span class="k">using</span> <span class="nn">Microsoft.AspNetCore.Http</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">React.AspNet</span><span class="p">;</span>
</code>

Directly above:

<code class="csharp language-csharp" data-lang="csharp"><span class="c1">// Add framework services.</span>
<span class="n">services</span><span class="p">.</span><span class="n">AddMvc</span><span class="p">();</span>
</code>

Add:

<code class="csharp language-csharp" data-lang="csharp"><span class="n">services</span><span class="p">.</span><span class="n">AddSingleton</span><span class="p">&lt;</span><span class="n">IHttpContextAccessor</span><span class="p">,</span> <span class="n">HttpContextAccessor</span><span class="p">&gt;();</span>
<span class="n">services</span><span class="p">.</span><span class="n">AddReact</span><span class="p">();</span>
</code>

Directly above:

<code class="csharp language-csharp" data-lang="csharp"><span class="n">app</span><span class="p">.</span><span class="n">UseStaticFiles</span><span class="p">();</span>
</code>

Add:

<code class="csharp language-csharp" data-lang="csharp"><span class="c1">// Initialise ReactJS.NET. Must be before static files.</span>
<span class="n">app</span><span class="p">.</span><span class="n">UseReact</span><span class="p">(</span><span class="n">config</span> <span class="p">=&gt;</span>
<span class="p">{</span>
  <span class="c1">// If you want to use server-side rendering of React components,</span>
  <span class="c1">// add all the necessary JavaScript files here. This includes</span>
  <span class="c1">// your components as well as all of their dependencies.</span>
  <span class="c1">// See http://reactjs.net/ for more information. Example:</span>
  <span class="c1">//config</span>
  <span class="c1">//  .AddScript("~/Scripts/First.jsx")</span>
  <span class="c1">//  .AddScript("~/Scripts/Second.jsx");</span>

  <span class="c1">// If you use an external build too (for example, Babel, Webpack,</span>
  <span class="c1">// Browserify or Gulp), you can improve performance by disabling</span>
  <span class="c1">// ReactJS.NET's version of Babel and loading the pre-transpiled</span>
  <span class="c1">// scripts. Example:</span>
  <span class="c1">//config</span>
  <span class="c1">//  .SetLoadBabel(false)</span>
  <span class="c1">//  .AddScriptWithoutTransform("~/Scripts/bundle.server.js");</span>
<span class="p">});</span>
</code>

Finally, add this to Views\_ViewImports.cshtml:

<code class="csharp language-csharp" data-lang="csharp"><span class="n">@using</span> <span class="n">React</span><span class="p">.</span><span class="n">AspNet</span></code>

 

Choosing a JavaScript Framework

Choosing a JavaScript Framework has been never an easy decision because there is so much to consider.

Rob Eisenberg is a JavaScript framework expert. He is the mechanic behind Caliburn.Micro, Durandal and Aurelia, and has also worked on the Angular 2.0 and Angular Material teams. This post was originally written as a summary of Rob’s talk. 

The frameworks under the spotlight are:

Angular 1.x
Angular 2 (Angular 2+)
Aurelia
Ember
Polymer
React

Angular 1.x is an all-in-one framework. Rob says it is pretty much deprecated, there’s literally a fixed number of months left on the lifetime of that framework
and it’s probably fair to say that you shouldn’t start a new project in Angular JS right now, and you should be thinking about how you might migrate any existing code bases.

Rob describes Angular 2, Aurelia, Ember and Polymer as also All-in-one frameworks, but modern ones.

React is not a framework, per se. It’s a view rendering engine or a component model.

Rob recommends Visual Studio Code and is using it on his Mac. 

For a very simple Hello World application, we will compare these frameworks:

Angular 1.x
index.html is 13 lines of code
We see the ng-controller and ng-model directives.
app.js is 8 lines of code.

Rob describes this as a throwback to the previous generation of frameworks: Angular specific modules rather than ES2015 modules. He describes the Angular 1 two way data-binding model.
(As of Angular 1.5 we have Angular Components as a superior alternative to using controllers and directives.)

Angular 2
Rob says Angular 2 really focuses on TypeScript, and it is much more difficult to use plain JavaScript so most people are going to be kind of pushed down the TypeScript road necessarily with Angular 2 (The equivalent documentation is available for TypeScript, JavaScript and Dart. Judge for yourself how much more difficult it is to use with plain JavaScript)
index.html is 32 lines of code
(I could not believe that there isn’t a simpler way to write this in Angular 2. Rob has found some Angular 2 documentation that pulls in a whole load of modules. For the purposes of developing a hello world type app, Rob is pulling in the following modules:
es6-shim
system-polyfills.js
shims for IE.js
angular2-polyfills.js (no longer part of the Angular2 RC)
system.src.js
Rx.js
angular.dev.js
There is also a bunch of code for here configuring a System JS module loader. System JS is written by Guy Bedford and Max Norlund and has nothing to do with Angular 2)
main.ts — 4 lines
app.component.ts — 20 lines

Rob explains the Angular2 decorator. He uses an inline template rather than using a template URL. He also explains two-way data-binding in Angular2, and points out that Google have deviated from the HTML specification by using mixed casing.

Aurelia
index.html — 10 lines. This imports System JS and uses it to import the Aurelia bootstrapper.
app.js — 8 lines
app.html — a template with 5 lines of code. Rob explains the two way data binding mechanism used here.

Ember
index.html — 16 lines. Imports jquery, handlebars, ember and app.js
app.js — 23 lines.

Rob says Ember is a very strict MVC paradigm and requires a router even for Hello World.

Polymer
index.html — 10 lines.
my-app.html — 22 lines including template, a script block and 4 blank lines.

Rob says the web components centric philosophy concerns him because it doesn’t make sense to do everything in HTML but there it is, that’s my opinion
Rob likens Polymer to the long forgotten Microsoft Acropolis project from 2008 which tried to do everything in XAML.

React
index.html — 13 lines, importing es5-shim, es5-sham and console-polyfill
app.js — 39 lines.

ASP.NET MVC and Redux

When we at Spoil decided to roll out our mobile app, one of the first decisions we had to make was: what language do we use? After some deliberation, the decision was made: React-Native it was going to be. Learning a new “language” or framework isn’t a huge issue. 

React-Native and Redux?

As soon as you start learning about react-native (or react), you start to understand state vs props, you know what componentDidMount does and you even understand how to properly create your components so they are re-usable. Now all of a sudden you found yourself talking about stores, reducer compositions, actions and mapping state to props.

Some Analogies

If you are coming from an MVC (or MVVC) world, you are used to models, views and controllers. However in Redux we are dealing with actions, reducers, stores and components. Trying to “translate” MVC to Redux is tricky but here is how I would do it:

Actions = Controller. Think of your actions as the controller. Whenever you want something to happen in your app (i.e. load some data, change a isLoading flag from true to false…) you will have to dispatch an action. Just like in MVC where you would have to call a controller endpoint.

Reducer = Model. Sort of. Your reducers will be in charge of holding the current state of your application (i.e. user info, information loaded from the api, items you want to display…). It will also be the part that decides what to do when an action is called. While in MVC you might have a model with the method setName(), with Redux you would have a reducer handle an action to set the name in the state.

Stores = ???. The store is Redux specific and doesn’t really have an equivalent in MVC. Not to worry though. This part is taken care off behind the scenes. The store is like a container for the state that aggregates all of the reducers. It has a method to the get the current state, and exposes ways to subscribe to the state changes (using the “connect()” method). This is what will allow you to call actions and pass them in as props to your components.

Components = Views. Components are kind of like your smart views. They display the information that they get from the state. I recommend splitting up your components into two parts. One just for the presentational part (dumb components) and one to handle all of the actions and state changes (smart components).

Moving From MVC Thinking to Redux Thinking

One of the main differences between MVC and Redux is that, while in MVC data can flow in a bidirectional manner, in Redux it strictly moves in one direction.

With Redux things work a little differently. Let’s say you have a component and you want to do something when a button gets pressed. Where do you start? 

  1. Define your Action
  2. Define your Reducer
  3. Define the Actions as a Prop in your Component
  4. Wire it up in your View

 

.NET Core Angular Templates

The latest tooling in Visual Studio for .NET Core will be pretty good. Fortunately, the dotnet sdk, and subsequently the CLI, have libraries available for various Single Page Application framework quick starts.

With the latest version of Visual Studio 2015+ installed, you should have the dotnet core SDK version 1.0.3 installed. If not, you can download the SDK.

The “dotnet –info” command can be used to confirm SDK version. 

To get started with “dotnet new” (new being the command to create new projects), the SPA templates for Angular and other various frameworks can be utilized after installing this package:

dotnet new –install Microsoft.AspNetCore.SpaTemplates::*

This will run for a bit and install various dependencies. After installation is complete, the available templates can be viewed by running “dotnet new” by itself.

By using this template, you get a nice base starting point for an Angular application. Some of the niceties are having the build process already configured for bundling, minification, and various dependencies already configured.

Webpack, TypeScript, and other things will appear already configured when the project is opened in future version of Visual Studio 2015+.

Running the project for the first time can take a bit of time since all of the npm packages and such are pulled down. But, the template does have a few little niceties and is a fully working Angular project. The “Hello, world!” view has some nice information about the template and details some parts of the technology used in the template.

Copyright © All Rights Reserved - C# Learners