ASP.NET Single Page Applications Angular Release Candidate
I was doing some Angular then remembered that the ASP.NET "Angular Project Template" has a release candidate and is scheduled to release sometime soon in 2018.
Starting with just a .NET Core 2.0 install plus Node v6 or later, I installed the updated angular template. Note that this isn't the angular/react/redux templates that came with .NET Core's base install.
I'll start by adding the updated SPA (single page application) template:
dotnet new --install Microsoft.DotNet.Web.Spa.ProjectTemplates::2.0.0-rc1-final
Then from a new directory, just
dotnet new angular
Then I can open it in either VSCode or Visual Studio Community (free for Open Source). If you're interested in the internals, open up the .csproj project file and note the checks for ensuring node is install, running npm, and running WebPack.
If you've got the Angular "ng" command line tool installed you can do the usual ng related stuff, but you don't need to run "ng serve" because ASP.NET Core will run it automatically for you.
I set development mode with "SET ASPNETCORE_Environment=Development" then do a "dotnet build." It will also restore your npm dependencies as part of the build. The client side app lives in ./ClientApp.
C:\Users\scott\Desktop\my-new-app> dotnet build
Microsoft (R) Build Engine version 15.5 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
Restore completed in 73.16 ms for C:\Users\scott\Desktop\my-new-app\my-new-app.csproj.
Restore completed in 99.72 ms for C:\Users\scott\Desktop\my-new-app\my-new-app.csproj.
my-new-app -> C:\Users\scott\Desktop\my-new-app\bin\Debug\netcoreapp2.0\my-new-app.dll
v8.9.4
Restoring dependencies using 'npm'. This may take several minutes...
"dotnet run" then starts the ng development server and ASP.NET all at once.
If we look at the "Fetch Data" menu item, you can see and example of how Angular and open source ASP.NET Core work together. Here's the Weather Forecast *client-side* template:
<p *ngIf="!forecasts"><em>Loading...</em></p>
<table class='table' *ngIf="forecasts">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let forecast of forecasts">
<td>{{ forecast.dateFormatted }}</td>
<td>{{ forecast.temperatureC }}</td>
<td>{{ forecast.temperatureF }}</td>
<td>{{ forecast.summary }}</td>
</tr>
</tbody>
</table>
And the TypeScript:
import { Component, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-fetch-data',
templateUrl: './fetch-data.component.html'
})
export class FetchDataComponent {
public forecasts: WeatherForecast[];
constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
http.get<WeatherForecast[]>(baseUrl + 'api/SampleData/WeatherForecasts').subscribe(result => {
this.forecasts = result;
}, error => console.error(error));
}
}
interface WeatherForecast {
dateFormatted: string;
temperatureC: number;
temperatureF: number;
summary: string;
}
Note the URL. Here's the back-end. The request is serviced by ASP.NET Core. Note the interface as well as the TemperatureF server-side conversion.
[Route("api/[controller]")]
public class SampleDataController : Controller
{
private static string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
[HttpGet("[action]")]
public IEnumerable<WeatherForecast> WeatherForecasts()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
DateFormatted = DateTime.Now.AddDays(index).ToString("d"),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
});
}
public class WeatherForecast
{
public string DateFormatted { get; set; }
public int TemperatureC { get; set; }
public string Summary { get; set; }
public int TemperatureF
{
get
{
return 32 + (int)(TemperatureC / 0.5556);
}
}
}
}
Sponsor: Scale your Python for big data & big science with Intel® Distribution for Python. Near-native code speed. Use with NumPy, SciPy & scikit-learn. Get it Today!
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
Your application is running in Production mode, so make sure it has been published, or that you have built your SPA manually. Alternatively you may wish to switch to the Development environment.
I can build the client app with ng build and run it with ng serve but then there is no API to call.
Using SET ASPNETCORE_Environment=Development doesn't seem to be enough to get the Dev version built. Is there something I've missed?
Why is that?
Does anyone else have the same issue?
dotnet new --install "Microsoft.AspNetCore.SpaTemplates::*"
So, which is the definitive SPA template collection from Microsoft? Do these templates clobber each other when grabbing names or do they derive ownership of a name from placement in github (for example). How does it all work? SO MANY QUESTIONS
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[0] An exception was thrown attempting to execute the error handler. System.InvalidOperationException: The SPA default page middleware could not return the default page '/index.html' because it was not found, and no other middleware handled the request.
I might even have to upgrade my SPA demo project "The Discworld Disorganiser" to the Release Candidate, too.
I had this issue too when attempting to run from a Powershell prompt; it seems SET here isn't going to work, instead I used
$env:ASPNETCORE_ENVIRONMENT="Development"
And that did the trick for me, hopefully it will work for you too.
ERROR in ./app/services/brokerfake.service.ts
Module build failed: Error: \Desktop\Producer Search\producer-search\ClientApp\src\app\services\brokerfake.service.ts is missing from the TypeScript compilation. Please make sure it is in your tsconfig via the 'files' or 'include' property.
at AngularCompilerPlugin.getCompiledFile (\Desktop\Producer Search\producer-search\ClientApp\node_modules\@ngtools\webpack\src\angular_compiler_plugin.js:656:23)
at plugin.done.then (\Producer Search\producer-search\ClientApp\node_modules\@ngtools\webpack\src\loader.js:467:39)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
@ ./app/components/broker/broker.component.ts 14:0-70
@ ./app/app.module.ts
@ ./main.ts
@ multi ./main.ts
Comments are closed.