Complete Rebuild of Project from HelloWorld to Blazer WebApp
This commit is contained in:
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# .NET Build-Artefakte
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
|
||||||
|
# Kompilierte Bibliotheken
|
||||||
|
*.so
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Datenbank-Dateien (lokale SQLite)
|
||||||
|
*.db
|
||||||
20
Components/App.razor
Normal file
20
Components/App.razor
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<base href="/" />
|
||||||
|
<link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
|
||||||
|
<link rel="stylesheet" href="app.css" />
|
||||||
|
<link rel="stylesheet" href="SecDevOpsLab.styles.css" />
|
||||||
|
<link rel="icon" type="image/png" href="favicon.png" />
|
||||||
|
<HeadOutlet />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<Routes />
|
||||||
|
<script src="_framework/blazor.web.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
23
Components/Layout/MainLayout.razor
Normal file
23
Components/Layout/MainLayout.razor
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
<div class="sidebar">
|
||||||
|
<NavMenu />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div class="top-row px-4">
|
||||||
|
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<article class="content px-4">
|
||||||
|
@Body
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="blazor-error-ui">
|
||||||
|
An unhandled error has occurred.
|
||||||
|
<a href="" class="reload">Reload</a>
|
||||||
|
<a class="dismiss">🗙</a>
|
||||||
|
</div>
|
||||||
96
Components/Layout/MainLayout.razor.css
Normal file
96
Components/Layout/MainLayout.razor.css
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
.page {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row {
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
border-bottom: 1px solid #d6d5d5;
|
||||||
|
justify-content: flex-end;
|
||||||
|
height: 3.5rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row ::deep a, .top-row ::deep .btn-link {
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-left: 1.5rem;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row ::deep a:first-child {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640.98px) {
|
||||||
|
.top-row {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row ::deep a, .top-row ::deep .btn-link {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 641px) {
|
||||||
|
.page {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: 250px;
|
||||||
|
height: 100vh;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row.auth ::deep a:first-child {
|
||||||
|
flex: 1;
|
||||||
|
text-align: right;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row, article {
|
||||||
|
padding-left: 2rem !important;
|
||||||
|
padding-right: 1.5rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#blazor-error-ui {
|
||||||
|
background: lightyellow;
|
||||||
|
bottom: 0;
|
||||||
|
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||||
|
display: none;
|
||||||
|
left: 0;
|
||||||
|
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#blazor-error-ui .dismiss {
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
right: 0.75rem;
|
||||||
|
top: 0.5rem;
|
||||||
|
}
|
||||||
30
Components/Layout/NavMenu.razor
Normal file
30
Components/Layout/NavMenu.razor
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<div class="top-row ps-3 navbar navbar-dark">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="">SecDevOpsLab</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="checkbox" title="Navigation menu" class="navbar-toggler" />
|
||||||
|
|
||||||
|
<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
|
||||||
|
<nav class="flex-column">
|
||||||
|
<div class="nav-item px-3">
|
||||||
|
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
|
||||||
|
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-item px-3">
|
||||||
|
<NavLink class="nav-link" href="counter">
|
||||||
|
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-item px-3">
|
||||||
|
<NavLink class="nav-link" href="weather">
|
||||||
|
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
105
Components/Layout/NavMenu.razor.css
Normal file
105
Components/Layout/NavMenu.razor.css
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
.navbar-toggler {
|
||||||
|
appearance: none;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 3.5rem;
|
||||||
|
height: 2.5rem;
|
||||||
|
color: white;
|
||||||
|
position: absolute;
|
||||||
|
top: 0.5rem;
|
||||||
|
right: 1rem;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-toggler:checked {
|
||||||
|
background-color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row {
|
||||||
|
height: 3.5rem;
|
||||||
|
background-color: rgba(0,0,0,0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-brand {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bi {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
margin-right: 0.75rem;
|
||||||
|
top: -1px;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bi-house-door-fill-nav-menu {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
.bi-plus-square-fill-nav-menu {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
.bi-list-nested-nav-menu {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:first-of-type {
|
||||||
|
padding-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:last-of-type {
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item ::deep .nav-link {
|
||||||
|
color: #d7d7d7;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
height: 3rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 3rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item ::deep a.active {
|
||||||
|
background-color: rgba(255,255,255,0.37);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item ::deep .nav-link:hover {
|
||||||
|
background-color: rgba(255,255,255,0.1);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-scrollable {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-toggler:checked ~ .nav-scrollable {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 641px) {
|
||||||
|
.navbar-toggler {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-scrollable {
|
||||||
|
/* Never collapse the sidebar for wide screens */
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
/* Allow sidebar to scroll for tall menus */
|
||||||
|
height: calc(100vh - 3.5rem);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
31
Components/Pages/Books.razor
Normal file
31
Components/Pages/Books.razor
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
@page "/books"
|
||||||
|
@using SecDevOpsLab.Models
|
||||||
|
@using SecDevOpsLab.Data
|
||||||
|
@inject AppDbContext Db
|
||||||
|
@rendermode InteractiveServer
|
||||||
|
|
||||||
|
<h3>Bücherverwaltung</h3>
|
||||||
|
<input @bind="newBook.Title" placeholder="Titel" />
|
||||||
|
<input @bind="newBook.Author" placeholder="Autor" />
|
||||||
|
<button @onclick="Save">Speichern</button>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<ul>
|
||||||
|
@foreach (var b in bookList) {
|
||||||
|
<li>@b.Title von @b.Author</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private Book newBook = new();
|
||||||
|
private List<Book> bookList = new();
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync() => bookList = await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync(Db.Books);
|
||||||
|
|
||||||
|
private async Task Save() {
|
||||||
|
Db.Books.Add(newBook);
|
||||||
|
await Db.SaveChangesAsync();
|
||||||
|
newBook = new();
|
||||||
|
bookList = await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync(Db.Books);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Components/Pages/Counter.razor
Normal file
19
Components/Pages/Counter.razor
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
@page "/counter"
|
||||||
|
@rendermode InteractiveServer
|
||||||
|
|
||||||
|
<PageTitle>Counter</PageTitle>
|
||||||
|
|
||||||
|
<h1>Counter</h1>
|
||||||
|
|
||||||
|
<p role="status">Current count: @currentCount</p>
|
||||||
|
|
||||||
|
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private int currentCount = 0;
|
||||||
|
|
||||||
|
private void IncrementCount()
|
||||||
|
{
|
||||||
|
currentCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
36
Components/Pages/Error.razor
Normal file
36
Components/Pages/Error.razor
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
@page "/Error"
|
||||||
|
@using System.Diagnostics
|
||||||
|
|
||||||
|
<PageTitle>Error</PageTitle>
|
||||||
|
|
||||||
|
<h1 class="text-danger">Error.</h1>
|
||||||
|
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||||
|
|
||||||
|
@if (ShowRequestId)
|
||||||
|
{
|
||||||
|
<p>
|
||||||
|
<strong>Request ID:</strong> <code>@RequestId</code>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
<h3>Development Mode</h3>
|
||||||
|
<p>
|
||||||
|
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||||
|
It can result in displaying sensitive information from exceptions to end users.
|
||||||
|
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||||
|
and restarting the app.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
@code{
|
||||||
|
[CascadingParameter]
|
||||||
|
private HttpContext? HttpContext { get; set; }
|
||||||
|
|
||||||
|
private string? RequestId { get; set; }
|
||||||
|
private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||||
|
|
||||||
|
protected override void OnInitialized() =>
|
||||||
|
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
|
||||||
|
}
|
||||||
7
Components/Pages/Home.razor
Normal file
7
Components/Pages/Home.razor
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
@page "/"
|
||||||
|
|
||||||
|
<PageTitle>Home</PageTitle>
|
||||||
|
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
|
||||||
|
Welcome to your new app.
|
||||||
64
Components/Pages/Weather.razor
Normal file
64
Components/Pages/Weather.razor
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
@page "/weather"
|
||||||
|
@attribute [StreamRendering]
|
||||||
|
|
||||||
|
<PageTitle>Weather</PageTitle>
|
||||||
|
|
||||||
|
<h1>Weather</h1>
|
||||||
|
|
||||||
|
<p>This component demonstrates showing data.</p>
|
||||||
|
|
||||||
|
@if (forecasts == null)
|
||||||
|
{
|
||||||
|
<p><em>Loading...</em></p>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Temp. (C)</th>
|
||||||
|
<th>Temp. (F)</th>
|
||||||
|
<th>Summary</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var forecast in forecasts)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>@forecast.Date.ToShortDateString()</td>
|
||||||
|
<td>@forecast.TemperatureC</td>
|
||||||
|
<td>@forecast.TemperatureF</td>
|
||||||
|
<td>@forecast.Summary</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private WeatherForecast[]? forecasts;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
// Simulate asynchronous loading to demonstrate streaming rendering
|
||||||
|
await Task.Delay(500);
|
||||||
|
|
||||||
|
var startDate = DateOnly.FromDateTime(DateTime.Now);
|
||||||
|
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
|
||||||
|
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||||
|
{
|
||||||
|
Date = startDate.AddDays(index),
|
||||||
|
TemperatureC = Random.Shared.Next(-20, 55),
|
||||||
|
Summary = summaries[Random.Shared.Next(summaries.Length)]
|
||||||
|
}).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class WeatherForecast
|
||||||
|
{
|
||||||
|
public DateOnly Date { get; set; }
|
||||||
|
public int TemperatureC { get; set; }
|
||||||
|
public string? Summary { get; set; }
|
||||||
|
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||||
|
}
|
||||||
|
}
|
||||||
6
Components/Routes.razor
Normal file
6
Components/Routes.razor
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<Router AppAssembly="typeof(Program).Assembly">
|
||||||
|
<Found Context="routeData">
|
||||||
|
<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
|
||||||
|
<FocusOnNavigate RouteData="routeData" Selector="h1" />
|
||||||
|
</Found>
|
||||||
|
</Router>
|
||||||
10
Components/_Imports.razor
Normal file
10
Components/_Imports.razor
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
@using System.Net.Http
|
||||||
|
@using System.Net.Http.Json
|
||||||
|
@using Microsoft.AspNetCore.Components.Forms
|
||||||
|
@using Microsoft.AspNetCore.Components.Routing
|
||||||
|
@using Microsoft.AspNetCore.Components.Web
|
||||||
|
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||||
|
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||||
|
@using Microsoft.JSInterop
|
||||||
|
@using SecDevOpsLab
|
||||||
|
@using SecDevOpsLab.Components
|
||||||
8
Data/AppDbContext.cs
Normal file
8
Data/AppDbContext.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace SecDevOpsLab.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using SecDevOpsLab.Models;
|
||||||
|
|
||||||
|
public class AppDbContext : DbContext {
|
||||||
|
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
|
||||||
|
public DbSet<Book> Books => Set<Book>();
|
||||||
|
}
|
||||||
16
Dockerfile
16
Dockerfile
@@ -3,20 +3,28 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build-env
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# 1. Nur Projektdatei kopieren und Abhängigkeiten laden (Nutzt Docker-Caching)
|
# 1. Nur Projektdatei kopieren und Abhängigkeiten laden (Nutzt Docker-Caching)
|
||||||
COPY *.sln ./
|
COPY *.csproj ./
|
||||||
COPY MyHelloWorld/*.csproj ./MyHelloWorld/
|
#COPY *.sln ./
|
||||||
COPY MyHelloWorld.Tests/*.csproj ./MyHelloWorld.Tests/
|
#COPY MyHelloWorld/*.csproj ./MyHelloWorld/
|
||||||
|
#COPY MyHelloWorld.Tests/*.csproj ./MyHelloWorld.Tests/
|
||||||
RUN dotnet restore
|
RUN dotnet restore
|
||||||
|
|
||||||
# 2. Den restlichen Quellcode kopieren und die App kompilieren
|
# 2. Den restlichen Quellcode kopieren und die App kompilieren
|
||||||
COPY . ./
|
COPY . ./
|
||||||
RUN dotnet publish MyHelloWorld/*.csproj -c Release -o out
|
#RUN dotnet publish MyHelloWorld/*.csproj -c Release -o out
|
||||||
|
RUN dotnet publish "SecDevOpsLab.csproj" -c Release -o out
|
||||||
|
|
||||||
# --- Stage 2: Runtime (Das fertige, schlanke Image) ---
|
# --- Stage 2: Runtime (Das fertige, schlanke Image) ---
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 3. Port für die Web-App öffnen (Standard bei .NET 8 Web-Apps ist 8080)
|
||||||
|
EXPOSE 8080
|
||||||
|
ENV ASPNETCORE_URLS=http://+:8080
|
||||||
|
|
||||||
# 3. Den vorinstallierten User 'app' von Microsoft nutzen
|
# 3. Den vorinstallierten User 'app' von Microsoft nutzen
|
||||||
|
# Erlaube dem User 'app' in das Verzeichnis zu schreiben (für SQLite)
|
||||||
|
RUN chown -R app:app /app
|
||||||
USER app
|
USER app
|
||||||
|
|
||||||
# 4. Nur die fertigen Binärdateien aus der Bau-Umgebung rüberschieben
|
# 4. Nur die fertigen Binärdateien aus der Bau-Umgebung rüberschieben
|
||||||
|
|||||||
14
Jenkinsfile
vendored
14
Jenkinsfile
vendored
@@ -74,15 +74,15 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stage('Unit Tests') {
|
//stage('Unit Tests') {
|
||||||
steps {
|
// steps {
|
||||||
container('dotnet8') {
|
// container('dotnet8') {
|
||||||
// Erstellt eine XML-Datei im Format 'junit', die Jenkins lesen kann
|
// Erstellt eine XML-Datei im Format 'junit', die Jenkins lesen kann
|
||||||
// sh 'dotnet test --configuration Release'
|
// sh 'dotnet test --configuration Release'
|
||||||
sh 'dotnet test --configuration Release --logger "junit;LogFileName=results.xml"'
|
// sh 'dotnet test --configuration Release --logger "junit;LogFileName=results.xml"'
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
}
|
//}
|
||||||
|
|
||||||
stage('Set Build Name') {
|
stage('Set Build Name') {
|
||||||
steps {
|
steps {
|
||||||
|
|||||||
8
Models/Books.cs
Normal file
8
Models/Books.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace SecDevOpsLab.Models;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
public class Book {
|
||||||
|
public int Id { get; set; }
|
||||||
|
[Required] public string Title { get; set; } = string.Empty;
|
||||||
|
[Required] public string Author { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
|
||||||
<IsTestProject>true</IsTestProject>
|
|
||||||
<WarningsAsErrors></WarningsAsErrors>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
|
||||||
<PackageReference Include="JunitXml.TestLogger" Version="8.0.0" />
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
|
||||||
<PackageReference Include="xunit" Version="2.5.3" />
|
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Using Include="Xunit" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\MyHelloWorld\SecDevOpsLab.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using Xunit;
|
|
||||||
using MyHelloWorld; // Dein Namespace der Haupt-App
|
|
||||||
|
|
||||||
namespace MyHelloWorld.Tests
|
|
||||||
{
|
|
||||||
public class HelloTests
|
|
||||||
{
|
|
||||||
[Fact]
|
|
||||||
public void GetGreeting_ShouldReturnCorrectText()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var generator = new HelloGenerator();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var result = generator.GetGreeting();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal("Hello World", result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"runtimeOptions": {
|
|
||||||
"tfm": "net8.0",
|
|
||||||
"framework": {
|
|
||||||
"name": "Microsoft.NETCore.App",
|
|
||||||
"version": "8.0.0"
|
|
||||||
},
|
|
||||||
"configProperties": {
|
|
||||||
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"runtimeTarget": {
|
|
||||||
"name": ".NETCoreApp,Version=v8.0",
|
|
||||||
"signature": ""
|
|
||||||
},
|
|
||||||
"compilationOptions": {},
|
|
||||||
"targets": {
|
|
||||||
".NETCoreApp,Version=v8.0": {
|
|
||||||
"SecDevOpsLab/1.0.0": {
|
|
||||||
"runtime": {
|
|
||||||
"SecDevOpsLab.dll": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"libraries": {
|
|
||||||
"SecDevOpsLab/1.0.0": {
|
|
||||||
"type": "project",
|
|
||||||
"serviceable": false,
|
|
||||||
"sha512": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"runtimeOptions": {
|
|
||||||
"tfm": "net8.0",
|
|
||||||
"framework": {
|
|
||||||
"name": "Microsoft.NETCore.App",
|
|
||||||
"version": "8.0.0"
|
|
||||||
},
|
|
||||||
"configProperties": {
|
|
||||||
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user