3/19/2017 Webmaster

An Angular 2+ .Net Core Application Consuming an Azure Machine Learning Model


image

You can create an Angular 2+ application that consumes a web service created from an Azure Machine Learning experiment.

This article is part of a series of articles where we create an Azure Machine Learning experiment that predicts the price of a vehicle given parameters such as make, horsepower, and body style. It does that by creating a Model based on prices of previous vehicles. We then operationalize the model by creating a web service.

In this installment, we will create an Angular 2+ application that consumes the web service. Finally we will create a programmatic method to update the model with new data gathered from our Angular 2+ application.

The series of articles are as follows:

  • An End-To-End Azure Machine Learning Studio Application   – Create an Azure Machine Learning experiment and operationalize it by creating a web service and consuming it using Microsoft Excel.
  • (This article) An Angular 2+ Application Consuming an Azure Machine Learning Model – Create an Angular 2+ application that consumes a web service created from an Azure Machine Learning experiment.
  • Retraining an Azure Machine Learning Application – This article covers the steps needed to update the Azure Machine Learning model with new data to improve its predictions.

The Application

image

The Angular 2+ application, that will be covered in this article, allows users to set the values that will be passed to the Azure Machine Learning web service (that was created in An End-To-End Azure Machine Learning Studio Application ).

image

The user can click the Price Vehicle button to call the web service.

The Predicted Price, returned by the web service, will then display.

image

The user can also record the actual sale price (based on the currently selected values) by entering the value and clicking the Record Price button.

The data will be stored in the local database file.

image

Clicking the Export Data button will produce a .csv file that can then be used to retrain the Azure Machine Learning Model, thereby improving the future predictions.

Creating The Application

If you do not already have them, install the following prerequisites:

image

Log into the Azure Machine Learning Studio at: https://studio.azureml.net/.

image

Select Web Services, then the predictive web service that we created in the previous article.

image

1) Click the button to copy the API Key. Save it. We will need it later. This will be what we will use as the PrimaryKey value in the appsettings.json file.

2) Click the REQUEST/RESPONSE link that will take us to the sample code page.

image

When the Request Response API Documentation page appears, copy the Request POST web address. Save it. We will need it later.

This will be what we will use as the BaseAddress value in the appsettings.json file.

image

Next, scroll down to the bottom of the page to see sample code that calls the web service.

This is what we will use at the base code for our application.

Create The .Net Core Application

image

Create a folder on your Microsoft Windows computer (this tutorial was created using Windows 10).

Note: Do not have any special characters in the folder name. For example, and exclamation mark (!) will break the JavaScript code.

image

You can type CMD and press Enter to switch to the command line (and still be in that directory).

image

If you have not already installed JavaScriptServices, install them by entering (and pressing Enter):

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

								
									
										image
									
								
									
									The screen will display indicating the templates now available.
								

								
									image
								

Create the ASP.NET Core JavaScriptServices application by entering (and pressing Enter):

								
dotnet
									new
									angular

image

The application will be created.

Double-click on the *.csproj file to open it in Visual Studio 2017.

image

It will start restoring .Net dependencies and the node_modules (you can view the ../node_modules directory to see the items populated).

(Note: This can take 3-10 minutes or more)

image

Visual Studio will indicate when everything is complete.

image

Press Ctrl+F5 to Start Without Debugging.

image

The application will show.

Close the web browser for now.

Add PrimeNG

image

We will now install the free open source PrimeNG Angular 2 components.

image

Open the package.json file and add:

								
									"font-awesome": "^4.7.0",
								
									"primeng": "^2.0.0"

Save the file.

image

Open the webpack.config.vendor.js file and add:

								
									'font-awesome/css/font-awesome.css',
								
									'primeng/primeng',
								
									'primeng/resources/themes/omega/theme.css',
								
									'primeng/resources/primeng.min.css',

image

Also, in rules/test, add:

								
									|gif

Save the file.

image

At this time, PrimeNg does not support pre-rendering so in ..\Views\Home\Index.cshtml, change:

								
									
										<
										app
										asp-prerender-module="ClientApp/dist/main-server"
										>Loading...</
										app
										>
									

to:

								
									
										<
										app
										>Loading...</
										app
										>
									

Save the file.

image

Open ..\Views\Shared\_Layout.cshtml and replace all the code with the following code:

								
									<!DOCTYPE html>
								
									<
									html
									>
								
									<
									head
									>
								
									<
									meta
									charset="utf-8"
									/>
								
									<
									meta
									name="viewport"
									content="width=device-width, initial-scale=1.0"
									/>
								
									<
									title
									>@ViewData["Title"] - AzureMLCore</
									title
									>
								
									<
									base
									href="/"
									/>
								
									<
									link
									rel="stylesheet"
									href="~/dist/vendor.css"
									asp-append-version="true"
									/>
								
									</
									head
									>
								
									<
									body
									>
								
									<
									div
									class="navbar navbar-inverse navbar-fixed-top"
									>
								
									<
									div
									class="container"
									>
								
									<
									div
									class="navbar-header"
									>
								
									<
									button
									type="button"
									class="navbar-toggle"
								
									data-toggle="collapse"
									data-target=".navbar-collapse"
									>
								
									<
									span
									class="icon-bar"
									>
									</
									span
									>
								
									<
									span
									class="icon-bar"
									>
									</
									span
									>
								
									<
									span
									class="icon-bar"
									>
									</
									span
									>
								
									</
									button
									>
								
									@Html.ActionLink(".Net Core Angular 2 Azure Machine Learning App",
								
									"Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
								
									</
									div
									>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="container body-content"
									>
								
									@RenderBody()
								
									</
									div
									>
								
									<
									hr
									/>
								
									@RenderSection("scripts", required: false)
								
									</
									body
									>
								
									</
									html
									>
								

							

image

We altered the webpack.config.vendor.js file (to add PrimeNg and Font Awesome) but the compiled files that it creates (that are used at runtime) are not updated by the normal build process. We have to run its configuration manually whenever we alter it.

In a command prompt, at the project root, run:

								
webpack --config webpack.config.vendor.js

(Note: If you don’t already have the webpack tool installed (for example you get an error when you run the code above), you’ll need to run: npm install -g webpack first)

Add The Database

image

Right-click on the project node, select Add then New Scaffolded Item…

image

Select Full Dependencies then click Add.

image

The Scaffolding will run.

image

Close the ScaffoldingReadMe.txt file that opens.

We will perform the needed changes it describes in the next steps.

image

Right-click on the project node and select Edit AzureMLCore.csproj.

image

Add:

								
									
										<
										DotNetCliToolReference
										Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools"
										Version="1.0.0"
										/>
									

Save and close the file.

image

From the menu in Visual Studio, select Tools then Connect to Database…

image

  • Ensure that Microsoft SQL Server Database File (SqlClient) is selected for Data source (use the Change button if not)
  • Enter AzureMLData.mdf for the database name and indicate that it is in a folder called Data that is under your project root (the file does not exist, it will be created by Visual Studio)
  • Click OK

image

Click Yes to create the database.

image

In the Server Explorer window in Visual Studio (you can get to it from the Visual Studio menu using View then Server Explorer), the database will show.

Expand it, right-click on the Tables node and select Add New Table.

image

Enter the following script and click the Update button:

								
									CREATE
									TABLE
									[dbo].[Vehicles] (
								
									[Id]
									INT
									IDENTITY
									(1, 1)
									NOT
									NULL,
								
									[symboling]
									NVARCHAR
									(50)
									NULL,
								
									[normalized-losses]
									NVARCHAR
									(50)
									NULL,
								
									[make]
									NVARCHAR
									(50)
									NULL,
								
									[fuel-type]
									NVARCHAR
									(50)
									NULL,
								
									[aspiration]
									NVARCHAR
									(50)
									NULL,
								
									[num-of-doors]
									NVARCHAR
									(50)
									NULL,
								
									[body-style]
									NVARCHAR
									(50)
									NULL,
								
									[drive-wheels]
									NVARCHAR
									(50)
									NULL,
								
									[engine-location]
									NVARCHAR
									(50)
									NULL,
								
									[wheel-base]
									NVARCHAR
									(50)
									NULL,
								
									[length]
									NVARCHAR
									(50)
									NULL,
								
									[width]
									NVARCHAR
									(50)
									NULL,
								
									[height]
									NVARCHAR
									(50)
									NULL,
								
									[curb-weight]
									NVARCHAR
									(50)
									NULL,
								
									[engine-type]
									NVARCHAR
									(50)
									NULL,
								
									[num-of-cylinders]
									NVARCHAR
									(50)
									NULL,
								
									[engine-size]
									NVARCHAR
									(50)
									NULL,
								
									[fuel-system]
									NVARCHAR
									(50)
									NULL,
								
									[bore]
									NVARCHAR
									(50)
									NULL,
								
									[stroke]
									NVARCHAR
									(50)
									NULL,
								
									[compression-ratio]
									NVARCHAR
									(50)
									NULL,
								
									[horsepower]
									NVARCHAR
									(50)
									NULL,
								
									[peak-rpm]
									NVARCHAR
									(50)
									NULL,
								
									[city-mpg]
									NVARCHAR
									(50)
									NULL,
								
									[highway-mpg]
									NVARCHAR
									(50)
									NULL,
								
									[price]
									NVARCHAR
									(50)
									NULL,
								
									PRIMARY
									KEY
									CLUSTERED
									([Id]
									ASC)
								
);

image

Click Update Database.

image

The Data Tools Operations window will indicate when the update is complete.

image

In the Server Explorer window, right-click on the database and select Refresh.

You will see the Vehicles table.

Always Close the database connection when done working with it to prevent locking.

image

In the Solution Explorer, right-click on the project node and select Manage NuGet Packages.

image

Search for and install: Microsoft.EntityFrameworkCore.Tools.

image

Open the NuGet Package Manager Console.

image

Enter:

Scaffold-DbContext "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\TEMP\AzureMLCore\Data\AzureMLData.mdf;Integrated Security=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models

and press Enter.

(update the connection string above to point to the location of the .mdf file in the project)

image

The scaffolded files will appear in the Models directory.

Note: If you get DBContext cannot be found errors (red squiggly lines in the Visual Studio text editor, simply close Visual Studio and re-open it.

image

Rename the DataContext file and the class to AzureMLDataContext.

image

Next, we follow the directions at this link: ASP.NET Core - Existing Database.

We remove the OnConfiguring method.

We add the following constructor to the class:

								
									public
									AzureMLDataContext(DbContextOptions<AzureMLDataContext> options) :
								
									base(options) { }

image

We add the following using statements to Startup.cs:

								
									using
									AzureMLCore.Models;
								
									using
									Microsoft.EntityFrameworkCore;

image

We add the following code to the ConfigureServices section to configure the database setting:

								
									services.AddDbContext<AzureMLDataContext>(
								
									options => options.UseSqlServer(
								
									Configuration.GetConnectionString("AzureMLDataDatabase")));

image

Add the following database setting to the appsettings.json file:

								
									
"ConnectionStrings": {
									
										"AzureMLDataDatabase": "Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename=
										
									
										C:\\Temp\\AzureMLCore\\Data\\AzureMLData.mdf;Integrated Security=True;"
										
									
},

(Note: The AzureMLDataDatabase value needs to be on a single line – see the source code for the exact setting)

Create Code To Call Azure Machine Learning Web Service

We will now create the code that will call the Azure Machine Learning web service (that was created in An End-To-End Azure Machine Learning Studio Application ), passing the parameters (such as such as make, horsepower, and body style) and retrieve a response by the underlying Model in the form of a predicted price.

image

First, we need to create a class that will pass the settings (PrimaryKey and BaseAddress) from the app settings file to the code we will create.

Create a file called AzureMLSettings.cs using the following code:

								
									using
									System;
								
									using
									System.Collections.Generic;
								
									using
									System.Linq;
								
									using
									System.Threading.Tasks;
								

								
									namespace
									AzureMLCore.Models
								
{
								
									public
									class
									AzureMLSettings
								
									{
								
									public
									string
									PrimaryKey {
									get;
									set; }
								
									public
									string
									BaseAddress {
									get;
									set; }
								
									}
								
}

image

Add  the following code to the ConfigureServices method in the Startup.cs file:

								
									// Get the AzureMLSettings
								
									services.Configure<AzureMLSettings>(
								
									Configuration.GetSection("AzureMLSettings"));

image

Next, add the settings to the appsettings.json file, replacing {{ API Key }} and {{ Base Address }} with the values you saved earlier:

								
									"AzureMLSettings": {
								
									"PrimaryKey": "{{ API Key }}",
								
									"BaseAddress": "{{ Base Address }}"
								
									},

The values will be retrieved and passed to the web service using the code we will create in the following two steps.

image

Create a file called AzureMLParameter.cs using the following code:

								
									using
									System.ComponentModel.DataAnnotations;
								

								
									namespace
									AzureMLCore.Models
								
{
								
									public
									class
									AzureMLParameter
								
									{
								
									[Key]
								
									public
									int
									Id {
									get;
									set; }
								
									public
									string
									symboling {
									get;
									set; }
								
									public
									string
									normalizedlosses {
									get;
									set; }
								
									public
									string
									make {
									get;
									set; }
								
									public
									string
									fueltype {
									get;
									set; }
								
									public
									string
									aspiration {
									get;
									set; }
								
									public
									string
									numofdoors {
									get;
									set; }
								
									public
									string
									bodystyle {
									get;
									set; }
								
									public
									string
									drivewheels {
									get;
									set; }
								
									public
									string
									enginelocation {
									get;
									set; }
								
									public
									string
									wheelbase {
									get;
									set; }
								
									public
									string
									length {
									get;
									set; }
								
									public
									string
									width {
									get;
									set; }
								
									public
									string
									height {
									get;
									set; }
								
									public
									string
									curbweight {
									get;
									set; }
								
									public
									string
									enginetype {
									get;
									set; }
								
									public
									string
									numofcylinders {
									get;
									set; }
								
									public
									string
									enginesize {
									get;
									set; }
								
									public
									string
									fuelsystem {
									get;
									set; }
								
									public
									string
									bore {
									get;
									set; }
								
									public
									string
									stroke {
									get;
									set; }
								
									public
									string
									compressionratio {
									get;
									set; }
								
									public
									string
									horsepower {
									get;
									set; }
								
									public
									string
									peakrpm {
									get;
									set; }
								
									public
									string
									citympg {
									get;
									set; }
								
									public
									string
									highwaympg {
									get;
									set; }
								
									public
									string
									price {
									get;
									set; }
								
									public
									string
									Scoredlabels {
									get;
									set; }
								
									}
								
}

image

Finally, to we will create the controller class, that will be called by the Angular code, that will call the web service.

Create a file called AzureMLParameterController.cs using the following code:

								
									using
									System;
								
									using
									System.Collections.Generic;
								
									using
									System.Linq;
								
									using
									System.Threading.Tasks;
								
									using
									Microsoft.AspNetCore.Http;
								
									using
									Microsoft.AspNetCore.Mvc;
								
									using
									Microsoft.EntityFrameworkCore;
								
									using
									AzureMLCore.Models;
								
									using
									Newtonsoft.Json;
								
									using
									System.Net.Http.Headers;
								
									using
									System.Net.Http;
								
									using
									Microsoft.Extensions.Options;
								
									using
									System.Text;
								

								
									namespace
									AngularAzureMLApp.Controllers
								
{
								
									[Produces("application/json")]
								
									[Route("api/AzureMLParameter")]
								
									public
									class
									AzureMLParameterController : Controller
								
									{
								
									// Global values to hold the PrimaryKey and BaseAddress
								
									private
									string
									_PrimaryKey;
								
									private
									string
									_BaseAddress;
								

								
									// This is the default contructor for the class
								
									// We will inject the AzureMLSettings when the class
								
									// is instantiated
								
									public
									AzureMLParameterController(
								
									IOptions<AzureMLSettings> AzureMLSettings)
								
									{
								
									// Set the values for PrimaryKey and BaseAddress
								
									_PrimaryKey = AzureMLSettings.Value.PrimaryKey;
								
									_BaseAddress = AzureMLSettings.Value.BaseAddress;
								
									}
								

								
									#region
									public
									IHttpActionResult Post(AzureMLParameter paramAzureMLParameter)
								
									// POST: odata/AzureMLParameter
								
									[HttpPost]
								
									public
									async Task<IActionResult> Post([FromBody] AzureMLParameter paramAzureMLParameter)
								
									{
								
									// Call the web service
								
									string
									ScoredLabels = await InvokeRequestResponseService(paramAzureMLParameter);
								
									paramAzureMLParameter.Scoredlabels = ScoredLabels;
								

								
									// Return the result
								
									return
									Ok(paramAzureMLParameter);
								
									}
								
									#endregion
								

								
									// Helpers
								

								
									#region async Task<string> InvokeRequestResponseService(AzureMLParameter objAzureMLParameter)
								
									async Task<string> InvokeRequestResponseService(AzureMLParameter objAzureMLParameter)
								
									{
								
									string
									strResponse = "";
								
									try
								
									{
								
									// Get the Global values for PrimaryKey and BaseAddress
								
									string
									PrimaryKey = _PrimaryKey;
								
									string
									BaseAddress = _BaseAddress;
								

								
									using
									(var client =
									new
									HttpClient())
								
									{
								
									// We will create a request to the web service
								

								
									// Note: The only columns that are actually being used by the Model and that need to be set:
								
									// highwaympg, citympg, horsepower, fuelsystem, enginesize, numofcylinders
								
									// enginetype, bodystyle, make, curbweight, wheelbase, numofdoors, fueltype
								
								
									var scoreRequest =
									new
								
									{
								
									Inputs =
									new
									Dictionary<string, StringTable>() {
								
									{
								
									"input1",
								
									new
									StringTable()
								
									{
								
									ColumnNames =
									new
									string[] {
								
									"symboling", "normalized-losses","make","fuel-type","aspiration",
								
									"num-of-doors","body-style","drive-wheels","engine-location",
								
									"wheel-base","length","width", "height","curb-weight","engine-type",
								
									"num-of-cylinders","engine-size","fuel-system","bore","stroke",
								
									"compression-ratio","horsepower","peak-rpm","city-mpg","highway-mpg","price"},
								
									Values =
									new
									string[,] {
								
									{
								
									objAzureMLParameter.symboling,
								
									objAzureMLParameter.normalizedlosses,
								
									objAzureMLParameter.make,
								
									objAzureMLParameter.fueltype,
								
									objAzureMLParameter.aspiration,
								
									objAzureMLParameter.numofdoors,
								
									objAzureMLParameter.bodystyle,
								
									objAzureMLParameter.drivewheels,
								
									objAzureMLParameter.enginelocation,
								
									objAzureMLParameter.wheelbase,
								
									objAzureMLParameter.length,
								
									objAzureMLParameter.width,
								
									objAzureMLParameter.height,
								
									objAzureMLParameter.curbweight,
								
									objAzureMLParameter.enginetype,
								
									objAzureMLParameter.numofcylinders,
								
									objAzureMLParameter.enginesize,
								
									objAzureMLParameter.fuelsystem,
								
									objAzureMLParameter.bore,
								
									objAzureMLParameter.stroke,
								
									objAzureMLParameter.compressionratio,
								
									objAzureMLParameter.horsepower,
								
									objAzureMLParameter.peakrpm,
								
									objAzureMLParameter.citympg,
								
									objAzureMLParameter.highwaympg,
								
									objAzureMLParameter.price
								
									}
								
									}
								
									}
								
									},
								
									},
								
									GlobalParameters =
									new
									Dictionary<string,
									string>()
								
									{
								
									}
								
									};
								

								
									// Create an authorization value
								
									client.DefaultRequestHeaders.Authorization =
								
									new
									AuthenticationHeaderValue("Bearer", PrimaryKey);
								

								
									// Call the web service
								
									HttpResponseMessage response =
								
									await client.PostAsync(new
									Uri(BaseAddress),
								
									new
									StringContent(JsonConvert.SerializeObject(scoreRequest),
								
									Encoding.UTF8, "application/json"));
								

								
									if
									(response.IsSuccessStatusCode)
								
									{
								
									// The call was a success -- get the response
								
									string
									result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
								
									Rootobject obj = JsonConvert.DeserializeObject<Rootobject>(result);
								
									// The predicted price is in the last element
								
									int
									intLastElement = (obj.Results.output1.value.Values[0].Count() - 1);
								
									var Price = obj.Results.output1.value.Values[0][intLastElement];
								
									// Convert the value to a currency string
								
									strResponse = Convert.ToDecimal(Price).ToString("C");
								
									}
								
									else
								
									{
								
									// The call returned an error
								
									var strContent = await response.Content.ReadAsStringAsync();
								
									strResponse =
									string.Format("The request failed with status code: {0}",
								
									response.StatusCode);
								

								
									// Add the headers - they include the request ID and the timestamp,
									
								
									// which are useful for debugging the failure
								
									strResponse = strResponse + "
									" + response.Headers.ToString();
								
									strResponse = strResponse + "
									" + strContent;
								
									}
								
									}
								
									}
								
									catch
									(Exception ex)
								
									{
								
									return
									ex.Message;
								
									}
								

								
									return
									strResponse;
								
									}
								
									#endregion
								

								
									#region
									public
									class
									StringTable
								
									public
									class
									StringTable
								
									{
								
									public
									string[] ColumnNames {
									get;
									set; }
								
									public
									string[,] Values {
									get;
									set; }
								
									}
								
									#endregion
								

								
									#region JSON Result Classes
								
									public
									class
									Rootobject
								
									{
								
									public
									Results Results {
									get;
									set; }
								
									}
								

								
									public
									class
									Results
								
									{
								
									public
									Output1 output1 {
									get;
									set; }
								
									}
								

								
									public
									class
									Output1
								
									{
								
									public
									string
									type {
									get;
									set; }
								
									public
									Value
									value
									{
									get;
									set; }
								
									}
								

								
									public
									class
									Value
								
									{
								
									public
									string[] ColumnNames {
									get;
									set; }
								
									public
									string[] ColumnTypes {
									get;
									set; }
								
									public
									string[][] Values {
									get;
									set; }
								
									}
								
									#endregion
								
									}
								
}

Create The Angular Application

Let’s build the entire Angular application from scratch.

Highlight all the files under: …\ClientApp\app\

image

…and delete them.

image

The entry point for the custom code for the application is in app.module.ts.

Create the file using the following code:

								
import { NgModule } from '@angular/core';
								
import { RouterModule } from '@angular/router';
								
import { UniversalModule } from 'angular2-universal';
								
import { AppComponent } from './app.component'
								

								
import { BrowserModule } from '@angular/platform-browser';
								
import { HttpModule } from '@angular/http';
								
import { FormsModule } from '@angular/forms';
								

								

								
import {
								
									InputTextModule,
								
									DropdownModule,
								
									ButtonModule,
								
									FieldsetModule,
								
									TreeModule,
								
									TreeNode,
								
									SelectItem,
								
									TabMenuModule,
								
									MenuItem,
								
									TabViewModule,
								
									PanelModule,
								
									InputSwitchModule,
								
									PasswordModule
								
} from 'primeng/primeng';
								

								
import { PriceVehicleComponent } from './priceVehicle/priceVehicle.component';
								
import { PriceVehicleService } from './priceVehicle/priceVehicle.service';
								

								
@NgModule({
								
									bootstrap: [ AppComponent ],
								
									declarations: [
								
									AppComponent,
								
									PriceVehicleComponent,
								
									],
								
									imports: [
								
									UniversalModule,
									// Must be first import.
									
								
									BrowserModule,
								
									HttpModule,
								
									FormsModule,
								
									InputTextModule,
								
									TreeModule,
								
									DropdownModule,
								
									ButtonModule,
								
									FieldsetModule,
								
									TabMenuModule,
								
									TabViewModule,
								
									PanelModule,
								
									InputSwitchModule,
								
									PasswordModule
								
									],
								
									providers: [
								
									PriceVehicleService
								
									]
								
})
								
export
									class
									AppModule {
								
}
								

							

(note: you will see red swiggly lines in the Visual Studio editor because there are files being referenced that we have not created yet)

image

app.module, in it’s bootstrap setting, it indicates that AppComponent is the first component to be loaded.

To implement it, create the file: app.component.ts using the following code:

								
import { Component } from '@angular/core';
								

								
@Component({
								
									selector: 'app',
								
									templateUrl: './app.component.html',
								
									styleUrls: ['./app.component.css']
								
})
								
export
									class
									AppComponent {
								
}
								

							

image

app.component.ts specifies app.component.html for templateUrl and app.component.css for styleUrls.

Create those files and implement them using the following code:

app.component.html:

								
									<
									priceVehicle-form
									>Loading...</
									priceVehicle-form>
								

app.component.css:

								
@media
									(max-width:
									767px) {
								
									/* On small screens, the nav menu spans the full width of the screen.
									
								
									Leave a space for it. */
								
									.body-content
									{
									
								
									padding-top: 50px;
								
									}
								
}
								

							

image

The primary code for the application will be placed in the priceVehicle folder.

Create It.

image

We will create an interface that will allow us to communicate with the AzureMLParameterController.cs file using a strongly typed class.

Create a file: azureMLParameter.ts using the following code:

								
									/* Defines the AzureMLParameter entity */
								
export
									interface
									IAzureMLParameter {
								
									id: number;
								
									symboling:
									string;
								
									normalizedlosses:
									string;
								
									make:
									string;
								
									fueltype:
									string;
								
									aspiration:
									string;
								
									numofdoors:
									string;
								
									bodystyle:
									string;
								
									drivewheels:
									string;
								
									enginelocation:
									string;
								
									wheelbase:
									string;
								
									length:
									string;
								
									width:
									string;
								
									height:
									string;
								
									curbweight:
									string;
								
									enginetype:
									string;
								
									numofcylinders:
									string;
								
									enginesize:
									string;
								
									fuelsystem:
									string;
								
									bore:
									string;
								
									stroke:
									string;
								
									compressionratio:
									string;
								
									horsepower:
									string;
								
									peakrpm:
									string;
								
									citympg:
									string;
								
									highwaympg:
									string;
								
									price:
									string;
									// price we submit
								
									scoredlabels:
									string;
									// prediction we get back
									
								
}

image

We will create a service that will communicate with the C# controller code, both to get price predictions and to save actual prices to the database.

Create a file: priceVehicle.service.ts using the following code:

								
import { Injectable } from '@angular/core';
								
import { Http, Response, RequestOptions, Request, RequestMethod, Headers } from '@angular/http';
								

								
import { Observable } from 'rxjs/Observable';
								
import 'rxjs/add/operator/do';
								
import 'rxjs/add/operator/catch';
								
import 'rxjs/add/operator/map';
								

								
import { IAzureMLParameter } from './azureMLParameter';
								

								
@Injectable()
								
export
									class
									PriceVehicleService {
								

								
									constructor(private
									_http: Http) { }
								

								
									priceVehicle(AzureMLParameter: IAzureMLParameter): Observable<IAzureMLParameter> {
								
									var _Url = 'api/AzureMLParameter';
								
									AzureMLParameter.price = "0";
								
									// This is a Post so we have to pass Headers
								
									let headers =
									new
									Headers({ 'Content-Type': 'application/json' });
								
									let options =
									new
									RequestOptions({ headers: headers });
								

								
									// Make the Angular 2 Post
								
									// passing the AzureMLParameter
								
									return
									this._http.post(_Url, JSON.stringify(AzureMLParameter), options)
								
									.map((response: Response) => <IAzureMLParameter>response.json())
								
									.catch(this.handleError);
								
									}
								

								
									recordPrice(AzureMLParameter: IAzureMLParameter): Observable<IAzureMLParameter> {
								
									var _Url = 'api/Vehicles';
								
									// This is a Post so we have to pass Headers
								
									let headers =
									new
									Headers({ 'Content-Type': 'application/json' });
								
									let options =
									new
									RequestOptions({ headers: headers });
								

								
									// Make the Angular 2 Post
								
									// passing the AzureMLParameter
								
									return
									this._http.post(_Url, JSON.stringify(AzureMLParameter), options)
								
									.map((response: Response) => <IAzureMLParameter>response.json())
								
									.catch(this.handleError);
								
									}
								

								
									// Utility
								

								
									private
									handleError(error: Response) {
								
									// in a real world app, we may send the server to some remote logging infrastructure
								
									// instead of just logging it to the console
								
									console.error(error);
								
									return
									Observable.throw(error.json().error || 'Server error');
								
									}
								
}

(Note: we have implemented code to save recorded prices, but we have not added the server-side C# code yet)

image

Next we will add the actual markup for the application.

Create a file: priceVehicle.component.html using the following code:

								
									<
									div
									style="width:800px"
									>
								
									<
									br
									/>
									<
									br
									/>
									<
									br
									/>
								
									<
									div
									>
								
									<
									span
									style="background-color: #FFFF00"
									>{{errorMessage}}</
									span
									>
								
									</
									div
									>
								
									<
									h3
									class="first"
									>Price A Vehicle</
									h3
									>
								
									<
									button
									pButton
									type="button"
									label="Export Data"
									(click)="getVehicles()"
									class="ui-button-secondary"
									>
									</
									button
									>
								
									<
									div
									class="ui-grid ui-grid-responsive ui-grid-pad"
									>
								
									<
									div
									class="ui-grid-row"
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									Make:
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									p-dropdown
									id="Make"
								
									[options]="makeDropdown"
								
									[(ngModel)]="AzureMLParameter.make"
								
									[style]="{'width':'150px'}">
									</
									p-dropdown>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									Fuel type:
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									p-dropdown
									id="FuelType"
								
									[options]="fueltypeDropdown"
								
									[(ngModel)]="AzureMLParameter.fueltype"
								
									[style]="{'width':'150px'}">
									</
									p-dropdown>
								
									</
									div
									>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-row"
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									Num of doors:
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									p-dropdown
									id="NumOfDoors"
								
									[options]="numofdoorsDropdown"
								
									[(ngModel)]="AzureMLParameter.numofdoors"
								
									[style]="{'width':'150px'}">
									</
									p-dropdown>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									Body style:
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									p-dropdown
									id="BodyStyle"
								
									[options]="bodystyleDropdown"
								
									[(ngModel)]="AzureMLParameter.bodystyle"
								
									[style]="{'width':'150px'}">
									</
									p-dropdown>
								
									</
									div
									>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-row"
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									Wheel base:
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									input
									type="text"
									id="WheelBase"
									pInputText
									[(ngModel)]="AzureMLParameter.wheelbase"
									/>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									Curb weight:
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									input
									type="text"
									id="CurbWeight"
									pInputText
									[(ngModel)]="AzureMLParameter.curbweight"
									/>
								
									</
									div
									>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-row"
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									Engine type:
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									p-dropdown
									id="EngineType"
								
									[options]="enginetypeDropdown"
								
									[(ngModel)]="AzureMLParameter.enginetype"
								
									[style]="{'width':'150px'}">
									</
									p-dropdown>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									Num of cylinders:
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									p-dropdown
									id="NumOfCylinders"
								
									[options]="numofcylindersDropdown"
								
									[(ngModel)]="AzureMLParameter.numofcylinders"
								
									[style]="{'width':'150px'}">
									</
									p-dropdown>
								
									</
									div
									>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-row"
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									Engine size:
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									input
									type="text"
									id="EngineSize"
									pInputText
									[(ngModel)]="AzureMLParameter.enginesize"
									/>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									Fuel system:
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									p-dropdown
									id="FuelSystem"
								
									[options]="fuelsystemDropdown"
								
									[(ngModel)]="AzureMLParameter.fuelsystem"
								
									[style]="{'width':'150px'}">
									</
									p-dropdown>
								
									</
									div
									>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-row"
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									Horsepower:
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									input
									type="text"
									id="Horsepower"
									pInputText
									[(ngModel)]="AzureMLParameter.horsepower"
									/>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									City mpg:
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									input
									type="text"
									id="CityMpg"
									pInputText
									[(ngModel)]="AzureMLParameter.citympg"
									/>
								
									</
									div
									>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-row"
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									Highway mpg:
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									input
									type="text"
									id="HighwayMpg"
									pInputText
									[(ngModel)]="AzureMLParameter.highwaympg"
									/>
								
									</
									div
									>
								
									</
									div
									>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid ui-grid-responsive ui-grid-pad"
									>
								
									<
									div
									class="ui-grid-row"
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									<
									button
									pButton
									type="button"
									label="Price Vehicle"
									(click)="priceVehicle()">
									</
									button
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									p
									>Predicted Price:
									<
									b
									>{{AzureMLParameter.scoredlabels}}</
									b
									>
									</
									p
									>
								
									</
									div
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-6"
									>
								
									<
									div
									class="ui-grid-col-4"
									>
								
									<
									button
									pButton
									type="button"
									label="Record Price"
									(click)="recordPrice()">
									</
									button
									>
								
									</
									div
									>
								
									<
									div
									class="ui-grid-col-8"
									>
								
									<
									input
									type="text"
									id="Price"
									pInputText
									[(ngModel)]="AzureMLParameter.price"
									/>
								
									</
									div
									>
								
									</
									div
									>
								
									</
									div
									>
								
									</
									div
									>
								
									</
									div
									>
								

image

Finally, add the primary custom code for the application by creating a file called priceVehicle.component.ts using the following code:

								
import { Component, OnInit, OnDestroy } from '@angular/core';
								
import { Router, ActivatedRoute } from '@angular/router';
								

								
import { Subscription } from 'rxjs/Subscription';
								

								
import {
								
									SelectItem,
								
									InputTextModule,
								
									ButtonModule,
								
									DropdownModule
								
}
								
									from 'primeng/primeng';
								

								
import { IAzureMLParameter } from './azureMLParameter';
								
import { PriceVehicleService } from './priceVehicle.service';
								

								
@Component({
								
									selector: 'priceVehicle-form',
								
									templateUrl: './priceVehicle.component.html'
								
})
								
export
									class
									PriceVehicleComponent implements OnInit {
								
									errorMessage:
									string;
								
									AzureMLParameter: IAzureMLParameter;
								
									makeDropdown: SelectItem[] = [];
								
									fueltypeDropdown: SelectItem[] = [];
								
									numofdoorsDropdown: SelectItem[] = [];
								
									bodystyleDropdown: SelectItem[] = [];
								
									enginetypeDropdown: SelectItem[] = [];
								
									numofcylindersDropdown: SelectItem[] = [];
								
									fuelsystemDropdown: SelectItem[] = [];
								

								
									// Register the service
								
									constructor(private
									_PriceVehicleService: PriceVehicleService) { }
								

								
									ngOnInit():
									void
									{
								
									// Set default values for vehicle parameters
								
									this.setDefaultValues();
								
									// Fill the dropdowns
								
									this.fillDropdowns();
								
									}
								

								
									priceVehicle() {
								
									this.errorMessage = "";
								
									// Get the predicted price for a vehicle
								
									// Call the service
								
									this._PriceVehicleService.priceVehicle(this.AzureMLParameter)
								
									.subscribe(
								
									AzureMLParameter => {
								
									this.AzureMLParameter = AzureMLParameter
								
									},
								
									error =>
									this.errorMessage = <any>error);
								
									}
								

								
									recordPrice() {
								
									this.errorMessage = "";
								
									// Save the price of a vehicle to the database
								
									// Call the service
								
									this._PriceVehicleService.recordPrice(this.AzureMLParameter)
								
									.subscribe(
								
									AzureMLParameter => {
								
									alert('Recorded: ' + AzureMLParameter.id);
								
									},
								
									error =>
									this.errorMessage = <any>error);
								
									}
								

								
									getVehicles() {
								
									window.location.href = 'Home/DownloadCSV';
								
									}
								

								
									// Utility
								

								
									setDefaultValues() {
								

								
									// Note: The only columns that are actually being used by the Model and that need to be set:
								
									// highwaympg, citympg, horsepower, fuelsystem, enginesize, numofcylinders
								
									// enginetype, bodystyle, make, curbweight, wheelbase, numofdoors, fueltype
								

								
									let NewAzureMLParameter: IAzureMLParameter = {
								
									id: 0,
								
									symboling: "0",
								
									normalizedlosses: "1",
								
									make: "toyota",
									fueltype: "gas",
								
									aspiration: "
									",
								
									numofdoors: "four",
								
									bodystyle: "sedan",
								
									drivewheels: "
									",
								
									enginelocation: "
									",
								
									wheelbase: "99.4",
								
									length: "0",
								
									width: "0",
								
									height: "0",
								
									curbweight: "2824",
								
									enginetype: "ohc",
								
									numofcylinders: "five",
								
									enginesize: "136",
								
									fuelsystem: "mpfi",
								
									bore: "0",
								
									stroke: "0",
								
									compressionratio: "0",
								
									horsepower: "115",
								
									peakrpm: "0",
								
									citympg: "18",
								
									highwaympg: "22",
								
									price: "0",
								
									scoredlabels: "
									"
								
									}
								

								
									this.AzureMLParameter = NewAzureMLParameter;
								
									}
								

								
									fillDropdowns() {
								
									// makeDropdown
								
									this.makeDropdown.push({ label: 'toyota',
									value: 'toyota' });
								
									this.makeDropdown.push({ label: 'nissan',
									value: 'nissan' });
								
									this.makeDropdown.push({ label: 'mazda',
									value: 'mazda' });
								
									this.makeDropdown.push({ label: 'mitsubishi',
									value: 'mitsubishi' });
								
									this.makeDropdown.push({ label: 'honda',
									value: 'honda' });
								
									this.makeDropdown.push({ label: 'volkswagen',
									value: 'volkswagen' });
								
									this.makeDropdown.push({ label: 'subaru',
									value: 'subaru' });
								
									this.makeDropdown.push({ label: 'volvo',
									value: 'volvo' });
								
									this.makeDropdown.push({ label: 'peugot',
									value: 'peugot' });
								
									this.makeDropdown.push({ label: 'dodge',
									value: 'dodge' });
								

								
									// fueltypeDropdown
								
									this.fueltypeDropdown.push({ label: 'gas',
									value: 'gas' });
								
									this.fueltypeDropdown.push({ label: 'diesel',
									value: 'diesel' });
								

								
									// numofdoorsDropdown
								
									this.numofdoorsDropdown.push({ label: 'four',
									value: 'four' });
								
									this.numofdoorsDropdown.push({ label: 'two',
									value: 'two' });
								

								
									// bodystyleDropdown
								
									this.bodystyleDropdown.push({ label: 'sedan',
									value: 'sedan' });
								
									this.bodystyleDropdown.push({ label: 'hatchback',
									value: 'hatchback' });
								
									this.bodystyleDropdown.push({ label: 'wagon',
									value: 'wagon' });
								
									this.bodystyleDropdown.push({ label: 'hardtop',
									value: 'hardtop' });
								
									this.bodystyleDropdown.push({ label: 'convertible',
									value: 'convertible' });
								

								
									// enginetypeDropdown
								
									this.enginetypeDropdown.push({ label: 'ohc',
									value: 'ohc' });
								
									this.enginetypeDropdown.push({ label: 'ohcf',
									value: 'ohcf' });
								
									this.enginetypeDropdown.push({ label: 'ohcv',
									value: 'ohcv' });
								
									this.enginetypeDropdown.push({ label: 'dohc',
									value: 'dohc' });
								
									this.enginetypeDropdown.push({ label: 'l',
									value: 'l' });
								
									this.enginetypeDropdown.push({ label: 'rotor',
									value: 'rotor' });
								
									this.enginetypeDropdown.push({ label: 'dohcv',
									value: 'dohcv' });
								

								
									// numofcylindersDropdown
								
									this.numofcylindersDropdown.push({ label: 'four',
									value: 'four' });
								
									this.numofcylindersDropdown.push({ label: 'six',
									value: 'six' });
								
									this.numofcylindersDropdown.push({ label: 'five',
									value: 'five' });
								
									this.numofcylindersDropdown.push({ label: 'eight',
									value: 'eight' });
								
									this.numofcylindersDropdown.push({ label: 'two',
									value: 'two' });
								
									this.numofcylindersDropdown.push({ label: 'three',
									value: 'three' });
								
									this.numofcylindersDropdown.push({ label: 'twelve',
									value: 'twelve' });
								

								
									// fuelsystemDropdown
								
									this.fuelsystemDropdown.push({ label: 'mpfi',
									value: 'mpfi' });
								
									this.fuelsystemDropdown.push({ label: '2bbl',
									value: '2bbl' });
								
									this.fuelsystemDropdown.push({ label: 'idi',
									value: 'idi' });
								
									this.fuelsystemDropdown.push({ label: '1bbl',
									value: '1bbl' });
								
									this.fuelsystemDropdown.push({ label: 'spdi',
									value: 'spdi' });
								
									this.fuelsystemDropdown.push({ label: '4bbl',
									value: '4bbl' });
								
									this.fuelsystemDropdown.push({ label: 'mfi',
									value: 'mfi' });
								
									this.fuelsystemDropdown.push({ label: 'spfi',
									value: 'spfi' });
								
									}
								
}

image

Run the application.

image

The application will show, and we can click the Price Vehicle button to see the predicted price for the options selected on the form.

Saving Data

image

To save data, we need to add a server-side method.

Create a file at: ..\Controllers\VehiclesController.cs using the following code:

								
									using
									System;
								
									using
									System.Collections.Generic;
								
									using
									System.Linq;
								
									using
									System.Threading.Tasks;
								
									using
									Microsoft.AspNetCore.Http;
								
									using
									Microsoft.AspNetCore.Mvc;
								
									using
									Microsoft.EntityFrameworkCore;
								
									using
									AzureMLCore.Models;
								

								
									namespace
									AzureMLCore.Controllers
								
{
								
									[Produces("application/json")]
								
									[Route("api/Vehicles")]
								
									public
									class
									VehiclesController : Controller
								
									{
								
									private
									readonly
									AzureMLDataContext _context;
								

								
									public
									VehiclesController(AzureMLDataContext context)
								
									{
								
									_context = context;
								
									}
								

								
									// POST: api/Vehicles
								
									[HttpPost]
								
									public
									IActionResult PostVehicles([FromBody] Vehicles vehicles)
								
									{
								
									if
									(!ModelState.IsValid)
								
									{
								
									return
									BadRequest(ModelState);
								
									}
								

								
									_context.Vehicles.Add(vehicles);
								
									_context.SaveChanges();
								

								
									return
									CreatedAtAction("GetVehicles",
									new
									{ id = vehicles.Id }, vehicles);
								
									}
								
									}
								
}

image

Rebuild the application and re-launch or refresh it in the web browser.

We can now enter a recorded price and save it to the database.

Viewing Data

image

We can export the recorded prices.

We will use this data in the next article to retrain the Model used by the web service to make price predictions.

image

Open the HomeController.cs file and add the following code to the class:

								
									private
									readonly
									Models.AzureMLDataContext _context;
								

								
									public
									HomeController(Models.AzureMLDataContext context)
								
									{
								
									_context = context;
								
									}
								

								
									public
									FileContentResult DownloadCSV()
								
									{
								
									// Break up array so the code formats properly for the blog post article
								
									string
									strArray1 = "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},";
								
									string
									strArray2 = "{11},{12},{13},{14},{15},{16},{17},{18},{19},";
								
									string
									strArray3 = "{20},{21},{22},{23},{24},{25}\n";
								
									string
									strFullArray = strArray1 + strArray2 + strArray3;
								

								
									// This returns all vehicles in the database
								
									var result = (from vehicle
									in
									_context.Vehicles
								
									select
									new
									Models.AzureMLParameter
								
									{
								
									Id = vehicle.Id,
								
									symboling = vehicle.Symboling,
								
									normalizedlosses = vehicle.NormalizedLosses,
								
									make = vehicle.Make,
								
									fueltype = vehicle.FuelType,
								
									aspiration = vehicle.Aspiration,
								
									numofdoors = vehicle.NumOfDoors,
								
									bodystyle = vehicle.BodyStyle,
								
									drivewheels = vehicle.DriveWheels,
								
									enginelocation = vehicle.EngineLocation,
								
									wheelbase = vehicle.WheelBase,
								
									length = vehicle.Length,
								
									width = vehicle.Width,
								
									height = vehicle.Height,
								
									curbweight = vehicle.CurbWeight,
								
									enginetype = vehicle.EngineType,
								
									numofcylinders = vehicle.NumOfCylinders,
								
									enginesize = vehicle.EngineSize,
								
									fuelsystem = vehicle.FuelSystem,
								
									bore = vehicle.Bore,
								
									stroke = vehicle.Stroke,
								
									compressionratio = vehicle.CompressionRatio,
								
									horsepower = vehicle.Horsepower,
								
									peakrpm = vehicle.PeakRpm,
								
									citympg = vehicle.CityMpg,
								
									highwaympg = vehicle.HighwayMpg,
								
									price = vehicle.Price
								
									}).ToList();
								

								
									// Write headers
								
									string
									csv =
									string.Format(strFullArray,
								
									"symboling",
								
									"normalized-losses",
								
									"make",
								
									"fuel-type",
								
									"aspiration",
								
									"num-of-doors",
								
									"body-style",
								
									"drive-wheels",
								
									"engine-location",
								
									"wheel-base",
								
									"length",
								
									"width",
								
									"height",
								
									"curb-weight",
								
									"engine-type",
								
									"num-of-cylinders",
								
									"engine-size",
								
									"fuel-system",
								
									"bore",
								
									"stroke",
								
									"compression-ratio",
								
									"horsepower",
								
									"peak-rpm",
								
									"city-mpg",
								
									"highway-mpg",
								
									"price");
								

								
									// Write data
								
									csv = csv +
									string.Concat(from vehicle
									in
									result
								
									select
									string.Format(strFullArray,
								
									vehicle.symboling,
								
									vehicle.normalizedlosses,
								
									vehicle.make,
								
									vehicle.fueltype,
								
									vehicle.aspiration,
								
									vehicle.numofdoors,
								
									vehicle.bodystyle,
								
									vehicle.drivewheels,
								
									vehicle.enginelocation,
								
									vehicle.wheelbase,
								
									vehicle.length,
								
									vehicle.width,
								
									vehicle.height,
								
									vehicle.curbweight,
								
									vehicle.enginetype,
								
									vehicle.numofcylinders,
								
									vehicle.enginesize,
								
									vehicle.fuelsystem,
								
									vehicle.bore,
								
									vehicle.stroke,
								
									vehicle.compressionratio,
								
									vehicle.horsepower,
								
									vehicle.peakrpm,
								
									vehicle.citympg,
								
									vehicle.highwaympg,
								
									vehicle.price
								
									));
								

								
									return
									File(new
									System.Text.UTF8Encoding().GetBytes(csv), "text/csv", "vehicles.csv");
								
									}

Links

Download

You can download the code from the Download page

An error has occurred. This application may no longer respond until reloaded. Reload 🗙