admin管理员组

文章数量:1406753

Project overview
I'm trying to make a webshop for a school project using blazor Server/Web App. All I have now is a login/register page and an overview where a user (admin) can add, remove or edit categories.

Problem
The problem is, when editing a category, the user is not supposed to be able to change the category name to an already existing category. This does work on the backend side, when submitting the change to an existing category name, the user gets an error and the category name is not changed in the database. However, when then navigating to the category overview, this does show the change, so you see the same category name twice. When reloading the page the issue is fixed.

What I've tried
I've tried using StateHasChanged() in the OnInitializedAsync() function, changing it to OnParametersSetAsync(), using NavigationManager.LocationChanged and using that resetCategory function, but none of it helped.

If someone could help that would be great, my teachers don't know. Also please let me know if I haven't provided enough/the correct information! Thank you for your time!

Edit Category page

@page "/edit-category"
@page "/edit-category/{Id:int}"
@inject ICategoryService CategoryService
@inject NavigationManager NavigationManager
@rendermode @(new InteractiveServerRenderMode(prerender: false))
@attribute [Authorize(Roles = "Administrator")]

@if (Id is null)
{
    <PageTitle>Categorie toevoegen</PageTitle>
    <h3>Categorie toevoegen</h3>
}
else
{
    <PageTitle>@OriginalCategoryName aanpassen</PageTitle>
    <h3>@OriginalCategoryName aanpassen</h3>
}

<EditForm Model="CurrentCategory" OnSubmit="HandleSubmit">
    <div>
        <label for="name">Name</label>
        <InputText id="name" @bind-Value="CurrentCategory.Name" class="form-control" />
    </div>
    <div>
        <label for="description">Omschrijving</label>
        <InputText id="description" @bind-Value="CurrentCategory.Description" class="form-control" />
    </div>
    <div class="mb-3 text-center">
        <span class="text-danger">@errorMessage</span>
    </div>
    <button type="submit" class="btn btn-primary mt-2">Save</button>
</EditForm>

@code {
        [Parameter]
        public int? Id { get; set; }

    public Category CurrentCategory { get; set; } = new();

    private string? errorMessage;
    private string? OriginalCategoryName;

    protected override async Task OnParametersSetAsync()
    {
        if (Id is not null)
        {
            var category = await CategoryService.GetCategoryByIdAsync((int)Id);
            if (category is not null)
            {
                CurrentCategory = category;
                OriginalCategoryName = category.Name;
            }
        }
    }

    async Task HandleSubmit()
    {
        if (string.IsNullOrWhiteSpace(CurrentCategory.Name))
        {
            errorMessage = "De categorienaam mag niet leeg zijn.";
            await ResetCategory();
        }
        else if (await CategoryService.CategoryExists(CurrentCategory.Name))
        {
            errorMessage = "Deze categorie bestaat al.";
            await ResetCategory();
        } else 
        {
            if (Id is not null)
            {
                // Update
                await CategoryService.UpdateCategoryAsync(CurrentCategory, (int)Id);
                NavigationManager.NavigateTo("/categories", true);
            }
            else
            {
                // Add
                await CategoryService.AddCategoryAsync(CurrentCategory);
                NavigationManager.NavigateTo("/categories", true);
            }
        }
    }

    private async Task ResetCategory()
    {
        if (Id is not null)
        {
            var category = await CategoryService.GetCategoryByIdAsync((int)Id);
            if (category is not null)
            {
                CurrentCategory = category;
            }
        }
        else
        {
            CurrentCategory = new(); 
        }

        StateHasChanged();
    }
}

Category Overview page

@page "/categories"
@inject ICategoryService CategoryService
@inject NavigationManager NavigationManager
@rendermode @(new InteractiveServerRenderMode(prerender: false))
@attribute [Authorize(Roles = "Administrator")]

<PageTitle>Categorieën</PageTitle>
<h3>Categorieën</h3>

@if (categories.Count == 0)
{
    <p><em>Loading categories...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Naam</th>
                <th>Beschrijving (optioneel)</th>
                <th></th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var category in categories)
            {
                <tr>
                    <td>@category.Name</td>
                    <td>@category.Description</td>
                    <td><button class="btn btn-primary" @onclick="@(() => EditCategory(category.Id))">Aanpassen</button></td>
                    <td><button class="btn btn-danger" @onclick="@(() => DeleteCategory(category.Id))">Verwijderen</button></td>
                </tr>
            }
        </tbody>
    </table>

    <button class="btn btn-primary" @onclick="AddCategory">Categorie toevoegen</button>
}

@code {
    List<Category> categories = new List<Category>();

    protected override async Task OnInitializedAsync()
    {
        categories = await CategoryService.GetAllCategoriesAsync();
    }

    void EditCategory(int? id)
    {
        NavigationManager.NavigateTo($"/edit-category/{id}");
    }

    async Task DeleteCategory(int id)
    {
        await CategoryService.DeleteCategoryAsync(id);
        categories = await CategoryService.GetAllCategoriesAsync();
    }

    void AddCategory()
    {
        NavigationManager.NavigateTo($"/edit-category");
    }

}

Project overview
I'm trying to make a webshop for a school project using blazor Server/Web App. All I have now is a login/register page and an overview where a user (admin) can add, remove or edit categories.

Problem
The problem is, when editing a category, the user is not supposed to be able to change the category name to an already existing category. This does work on the backend side, when submitting the change to an existing category name, the user gets an error and the category name is not changed in the database. However, when then navigating to the category overview, this does show the change, so you see the same category name twice. When reloading the page the issue is fixed.

What I've tried
I've tried using StateHasChanged() in the OnInitializedAsync() function, changing it to OnParametersSetAsync(), using NavigationManager.LocationChanged and using that resetCategory function, but none of it helped.

If someone could help that would be great, my teachers don't know. Also please let me know if I haven't provided enough/the correct information! Thank you for your time!

Edit Category page

@page "/edit-category"
@page "/edit-category/{Id:int}"
@inject ICategoryService CategoryService
@inject NavigationManager NavigationManager
@rendermode @(new InteractiveServerRenderMode(prerender: false))
@attribute [Authorize(Roles = "Administrator")]

@if (Id is null)
{
    <PageTitle>Categorie toevoegen</PageTitle>
    <h3>Categorie toevoegen</h3>
}
else
{
    <PageTitle>@OriginalCategoryName aanpassen</PageTitle>
    <h3>@OriginalCategoryName aanpassen</h3>
}

<EditForm Model="CurrentCategory" OnSubmit="HandleSubmit">
    <div>
        <label for="name">Name</label>
        <InputText id="name" @bind-Value="CurrentCategory.Name" class="form-control" />
    </div>
    <div>
        <label for="description">Omschrijving</label>
        <InputText id="description" @bind-Value="CurrentCategory.Description" class="form-control" />
    </div>
    <div class="mb-3 text-center">
        <span class="text-danger">@errorMessage</span>
    </div>
    <button type="submit" class="btn btn-primary mt-2">Save</button>
</EditForm>

@code {
        [Parameter]
        public int? Id { get; set; }

    public Category CurrentCategory { get; set; } = new();

    private string? errorMessage;
    private string? OriginalCategoryName;

    protected override async Task OnParametersSetAsync()
    {
        if (Id is not null)
        {
            var category = await CategoryService.GetCategoryByIdAsync((int)Id);
            if (category is not null)
            {
                CurrentCategory = category;
                OriginalCategoryName = category.Name;
            }
        }
    }

    async Task HandleSubmit()
    {
        if (string.IsNullOrWhiteSpace(CurrentCategory.Name))
        {
            errorMessage = "De categorienaam mag niet leeg zijn.";
            await ResetCategory();
        }
        else if (await CategoryService.CategoryExists(CurrentCategory.Name))
        {
            errorMessage = "Deze categorie bestaat al.";
            await ResetCategory();
        } else 
        {
            if (Id is not null)
            {
                // Update
                await CategoryService.UpdateCategoryAsync(CurrentCategory, (int)Id);
                NavigationManager.NavigateTo("/categories", true);
            }
            else
            {
                // Add
                await CategoryService.AddCategoryAsync(CurrentCategory);
                NavigationManager.NavigateTo("/categories", true);
            }
        }
    }

    private async Task ResetCategory()
    {
        if (Id is not null)
        {
            var category = await CategoryService.GetCategoryByIdAsync((int)Id);
            if (category is not null)
            {
                CurrentCategory = category;
            }
        }
        else
        {
            CurrentCategory = new(); 
        }

        StateHasChanged();
    }
}

Category Overview page

@page "/categories"
@inject ICategoryService CategoryService
@inject NavigationManager NavigationManager
@rendermode @(new InteractiveServerRenderMode(prerender: false))
@attribute [Authorize(Roles = "Administrator")]

<PageTitle>Categorieën</PageTitle>
<h3>Categorieën</h3>

@if (categories.Count == 0)
{
    <p><em>Loading categories...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Naam</th>
                <th>Beschrijving (optioneel)</th>
                <th></th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var category in categories)
            {
                <tr>
                    <td>@category.Name</td>
                    <td>@category.Description</td>
                    <td><button class="btn btn-primary" @onclick="@(() => EditCategory(category.Id))">Aanpassen</button></td>
                    <td><button class="btn btn-danger" @onclick="@(() => DeleteCategory(category.Id))">Verwijderen</button></td>
                </tr>
            }
        </tbody>
    </table>

    <button class="btn btn-primary" @onclick="AddCategory">Categorie toevoegen</button>
}

@code {
    List<Category> categories = new List<Category>();

    protected override async Task OnInitializedAsync()
    {
        categories = await CategoryService.GetAllCategoriesAsync();
    }

    void EditCategory(int? id)
    {
        NavigationManager.NavigateTo($"/edit-category/{id}");
    }

    async Task DeleteCategory(int id)
    {
        await CategoryService.DeleteCategoryAsync(id);
        categories = await CategoryService.GetAllCategoriesAsync();
    }

    void AddCategory()
    {
        NavigationManager.NavigateTo($"/edit-category");
    }

}
Share Improve this question edited Mar 11 at 10:16 DarkBee 15.5k8 gold badges72 silver badges118 bronze badges asked Mar 11 at 10:11 JipJipJipJip 133 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

However, when then navigating to the category overview, this does show the change, so you see the same category name twice. When reloading the page the issue is fixed.

I've reproduced the problem, which is related to the CategoryService maintaining a list of categories in memory and updating it incorrectly. You can add a breakpoint in the ResetCategory() and OnInitializedAsync() methods to check the category/categories. When we detect a duplicate category name and fetch the categories again, the data is no longer the data from the database, but rather the data from memory.

To solve this issue, you can use the AsNoTracking() method to always re-fetch data from the database. Code as below:

public class CategoryService : ICategoryService
{
    private readonly ApplicationDbContext _context;  
    public CategoryService(ApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<List<Category>> GetAllCategoriesAsync()
    {
        return await _context.Categories.AsNoTracking().ToListAsync();
    }

    public async Task<Category?> GetCategoryByIdAsync(int id)
    {
        return await _context.Categories.AsNoTracking().Where(c=>c.Id == id).FirstOrDefaultAsync();
    }

本文标签: cUI Shows Stale Data After Editing Category Name (Database Correct)Stack Overflow