Vue and MVC API

by Lewis


Posted on January 1, 2018 at 12:00 PM


This article describes creating a Vue client application that will consume data from an MVC API. The code described in this article can be downloaded or cloned from here: https://github.com/githubLewis/vue_dot_net



Getting started

To install and use the Vue CLI as well as run the Vue application server, you'll need the Node.js JavaScript runtime and npm (the Node.js package manager) installed. npm is included with Node.js which you can install from here.

To install the vue/cli , in a terminal or command prompt type:

npm install -g @vue/cli

This may take a few minutes to install. Once complete, you can now create a new Vue.js application by navigating to your source folder and in your command window or terminal typing:

vue create <my-app>

where <my-app> is the name of your application this will be used as the folder name and must be in lowercase. You will be prompted to select a preset, for this example you can keep the default (babel, eslint), which will use Babel to transpile the JavaScript to browser compatible ES5 and install the ESLint linter to detect coding errors. It may take a few minutes to create the Vue application and install its dependencies.

Let's quickly run our Vue application by navigating to the new folder in the terminal or command window and typing "npm run serve" to start the web server and open the application in a browser:

cd my-app
npm run serve

After npm reports that the app is running, navigate to http://localhost:8080 or the address shown in the terminal window or command prompt and you should see "Welcome to your Vue.js App". You can press Ctrl+C to stop the vue-cli-service server.

To open your Vue application in VS Code, from a terminal (or command prompt), navigate to the my-app folder - if you are following so far you will already be in this folder - and type the following;

cd my-app [if not in the app folder already]
code .

VS Code will launch and display your Vue application in the File Explorer. Restart your server (npm run serve) and then in VS Code press F5. This will prompt you for a configuration and then create a .vscode folder and a launch.json with your selected config. E.g;

{

"version": "0.2.0",

"configurations": [

{

"type": "chrome",

"request": "launch",

"name": "Launch Chrome against localhost",

"sourceMaps": true,

"url": "http://localhost:8080",

"webRoot": "${workspaceRoot}",

"trace": true

}

]

}

I have edited mine as above and added the sourceMaps & trace property. <expand why>

Install required packages

For this project we will be using some 3rd party packages to provide us with additional functionality, these are as follows;

bootstrap-vue - a vue implementation of the Bootstrap library
axios - a vue implementation of a Http Client
vue-router - a vue implementation reuired for routing our pages throughout the site

To install these, navigate back to the command prompt or terminal window and enter;

npm install bootstrap-vue
npm install axios
npm install vue-router

With that complete, we can move onto the next step.

 

Creating our MVC Web API

For this step we will be using Visual Studio 2017. Fire it up and select "New Project"
From the project types, select "ASP.NET Web Application (.NET Framework)"

From the Web Application type box, select "Web API" & press OK


Your web API will be created with the default controllers. Pressing F5 at this point will start up the API, displaying a default Home page - you will also be able to execute the following example calls;

Values/Get

For the purpose of this walk-through, we will just leave everything as it is. For a production solution you may wish to remove the default controllers\views\scripts etc. Make a note of the localhost address this project is using, we will be needing it shortly.

Install required packages

For this project we will be using some additional packages to provide functionality, in particular we need the latest Microsoft.AspNet.WebApi.Cors library (I will discuss further later in the article).

From your Package Manager Console in Visual Studio 2017 type the following

Install-Package Microsoft.AspNet.WebApi.Cors

or from within the Nuget manager, search for "Microsoft.AspNet.WebApi.Cors" and install it.

Adding code

Lets add a basic controller and method that will return a simple object containing a list of people that we can consume in our Vue front end. Delete any default controllers and add the following code to your project;

Person.cs

public class Person

{

public int Key { get; set; }

public string Name { get; set; }

}

TestAPIResult.cs

public class TestAPIResult

{

public bool success { get; set; }

public Person[] audience { get; set; }

}

To create the controller:

  1. right click the "Controllers" folder
  2. select Add New > Controller
  3. select "Web API 2 Controller - Empty"

Alternatively add a new class and paste the following code in;

TestController.cs

[RoutePrefix("audience")]

public class TestController : ApiController

{

[HttpGet]

[Route("list")]

public TestAPIResult GetPeople()

{

TestAPIResult tar = new TestAPIResult();

tar.audience = new Person[3] {

new Person() { Key = 1, Name = "Charmaine" },

new Person() { Key = 2, Name = "Lewis" },

new Person() { Key = 3, Name = "Jessica" }

};

tar.success = true;

return tar;

}

}

This method is simply returning a simple object that will contain list of people. Save and run the project. Using your browser or a REST client (Fiddler, PostMan etc..) call the API;

<api_url>/audience/list

which will return;

Browser

Fiddler


Great! So with both our projects configured and set up, its time to get them communicating!

Calling our Web API from Vue

For our REST calls, we will be using the axios library that we installed in a previous step, more details can be found here.

Navigate to the Vue application currently open in VS code. In the Explorer pane, add a new file to the src folder and call it "api.js". The code in this file will be responsible for consuming our Web API. At the top of the file add this code;

import axios from 'axios'

const client = axios.create({

baseURL: '<api_url>',

json: true

})

Quick overview of this code - all we are doing here is importing the axios library and configuring a default client. Remember that Host address from the Web API project? That url needs to be entered where it says <api_url>. Next we will create a method to call our REST API audience method we created earlier. In the api.js file add this code directly below the code above that is already in the file;

export default {

async execute (method, resource, data) {

// inject the accessToken for each request

// let accessToken = await Vue.prototype.$auth.getAccessToken()

return client({

method,

url: resource,

data,

headers: {

'Content-Type': 'application/json'

/*Authorization: `Bearer ${accessToken}`*/

}

}).then(req => {

return req.data

}).catch()

.finally()

},

getAudience () {

return this.execute('get', '/audience/list')

}

}

In the code above, we are creating a method (getAudience) that will use the default axios client, created in the execute method, to call the REST API. I have implemented a custom execute method solely as I want to add a Authorization header a bit further down the line but to keep this simple for now, the lines pertinent to that are commented out.
With the above code implemented, we can now move on and display the data returned from the API. Save and close the API.js file.

Using vue-router and Bootstrap-vue

Open up "main.js" and remove all the created code. Add the following code to the top of the file;

import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App.vue'
import BootstrapVue from 'bootstrap-vue'
import axios from 'axios'

import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

import home from '@/components/projectsDashboard'
import about from '@/components/projectsDashboard'

 

Vue.use(VueRouter)

Vue.use(BootstrapVue)

The code above is fairly straight forward, we are importing our libraries, followed by importing the bootstrap (and bootstrap-vue) specific css files. The next two lines then import our two components and the final two tell Vue to use the bootstrap-vue and the vue-router plug ins we installed earlier.

Next add the following lines;

const routes = [

{ path: '/', component: home },

{ path: '/about', component: about }

]

 

const router = new VueRouter({

routes // short for `routes: routes`

})

The lines above are required for the vue-router package and describes the routes our app will use. For this example, I have kept it extremely simple by adding just the two routes. Entering http://localhost:8080/ will display the "home" component and Entering http://localhost:8080/about will display the "About" component. More on these components shortly.

Now add the following lines;

Vue.config.productionTip = false
Vue.prototype.$http = axios

The code above sets the "productionTip" config property and sets axios to be our default http client. Next;

new Vue({

router,

render: h => h(App),

}).$mount('#app')

These lines simply configure the Vue client with the route and kicks our application off.

The "home" and "about" components

In our routes defined previously, we routed calls to / and /About to components called "home" and "about". However, these components do not exist yet. To create them do the following;

  • In Visual Studio Code, navigate to the "components" folder under the "src" folder.
  • You can delete the "HelloWorld.vue" if you like.
  • Add a new file and call it "home.vue"
  • Add a new file and call it "about.vue"

In the "home.vue" file created, add the following code;

<template>

<div>

<p>I'm the HOME page!</p>

</div>

</template>

<script>

export default {

name: 'home'

}

</script>

In the "about.vue" file created, add the following code;

<template>

<div>

<p>I'm the ABOUT page!</p>

</div>

</template>

<script>

export default {

name: 'about'

}

</script>

Your Vue project should now look similar to this;

Now we have two custom components that we can display when we navigate to the routes described previously. You might expect that by running this project now, these components will be displayed. However this will not be the case, because while we have defined the components & the routes we haven't a parent that will render them. Lets fix that now;

Navigate to the default App.Vue file. The App.Vue file out of the box contains some simple code to display a "hello world" message. We won't be needing this so within the App.vue file replace the existing code with this;

<template>

<div id="app">

<body>

<div class="container-fluid">

<router-view />

</div>

</body>

</div>

</template>

<script>

export default {

name: 'app',

components: {

}

}

</script>

<style>

#app {

font-family: 'Avenir', Helvetica, Arial, sans-serif;

-webkit-font-smoothing: antialiased;

-moz-osx-font-smoothing: grayscale;

text-align: center;

color: #2c3e50;

margin-top: 60px;

}

</style>

Notice the <router-view /> tag? This tag comes from the vue-router package that we installed early on in this tutorial. This is where our components - referenced in the routes definition - will be rendered. Time to test!

In your command or terminal window, navigate to your project folder & start your development server;

npm run serve

 

Navigate to http://localhost:8080 and you will see the following page;

Navigate to http://localhost:8080/#/about and you will see the following page;

 

So at this point we will take stock of where we are, so far we have;

1) Created a Vue application & installed required libraries.
2) Defined routes and components to display on the website.
3) Created a MVC Web API that will accept REST calls to audience/list and return a list of people.
4) Written the code to call our custom API from Vue.

The final piece is to call the API from one of our Vue components and display the data returned on the web page. Open up the "home" component we created in the previous step.

Replace the existing code (added previously) with the following code;

<template>

<div>

<div>

<b-list-group>

<b-list-group-item disabled>My Audience</b-list-group-item>

<b-list-group-item button v-for="person in people" :key="person.Key">

<router-link :to="`/project/${person.Key}/overview`">{{ person.Name }}</router-link>

</b-list-group-item>

</b-list-group>

</div>

<section v-if="errored">

<p>We're sorry, we're not able to retrieve this information at the moment, please try back later</p>

</section>

<section v-else>

<div v-if="loading">Loading...</div>

</section>

</div>

</template>

<script>

import api from '@/api'

export default {

name: 'home',

data () {

return {

people: [],

loading: true,

errored: false

}

},

mounted () {

api.getAudience()

.then(response => {

this.people = response.data.audience

})

.catch(() => this.errored = true )

.finally(() => this.loading = false )

}

}

</script>

Navigate to http://localhost:8080

Has your data been successfully displayed? No!

What is going on here? Open up the console in the developer tools in your preferred browser (mine is Chrome so F12) and refresh the page. Do you notice any errors? In particular we are looking for errors similar to his;

So why is this occurring? A CORs request can be used by hackers etc to exploit your browser and perform attacks, by default MVC will not allow Cross Origin Requests. To resolve this we must make use of the Cors package that we installed when we initially created our API. To use the Cors library follow these steps;

  • Navigate to Visual Studio 2017 and the API project.
  • Open the file "WebApiConfig.cs" in the App_Start folder.

Add the using statement at the top

using System.Web.Http.Cors;

Add the following lines below any existing code in the Register function;

var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);

These two lines simply tell the API to accept request from any domain. in a production environment you may wish to lock this down and\or indeed secure with a Authorization header I touched on earlier.

Rebuild and run the API project again.
Navigate to your Vue website - http://localhost:8080/ and now you should see data being returned and displayed in a list.

And thats it, we now have a Vue front end that talks to a .NET API.

Finishing up

There are a couple of areas I didn't cover in this article;

Vue extensions for VS Code. There are plenty, I use:
Bootstrap\Bootstrap-Vue. More info on Bootstrap here or go directly to the Vue implementation - Bootstrap-vue.
launch.json options & config: