Skip to content

Instantly share code, notes, and snippets.

@brianmed
Last active January 20, 2025 04:16
Show Gist options
  • Save brianmed/38a87e116cc0a415831d194394605c01 to your computer and use it in GitHub Desktop.
Save brianmed/38a87e116cc0a415831d194394605c01 to your computer and use it in GitHub Desktop.
C# Clean Code with Dto, Entities, Services, and ViewModels
namespace App.Shared.Dto;
public class RecordingDto
{
public long RecordingId { get; set; }
public bool HasTemplate { get; set; }
public bool IsEnabled { get; set; }
public string? Name { get; set; }
public string Uri { get; set; }
}
// In Blazor WebAssembly:
//
// Create:
// await HttpClient.PostAsJsonAsync("/v1/recording", recordingViewModel.ToDto()))
//
// Read:
// await HttpClient.GetFromJsonAsync<List<RecordingViewModel>>("/v1/recording")
//
// Update:
// await HttpClient.PutAsJsonAsync("/v1/recording", recordingViewModel.ToDto())
//
// Delete:
// await HttpClient.DeleteAsync($"/v1/recording/{recordingDatum.RecordingId}");
namespace App;
public static class RecordingEndpoints
{
public static void Map(WebApplication app)
{
app.MapPost("/v1/Recording", async Task<Ok<RecordingDto>> (IRecordingService recordingService, [FromBody]RecordingDto recordingDto) =>
{
RecordingDto recordingCreateDto = await recordingService.Create(recordingDto);
return TypedResults.Ok(recordingCreateDto);
})
.RequireAuthorization("require_admin");
app.MapGet("/v1/Recording", async Task<Ok<List<RecordingDto>>> (IRecordingService recordingService) =>
{
List<RecordingDto> recordingDto = await recordingService.ReadList();
return TypedResults.Ok(recordingDto);
})
.RequireAuthorization("require_admin");
app.MapGet("/v1/Recording/{recordingId}", async Task<Ok<RecordingDto>> (IRecordingService recordingService, long recordingId) =>
{
RecordingDto recordingDto = await recordingService.ReadSingle(recordingId);
return TypedResults.Ok(recordingDto);
})
.RequireAuthorization("require_admin");
app.MapPut("/v1/Recording", async Task<Ok<RecordingDto>> (IRecordingService recordingService, [FromBody]RecordingDto recordingDto) =>
{
RecordingDto recordingUpdateDto = await recordingService.Update(recordingDto);
return TypedResults.Ok(recordingUpdateDto);
})
.RequireAuthorization("require_admin");
app.MapDelete("/v1/Recording/{recordingId}", async Task<Ok> (IRecordingService recordingService, long recordingId) =>
{
await recordingService.Delete(recordingId);
return TypedResults.Ok();
})
.RequireAuthorization("require_admin");
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace App.Entities;
[Table("Recording")]
public class RecordingEntity
{
[Key]
public long RecordingId { get; set; }
[Required]
public bool HasTemplate { get; set; }
[Required]
public bool IsEnabled { get; set; }
[MaxLength(128)]
public string? Name { get; set; }
[MaxLength(2048)]
[Required]
public string Uri { get; set; }
public DateTime Updated { get; set; }
public DateTime Inserted { get; set; } = DateTime.UtcNow;
}
namespace App.Services;
public interface IRecordingService
{
Task<RecordingDto> Create(RecordingDto recordingDto);
Task<RecordingDto> ReadSingle(long recordingId);
Task<List<RecordingDto>> ReadList();
Task<RecordingDto> Update(RecordingDto recordingDto);
Task Delete(long recordingId);
}
public static class RecordingServiceExtensions
{
public static RecordingDto ToDto(this RecordingEntity recordingEntity)
{
RecordingDto recordingDto = new()
{
RecordingId = recordingEntity.RecordingId,
HasTemplate = recordingEntity.HasTemplate,
IsEnabled = recordingEntity.IsEnabled,
Name = recordingEntity.Name,
Uri = recordingEntity.Uri
};
return recordingDto;
}
public static void With(this RecordingEntity recordingEntity, RecordingDto recordingDto)
{
recordingEntity.RecordingId = recordingDto.RecordingId;
recordingEntity.HasTemplate = recordingDto.HasTemplate;
recordingEntity.IsEnabled = recordingDto.IsEnabled;
recordingEntity.Name = recordingDto.Name;
recordingEntity.Uri = recordingDto.Uri;
}
}
public class RecordingService : IRecordingService
{
public DbContext DbContext { get; set; }
public RecordingService(
DbContext DbContext)
{
this.DbContext = DbContext;
}
public async Task<RecordingDto> Create(RecordingDto recordingDto)
{
RecordingEntity? recordingEntity = new();
recordingEntity.With(recordingDto);
this.DbContext.Recordings.Add(recordingEntity);
await this.DbContext.SaveChangesAsync();
return recordingEntity.ToDto();
}
public async Task<RecordingDto> ReadSingle(long recordingId)
{
RecordingEntity? recording = await this.DbContext
.Recordings
.AsNoTracking()
.Where(r => r.RecordingId == recordingId)
.SingleOrDefaultAsync();
return recording?.ToDto();
}
public async Task<List<RecordingDto>> ReadList()
{
List<RecordingDto> recordings = await this.DbContext
.Recordings
.AsNoTracking()
.Select(r => r.ToDto())
.ToListAsync();
return recordings;
}
public async Task<RecordingDto> Update(RecordingDto recordingDto)
{
RecordingEntity? recordingEntity = await this.DbContext
.Recordings
.Where(r => r.RecordingId == recordingDto.RecordingId)
.SingleAsync();
recordingEntity.With(recordingDto);
await this.DbContext.SaveChangesAsync();
return recordingEntity.ToDto();
}
public async Task Delete(long recordingId)
{
RecordingEntity? recordingEntity = await this.DbContext
.Recordings
.Where(r => r.RecordingId == recordingId)
.SingleAsync();
this.DbContext.Recordings.Remove(recordingEntity);
await this.DbContext.SaveChangesAsync();
}
}
using System.ComponentModel.DataAnnotations;
namespace App.Shared.ViewModels;
public class RecordingViewModel
{
[Display(AutoGenerateField = false)]
public long RecordingId { get; set; }
[Required]
public bool HasTemplate { get; set; }
[Required]
public bool IsEnabled { get; set; }
[MaxLength(128)]
public string? Name { get; set; }
[MaxLength(2048)]
[Required]
public string Uri { get; set; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment