Added BlazorAppRadzenNet8SerilogLogging

This commit is contained in:
M. Akif Tokatlioglu
2024-05-19 22:27:58 +03:00
parent 37df7aa1e8
commit 27bb1f00de
39 changed files with 1546 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
!BlazorAppRadzenNet8SerilogLogging/Components/Pages/Log
/BlazorAppRadzenNet8SerilogLogging/LogsFolder/logs*

View File

@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34601.278
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorAppRadzenNet8SerilogLogging", "BlazorAppRadzenNet8SerilogLogging\BlazorAppRadzenNet8SerilogLogging.csproj", "{A0D005D1-56D6-4540-B107-42D5188042A1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A0D005D1-56D6-4540-B107-42D5188042A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A0D005D1-56D6-4540-B107-42D5188042A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A0D005D1-56D6-4540-B107-42D5188042A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A0D005D1-56D6-4540-B107-42D5188042A1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EDF75B28-8549-46F9-A08B-A83715AEB2C4}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.5" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.5" />
<PackageReference Include="Radzen.Blazor" Version="4.31.5" />
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog.Sinks.Seq" Version="7.0.1" />
<PackageReference Include="Serilog.Sinks.SQLite" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<None Update="LogsFolder\readme.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,26 @@
<!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="_content/Radzen.Blazor/css/standard-base.css">
@* <link rel="stylesheet" href="app.css" /> *@
@* <link rel="stylesheet" href="BlazorAppRadzenNet8SerilogLogging.styles.css" /> *@
<link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet @rendermode="InteractiveServer" />
</head>
<body>
<Routes @rendermode="InteractiveServer" />
<script src="_content/Radzen.Blazor/Radzen.Blazor.js"></script>
<script src="_framework/blazor.web.js"></script>
</body>
</html>

View File

@@ -0,0 +1,65 @@
@inherits LayoutComponentBase
@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager
@inject DialogService DialogService
@inject ContextMenuService ContextMenuService
@inject TooltipService TooltipService
@inject NotificationService NotificationService
<RadzenDialog />
<RadzenNotification />
<RadzenTooltip />
<RadzenContextMenu />
@* <RadzenComponents /> *@
<RadzenLayout style="grid-template-areas: 'rz-sidebar rz-header' 'rz-sidebar rz-body';">
<RadzenHeader>
<RadzenRow JustifyContent="JustifyContent.Start" AlignItems="AlignItems.Center" Gap="0">
<RadzenColumn Size="5">
<RadzenSidebarToggle Click="@SidebarToggleClick"></RadzenSidebarToggle>
</RadzenColumn>
<RadzenColumn Size="7">
<RadzenStack AlignItems="AlignItems.Center" Orientation="Orientation.Horizontal" JustifyContent="JustifyContent.End"></RadzenStack>
</RadzenColumn>
</RadzenRow>
</RadzenHeader>
<RadzenBody Expanded="@sidebarExpanded">
<RadzenRow class="rz-mx-auto rz-px-4 rz-pt-2 rz-pt-md-4 rz-pt-lg-6 rz-pt-xl-12 rz-pb-2 rz-pb-lg-12" Style="max-width: 1440px;">
<RadzenColumn Size="12">
@Body
</RadzenColumn>
</RadzenRow>
</RadzenBody>
<RadzenSidebar Expanded="@sidebarExpanded" style="z-index: 2">
<RadzenStack AlignItems="Radzen.AlignItems.Center" class="rz-py-4 rz-py-lg-6" Style="padding: var(--rz-panel-menu-item-padding); border-bottom: var(--rz-panel-menu-item-border);">
@* <RadzenImage Path="images/logo.png" style="width: 48px; height: 48px;"></RadzenImage>
*@
<RadzenText Text="appname" TextStyle="Radzen.Blazor.TextStyle.Subtitle1" class="rz-mb-0" style="color: var(--rz-sidebar-color);" />
</RadzenStack>
<NavMenu />
<RadzenStack AlignItems="Radzen.AlignItems.Center" Gap="0" class="rz-py-4 rz-py-lg-6" Style="padding: var(--rz-panel-menu-item-padding);">
<RadzenText Text="appname v1.0.0" TextStyle="Radzen.Blazor.TextStyle.Caption" style="color: var(--rz-text-disabled-color);" TagName="Radzen.Blazor.TagName.P" TextAlign="Radzen.TextAlign.Center" />
<RadzenText Text="Copyright Ⓒ 2024" TextStyle="Radzen.Blazor.TextStyle.Caption" class="rz-mb-0" style="color: var(--rz-text-disabled-color);" TagName="Radzen.Blazor.TagName.P" TextAlign="Radzen.TextAlign.Center" />
</RadzenStack>
</RadzenSidebar>
</RadzenLayout>
@code {
bool sidebarExpanded = true;
void SidebarToggleClick()
{
sidebarExpanded = !sidebarExpanded;
}
}

View File

@@ -0,0 +1,8 @@
<RadzenPanelMenu>
<RadzenPanelMenuItem Text="Home" Path="/" />
<RadzenPanelMenuItem Text="Posts" Path="/BlogPost" />
<RadzenPanelMenuItem Text="Logs" Path="/Log" />
</RadzenPanelMenu>

View File

@@ -0,0 +1,77 @@
@page "/BlogPost/Create"
<RadzenText Text="Create" TextStyle="TextStyle.H5" />
@if (blogPostViewModel == null)
{
<p>Loading...</p>
}
else
{
<RadzenStack>
<RadzenFieldset Text="New Post">
<RadzenStack Gap="2rem">
<EditForm Context="editFormNewPost" Model="@blogPostViewModel" OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Title" for="title" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<InputText id="title" class="form-control" placeholder="Title"
@bind-Value="blogPostViewModel.Title" />
<ValidationMessage For="@(() => blogPostViewModel.Title)" />
</RadzenColumn>
</RadzenRow>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Content" for="content" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<InputText id="content" class="form-control" placeholder="Content"
@bind-Value="blogPostViewModel.Content" />
<ValidationMessage For="@(() => blogPostViewModel.Content)" />
</RadzenColumn>
</RadzenRow>
<RadzenButton Text="Save" Icon="save"
ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Success" />
</EditForm>
</RadzenStack>
</RadzenFieldset>
</RadzenStack>
<RadzenButton Text="Back" Icon="arrow_back" Class="rz-mt-2"
Click="NavigatetoBlogPostIndex"
ButtonStyle="ButtonStyle.Primary" />
}
@code {
private BlogPostViewModel? blogPostViewModel;
protected override void OnInitialized()
{
blogPostViewModel = new();
}
protected async Task HandleValidSubmit()
{
if (blogPostViewModel == null) return;
var blogPost = Mapper.Map<BlogPostViewModel, BlogPost>(blogPostViewModel);
bool result = await BlogPostService.AddBlogPostAsync(blogPost);
if (result)
NavigationManager.NavigateTo("/BlogPost/");
}
private void NavigatetoBlogPostIndex() => NavigationManager.NavigateTo("/BlogPost");
}

View File

@@ -0,0 +1,79 @@
@page "/BlogPost/Delete/{id:int}"
<h3>Delete</h3>
@if (blogPostViewModel == null)
{
<p>Loading...</p>
}
else
{
<RadzenStack>
<RadzenFieldset Text="Post Delete">
<RadzenStack>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Id" for="id" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<RadzenTextBox id="id" class="form-control" placeholder="Id" ReadOnly=true
Value="@blogPostViewModel.Id.ToString()" />
</RadzenColumn>
</RadzenRow>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Title" for="title" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<RadzenTextBox id="title" class="form-control" placeholder="Title" ReadOnly=true
Value="@blogPostViewModel.Title" />
</RadzenColumn>
</RadzenRow>
</RadzenStack>
<RadzenButton Text="REMOVE" Icon="delete_forever" ButtonStyle="ButtonStyle.Danger"
Click="RemoveButtonClick" />
</RadzenFieldset>
</RadzenStack>
<RadzenButton Text="Back" Icon="arrow_back" Class="rz-mt-2"
Click="NavigatetoBlogPostIndex"
ButtonStyle="ButtonStyle.Primary" />
}
@code {
[Parameter]
public int id { get; set; }
BlogPostViewModel? blogPostViewModel;
protected override async Task OnInitializedAsync()
{
if (blogPostViewModel == null)
{
var blogPost = await BlogPostService.GetBlogPostByIdAsync(id);
if (blogPost == null)
return;
blogPostViewModel = Mapper.Map<BlogPost, BlogPostViewModel>(blogPost);
}
}
private async void RemoveButtonClick()
{
bool result = await BlogPostService.DeleteBlogPostByIdAsync(id);
if (result)
NavigationManager.NavigateTo("/BlogPost");
}
private void NavigatetoBlogPostIndex() => NavigationManager.NavigateTo("/BlogPost");
}

View File

@@ -0,0 +1,78 @@
@page "/BlogPost/Detail/{id:int}"
<h3>Detail</h3>
@if (blogPostViewModel == null)
{
<p>Loading...</p>
}
else
{
<RadzenStack>
<RadzenFieldset Text="Post Detail">
<RadzenStack>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Id" for="id" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<RadzenTextBox id="id" class="form-control" placeholder="Id" ReadOnly=true
Value="@blogPostViewModel.Id.ToString()" />
</RadzenColumn>
</RadzenRow>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Title" for="title" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<RadzenTextBox id="title" class="form-control" placeholder="Title" ReadOnly=true
Value="@blogPostViewModel.Title" />
</RadzenColumn>
</RadzenRow>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Content" for="content" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<RadzenTextBox id="content" class="form-control" placeholder="Content" ReadOnly=true
Value="@blogPostViewModel.Content" />
</RadzenColumn>
</RadzenRow>
</RadzenStack>
</RadzenFieldset>
</RadzenStack>
<RadzenButton Text="Back" Icon="arrow_back" Class="rz-mt-2"
Click="NavigatetoBlogPostIndex"
ButtonStyle="ButtonStyle.Primary" />
}
@code {
[Parameter]
public int id { get; set; }
BlogPostViewModel? blogPostViewModel;
protected override async Task OnInitializedAsync()
{
if (blogPostViewModel == null)
{
var blogPost = await BlogPostService.GetBlogPostByIdAsync(id);
if (blogPost == null)
return;
blogPostViewModel = Mapper.Map<BlogPost, BlogPostViewModel>(blogPost);
}
}
private void NavigatetoBlogPostIndex() => NavigationManager.NavigateTo("/BlogPost");
}

View File

@@ -0,0 +1,105 @@
@page "/BlogPost/Edit/{id:int}"
<h3>Edit</h3>
@if (blogPostViewModel == null)
{
<p>Loading...</p>
}
else
{
<RadzenStack>
<RadzenFieldset Text="Edit Post">
<RadzenStack Gap="2rem">
<EditForm Context="editFormEdit" Model="@blogPostViewModel" OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Title" for="title" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<InputText id="title" class="form-control" placeholder="Title"
@bind-Value="blogPostViewModel.Title" />
<ValidationMessage For="@(() => blogPostViewModel.Title)" />
</RadzenColumn>
</RadzenRow>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Content" for="content" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<InputText id="content" class="form-control" placeholder="Content"
@bind-Value="blogPostViewModel.Content" />
<ValidationMessage For="@(() => blogPostViewModel.Content)" />
</RadzenColumn>
</RadzenRow>
<RadzenButton Text="Save" Icon="save"
ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Success" />
</EditForm>
</RadzenStack>
</RadzenFieldset>
</RadzenStack>
<RadzenButton Text="Back" Icon="arrow_back" Class="rz-mt-2"
Click="NavigatetoBlogPostIndex"
ButtonStyle="ButtonStyle.Primary" />
}
@code {
[Parameter]
public int id { get; set; }
BlogPostViewModel? blogPostViewModel;
protected override async Task OnInitializedAsync()
{
if (blogPostViewModel == null)
{
var blogPost = await BlogPostService.GetBlogPostByIdAsync(id);
if (blogPost == null)
return;
blogPostViewModel = Mapper.Map<BlogPost, BlogPostViewModel>(blogPost);
}
}
void OnPaste(HtmlEditorPasteEventArgs args)
{
}
void OnChange(string html)
{
}
void OnInput(string html)
{
}
void OnExecute(HtmlEditorExecuteEventArgs args)
{
}
protected async Task HandleValidSubmit()
{
if (blogPostViewModel == null) return;
var blogPost = Mapper.Map<BlogPostViewModel, BlogPost>(blogPostViewModel);
bool result = await BlogPostService.UpdateBlogPostAsync(id, blogPost);
if (result)
NavigationManager.NavigateTo("/BlogPost/");
}
private void NavigatetoBlogPostIndex() => NavigationManager.NavigateTo("/BlogPost");
}

View File

@@ -0,0 +1,81 @@
@page "/BlogPost"
<PageTitle>Posts</PageTitle>
<RadzenRow>
<RadzenColumn SizeSM="12" SizeMD="12" SizeLG="4">
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center">
<RadzenText Text="Posts" TextStyle="TextStyle.H5" />
<RadzenButton Text="Create" Icon="add_circle_outline"
Click="NavigatetoCreate"
ButtonStyle="ButtonStyle.Success" class="rz-mb-2 rz-p-2" />
</RadzenStack>
</RadzenColumn>
</RadzenRow>
<RadzenDataGrid KeyProperty="Id" IsLoading="@isLoading" ShowPagingSummary=true
Count="@totalCount" Data="@blogPosts" LoadData="@LoadData"
FilterPopupRenderMode="PopupRenderMode.OnDemand"
FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive"
FilterMode="FilterMode.Advanced" AllowSorting="true" AllowFiltering="true"
AllowPaging="true" PageSize="@itemPageSize" PagerHorizontalAlign="HorizontalAlign.Center"
TItem="BlogPostViewModel" ColumnWidth="200px">
<Columns>
<RadzenDataGridColumn TItem="BlogPostViewModel" Property="Id" Filterable="false" Title="Id" Frozen="true" Width="30px" MinWidth="30px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="BlogPostViewModel" Property="Title" Title="Title" />
<RadzenDataGridColumn TItem="BlogPostViewModel" Property="Content" Title="Content" />
<RadzenDataGridColumn TItem="BlogPostViewModel" Context="blogPost" Filterable="false" Sortable="false" Width="150px" TextAlign="TextAlign.Center">
<Template Context="blogPost">
<RadzenRow JustifyContent="JustifyContent.Center">
<RadzenButton Icon="pageview" ButtonStyle="ButtonStyle.Info" Variant="Variant.Flat" Size="ButtonSize.Medium"
Click="@(args => NavigatetoDetail(blogPost.Id))" @onclick:stopPropagation="true">
</RadzenButton>
<RadzenButton Icon="edit" ButtonStyle="ButtonStyle.Warning" Variant="Variant.Flat" Size="ButtonSize.Medium"
Click="@(args => NavigatetoEdit(blogPost.Id))" @onclick:stopPropagation="true">
</RadzenButton>
<RadzenButton Icon="delete_forever" ButtonStyle="ButtonStyle.Danger" Variant="Variant.Flat" Size="ButtonSize.Medium"
Click="@(args => NavigatetoDelete(blogPost.Id))" @onclick:stopPropagation="true">
</RadzenButton>
</RadzenRow>
</Template>
</RadzenDataGridColumn>
</Columns>
</RadzenDataGrid>
@code {
const int itemPageSize = 10;
private bool isLoading;
private int totalCount;
private IEnumerable<BlogPostViewModel>? blogPosts;
private async Task LoadData(LoadDataArgs args)
{
isLoading = true;
var result = await BlogPostService.GetBlogPostsAsync(filter: args.Filter, top: args.Top, skip: args.Skip, orderby: args.OrderBy, count: true);
blogPosts = Mapper.Map<IEnumerable<BlogPost>, IEnumerable<BlogPostViewModel>>(result.Result);
totalCount = result.TotalCount;
isLoading = false;
}
private void NavigatetoCreate() => NavigationManager.NavigateTo("/BlogPost/Create");
private void NavigatetoDetail(int id) => NavigationManager.NavigateTo($"/BlogPost/Detail/{id}");
private void NavigatetoEdit(int id) => NavigationManager.NavigateTo($"/BlogPost/Edit/{id}");
private void NavigatetoDelete(int id) => NavigationManager.NavigateTo($"/BlogPost/Delete/{id}");
}

View File

@@ -0,0 +1,7 @@
@using BlazorAppRadzenNet8SerilogLogging.Data;
@using BlazorAppRadzenNet8SerilogLogging.Models;
@using BlazorAppRadzenNet8SerilogLogging.Services;
@using BlazorAppRadzenNet8SerilogLogging.ViewModels;
@inject NavigationManager NavigationManager
@inject BlogPostService BlogPostService

View 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;
}

View File

@@ -0,0 +1,7 @@
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.

View File

@@ -0,0 +1,69 @@
@page "/Log/Delete/{id:int}"
<h3>Delete</h3>
@if (logViewModel == null)
{
<p>Loading...</p>
}
else
{
<RadzenStack>
<RadzenFieldset Text="Log Delete">
<RadzenStack>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Id" for="id" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<RadzenTextBox id="id" class="form-control" placeholder="Id" ReadOnly=true
Value="@logViewModel.id.ToString()" />
</RadzenColumn>
</RadzenRow>
</RadzenStack>
<RadzenButton Text="REMOVE" Icon="delete_forever" ButtonStyle="ButtonStyle.Danger"
Click="RemoveButtonClick" />
</RadzenFieldset>
</RadzenStack>
<RadzenButton Text="Back" Icon="arrow_back" Class="rz-mt-2"
Click="NavigatetoLogIndex"
ButtonStyle="ButtonStyle.Primary" />
}
@code {
[Parameter]
public int id { get; set; }
LogViewModel? logViewModel;
protected override async Task OnInitializedAsync()
{
if (logViewModel == null)
{
var log = await LoggerService.GetLogByIdAsync(id);
if (log == null)
return;
logViewModel = Mapper.Map<Log, LogViewModel>(log);
}
}
private async void RemoveButtonClick()
{
bool result = await LoggerService.DeleteLogByIdAsync(id);
if (result)
NavigationManager.NavigateTo("/Log");
}
private void NavigatetoLogIndex() => NavigationManager.NavigateTo("/Log");
}

View File

@@ -0,0 +1,108 @@
@page "/Log/Detail/{id:int}"
<h3>Detail</h3>
@if (logViewModel == null)
{
<p>Loading...</p>
}
else
{
<RadzenStack>
<RadzenFieldset Text="Log Detail">
<RadzenStack>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Id" for="id" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<RadzenTextBox id="id" class="form-control" placeholder="Id" ReadOnly=true
Value="@logViewModel.id.ToString()" />
</RadzenColumn>
</RadzenRow>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Timestamp" for="timestamp" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<RadzenTextBox id="timestamp" class="form-control" placeholder="Timestamp" ReadOnly=true
Value="@logViewModel.Timestamp.ToString("yyyy-MM-dd HH:mm:ss")" />
</RadzenColumn>
</RadzenRow>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Level" for="level" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<RadzenTextBox id="level" class="form-control" placeholder="Level" ReadOnly=true
Value="@logViewModel.Level" />
</RadzenColumn>
</RadzenRow>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Exception" for="exception" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<RadzenTextArea ReadOnly="true" Rows="5" id="exception" class="form-control" placeholder="Exception"
Value="@logViewModel.Exception" />
</RadzenColumn>
</RadzenRow>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="RenderedMessage" for="renderedMessage" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<RadzenTextArea ReadOnly="true" Rows="5" id="renderedMessage" class="form-control" placeholder="RenderedMessage"
Value="@logViewModel.RenderedMessage" />
</RadzenColumn>
</RadzenRow>
<RadzenRow AlignItems="AlignItems.Center" Class="rz-mb-2">
<RadzenColumn SizeSM="12" SizeMD="2" SizeLG="2">
<RadzenLabel Text="Properties" for="properties" />
</RadzenColumn>
<RadzenColumn SizeSM="12" SizeMD="10" SizeLG="10">
<RadzenTextArea ReadOnly="true" Rows="5" id="properties" class="form-control" placeholder="Properties"
Value="@logViewModel.Properties" />
</RadzenColumn>
</RadzenRow>
</RadzenStack>
</RadzenFieldset>
</RadzenStack>
<RadzenButton Text="Back" Icon="arrow_back" Class="rz-mt-2"
Click="NavigatetoLogIndex"
ButtonStyle="ButtonStyle.Primary" />
}
@code {
[Parameter]
public int id { get; set; }
LogViewModel? logViewModel;
protected override async Task OnInitializedAsync()
{
if (logViewModel == null)
{
var log = await LoggerService.GetLogByIdAsync(id);
if (log == null)
return;
logViewModel = Mapper.Map<Log, LogViewModel>(log);
}
}
private void NavigatetoLogIndex() => NavigationManager.NavigateTo("/Log");
}

View File

@@ -0,0 +1,102 @@
@page "/Log"
@inject DialogService DialogService
<PageTitle>Logs</PageTitle>
<RadzenRow>
<RadzenColumn SizeSM="12" SizeMD="12" SizeLG="4">
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center">
<RadzenText Text="Logs" TextStyle="TextStyle.H5" />
<RadzenButton Text="DELETE ALL LOGS" Icon="delete_forever"
Click="DeleteAllLogs"
ButtonStyle="ButtonStyle.Danger" class="rz-mb-2 rz-p-2" />
</RadzenStack>
</RadzenColumn>
</RadzenRow>
<RadzenDataGrid KeyProperty="id" IsLoading="@isLoading" ShowPagingSummary=true
Count="@totalCount" Data="@logs" LoadData="@LoadData"
FilterPopupRenderMode="PopupRenderMode.OnDemand"
FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive"
FilterMode="FilterMode.Advanced" AllowSorting="true" AllowFiltering="true"
AllowPaging="true" PageSize="@itemPageSize" PagerHorizontalAlign="HorizontalAlign.Center"
TItem="LogViewModel" ColumnWidth="200px">
<Columns>
<RadzenDataGridColumn TItem="LogViewModel" Property="id" Filterable="false" Title="Id" Frozen="true" Width="30px" MinWidth="30px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="LogViewModel" Property="Timestamp" Title="Timestamp" />
<RadzenDataGridColumn TItem="LogViewModel" Property="Level" Title="Level" Context="log">
<Template>
<span class="text-@Helpers.LogEventLevelHelper.GetBootstrapUIClass(log.Level)">
@log.Level
</span>
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="LogViewModel" Property="Exception" Title="Exception" />
<RadzenDataGridColumn TItem="LogViewModel" Property="RenderedMessage" Title="RenderedMessage" />
<RadzenDataGridColumn TItem="LogViewModel" Property="Properties" Title="Properties" />
<RadzenDataGridColumn TItem="LogViewModel" Context="log" Filterable="false" Sortable="false" Width="150px" TextAlign="TextAlign.Center">
<Template Context="log">
<RadzenRow JustifyContent="JustifyContent.Center">
<RadzenButton Icon="pageview" ButtonStyle="ButtonStyle.Info" Variant="Variant.Flat" Size="ButtonSize.Medium"
Click="@(args => NavigatetoDetail(log.id))" @onclick:stopPropagation="true">
</RadzenButton>
<RadzenButton Icon="delete_forever" ButtonStyle="ButtonStyle.Danger" Variant="Variant.Flat" Size="ButtonSize.Medium"
Click="@(args => NavigatetoDelete(log.id))" @onclick:stopPropagation="true">
</RadzenButton>
</RadzenRow>
</Template>
</RadzenDataGridColumn>
</Columns>
</RadzenDataGrid>
@code {
const int itemPageSize = 10;
private bool isLoading;
private int totalCount;
private IEnumerable<LogViewModel>? logs;
private async Task LoadData(LoadDataArgs args)
{
isLoading = true;
var result = await LoggerService.GetLogsAsync(filter: args.Filter, top: args.Top, skip: args.Skip, orderby: args.OrderBy, count: true);
logs = Mapper.Map<IEnumerable<Log>, IEnumerable<LogViewModel>>(result.Result);
totalCount = result.TotalCount;
isLoading = false;
}
private async Task DeleteAllLogs()
{
var dialogResult = await DialogService.Confirm("Are you sure DELETE All Logs?", "Delete All Logs",
new ConfirmOptions { OkButtonText = "Ok", CancelButtonText = "Cancel" });
if (dialogResult == true)
{
var deleteAllLogsResult = await LoggerService.DeleteAllLogsAsync();
if (deleteAllLogsResult == true)
NavigationManager.NavigateTo("/Log", true);
}
}
private void NavigatetoDetail(int id) => NavigationManager.NavigateTo($"/Log/Detail/{id}");
private void NavigatetoDelete(int id) => NavigationManager.NavigateTo($"/Log/Delete/{id}");
}

View File

@@ -0,0 +1,7 @@
@using BlazorAppRadzenNet8SerilogLogging.Data;
@using BlazorAppRadzenNet8SerilogLogging.Models;
@using BlazorAppRadzenNet8SerilogLogging.Services;
@using BlazorAppRadzenNet8SerilogLogging.ViewModels;
@inject NavigationManager NavigationManager
@inject LoggerService LoggerService

View 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>

View File

@@ -0,0 +1,16 @@
@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 BlazorAppRadzenNet8SerilogLogging
@using BlazorAppRadzenNet8SerilogLogging.Components
@using MapsterMapper
@using Radzen
@using Radzen.Blazor
@inject IMapper Mapper

View File

@@ -0,0 +1,19 @@
using BlazorAppRadzenNet8SerilogLogging.Models;
using Microsoft.EntityFrameworkCore;
namespace BlazorAppRadzenNet8SerilogLogging.Data;
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<BlogPost> BlogPosts => Set<BlogPost>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}

View File

@@ -0,0 +1,19 @@
using BlazorAppRadzenNet8SerilogLogging.Models;
using Microsoft.EntityFrameworkCore;
namespace BlazorAppRadzenNet8SerilogLogging.Data;
public class ApplicationLoggerDbContext : DbContext
{
public ApplicationLoggerDbContext(DbContextOptions<ApplicationLoggerDbContext> options)
: base(options)
{
}
public DbSet<Log> Logs => Set<Log>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}

View File

@@ -0,0 +1,101 @@
using BlazorAppRadzenNet8SerilogLogging.Models;
namespace BlazorAppRadzenNet8SerilogLogging.Data;
public class SeedData
{
private readonly ApplicationDbContext _context;
public SeedData(ApplicationDbContext context)
{
_context = context;
}
public async Task CreateInitialData()
{
var posts = GetAllBlogPosts();
await _context.BlogPosts.AddRangeAsync(posts);
await _context.SaveChangesAsync();
}
private static IEnumerable<BlogPost> GetAllBlogPosts()
{
List<BlogPost> posts = new();
for (int i = 0; i < 50; i++)
{
BlogPost post = new() { Id = i + 1, Title = titles[i], Content = contents[i % 10] };
posts.Add(post);
}
return posts;
}
private static readonly string[] titles = {
"Introduction to Object-Oriented Programming",
"Mastering Data Structures and Algorithms",
"Building Web Applications with ASP.NET",
"Creating Mobile Apps with Xamarin",
"Exploring Artificial Intelligence and Machine Learning",
"Understanding Functional Programming Concepts",
"Developing Games with Unity",
"Securing Web Applications from Cyber Attacks",
"Optimizing Code Performance for Better Efficiency",
"Implementing Design Patterns in Software Development",
"Testing and Debugging Strategies for Reliable Software",
"Working with Databases and SQL",
"Building Responsive User Interfaces with HTML and CSS",
"Exploring Cloud Computing and Serverless Architecture",
"Developing Cross-Platform Applications with React Native",
"Introduction to Internet of Things (IoT)",
"Creating Scalable Microservices with Docker and Kubernetes",
"Understanding Network Protocols and TCP/IP",
"Building RESTful APIs with Node.js and Express",
"Exploring Big Data Analytics and Apache Hadoop",
"Mastering Version Control with Git and GitHub",
"Developing Desktop Applications with WPF",
"Securing Mobile Applications from Malicious Attacks",
"Optimizing Database Performance with Indexing",
"Implementing Continuous Integration and Deployment",
"Testing Mobile Apps on Different Platforms",
"Working with NoSQL Databases like MongoDB",
"Building Progressive Web Apps with React",
"Exploring Quantum Computing and Quantum Algorithms",
"Introduction to Cybersecurity and Ethical Hacking",
"Creating Chatbots with Natural Language Processing",
"Understanding Software Development Life Cycle",
"Developing Augmented Reality (AR) Applications",
"Securing Web APIs with OAuth and JWT",
"Optimizing Front-End Performance for Better User Experience",
"Implementing Machine Learning Models with TensorFlow",
"Testing Web Applications for Cross-Browser Compatibility",
"Working with Blockchain Technology and Smart Contracts",
"Building Real-Time Applications with SignalR",
"Exploring Cryptography and Encryption Techniques",
"Introduction to Agile Software Development",
"Creating Voice User Interfaces with Amazon Alexa",
"Understanding Web Accessibility and Inclusive Design",
"Developing Natural Language Processing Applications",
"Securing Cloud Infrastructure and Services",
"Optimizing Backend Performance for Scalability",
"Implementing Continuous Monitoring and Alerting",
"Testing APIs with Postman and Swagger",
"Working with Data Visualization Libraries like D3.js",
"Building E-commerce Applications with Shopify",
"Exploring Robotic Process Automation (RPA)",
"Introduction to DevOps and CI/CD Pipelines"
};
private static readonly string[] contents = new string[]
{
"Lorem ipsum dolor sit amet, consectetur t.",
"Sed ut perspiciatis unde omnis iste natuccusantium doloremque laudantium.",
"Nemo enim ipsam voluptatem quia voluptas aut fugit.",
"Quis autem vel eum iure reprehenderit quesse quam nihil molestiae consequatur.",
"At vero eos et accusamus et iusto odio d.",
"Similique sunt in culpa qui officia de.",
"Et harum quidem rerum facilis est et expio.",
"Nam libero tempore, cum soluta nobis est.",
"Omnis voluptas assumenda est, omnis dolo",
"Temporibus autem quibusdam et aut offic"
};
}

View File

@@ -0,0 +1,32 @@
using Serilog.Events;
namespace BlazorAppRadzenNet8SerilogLogging.Helpers;
public static class LogEventLevelHelper
{
public static string GetBootstrapUIClass(string value)
{
var level = StringtoEnum(value);
return level switch
{
LogEventLevel.Verbose or LogEventLevel.Debug or LogEventLevel.Information => "info",
LogEventLevel.Warning => "warning",
LogEventLevel.Error or LogEventLevel.Fatal => "danger",
_ => throw new Exception("not valid logeventlevel")
};
}
public static LogEventLevel StringtoEnum(string value)
{
return value switch
{
"Verbose" => LogEventLevel.Verbose,
"Debug" => LogEventLevel.Debug,
"Information" => LogEventLevel.Information,
"Warning" => LogEventLevel.Warning,
"Error" => LogEventLevel.Error,
"Fatal" => LogEventLevel.Fatal,
_ => throw new Exception("not valid logeventlevel")
};
}
}

View File

@@ -0,0 +1,8 @@
namespace BlazorAppRadzenNet8SerilogLogging.Models;
public class BlogPost
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,11 @@
namespace BlazorAppRadzenNet8SerilogLogging.Models;
public class Log
{
public int id { get; set; }
public DateTime Timestamp { get; set; }
public string Level { get; set; } = string.Empty;
public string Exception { get; set; } = string.Empty;
public string RenderedMessage { get; set; } = string.Empty;
public string Properties { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,127 @@
using BlazorAppRadzenNet8SerilogLogging.Components;
using BlazorAppRadzenNet8SerilogLogging.Data;
using BlazorAppRadzenNet8SerilogLogging.Services;
using BlazorAppRadzenNet8SerilogLogging.ViewModels;
using Mapster;
using MapsterMapper;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Radzen;
using Serilog;
using System.Reflection;
internal class Program
{
private static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var currentDir = Directory.GetCurrentDirectory();
// get connection string from configuration file (appsettings.json)
string? sqliteLoggerConnectionString = builder.Configuration.GetConnectionString("SqliteLogger");
SqliteConnectionStringBuilder sqliteLoggerConnectionStringBuilder = new SqliteConnectionStringBuilder(sqliteLoggerConnectionString);
sqliteLoggerConnectionStringBuilder.DataSource = Path.Combine(currentDir, sqliteLoggerConnectionStringBuilder.DataSource);
string sqliteDbFilePath = sqliteLoggerConnectionStringBuilder.DataSource;
// file logger path
string serilogFileLoggerFilePath = Path.Combine(currentDir, "LogsFolder", "logs.log");
builder.Host.UseSerilog((ctx, lc) => lc
.MinimumLevel.Information()
//.WriteTo.Console(new JsonFormatter(), restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Information)
.WriteTo.Console(restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Information)
.WriteTo.Seq("http://localhost:5001", restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Information)
.WriteTo.File(serilogFileLoggerFilePath,
restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Verbose,
rollingInterval: RollingInterval.Hour,
encoding: System.Text.Encoding.UTF8)
.WriteTo.SQLite(sqliteDbFilePath,
tableName: "Logs",
restrictedToMinimumLevel:
builder.Environment.IsDevelopment() ? Serilog.Events.LogEventLevel.Information : Serilog.Events.LogEventLevel.Warning,
storeTimestampInUtc: false,
batchSize:
builder.Environment.IsDevelopment() ? (uint)1 : (uint)100,
retentionPeriod: new TimeSpan(0, 1, 0, 0, 0),
maxDatabaseSize: 10)
);
builder.Services.AddDbContext<ApplicationLoggerDbContext>(options =>
options.UseSqlite(sqliteLoggerConnectionStringBuilder.ConnectionString)
);
// Add services to the container.
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseInMemoryDatabase("ConnectionInMemory")
);
builder.Services.AddScoped<SeedData>();
builder.Services.AddScoped<BlogPostService>();
builder.Services.AddScoped<LoggerService>();
// Radzen Services
builder.Services.AddScoped<DialogService>();
builder.Services.AddScoped<NotificationService>();
builder.Services.AddScoped<TooltipService>();
builder.Services.AddScoped<ContextMenuService>();
// Add mapster mapper
builder.Services.AddMapster();
builder.Services.CreateDatabase().GetAwaiter().GetResult();
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
var app = builder.Build();
app.UseSerilogRequestLogging();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAntiforgery();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.Run();
}
}
public static class ServiceCollectionExtensions
{
public static async Task CreateDatabase(this IServiceCollection services)
{
using (IServiceScope tmp = services.BuildServiceProvider().CreateScope())
{
await using var _context = tmp.ServiceProvider.GetRequiredService<ApplicationDbContext>();
var seedData = tmp.ServiceProvider.GetRequiredService<SeedData>();
await seedData.CreateInitialData();
}
}
}
public static class MapsterConfiguration
{
public static void AddMapster(this IServiceCollection services)
{
var typeAdapterConfig = TypeAdapterConfig.GlobalSettings;
Assembly applicationAssembly = typeof(BaseViewModel<,>).Assembly;
typeAdapterConfig.Scan(applicationAssembly);
var mapperConfig = new Mapper(typeAdapterConfig);
services.AddSingleton<IMapper>(mapperConfig);
}
}

View File

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

View File

@@ -0,0 +1,101 @@
using BlazorAppRadzenNet8SerilogLogging.Data;
using BlazorAppRadzenNet8SerilogLogging.Models;
using Microsoft.EntityFrameworkCore;
using Radzen;
using System.Linq.Dynamic.Core;
namespace BlazorAppRadzenNet8SerilogLogging.Services;
public class BlogPostService
{
private readonly ILogger<LoggerService> _logger;
private readonly ApplicationDbContext _context;
public BlogPostService(ILogger<LoggerService> logger, ApplicationDbContext context)
{
_logger = logger;
_context = context;
}
public async Task<BlogPost?> GetBlogPostByIdAsync(int id)
{
_logger.LogInformation($"Called GetBlogPostByIdAsync", id);
return await _context.BlogPosts.FirstOrDefaultAsync(x => x.Id == id);
}
public async Task<(IEnumerable<BlogPost> Result, int TotalCount)> GetBlogPostsAsync(string? filter = default, int? top = default, int? skip = default, string? orderby = default, string? expand = default, string? select = default, bool? count = default)
{
_logger.LogInformation($"Called GetBlogPostsAsync");
var query = _context.BlogPosts.AsQueryable();
if (!string.IsNullOrEmpty(filter))
query = query.Where(filter);
if (!string.IsNullOrEmpty(orderby))
query = query.OrderBy(orderby);
int totalCount = 0;
if (count == true)
totalCount = query.Count();
IEnumerable<BlogPost>? result;
if (skip == null || top == null)
result = await query.ToListAsync();
else
result = await query.Skip(skip.Value).Take(top.Value).ToListAsync();
return (result, totalCount);
}
public async Task<bool> AddBlogPostAsync(BlogPost blogPost)
{
_logger.LogInformation($"Called AddBlogPostAsync");
try
{
await _context.BlogPosts.AddAsync(blogPost);
await _context.SaveChangesAsync();
}
catch (Exception ex)
{
return false;
}
return true;
}
public async Task<bool> UpdateBlogPostAsync(int id, BlogPost blogPost)
{
_logger.LogInformation($"Called UpdateBlogPostAsync");
try
{
var oldBlogPost = _context.BlogPosts.FirstOrDefault(x => x.Id == id);
if (oldBlogPost == null) return false;
oldBlogPost.Title = blogPost.Title;
oldBlogPost.Content = blogPost.Content;
await _context.SaveChangesAsync();
}
catch (Exception ex)
{
return false;
}
return true;
}
public async Task<bool> DeleteBlogPostByIdAsync(int id)
{
_logger.LogInformation($"Called DeleteBlogPostByIdAsync", id);
var blogPost = await _context.BlogPosts.FirstOrDefaultAsync(x => x.Id == id);
if (blogPost == null)
return false;
_context.BlogPosts.Remove(blogPost);
await _context.SaveChangesAsync();
return true;
}
}

View File

@@ -0,0 +1,73 @@
using BlazorAppRadzenNet8SerilogLogging.Models;
using Microsoft.EntityFrameworkCore;
using Radzen;
using System.Linq.Dynamic.Core;
namespace BlazorAppRadzenNet8SerilogLogging.Data;
public class LoggerService
{
private readonly ILogger<LoggerService> _logger;
private readonly ApplicationLoggerDbContext _loggerDbContext;
public LoggerService(ILogger<LoggerService> logger, ApplicationLoggerDbContext loggerDbContext)
{
_logger = logger;
_loggerDbContext = loggerDbContext;
}
public async Task<Log?> GetLogByIdAsync(int id)
{
_logger.LogInformation($"Called GetLogByIdAsync", id);
return await _loggerDbContext.Logs.FirstOrDefaultAsync(x => x.id == id);
}
public async Task<(IEnumerable<Log> Result, int TotalCount)> GetLogsAsync(string? filter = default, int? top = default, int? skip = default, string? orderby = default, string? expand = default, string? select = default, bool? count = default)
{
_logger.LogInformation($"Called GetLogsAsync");
var query = _loggerDbContext.Logs.AsQueryable();
if (!string.IsNullOrEmpty(filter))
query = query.Where(filter);
if (!string.IsNullOrEmpty(orderby))
query = query.OrderBy(orderby);
int totalCount = 0;
if (count == true)
totalCount = query.Count();
IEnumerable<Log>? result;
if (skip == null || top == null)
result = await query.ToListAsync();
else
result = await query.Skip(skip.Value).Take(top.Value).ToListAsync();
return (result, totalCount);
}
public async Task<bool> DeleteLogByIdAsync(int id)
{
_logger.LogInformation($"Called DeleteLogByIdAsync", id);
var log = await _loggerDbContext.Logs.FirstOrDefaultAsync(x => x.id == id);
if (log == null)
return false;
_loggerDbContext.Logs.Remove(log);
await _loggerDbContext.SaveChangesAsync();
return true;
}
public async Task<bool?> DeleteAllLogsAsync()
{
_logger.LogInformation($"Called DeleteAllLogsAsync");
var all = await _loggerDbContext.Logs.ToListAsync();
_loggerDbContext.Logs.RemoveRange(all); ;
await _loggerDbContext.SaveChangesAsync();
_logger.LogInformation($"Deleted All Logs.");
return true;
}
}

View File

@@ -0,0 +1,45 @@
using Mapster;
namespace BlazorAppRadzenNet8SerilogLogging.ViewModels;
/// <summary>
/// Model <-> ViewModel Mapping
/// </summary>
/// <typeparam name="TViewModel">ViewModel</typeparam>
/// <typeparam name="TModel">Model</typeparam>
public abstract class BaseViewModel<TViewModel, TModel> : IRegister
where TViewModel : class, new()
where TModel : class, new()
{
public TModel ToModel()
{
return this.Adapt<TModel>();
}
public TModel ToModel(TModel model)
{
return (this as TViewModel).Adapt(model);
}
public static TViewModel FromModel(TModel model)
{
return model.Adapt<TViewModel>();
}
private TypeAdapterConfig Config { get; set; }
public virtual void AddCustomMappings()
{ }
protected TypeAdapterSetter<TViewModel, TModel> SetCustomMappings()
=> Config.ForType<TViewModel, TModel>();
protected TypeAdapterSetter<TModel, TViewModel> SetCustomMappingsInverse()
=> Config.ForType<TModel, TViewModel>();
public void Register(TypeAdapterConfig config)
{
Config = config;
AddCustomMappings();
}
}

View File

@@ -0,0 +1,18 @@
using BlazorAppRadzenNet8SerilogLogging.Models;
using System.ComponentModel.DataAnnotations;
namespace BlazorAppRadzenNet8SerilogLogging.ViewModels;
public class BlogPostViewModel : BaseViewModel<BlogPostViewModel, BlogPost>
{
public int Id { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "Title can not be empty")]
public string Title { get; set; } = string.Empty;
[Required(AllowEmptyStrings = false, ErrorMessage = "Content can not be empty")]
public string Content { get; set; } = string.Empty;
public string TitleShort { get; set; } = string.Empty;
public string ContentShort { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,13 @@
using BlazorAppRadzenNet8SerilogLogging.Models;
namespace BlazorAppRadzenNet8SerilogLogging.ViewModels;
public class LogViewModel : BaseViewModel<LogViewModel, Log>
{
public int id { get; set; }
public DateTime Timestamp { get; set; }
public string Level { get; set; } = string.Empty;
public string Exception { get; set; } = string.Empty;
public string RenderedMessage { get; set; } = string.Empty;
public string Properties { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,11 @@
{
"ConnectionStrings": {
"SqliteLogger": "Data Source=LogsFolder/logs.db;Cache=Shared"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -0,0 +1,12 @@
{
"ConnectionStrings": {
"SqliteLogger": "Data Source=LogsFolder/logs.db;Cache=Shared"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB