首页 > 解决方案 > 第一次在 Blazor 服务器端应用程序中调用 Web API 不起作用

问题描述

当我启动我的 ASP.Net Core Blazor 服务器端应用程序时,我第一次单击保存按钮时,没有任何反应。发送到控制器/API 的帖子会触发,但我的控制器/API 中的 PostListing 函数永远不会被调用。但是,如果我在之后第二次单击“保存”按钮,它会按预期工作。这是怎么回事?感谢任何可以提供帮助的人。

这是我的页面:

@page "/fetchdata"
@using SellEverywhere.Data
@using SellEverywhere.Models
@using System.Net.Http.Json
@inject HttpClient Http


<h1>Your Listings</h1>

<table width="100%" style="background:#05163D;color:honeydew">
    <tr>
        <td width="20"> </td>
        <td>
            <h2> Add New Listing Details</h2>
        </td>
        <td> </td>
        <td align="right">
            <button class="btn btn-info" @onclick="AddNewListing">Add New Listing</button>
        </td>
        <td width="10"> </td>
    </tr>
    <tr>
        <td colspan="2"></td>
    </tr>
</table>
<hr />
<form>
    <table class="form-group">
        <tr>
            <td>
                <label for="Name" class="control-label">ID</label>
            </td>
            <td>
                <input type="text" class="form-control" @bind="@lsts.Id" readonly />
            </td>
            <td width="20"> </td>
        </tr>
        <tr>
            <td>
                <label for="Name" class="control-label">Title</label>
            </td>
            <td>
                <input type="text" class="form-control" @bind="@lsts.Title" />
            </td>
            <td width="20"> </td>
            <td>
                <label for="Description" class="control-label">Description</label>
            </td>
            <td>
                <input type="text" class="form-control" @bind="@lsts.Description" />
            </td>
            <td width="20"> </td>
            <td>
                <label for="Name" class="control-label">Brand</label>
            </td>
            <td>
                <input type="text" class="form-control" @bind="@lsts.Brand" />
            </td>
        </tr>
        <tr>
            <td>
                <label for="Name" class="control-label">Size</label>
            </td>
            <td>
                <input type="text" class="form-control" @bind="@lsts.Size" />
            </td>
            <td width="20"> </td>
            <td>
                <label for="Name" class="control-label">Color</label>
            </td>
            <td>
                <input type="text" class="form-control" @bind="@lsts.Color" />
            </td>
            <td width="20"> </td>
            <td>
                <label for="Name" class="control-label">Condition</label>
            </td>
            <td>
                <input type="text" class="form-control" @bind="@lsts.Condition" />
            </td>
            <td width="20"> </td>
            <td></td>
            <td>
                <button type="submit" class="btn btn-success" @onclick="(async () => await AddListing())" style="width:220px;">Save</button>
            </td>
        </tr>
    </table>
</form>

<table width="100%" style="background:#0A2464;color:honeydew">
    <tr>
        <td width="20"> </td>
        <td>
            <h2>Listing Details</h2>
        </td>

    </tr>
    <tr>
        <td colspan="2"></td>
    </tr>
</table>

@if (listing == null)
{
    <p><em>No listing found...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Id</th>
                <th>Title</th>
                <th>Brand</th>
                <th>Color</th>
                <th>Condition</th>
                <th>Size</th>
                <th>Description</th>
                <th>Tag1</th>
                <th>Tag2</th>
                <th>Tag3</th>
                <th>Price</th>
                <th>Lowest Price</th>
                <th>Shipping Price</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var lst in listing)
            {
            <tr>
                <td>@lst.Id</td>
                <td>@lst.Title</td>
                <td>@lst.Brand</td>
                <td>@lst.Color</td>
                <td>@lst.Condition</td>
                <td>@lst.Size</td>
                <td>@lst.Description</td>
                <td>@lst.Tag1</td>
                <td>@lst.Tag2</td>
                <td>@lst.Tag3</td>
                <td>@lst.Price</td>
                <td>@lst.LowestPrice</td>
                <td>@lst.ShippingPrice</td>
                <td><button class="btn btn-primary" @onclick="@(async () => await EditListing(@lst.Id))" style="width:110px;">Edit</button></td>
                <td><button class="btn btn-danger" @onclick="@(async () => await DeleteListing(@lst.Id))">Delete</button></td>
            </tr>

            }
        </tbody>
    </table>
}

@code {
    Listing[] listing;
    Listing lsts = new Listing();
    string ids = "0";
    //bool showAddrow = false;
    protected override async Task OnInitializedAsync()
    {
        listing = await Http.GetFromJsonAsync<Listing[]>("https://localhost:44324/api/Listings/");
    }

    void AddNewListing()
    {
        lsts = new Listing();
    }
    // Add New Listings Details Method
    protected async Task AddListing()
    {
        if (lsts.Id == 0)

        {
            await Http.PostAsJsonAsync("https://localhost:44324/api/Listings/", lsts);
        }
        else
        {
            await Http.PutAsJsonAsync("https://localhost:44324/api/Listings/" + lsts.Id, lsts);
        }
        lsts = new Listing();
        listing = await Http.GetFromJsonAsync<Listing[]>("https://localhost:44324/api/Listings/");
    }
    // Edit Method
    protected async Task EditListing(int listingID)
    {
        ids = listingID.ToString();
        lsts = await Http.GetFromJsonAsync<Listing>("https://localhost:44324/api/Listings/" + Convert.ToInt32(listingID));
    }
    // Delete Method
    protected async Task DeleteListing(int listingID)
    {
        ids = listingID.ToString();
        await Http.DeleteAsync("https://localhost:44324/api/Listings/" + Convert.ToInt32(listingID));
        listing = await Http.GetFromJsonAsync<Listing[]>("https://localhost:44324/api/Listings/");
    }

}

这是我的控制器/API:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using SellEverywhere.Data;
using SellEverywhere.Models;

namespace SellEverywhere.Controllers
{   [Produces("application/json")]
    [Route("api/[controller]")]
    [ApiController]
    public class ListingsController : ControllerBase
    {
        private readonly ApplicationDbContext _context;

        public ListingsController(ApplicationDbContext context)
        {
            _context = context;
        }

        // GET: api/Listings
        [HttpGet]
        public async Task<ActionResult<IEnumerable<Listing>>> GetListing()
        {
            return await _context.Listing.ToListAsync();
        }

        // GET: api/Listings/5
        [HttpGet("{id}")]
        public async Task<ActionResult<Listing>> GetListing(int id)
        {
            var listing = await _context.Listing.FindAsync(id);

            if (listing == null)
            {
                return NotFound();
            }

            return listing;
        }

        // PUT: api/Listings/5
        // To protect from overposting attacks, enable the specific properties you want to bind to, for
        // more details, see https://go.microsoft.com/fwlink/?linkid=2123754.
        [HttpPut("{id}")]
        public async Task<IActionResult> PutListing(int id, Listing listing)
        {
            if (id != listing.Id)
            {
                return BadRequest();
            }

            _context.Entry(listing).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!ListingExists(id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return NoContent();
        }

        // POST: api/Listings
        // To protect from overposting attacks, enable the specific properties you want to bind to, for
        // more details, see https://go.microsoft.com/fwlink/?linkid=2123754.
        [HttpPost]
        public async Task<ActionResult<Listing>> PostListing(Listing listing)
        {
            listing.UserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
            _context.Listing.Add(listing);
            await _context.SaveChangesAsync();

            return CreatedAtAction("GetListing", new { id = listing.Id }, listing);
        }

        // DELETE: api/Listings/5
        [HttpDelete("{id}")]
        public async Task<ActionResult<Listing>> DeleteListing(int id)
        {
            var listing = await _context.Listing.FindAsync(id);
            if (listing == null)
            {
                return NotFound();
            }

            _context.Listing.Remove(listing);
            await _context.SaveChangesAsync();

            return listing;
        }

        private bool ListingExists(int id)
        {
            return _context.Listing.Any(e => e.Id == id);
        }
    }
}

这是我的模型:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;


namespace SellEverywhere.Models
{
    public class Listing
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        [Key]
        public int Id { get; set; }
        public string UserId { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string Color { get; set; }
        public string Condition { get; set; }
        public string Brand { get; set; }
        public string Type { get; set; }
        public string Size { get; set; }
        public string Tag1 { get; set; }
        public string Tag2 { get; set; }
        public string Tag3 { get; set; }
        public int Price { get; set; }
        public int LowestPrice { get; set; }
        public int ShippingPrice { get; set; }
        public ICollection<Photos> Photos { get; set; }
    }
    public class Photos
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        [Key]
        public int Id { get; set; }
        //[ForeignKey("Listing")]
        public int ListingId { get; set; }
        public byte[] Image { get; set; }
        public virtual Listing Listing { get; set; }
    }
}

标签: c#asp.net-core-webapiblazorrazor-pagesblazor-server-side

解决方案


“提交”按钮在执行时会将表单数据提交到服务器,对吗?这是你的意图吗?我猜不是......您实际上想要调用 AddListing 方法,您可以从该方法执行对 Web Api 端点的 HTTP Fetch API(HttpClient 服务)调用,而不是执行表单数据的传统发布请求,这不会存在于SPA应用领域。因此,您应该使用不执行发布请求的类型的按钮,而只调用您的 AddListing 方法...

注意:在 Blazor 开发的早期阶段,Blazor JS 代码包含简单地取消“提交”请求的代码。

对于像您这样的任务,您应该使用 EditForm 组件和 Blazor Forms 组件,例如 InputText 等。在这种情况下,您可以使用“提交”按钮,其提交操作会被框架自动取消。


推荐阅读