This commit is contained in:
Marc Wieland 2025-09-26 08:51:10 +02:00
commit da8f1f8ba3
195 changed files with 8237 additions and 0 deletions

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace api.Controllers
{
public class CommentController
{
}
}

View File

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using api.Data;
using api.Dtos.Stock;
using api.Interfaces;
using api.Mappers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace api.Controllers
{
[Route("api/stock")]
[ApiController]
public class StockController : ControllerBase
{
private readonly IStockRepository _stockRepo;
private readonly ApplicationDbContext _context;
public StockController(ApplicationDbContext context, IStockRepository stockRepo)
{
_stockRepo = stockRepo;
_context = context;
}
[HttpGet]
public async Task<IActionResult> GetAll()
{
var stocks = await _stockRepo.GetAllAsync();
var stockDto = stocks.Select(s => s.ToStockDto()).ToList();
return Ok(stockDto);
}
[HttpGet("{id}")]
public async Task<IActionResult> GetById([FromRoute] int id)
{
var stock = await _context.Stocks.FindAsync(id);
if (stock == null)
{
return NotFound();
}
return Ok(stock.ToStockDto());
}
[HttpPost]
public async Task<IActionResult> Create([FromBody] CreateStockRequestDto stockDto)
{
var stockModel = stockDto.ToStockModel();
await _context.Stocks.AddAsync(stockModel);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetById), new { id = stockModel.Id }, stockModel.ToStockDto());
}
[HttpPut]
[Route("{id}")]
public async Task<IActionResult> Update([FromRoute] int id, [FromBody] UpdateStockRequestDto updateDto)
{
var stockModel = await _context.Stocks.FirstOrDefaultAsync(x => x.Id == id);
if (stockModel == null)
{
return NotFound();
}
stockModel.Symbol = updateDto.Symbol;
stockModel.CompanyName = updateDto.CompanyName;
stockModel.Purchase = updateDto.Purchase;
stockModel.LastDiv = updateDto.LastDiv;
stockModel.Industry = updateDto.Industry;
stockModel.MarketCap = updateDto.MarketCap;
await _context.SaveChangesAsync();
return Ok(stockModel.ToStockDto());
}
[HttpDelete]
[Route("{id}")]
public async Task<IActionResult> Delete([FromRoute] int id)
{
var stockModel = await _context.Stocks.FirstOrDefaultAsync(x => x.Id == id);
if (stockModel == null)
{
return NotFound();
}
_context.Stocks.Remove(stockModel);
await _context.SaveChangesAsync();
return NoContent();
}
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using api.Models;
using Microsoft.EntityFrameworkCore;
namespace api.Data
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions dbContextOptions) : base(dbContextOptions)
{
}
public DbSet<Stock> Stocks { get; set; }
public DbSet<Comment> Comments { get; set; }
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace api.Dtos.Stock
{
public class CreateStockRequestDto
{
public string Symbol { get; set; } = string.Empty;
public string CompanyName { get; set; } = string.Empty;
public decimal Purchase { get; set; }
public decimal LastDiv { get; set; }
public string Industry { get; set; } = string.Empty;
public long MarketCap { get; set; }
}
}

25
Dtos/Stock/StockDto.cs Normal file
View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace api.Dtos.Stock
{
public class StockDto
{
public int Id { get; set; }
public string Symbol { get; set; } = string.Empty;
public string CompanyName { get; set; } = string.Empty;
public decimal Purchase { get; set; }
public decimal LastDiv { get; set; }
public string Industry { get; set; } = string.Empty;
public long MarketCap { get; set; }
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace api.Dtos.Stock
{
public class UpdateStockRequestDto
{
public string Symbol { get; set; } = string.Empty;
public string CompanyName { get; set; } = string.Empty;
public decimal Purchase { get; set; }
public decimal LastDiv { get; set; }
public string Industry { get; set; } = string.Empty;
public long MarketCap { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using api.Models;
namespace api.Interfaces
{
public interface IStockRepository
{
Task<List<Stock>> GetAllAsync();
}
}

43
Mappers/StockMappers.cs Normal file
View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using api.Dtos.Stock;
using api.Models;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace api.Mappers
{
public static class StockMappers
{
public static StockDto ToStockDto(this Stock stockModel)
{
return new StockDto
{
Id = stockModel.Id,
Symbol = stockModel.Symbol,
CompanyName = stockModel.CompanyName,
Purchase = stockModel.Purchase,
LastDiv = stockModel.LastDiv,
Industry = stockModel.Industry,
MarketCap = stockModel.MarketCap
};
}
public static Stock ToStockModel(this CreateStockRequestDto stockDto)
{
return new Stock
{
Symbol = stockDto.Symbol,
CompanyName = stockDto.CompanyName,
Purchase = stockDto.Purchase,
LastDiv = stockDto.LastDiv,
Industry = stockDto.Industry,
MarketCap = stockDto.MarketCap
};
}
}
}

107
Migrations/20250925120417_init.Designer.cs generated Normal file
View File

@ -0,0 +1,107 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using api.Data;
#nullable disable
namespace api.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20250925120417_init")]
partial class init
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.9")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("api.Models.Comment", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Content")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("datetime2");
b.Property<int?>("StockId")
.HasColumnType("int");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("StockId");
b.ToTable("Comments");
});
modelBuilder.Entity("api.Models.Stock", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("CompanyName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Industry")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<decimal>("LastDiv")
.HasColumnType("decimal(18,2)");
b.Property<long>("MarketCap")
.HasColumnType("bigint");
b.Property<decimal>("Purchase")
.HasColumnType("decimal(18,2)");
b.Property<string>("Symbol")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Stocks");
});
modelBuilder.Entity("api.Models.Comment", b =>
{
b.HasOne("api.Models.Stock", "Stock")
.WithMany("Comments")
.HasForeignKey("StockId");
b.Navigation("Stock");
});
modelBuilder.Entity("api.Models.Stock", b =>
{
b.Navigation("Comments");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,69 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace api.Migrations
{
/// <inheritdoc />
public partial class init : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Stocks",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Symbol = table.Column<string>(type: "nvarchar(max)", nullable: false),
CompanyName = table.Column<string>(type: "nvarchar(max)", nullable: false),
Purchase = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
LastDiv = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
Industry = table.Column<string>(type: "nvarchar(max)", nullable: false),
MarketCap = table.Column<long>(type: "bigint", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Stocks", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Comments",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Title = table.Column<string>(type: "nvarchar(max)", nullable: false),
Content = table.Column<string>(type: "nvarchar(max)", nullable: false),
CreatedOn = table.Column<DateTime>(type: "datetime2", nullable: false),
StockId = table.Column<int>(type: "int", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Comments", x => x.Id);
table.ForeignKey(
name: "FK_Comments_Stocks_StockId",
column: x => x.StockId,
principalTable: "Stocks",
principalColumn: "Id");
});
migrationBuilder.CreateIndex(
name: "IX_Comments_StockId",
table: "Comments",
column: "StockId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Comments");
migrationBuilder.DropTable(
name: "Stocks");
}
}
}

View File

@ -0,0 +1,104 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using api.Data;
#nullable disable
namespace api.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.9")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("api.Models.Comment", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Content")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("datetime2");
b.Property<int?>("StockId")
.HasColumnType("int");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("StockId");
b.ToTable("Comments");
});
modelBuilder.Entity("api.Models.Stock", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("CompanyName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Industry")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<decimal>("LastDiv")
.HasColumnType("decimal(18,2)");
b.Property<long>("MarketCap")
.HasColumnType("bigint");
b.Property<decimal>("Purchase")
.HasColumnType("decimal(18,2)");
b.Property<string>("Symbol")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Stocks");
});
modelBuilder.Entity("api.Models.Comment", b =>
{
b.HasOne("api.Models.Stock", "Stock")
.WithMany("Comments")
.HasForeignKey("StockId");
b.Navigation("Stock");
});
modelBuilder.Entity("api.Models.Stock", b =>
{
b.Navigation("Comments");
});
#pragma warning restore 612, 618
}
}
}

19
Models/Comment.cs Normal file
View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace api.Models
{
public class Comment
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public DateTime CreatedOn { get; set; }
public int? StockId { get; set; }
//Navigation property
public Stock? Stock { get; set; }
}
}

31
Models/Stock.cs Normal file
View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics.X86;
using System.Threading.Tasks;
using System.Xml;
namespace api.Models
{
public class Stock
{
public int Id { get; set; }
public string Symbol { get; set; } = string.Empty;
public string CompanyName { get; set; } = string.Empty;
[Column(TypeName = "decimal(18,2)")]
public decimal Purchase { get; set; }
[Column(TypeName = "decimal(18,2)")]
public decimal LastDiv { get; set; }
public string Industry { get; set; } = string.Empty;
public long MarketCap { get; set; }
public List<Comment> Comments { get; set; } = new List<Comment>();
}
}

36
Program.cs Normal file
View File

@ -0,0 +1,36 @@
using api.Data;
using api.Interfaces;
using api.Repository;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});
builder.Services.AddScoped<IStockRepository, StockRepository>();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapControllers();
app.Run();

View File

@ -0,0 +1,23 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "http://localhost:5128",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:7250;http://localhost:5128",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using api.Data;
using api.Interfaces;
using api.Models;
using Microsoft.EntityFrameworkCore;
namespace api.Repository
{
public class StockRepository : IStockRepository
{
private readonly ApplicationDbContext _context;
public StockRepository(ApplicationDbContext context)
{
_context = context;
}
public Task<List<Stock>> GetAllAsync()
{
return _context.Stocks.ToListAsync();
}
}
}

17
api.csproj Normal file
View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.9" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.4" />
</ItemGroup>
</Project>

6
api.http Normal file
View File

@ -0,0 +1,6 @@
@api_HostAddress = http://localhost:5128
GET {{api_HostAddress}}/weatherforecast/
Accept: application/json
###

View File

@ -0,0 +1,11 @@
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=finshark;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

9
appsettings.json Normal file
View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

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.

File diff suppressed because it is too large Load Diff

BIN
bin/Debug/net9.0/api.dll Normal file

Binary file not shown.

BIN
bin/Debug/net9.0/api.exe Normal file

Binary file not shown.

BIN
bin/Debug/net9.0/api.pdb Normal file

Binary file not shown.

View File

@ -0,0 +1,20 @@
{
"runtimeOptions": {
"tfm": "net9.0",
"frameworks": [
{
"name": "Microsoft.NETCore.App",
"version": "9.0.0"
},
{
"name": "Microsoft.AspNetCore.App",
"version": "9.0.0"
}
],
"configProperties": {
"System.GC.Server": true,
"System.Reflection.NullabilityInfoContext.IsSupported": true,
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
}
}
}

View File

@ -0,0 +1 @@
{"Version":1,"ManifestType":"Build","Endpoints":[]}

View File

@ -0,0 +1,11 @@
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=finshark;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

Some files were not shown because too many files have changed in this diff Show More