Added basic File upload and storage controllers, views, and models
This commit is contained in:
parent
71da65793e
commit
878810f1b8
|
|
@ -0,0 +1,107 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using FileStorageService.www.Data;
|
||||
using FileStorageService.www.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace FileStorageService.www.Controllers;
|
||||
|
||||
public class FilesController(ApplicationDbContext context) : Controller
|
||||
{
|
||||
// GET
|
||||
public async Task<IActionResult> Index(Guid? id)
|
||||
{
|
||||
if (id != null)
|
||||
{
|
||||
return await ViewSingleFile(id);
|
||||
}
|
||||
|
||||
var handles = await context.FileHandles
|
||||
.Include(e => e.FileBlocks)
|
||||
.Select(e => new FileHandleModel
|
||||
{
|
||||
FileName = e.Name,
|
||||
BlockCount = e.FileBlocks.Count,
|
||||
Id = e.Id,
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
var model = new FileHandleListModel
|
||||
{
|
||||
FileHandles = handles
|
||||
};
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
private async Task<IActionResult> ViewSingleFile([DisallowNull] Guid? id)
|
||||
{
|
||||
var fileHandle = await context.FileHandles
|
||||
.Include(e => e.FileBlocks)
|
||||
.FirstAsync(e => e.Id ==id);
|
||||
|
||||
var model = new FileHandleModel
|
||||
{
|
||||
FileName = fileHandle.Name,
|
||||
BlockCount = fileHandle.FileBlocks.Count,
|
||||
Id = fileHandle.Id,
|
||||
};
|
||||
|
||||
return View("SingleFile", model);
|
||||
}
|
||||
|
||||
public IActionResult New()
|
||||
{
|
||||
return View(new NewFileModel
|
||||
{
|
||||
Name = "",
|
||||
FileContents = null!
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> New(NewFileModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ModelState.Values.SelectMany(v => v.Errors));
|
||||
}
|
||||
|
||||
var handle = new FileHandle
|
||||
{
|
||||
Name = model.Name
|
||||
};
|
||||
context.Add(handle);
|
||||
|
||||
var readStream = model.FileContents.OpenReadStream();
|
||||
|
||||
await CreateFileBlocks(handle, readStream);
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
return Redirect($"/Files/{handle.Id}");
|
||||
}
|
||||
|
||||
private async Task CreateFileBlocks(FileHandle fileHandle, Stream reader)
|
||||
{
|
||||
|
||||
var blockNumber = 0;
|
||||
|
||||
var buffer = new byte[1024];
|
||||
|
||||
while (await reader.ReadAsync(buffer) > 0)
|
||||
{
|
||||
var block = new FileBlock
|
||||
{
|
||||
BlockNumber = blockNumber++,
|
||||
Data = buffer,
|
||||
FileHandle = fileHandle
|
||||
};
|
||||
|
||||
// context.Add(block);
|
||||
|
||||
fileHandle.FileBlocks.Add(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,4 +9,5 @@ public class ApplicationDbContext(
|
|||
{
|
||||
public DbSet<FileBlock> FileBlocks { get; set; }
|
||||
public DbSet<FileHandle> FileHandles { get; set; }
|
||||
|
||||
}
|
||||
|
|
@ -16,4 +16,5 @@ public class FileBlock
|
|||
public required byte[] Data { get; init; }
|
||||
|
||||
public required FileHandle FileHandle { get; init; }
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ using System.ComponentModel.DataAnnotations;
|
|||
|
||||
namespace FileStorageService.www.Data;
|
||||
|
||||
public class FileHandle(string name)
|
||||
public class FileHandle
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid Id { get; init; }
|
||||
|
||||
[MaxLength(64)]
|
||||
public string Name { get; set; } = name;
|
||||
public required string Name { get; set; }
|
||||
|
||||
public ICollection<FileBlock> Blocks { get; } = [];
|
||||
public ICollection<FileBlock> FileBlocks { get; } = new List<FileBlock>();
|
||||
}
|
||||
|
|
@ -11,8 +11,8 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|||
namespace FileStorageService.www.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20250317003031_InitialFileModels")]
|
||||
partial class InitialFileModels
|
||||
[Migration("20250317131631_FileHandleAndFileBlockMigration")]
|
||||
partial class FileHandleAndFileBlockMigration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
|
|
@ -63,7 +63,7 @@ namespace FileStorageService.www.Data.Migrations
|
|||
modelBuilder.Entity("FileStorageService.www.Data.FileBlock", b =>
|
||||
{
|
||||
b.HasOne("FileStorageService.www.Data.FileHandle", "FileHandle")
|
||||
.WithMany("Blocks")
|
||||
.WithMany("FileBlocks")
|
||||
.HasForeignKey("FileHandleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
|
@ -73,7 +73,7 @@ namespace FileStorageService.www.Data.Migrations
|
|||
|
||||
modelBuilder.Entity("FileStorageService.www.Data.FileHandle", b =>
|
||||
{
|
||||
b.Navigation("Blocks");
|
||||
b.Navigation("FileBlocks");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||
namespace FileStorageService.www.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitialFileModels : Migration
|
||||
public partial class FileHandleAndFileBlockMigration : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
|
|
@ -60,7 +60,7 @@ namespace FileStorageService.www.Data.Migrations
|
|||
modelBuilder.Entity("FileStorageService.www.Data.FileBlock", b =>
|
||||
{
|
||||
b.HasOne("FileStorageService.www.Data.FileHandle", "FileHandle")
|
||||
.WithMany("Blocks")
|
||||
.WithMany("FileBlocks")
|
||||
.HasForeignKey("FileHandleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
|
@ -70,7 +70,7 @@ namespace FileStorageService.www.Data.Migrations
|
|||
|
||||
modelBuilder.Entity("FileStorageService.www.Data.FileHandle", b =>
|
||||
{
|
||||
b.Navigation("Blocks");
|
||||
b.Navigation("FileBlocks");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
namespace FileStorageService.www.Models;
|
||||
|
||||
public class FileHandleListModel
|
||||
{
|
||||
public List<FileHandleModel> FileHandles { get; init; }
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
namespace FileStorageService.www.Models;
|
||||
|
||||
public class FileHandleModel
|
||||
{
|
||||
public required string FileName { get; init; }
|
||||
|
||||
public required int BlockCount { get; init; }
|
||||
public required Guid Id { get; init; }
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace FileStorageService.www.Models;
|
||||
|
||||
public class NewFileModel
|
||||
{
|
||||
|
||||
[MinLength(4)]
|
||||
[Required]
|
||||
public string Name { get; init; }
|
||||
|
||||
[Required]
|
||||
public IFormFile FileContents { get; init; }
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ builder.Services.AddDatabaseDeveloperPageExceptionFilter();
|
|||
builder.Services.AddControllersWithViews();
|
||||
builder.Services.AddRazorPages();
|
||||
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
@model FileHandleListModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Files";
|
||||
Layout = "_Layout";
|
||||
}
|
||||
|
||||
<h2>All Files</h2>
|
||||
|
||||
@if (!Model.FileHandles.Any())
|
||||
{
|
||||
<p>No files available</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Block Count</th>
|
||||
<th scope="col">Links</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach(var file in Model.FileHandles)
|
||||
{
|
||||
<tr>
|
||||
<th scope="row">@file.FileName</th>
|
||||
<th scope="row">@file.BlockCount</th>
|
||||
<th scope="row"><a asp-controller="Files" asp-action="Index" asp-route-id="@file.Id">View...</a></th>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
@model NewFileModel
|
||||
|
||||
@{
|
||||
ViewBag.Title = "title";
|
||||
Layout = "_Layout";
|
||||
}
|
||||
|
||||
<h2>New File</h2>
|
||||
|
||||
<form asp-controller="Files" asp-action="New" method="post" enctype="multipart/form-data">
|
||||
<div class="mb-3">
|
||||
<label asp-for="Name">Name</label>
|
||||
<input asp-for="Name">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label asp-for="FileContents">File</label>
|
||||
<input asp-for="FileContents">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
@model FileHandleModel;
|
||||
|
||||
@{
|
||||
|
||||
}
|
||||
|
||||
<h2>File - @Model.FileName</h2>
|
||||
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">File Name: @Model.FileName</li>
|
||||
<li class="list-group-item">Block Count: @Model.BlockCount</li>
|
||||
</ul>
|
||||
Loading…
Reference in New Issue