Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": ".NET in Codespaces",
"image": "mcr.microsoft.com/dotnet/sdk:8.0",
"image": "mcr.microsoft.com/dotnet/sdk:9.0",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/github-cli:1": {
Expand All @@ -15,8 +15,8 @@
"ghcr.io/devcontainers/features/common-utils:2": {},
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "none",
"dotnetRuntimeVersions": "7.0",
"aspNetCoreRuntimeVersions": "7.0"
"dotnetRuntimeVersions": "8.0",
"aspNetCoreRuntimeVersions": "8.0"
}
},
"customizations": {
Expand All @@ -42,7 +42,7 @@
},
"remoteEnv": {
"DOTNET_MULTILEVEL_LOOKUP": "0",
"TARGET": "net8.0"
"TARGET": "net9.0"
},
"portsAttributes": {
"8080": {
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Build Backend and Frontend

on:
pull_request:
branches:
- main

jobs:
build:
name: Build All Projects
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
project:
- SampleApp/BackEnd/BackEnd.csproj
- SampleApp/FrontEnd/FrontEnd.csproj

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'

- name: Restore dependencies
run: dotnet restore ${{ matrix.project }}

- name: Build project
run: dotnet build ${{ matrix.project }} --no-restore --configuration Release
14 changes: 7 additions & 7 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@
"order": 1
},
"configurations": [
"Back End",
"Front End"
"BackEnd",
"FrontEnd"
]
}
],
"configurations": [
{
"name": "Back End",
"name": "BackEnd",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build backend",
"program": "${workspaceFolder}/SampleApp/BackEnd/bin/Debug/net8.0/BackEnd.dll",
"program": "${workspaceFolder}/SampleApp/BackEnd/bin/Debug/net9.0/BackEnd.dll",
"args": [],
"cwd": "${workspaceFolder}/SampleApp/BackEnd",
"stopAtEntry": false,
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\bNow listening on:\\s+(https?://\\S+)",
"uriFormat": "%s/swagger"
"uriFormat": "%s/scalar"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
Expand All @@ -36,11 +36,11 @@
}
},
{
"name": "Front End",
"name": "FrontEnd",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build frontend",
"program": "${workspaceFolder}/SampleApp/FrontEnd/bin/Debug/net8.0/FrontEnd.dll",
"program": "${workspaceFolder}/SampleApp/FrontEnd/bin/Debug/net9.0/FrontEnd.dll",
"args": [],
"cwd": "${workspaceFolder}/SampleApp/FrontEnd",
"stopAtEntry": false,
Expand Down
6 changes: 3 additions & 3 deletions SampleApp/BackEnd/BackEnd.csproj
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0-preview.4.23260.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.*" />
<PackageReference Include="Scalar.AspNetCore" Version="2.0.*" />
</ItemGroup>

</Project>
26 changes: 19 additions & 7 deletions SampleApp/BackEnd/Program.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
using Microsoft.AspNetCore.OpenApi;
using Scalar.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi(options =>
{
// current workaround for port forwarding in codespaces
// https://github.com/dotnet/aspnetcore/issues/57332
options.AddDocumentTransformer((document, context, ct) =>
{
document.Servers = [];
return Task.CompletedTask;
});
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
app.MapOpenApi();
app.MapScalarApiReference();
}

app.UseHttpsRedirection();

var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
Expand All @@ -31,8 +44,7 @@
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();
.WithName("GetWeatherForecast");

app.Run();

Expand Down
17 changes: 8 additions & 9 deletions SampleApp/FrontEnd/Data/WeatherForecast.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
namespace FrontEnd.Data
namespace FrontEnd.Data;

public class WeatherForecast
{
public class WeatherForecast
{
public DateOnly Date { get; set; }
public DateOnly Date { get; set; }

public int TemperatureC { get; set; }
public int TemperatureC { get; set; }

public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

public string? Summary { get; set; }
}
}
public string? Summary { get; set; }
}
27 changes: 13 additions & 14 deletions SampleApp/FrontEnd/Data/WeatherForecastClient.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
namespace FrontEnd.Data
{
public class WeatherForecastClient
{
private HttpClient _httpClient;
private ILogger<WeatherForecastClient> _logger;
namespace FrontEnd.Data;

public WeatherForecastClient(HttpClient httpClient, ILogger<WeatherForecastClient> logger)
{
_httpClient = httpClient;
_logger = logger;
}
public class WeatherForecastClient
{
private HttpClient _httpClient;
private ILogger<WeatherForecastClient> _logger;

public async Task<WeatherForecast[]> GetForecastAsync(DateTime? startDate)
=> await _httpClient.GetFromJsonAsync<WeatherForecast[]>($"WeatherForecast?startDate={startDate}");
public WeatherForecastClient(HttpClient httpClient, ILogger<WeatherForecastClient> logger)
{
_httpClient = httpClient;
_logger = logger;
}
}

public async Task<WeatherForecast[]> GetForecastAsync(DateTime? startDate)
=> await _httpClient.GetFromJsonAsync<WeatherForecast[]>($"WeatherForecast?startDate={startDate}") ?? [];
}
2 changes: 1 addition & 1 deletion SampleApp/FrontEnd/FrontEnd.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Expand Down
33 changes: 16 additions & 17 deletions SampleApp/FrontEnd/Pages/Error.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,25 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Diagnostics;

namespace FrontEnd.Pages
namespace FrontEnd.Pages;

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public string? RequestId { get; set; }

public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);

private readonly ILogger<ErrorModel> _logger;
private readonly ILogger<ErrorModel> _logger;

public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}
public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}

public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}
}
Binary file removed images/Swagger.png
Binary file not shown.
Binary file added images/scalar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 10 additions & 9 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# GitHub Codespaces ♥️ .NET 8
# GitHub Codespaces ♥️ .NET

Want to try out the latest performance improvements coming with .NET 8 for web development?
Want to try out the latest performance improvements coming with .NET for web development?

This repo builds a Weather API using Minimal APIs, opens Swagger so you can call and test the API, and displays the data in a web application using Blazor with .NET 8.
This repo builds a Weather API, OpenAPI integration to test with [Scalar](https://learn.microsoft.com/aspnet/core/fundamentals/openapi/using-openapi-documents?view=aspnetcore-9.0#use-scalar-for-interactive-api-documentation), and displays the data in a web application using Blazor with .NET.

We've given you both a frontend and backend to play around with and where you go from here is up to you!

Expand All @@ -14,27 +14,28 @@ Everything you do here is contained within this one codespace. There is no repos
[![Open in Dev Container](https://img.shields.io/static/v1?style=for-the-badge&label=Dev+Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/github/dotnet-codespaces)

You can also run this repository locally by following these instructions:
1. Clone the repo to your local machine `git clone https://github.com/bradygaster/dotnet-codespace`
1. Clone the repo to your local machine `git clone https://github.com/github/dotnet-codespace`
1. Open repo in VS Code

## Getting started

1. **📤 One-click setup**: [Open a new Codespace](https://codespaces.new/github/dotnet-codespaces), giving you a fully configured cloud developer environment.
2. **▶️ Run all, one-click again**: Use VS Code's built-in *Run* command and open the forwarded ports *8080* and *8081* in your browser.

![](images/RunAll.png)
![Debug menu in VS Code showing Run All](images/RunAll.png)

3. The Blazor web app and Swagger tabs should now be open on your browser. On Swagger, click "Try it out" and "Execute" to call and test the API.
3. The Blazor web app and Scalar can be open by heading to **/scalar** in your browser. On Scalar, head to the backend API and click "Test Request" to call and test the API.

![](images/BlazorApp.png)
![](images/Swagger.png)
![A website showing weather](images/BlazorApp.png)

!["UI showing testing an API"](images/scalar.png)


4. **🔄 Iterate quickly:** Codespaces updates the server on each save, and VS Code's debugger lets you dig into the code execution.

5. To stop running, return to VS Code, and click Stop twice in the debug toolbar.

![](images/StopRun.png)
![VS Code stop debuggin on both backend and frontend](images/StopRun.png)


## Contributing
Expand Down