series

  1. Develop blog projects based on ABP vNext and.NET Core – build projects using ABP CLI
  2. Develop blog projects based on ABP vNext and.NET Core – slim the project down and make it run
  3. Development blog project based on ABP vNext and.NET Core – Refinement and beautification, Swagger enter
  4. Develop blog project based on ABP vNext and.NET Core – data access and code priority
  5. Development blog project based on ABP vNext and.NET Core – add, delete, change and check custom warehouse
  6. Develop blog project based on ABP vNext and.NET Core – Uniform specification API, wrapper back model
  7. Develop blog projects based on ABP vNext and.NET Core – say Swagger, grouping, description, little green lock
  8. Develop blog projects based on ABP vNext and.NET Core – access GitHub and protect your API with JWT
  9. Develop blog project based on ABP vNext and.NET Core – exception handling and logging
  10. Develop blog projects based on ABP vNext and.NET Core – using Redis to cache data
  11. Develop blog project based on ABP vNext and.NET Core – integrate Hangfire for timed task processing
  12. Develop blog projects based on ABP vNext and.NET Core – Use AutoMapper to map objects
  13. Developing blog projects based on ABP vNext and.NET Core – Best Practices for Timed Tasks (Part 1)
  14. Developing blog projects based on ABP vNext and.NET Core – Best Practices for Timed Tasks (Part 2)
  15. Developing blog projects based on ABP vNext and.NET Core – Best Practices for Timed Tasks (PART 3)
  16. Blog Development project based on ABP vNext and.NET Core
  17. Abp vNext and.NET Core
  18. Blog Development project based on ABP vNext and.NET Core
  19. Blog Development project based on ABP vNext and.NET Core
  20. Blog Development project based on ABP vNext and.NET Core
  21. Abp vNext and.NET Core Development Blog Project – Blazor
  22. Abp vNext and.NET Core Development Blog Project – Blazor – Part 2
  23. Abp vNext and.NET Core Development Blog Project – Blazor
  24. Abp vNext and.NET Core Development Blog Project – Blazor
  25. Abp vNext and.NET Core Development Blog Project – Blazor
  26. Abp vNext and.NET Core Development Blog Project – Blazor – Part 6
  27. Abp vNext and.NET Core Development Blog Project – Blazor
  28. Abp vNext and.NET Core Development Blog Project – Blazor Series (8)
  29. Abp vNext and.NET Core Development Blog Project – Blazor Series (9)
  30. Abp vNext and.NET Core development blog project – Final release project

The last chapter completed all the functions of the background classification module, this chapter continues to add, delete, change and check the tag module and the friendship link module.

Label management

The implementation is the same as the previous classification management, add Tags. Razor component under the Admin folder, set route @page “/ Admin/Tags “.

The same thing needs to be placed under the AdminLayout component, adding a few parameters: Popover status bool Open, New or updated tag field string tagName ServiceResult

> Tags.

/// <summary>
///Hide Box by default
/// </summary>
private bool Open { get; set; } = false;

/// <summary>
///Add or update the label field value
/// </summary>
private string tagName, displayName;

/// <summary>
///Update the Id value of the label
/// </summary>
private int id;

/// <summary>
///The tag list data returned by the API
/// </summary>
private ServiceResult<IEnumerable<QueryTagForAdminDto>> tags;
Copy the code
//QueryTagForAdminDto.cs
namespace Meowv.Blog.BlazorApp.Response.Blog
{
    public class QueryTagForAdminDto : QueryTagDto
    {
        /// <summary>
        ///A primary key
        /// </summary>
        public int Id { get; set; }}}Copy the code

Get the data in the initialization method OnInitializedAsync().

/// <summary>
///Initialize the
/// </summary>
/// <returns></returns>
protected override async Task OnInitializedAsync()
{
    var token = await Common.GetStorageAsync("token");
    Http.DefaultRequestHeaders.Add("Authorization".$"Bearer {token}");

    tags = await FetchData();
}

/// <summary>
///To get the data
/// </summary>
/// <returns></returns>
private async Task<ServiceResult<IEnumerable<QueryTagForAdminDto>>> FetchData()
{
    return await Http.GetFromJsonAsync<ServiceResult<IEnumerable<QueryTagForAdminDto>>>("/blog/admin/tags");
}
Copy the code

Note that you need to set up the request header, grant access, and bind data on the page.

<AdminLayout>
    @if (tags == null)
    {
        <Loading />
    }
    else
    {
        <div class="post-wrap tags">
            <h2 class="post-title">-&nbsp; Tags&nbsp; -</h2>
            @if (tags.Success && tags.Result.Any())
            {
                <div class="categories-card">
                    @foreach (var item in tags.Result)
                    {
                        <div class="card-item">
                            <div class="categories">
                                <NavLink title="āŒ delete" @onclick="@(async () => await DeleteAsync(item.Id))">āŒ</NavLink>
                                <NavLink title="šŸ“ editor" @onclick="@(() => ShowBox(item))">šŸ“</NavLink>
                                <NavLink target="_blank" href="@ ($"/tag/ {item.DisplayName}")">
                                    <h3>@item.TagName</h3>
                                    <small>(@item.Count)</small>
                                </NavLink>
                            </div>
                        </div>
                    }
                    <div class="card-item">
                        <div class="categories">
                            <NavLink><h3 @onclick="@(() => ShowBox())">šŸ“˜~~~ Add labels ~~~šŸ“˜</h3></NavLink>
                        </div>
                    </div>
                </div>
            }
            else
            {
                <ErrorTip />
            }
        </div>

        <Box OnClickCallback="@SubmitAsync" Open="@Open">
            <div class="box-item">
                <b>DisplayName:</b><input type="text" @bind="@displayName" @bind:event="oninput" />
            </div>
            <div class="box-item">
                <b>TagName:</b><input type="text" @bind="@tagName" @bind:event="oninput" />
            </div>
        </Box>
    }
</AdminLayout>
Copy the code

Tags displays
component content when no data is retrieved, loops through the data to bind, and deletes the button binding event to call DeleteAsync(). Add and edit button click events by calling the ShowBox() method to display pop-ups. There is no need to pass parameters when adding new items. The current item (QueryTagForAdminDto) needs to be passed in when editing.

The

component binds two parameters of the label, whether to open the Opne parameter and confirm the button callback event method SubmitAsync().

Delete tag method DeleteAsync(…) As follows:

// Popup confirmation
bool confirmed = await Common.InvokeAsync<bool> ("confirm"."\nšŸ’„šŸ’¢ Really want to kill this damn tag šŸ’¢šŸ’„");

if (confirmed)
{
    var response = await Http.DeleteAsync($"/blog/tag? id={id}");

    var result = await response.Content.ReadFromJsonAsync<ServiceResult>();

    if (result.Success)
    {
        tags = awaitFetchData(); }}Copy the code

Confirm the deletion again before deleting the data to avoid accidental damage.

Popover method ShowBox(…) As follows:

/// <summary>
///Show box, bind field
/// </summary>
/// <param name="dto"></param>
private void ShowBox(QueryTagForAdminDto dto = null)
{
    Open = true;
    id = 0;

    / / new
    if (dto == null)
    {
        displayName = null;
        tagName = null;
    }
    else / / update{ id = dto.Id; displayName = dto.DisplayName; tagName = dto.TagName; }}Copy the code

Finally, confirm the button’s callback event method SubmitAsync() in the popover as follows:

/// <summary>
///Confirm button click event
/// </summary>
/// <returns></returns>
private async Task SubmitAsync()
{
    var input = new EditTagInput()
    {
        DisplayName = displayName.Trim(),
        TagName = tagName.Trim()
    };

    if (string.IsNullOrEmpty(input.DisplayName) || string.IsNullOrEmpty(input.TagName))
    {
        return;
    }

    var responseMessage = new HttpResponseMessage();

    if (id > 0)
        responseMessage = await Http.PutAsJsonAsync($"/blog/tag? id={id}", input);
    else
        responseMessage = await Http.PostAsJsonAsync("/blog/tag", input);

    var result = await responseMessage.Content.ReadFromJsonAsync<ServiceResult>();
    if (result.Success)
    {
        tags = await FetchData();
        Open = false; }}Copy the code

The input parameter EditTagInput.

namespace Meowv.Blog.BlazorApp.Response.Blog
{
    public class EditTagInput : TagDto{}}Copy the code

The final execution of adding or updating data is carried out in the click event, assigning the value of the variable to EditTagInput, judging whether to add or update according to the ID, reloading the data after success, and closing the popover.

Label management page code is as follows:

Click to see the code
@page "/admin/categories"

<AdminLayout>
    @if (categories == null)
    {
        <Loading />
    }
    else
    {
        <div class="post-wrap categories">
            <h2 class="post-title">-&nbsp; Categories&nbsp; -</h2> @if (categories.Success && categories.Result.Any())
            {
                <div class="categories-card">
                    @foreach (var item in categories.Result)
                    {
                        <div class="card-item">
                            <div class="categories">
                                <NavLink title="āŒ delete" @onclick="@(async () => await DeleteAsync(item.Id))"> āŒ < / NavLink > < NavLink title ="šŸ“ editor" @onclick="@(() => ShowBox(item))"> šŸ“ < / NavLink > < NavLink target ="_blank" href="@ ($"/category/{item.DisplayName}")">
                                    <h3>@item.CategoryName</h3>
                                    <small>(@item.Count)</small>
                                </NavLink>
                            </div>
                        </div>
                    }
                    <div class="card-item">
                        <div class="categories">
                            <NavLink><h3 @onclick="@(() => ShowBox())"New classification > šŸ“• ~ ~ ~ ~ ~ ~ šŸ“• < / h3 > < / NavLink > < / div > < / div > < / div >}else
            {
                <ErrorTip />
            }
        </div>

        <Box OnClickCallback="@SubmitAsync" Open="@Open">
            <div class="box-item">< b>DisplayName: </b><input type="text" @bind="@displayName" @bind:event="oninput" />
            </div>
            <div class="box-item">< b>CategoryName: </b><input type="text" @bind="@categoryName" @bind:event="oninput" />
            </div>
        </Box>
    }
</AdminLayout>

@code {
    /// <summary>
    ///Hide Box by default
    /// </summary>
    private bool Open { get; set; } = false;

    /// <summary>
    ///New or updated category field value
    /// </summary>
    private string categoryName, displayName;

    /// <summary>
    ///Update the Id value of a category
    /// </summary>
    private int id;

    /// <summary>
    ///The category list data returned by the API
    /// </summary>
    private ServiceResult<IEnumerable<QueryCategoryForAdminDto>> categories;

    /// <summary>
    ///Initialize the
    /// </summary>
    /// <returns></returns>
    protected override async Task OnInitializedAsync()
    {
        var token = await Common.GetStorageAsync("token");
        Http.DefaultRequestHeaders.Add("Authorization".$"Bearer {token}");

        categories = await FetchData();
    }

    /// <summary>
    ///To get the data
    /// </summary>
    /// <returns></returns>
    private async Task<ServiceResult<IEnumerable<QueryCategoryForAdminDto>>> FetchData()
    {
        return await Http.GetFromJsonAsync<ServiceResult<IEnumerable<QueryCategoryForAdminDto>>>("/blog/admin/categories");
    }

    /// <summary>
    ///Delete the classification
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    private async Task DeleteAsync(int id)
    {
        Open = false;

        // Popup confirmation
        bool confirmed = await Common.InvokeAsync<bool> ("confirm"."\nšŸ’„šŸ’¢ Really want to kill this damn classification šŸ’¢šŸ’„");

        if (confirmed)
        {
            var response = await Http.DeleteAsync($"/blog/category? id={id}");

            var result = await response.Content.ReadFromJsonAsync<ServiceResult>();

            if (result.Success)
            {
                categories = awaitFetchData(); }}}/// <summary>
    ///Show box, bind field
    /// </summary>
    /// <param name="dto"></param>
    private void ShowBox(QueryCategoryForAdminDto dto = null)
    {
        Open = true;
        id = 0;

        / / new
        if (dto == null)
        {
            displayName = null;
            categoryName = null;
        }
        else / / update{ id = dto.Id; displayName = dto.DisplayName; categoryName = dto.CategoryName; }}/// <summary>
    ///Confirm button click event
    /// </summary>
    /// <returns></returns>
    private async Task SubmitAsync()
    {
        var input = new EditCategoryInput()
        {
            DisplayName = displayName.Trim(),
            CategoryName = categoryName.Trim()
        };

        if (string.IsNullOrEmpty(input.DisplayName) || string.IsNullOrEmpty(input.CategoryName))
        {
            return;
        }

        var responseMessage = new HttpResponseMessage();

        if (id > 0)
            responseMessage = await Http.PutAsJsonAsync($"/blog/category? id={id}", input);
        else
            responseMessage = await Http.PostAsJsonAsync("/blog/category", input);

        var result = await responseMessage.Content.ReadFromJsonAsync<ServiceResult>();
        if (result.Success)
        {
            categories = await FetchData();
            Open = false; }}}Copy the code

Friends of chain management

The implementation is the same, this is not to say, directly on the code.

First add the receive parameter returned by the API and the input parameter of the new edit.

//QueryFriendLinkForAdminDto.cs
namespace Meowv.Blog.BlazorApp.Response.Blog
{
    public class QueryFriendLinkForAdminDto : FriendLinkDto
    {
        /// <summary>
        ///A primary key
        /// </summary>
        public int Id { get; set; }}}//EditFriendLinkInput.cs
namespace Meowv.Blog.BlazorApp.Response.Blog
{
    public class EditFriendLinkInput : FriendLinkDto{}}Copy the code
@page "/admin/friendlinks"

<AdminLayout>
    @if (friendlinks == null)
    {
        <Loading />
    }
    else
    {
        <div class="post-wrap categories">
            <h2 class="post-title">-&nbsp; FriendLinks&nbsp; -</h2> @if (friendlinks.Success && friendlinks.Result.Any())
            {
                <div class="categories-card">
                    @foreach (var item in friendlinks.Result)
                    {
                        <div class="card-item">
                            <div class="categories">
                                <NavLink title="āŒ delete" @onclick="@(async () => await DeleteAsync(item.Id))"> āŒ < / NavLink > < NavLink title ="šŸ“ editor" @onclick="@(() => ShowBox(item))"> šŸ“ < / NavLink > < NavLink target ="_blank" href="@item.LinkUrl">
                                    <h3>@item.Title</h3>
                                </NavLink>
                            </div>
                        </div>
                    }
                    <div class="card-item">
                        <div class="categories">
                            <NavLink><h3 @onclick="@(() => ShowBox())"> šŸ“’ chain of new friends ~ ~ ~ ~ ~ ~ šŸ“’ < / h3 > < / NavLink > < / div > < / div > < / div >}else
            {
                <ErrorTip />
            }
        </div>

        <Box OnClickCallback="@SubmitAsync" Open="@Open">
            <div class="box-item">< b>Title: </b><input type="text" @bind="@title" @bind:event="oninput" />
            </div>
            <div class="box-item"LinkUrl: </b><input type="text" @bind="@linkUrl" @bind:event="oninput" />
            </div>
        </Box>
    }
</AdminLayout>

@code {
    /// <summary>
    ///Hide Box by default
    /// </summary>
    private bool Open { get; set; } = false;

    /// <summary>
    ///Add or update the value of the friend chain field
    /// </summary>
    private string title, linkUrl;

    /// <summary>
    ///Update the Id value of the friend chain
    /// </summary>
    private int id;

    /// <summary>
    ///The list of friends returned by the API
    /// </summary>
    private ServiceResult<IEnumerable<QueryFriendLinkForAdminDto>> friendlinks;

    /// <summary>
    ///Initialize the
    /// </summary>
    /// <returns></returns>
    protected override async Task OnInitializedAsync()
    {
        var token = await Common.GetStorageAsync("token");
        Http.DefaultRequestHeaders.Add("Authorization".$"Bearer {token}");

        friendlinks = await FetchData();
    }

    /// <summary>
    ///To get the data
    /// </summary>
    /// <returns></returns>
    private async Task<ServiceResult<IEnumerable<QueryFriendLinkForAdminDto>>> FetchData()
    {
        return await Http.GetFromJsonAsync<ServiceResult<IEnumerable<QueryFriendLinkForAdminDto>>>("/blog/admin/friendlinks");
    }

    /// <summary>
    ///Delete the classification
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    private async Task DeleteAsync(int id)
    {
        Open = false;

        // Popup confirmation
        bool confirmed = await Common.InvokeAsync<bool> ("confirm"."\nšŸ’„šŸ’¢ Really want to kill this damn classification šŸ’¢šŸ’„");

        if (confirmed)
        {
            var response = await Http.DeleteAsync($"/blog/friendlink? id={id}");

            var result = await response.Content.ReadFromJsonAsync<ServiceResult>();

            if (result.Success)
            {
                friendlinks = awaitFetchData(); }}}/// <summary>
    ///Show box, bind field
    /// </summary>
    /// <param name="dto"></param>
    private void ShowBox(QueryFriendLinkForAdminDto dto = null)
    {
        Open = true;
        id = 0;

        / / new
        if (dto == null)
        {
            title = null;
            linkUrl = null;
        }
        else / / update{ id = dto.Id; title = dto.Title; linkUrl = dto.LinkUrl; }}/// <summary>
    ///Confirm button click event
    /// </summary>
    /// <returns></returns>
    private async Task SubmitAsync()
    {
        var input = new EditFriendLinkInput()
        {
            Title = title.Trim(),
            LinkUrl = linkUrl.Trim()
        };

        if (string.IsNullOrEmpty(input.Title) || string.IsNullOrEmpty(input.LinkUrl))
        {
            return;
        }

        var responseMessage = new HttpResponseMessage();

        if (id > 0)
            responseMessage = await Http.PutAsJsonAsync($"/blog/friendlink? id={id}", input);
        else
            responseMessage = await Http.PostAsJsonAsync("/blog/friendlink", input);

        var result = await responseMessage.Content.ReadFromJsonAsync<ServiceResult>();
        if (result.Success)
        {
            friendlinks = await FetchData();
            Open = false; }}}Copy the code

So far, the function of the remaining article module has not been done, today I will stop here, tomorrow will continue, to be continued…

Open source: github.com/Meowv/Blog/…