65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 ASP.NET Web API 构建 RESTful API

2018 年 7 月 16 日

CPOL

15分钟阅读

viewsIcon

69955

在本文中,我们将构建、测试和使用一个 asp.net web api。

引言

让我们快速回顾一下 ASP.NET MVC 架构。因此,当请求到达我们的应用程序时,MVC 框架会将该请求交给控制器中的一个操作。该操作通常会返回一个视图,该视图会被 razor 视图引擎解析,然后最终将 HTML 标记返回给客户端。因此,在这种方法中,HTML 标记是在服务器上生成的,然后返回给客户端。

还有一种生成 HTML 标记的替代方法,我们可以在客户端生成它。因此,我们的操作将返回原始数据,而不是 HTML 标记。

这种方法有什么好处?

在客户端生成标记有很多好处。

  • 它需要更少的服务器资源(它可能会提高应用程序的可伸缩性,因为每个客户端将负责生成自己的视图)
  • 原始数据通常比 HTML 标记需要更少的带宽。因此,数据可能会更快地到达客户端。这可以提高应用程序的感知性能。
  • 这种方法支持移动和平板电脑应用程序等广泛的客户端。

这些应用程序被称为端点,它们获取数据并在本地生成视图。我们称这些端点为数据服务(Web API),因为它们只返回数据,而不是标记。

Web API 不仅限于跨设备,它还在我们的 Web 应用程序中广泛用于添加新功能,例如许多流行的网站(如 YouTube、Facebook 和 Twitter)公开了我们可以将其用于我们 Web 应用程序的公共数据服务。我们可以将它们的数据与我们应用程序中的数据合并,并为新用户提供新体验。这些就是它的好处。

这些数据服务不仅仅用于获取数据,我们还有用于修改数据(例如添加客户)的服务。我们用于构建这些数据服务的框架称为 Web API。该框架是在 ASP.Net MVC 之后开发的,但它遵循 ASP.NET MVC 的相同架构和原则,因此它具有路由、控制器、操作、操作结果等等。还有一些小的区别,我们将在本文中看到。在 .Net Core 中,Microsoft 已将这两个框架(ASP.NET MVC 和 ASP.NET Web API)合并为一个框架。

RESTful 约定

因此,您知道什么是 HTTP 服务和 Web API。在这里,我们将开发一个支持几种不同类型请求的应用程序。

GET                               /api/customers               (获取客户列表)

GET                               /api/customers/1             (获取单个客户)

POST                             /api/ customers              (添加客户并在请求正文中添加客户数据)

不要混淆 GET 和 POST 请求的数据,我们使用 GET 请求来获取资源或数据的列表。我们使用 POST 请求来创建新的。

现在要更新学生,我们使用 PUT 请求。

PUT                               /api/customers/1

因此,客户的 ID 在 URL 中,而要更新的实际数据或属性将在请求正文中。最后,要删除学生。

Delete                             /api/customers/1

我们向端点发送 HttpDelete 请求。因此,您在此处看到的请求类型和端点是称为 REST (Representational State Transfer) 的标准约定。

构建 API

此类派生自 ApiController,而不是 Controller。如果您正在处理任何现有项目,只需在 controllers 文件夹中添加一个新文件夹,并在那里添加 API 控制器。并添加这些操作,但在定义 API 中的操作之前,这是我的 Customer 模型类。

public class Customer
{
    public int Id { get; set; }

    [Required]
    [StringLength(255)]
    public string Name { get; set; }

    public bool IsSubscribedToNewsLetter { get; set; }

    [Display(Name = "Date of Birth")]
    public DateTime? Birthdate { get; set; }

    [Display(Name = "Membership Type")]
    public byte MembershipTypeId { get; set; }

    // it allows us to navigate from 1 type to another
    public MembershipType MembershipType { get; set; }
}

这是我的 DbContext 类。

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    public DbSet<Customer> Customers { get; set; }
    public DbSet<MembershipType> MembershipTypes { get; set; }
}

现在,为您编写 API 操作将变得很容易。

public IEnumerable<Customer> GetCustomers()
{
}

因为我们返回的是对象列表。此操作将根据约定响应于

// Get                              /api/customers

因此,这是 ASP.Net Web API 内置的约定。现在在这个操作中,我们将使用我们的上下文从数据库中获取客户。

namespace MyAPI.Controllers.Api
{
    public class CustomersController : ApiController
    {
        private readonly ApplicationDbContext _context;

        public CustomersController()
        {
            _context = new ApplicationDbContext();
        }

        // GET /api/customers
        public IEnumerable<Customer> GetCustomers()
        {
            return _context.Customers.ToList();
        }
    }
}

如果找不到资源,我们返回 not found httpresponse,否则我们返回对象。

// POST /api/customers
[HttpPost]
public Customer CreateCustomer(Customer customer)
{
}

因此,这个 customer 参数将在请求正文中,ASP.NET Web API 框架将自动初始化它。现在,我们应该用 HttpPost 标记此操作,因为我们正在创建资源。如果我们遵循命名约定,我们甚至不需要在操作上放置操作动词。

// POST /api/customers
public Customer PostCustomer(Customer customer)
{
}

但最初这不是一个好方法。假设您将来重构代码并重命名您的操作,您的代码肯定会中断。因此,始终建议在操作顶部使用 Http 动词。

现在,让我们使用 api 操作的 post 请求将 customer 对象插入数据库。

// POST /api/customers
[HttpPost]
public Customer CreateCustomer(Customer customer)
{
    if (!ModelState.IsValid)
    {
        throw new HttpResponseException(HttpStatusCode.BadRequest);
    }

    _context.Customers.Add(customer);
    _context.SaveChanges();

    return customer;
}

另一个操作,假设我们要更新记录。

// PUT /api/customers/1
[HttpPut]
public void UpdateCustomer(int id, Customer customer)
{
    if (!ModelState.IsValid)
    {
        throw new HttpResponseException(HttpStatusCode.BadRequest);
    }

    var custmr = _context.Customers.SingleOrDefault(x => x.Id == id);

    // Might be user sends invalid id.
    if (custmr == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    custmr.Birthdate = customer.Birthdate;
    custmr.IsSubscribedToNewsLetter = customer.IsSubscribedToNewsLetter;
    custmr.Name = customer.Name;
    custmr.MembershipTypeId = customer.MembershipTypeId;

    _context.SaveChanges();
}

在这种情况下,人们对于返回 void 还是 object 意见不一。如果我们进行 API 的 delete 操作,

// Delete /api/customers/1
[HttpDelete]
public void DeleteCustomer(int id)
{
    var custmr = _context.Customers.SingleOrDefault(x => x.Id == id);

    // Might be user sends invalid id.
    if (custmr == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    _context.Customers.Remove(custmr);
    // Now the object is marked as removed in memory

    // Now it is done
    _context.SaveChanges();
}

这就是我们使用 RESTful 约定来构建 API 的方式。

测试 API

如果我们运行应用程序并请求 API 控制器,我们可以看到 XML 格式的客户列表。

<a href="https://:53212/api/customers">https://:53212/api/customers</a>

因此,ASP.NET Web API 具有我们称之为媒体格式化器的功能。因此,我们从操作中返回的内容(在我们的例子中,客户列表将根据客户端的要求进行格式化)让我解释一下我的意思和我想说的。

检查上面的屏幕截图中的浏览器并刷新页面,您将在此处看到客户请求。

这里看 Content Type,如果我们不在请求中设置 content type 头,服务器将默认假定为 application/xml。

注意: General 是请求标头,Response Headers 是我们的响应标头。如您在 Request Header 中所见,我们没有任何 content type。现在让我向您展示测试 API 并以 JSON 格式获取数据的最佳方法。

在您的机器上安装 Postman 桌面应用程序。复制浏览器链接(包含 localhost 端口号)并将其粘贴到 Postman 中。

在这里,我们将请求的 URL 与 localhost 一起输入,然后响应就会以 JSON 格式返回。

如果我们点击 Header 选项卡,在这里我们将看到我们的请求头 content type 是 application/json。

大多数时候我们会使用 JSON,因为它对 JavaScript 代码来说是原生的,并且比 XML 快得多。XML 媒体格式主要用于政府等大型组织,因为它们落后于现代技术。JSON 格式更轻量级,因为它不像 XML 那样有冗余的打开和关闭标签。

一点困惑

有时,当您处理 API 或 Postman 时,大多数人会因为从未用过 Postman 而对 Postman 的界面感到困惑。它很简单,请记住,

因此,如果您正在处理请求并尝试更改一些请求信息,请专注于请求标头;如果您正在监控响应,则在响应标头中查看结果。它们看起来相似,有时向下滚动时,请求标头会消失。所以不要对这些事情感到困惑。

现在,让我们通过 API Post Action 将客户插入数据库。

从下拉列表中选择 Post 请求,然后在 request body 选项卡中。您可以通过点击 form-data 上的键值对插入客户。但大多数时候我们使用 JSON 格式。所以点击 raw,然后在这里写 JSON。

不要在 JSON 中放入 Id 属性,因为这是一个硬性规定,当我们向数据库插入数据时,ID 会在服务器上自动生成。

现在点击 Send 按钮,这里我已经成功地通过 Post API 操作插入了数据并获得了响应。

这里上面的块是请求块,下面的块是响应块。您可能会遇到类似这样的错误。

如果您阅读错误消息“此资源的请求实体介质类型‘text/plain’不受支持”。这就是错误消息。

现在要解决这个错误。点击 Header 选项卡,并为 content-type 添加值(‘application/json’)。

值已添加。查看请求的状态代码是 200 OK,我们可以在下方看到响应正文。

现在,让我们更新客户实体。

看,它已经被更新了。

现在让我们类似地删除一条记录,只需在下拉列表中选择 Delete,然后在 URL 中用斜杠指定 ID,然后点击 Send 按钮。它将自动删除。

最佳实践

最佳实践是,当您构建 API 并在应用程序中使用它之前。最好通过 Postman 测试 API。

数据传输对象 (DTO)

现在我们已经构建了这个 API,但这个设计存在一些问题。我们的 API 接收或返回 Customer 对象。您可能在想这种方法有什么问题?实际上,Customer 对象是我们应用程序的领域模型的一部分。它被认为是实现细节,随着我们在应用程序中实现新功能而可能频繁更改,这些更改可能会影响依赖于 Customer 对象的现有客户端,即如果我们重命名或删除属性,这可能会影响依赖于该属性的客户端。因此,我们基本上使 API 的合同尽可能稳定。在这里,我们使用 DTO。

DTO 是一个纯数据结构,用于将数据从客户端传输到服务器或反之亦然,这就是我们称之为数据传输对象的原因。通过创建 DTO,我们减少了在重构领域模型时 API 破坏的可能性。当然,我们应该记住,更改这些 DTO 可能会付出高昂的代价。因此,最重要的事情是我们 API 不应该接收或返回 Customer 模型类对象。

使用域对象在这里的 API 中的另一个问题是我们正在为我们的应用程序打开安全漏洞。黑客可以轻松地在 JSON 中传递额外数据,它们将被映射到我们的域对象。如果其中一个属性不应该被更新,黑客可以轻松绕过它,但如果我们使用 DTO,我们可以简单地排除可以更新的属性。因此,在您的项目中添加一个名为 DTOs 的新文件夹,并添加 CustomerDTO 类,将 Customer 域模型类的所有属性及其数据注释属性复制到 CustomerDTO 中。现在,从 CustomerDTO 中删除导航属性,因为它正在创建对 MembershipType 域模型类的依赖。

namespace MyAPI.DTOs
{
    public class CustomerDTO
    {
        public int Id { get; set; }

        [Required]
        [StringLength(255)]

        public string Name { get; set; }

        public bool IsSubscribedToNewsLetter { get; set; }

        public DateTime? Birthdate { get; set; }

        public byte MembershipTypeId { get; set; }
    }
}

现在下一件事是我们希望在 API 中使用 CustomerDTO 而不是 Customer 域类对象。因此,为了减少大量代码来逐个绑定属性,我们使用 Automapper。

Automapper

从程序包管理器控制台安装 automapper 程序包。

PM > Install-Package Automapper -version:4.1

现在,在 App_Start 中添加一个新类(MappingProfile.cs)并继承自 Profile。

using AutoMapper;

namespace MyAPI.App_Start
{
    public class MappingProfile : Profile
    {
    }
}

现在创建构造函数并添加两个类型之间的映射配置。

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        Mapper.CreateMap<Customer, CustomerDTO>();
        Mapper.CreateMap<CustomerDTO, Customer>();
    }
}

CreateMap 方法的第一个参数是源,第二个参数是目标。当我们使用 CreateMap 方法时,automapper 会自动使用反射来扫描这些类型。它查找它们的属性并根据它们的名称进行映射。这就是我们称 automapper 为(基于约定的映射工具),因为它使用属性名称作为映射对象的约定。因此,这里是映射配置文件,现在我们需要在应用程序启动时加载它。

现在打开 Global.asax.cs 文件并编写 Application_Start() 的代码。

protected void Application_Start()
{
    Mapper.Initialize(c => c.AddProfile<MappingProfile>());
    GlobalConfiguration.Configure(WebApiConfig.Register);
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
}

现在打开 API 的 CustomerController。让我们从这里开始更改。

// GET /api/customers
public IEnumerable<CustomerDTO> GetCustomers()
{
    return _context.Customers.ToList();
}

现在我们想返回 CustomerDTO 类型而不是 Customer 对象。现在我们需要将这个 Customer 对象映射到 CustomerDTO。所以我们使用 linq 扩展方法。

// GET /api/customers
public IEnumerable<CustomerDTO> GetCustomers()
{
    return _context.Customers.ToList()
    .Select(Mapper.Map<Customer, CustomerDTO>);
}

Mapper.Map<Customer, CustomerDTO>

此委托执行映射。正如我们所见,我们没有放置函数调用的小括号,因为我们没有调用函数。我们只是在这里引用它。映射函数在执行时自动调用。

// GET /api/customers/1
public Customer GetCustomer(int id)
{
    var customer = _context.Customers.SingleOrDefault(x => x.Id == id);

    // This is part of the RESTful Convention
    if (customer == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    return customer;
}

在此函数中,因为我们返回一个对象,所以我们不使用 Select 扩展方法。这里我们直接使用 mapper。

// GET /api/customers/1
public CustomerDTO GetCustomer(int id)
{
    var customer = _context.Customers.SingleOrDefault(x => x.Id == id);

    // This is part of the RESTful Convention
    if (customer == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    return Mapper.Map<Customer, CustomerDTO>(customer);
}

现在来到下一个 CreateCustomer 操作,

// POST /api/customers
[HttpPost]
public CustomerDTO CreateCustomer(CustomerDTO customerDto)
{
    if (!ModelState.IsValid)
    {
        throw new HttpResponseException(HttpStatusCode.BadRequest);
    }

    var customer = Mapper.Map<CustomerDTO, Customer>(customerDto);
    _context.Customers.Add(customer);
    _context.SaveChanges();

    // Here we make our CustomerDto completely fill, because after
    // adding customer to Customer table (id is assigned to it)
    // & Now we assigned this id to customerDto
    customerDto.Id = customer.Id;

    return customerDto;
}

这就是我们使用 DTO 和 Automapper 的方式。

现在,让我们更新 UpdateCustomer 操作 API 方法。

// PUT /api/customers/1
[HttpPut]
public void UpdateCustomer(int id, CustomerDTO customerDto)
{
    if (!ModelState.IsValid)
    {
        throw new HttpResponseException(HttpStatusCode.BadRequest);
    }

    var custmr = _context.Customers.SingleOrDefault(x => x.Id == id);

    // Might be user sends invalid id.
    if (custmr == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    Mapper.Map<CustomerDTO, Customer>(customerDto, custmr);
    //custmr.Birthdate = customerDto.Birthdate;
    //custmr.IsSubscribedToNewsLetter = customerDto.IsSubscribedToNewsLetter;
    //custmr.Name = customerDto.Name;
    //custmr.MembershipTypeId = customerDto.MembershipTypeId;

    _context.SaveChanges();
}

这就是我们如何使用 Automapper 映射对象。现在 automapper 有一些功能在某些情况下可能会很有用,即如果您的属性名称不匹配,您可以覆盖默认约定,或者您可以从映射中排除某些属性,或者您可能想创建自定义映射类。如果您想了解更多信息,可以从 Automapper 文档中学习。

IHttpActionResult

好的,看看这个 CreateCustomer 操作方法。

// POST /api/customers
[HttpPost]
public CustomerDTO CreateCustomer(CustomerDTO customerDto)
{
    if (!ModelState.IsValid)
    {
        throw new HttpResponseException(HttpStatusCode.BadRequest);
    }

    var customer = Mapper.Map<CustomerDTO, Customer>(customerDto);
    _context.Customers.Add(customer);
    _context.SaveChanges();

    // Here we make our CustomerDto completely fill, because after
    // adding customerDto to Customer table (id is assigned to it)
    // & Now we assigned this id to customerDto
    customerDto.Id = customer.Id;

    return customerDto;
}

在这里,我们只是返回 CustomerDto,最终会产生如下响应。

但在 RESTful 约定中,当我们创建一个资源时,状态代码应该是 201 或 created。所以我们需要更多地控制从操作返回的响应,为了实现这一点,我们返回 IHttpActionResult 而不是 CustomerDto。这个接口与 MVC 框架中的 ActionResult 类似,它由几个不同的类实现,并且在这里 ApiController 中,我们有一堆方法来创建一个实现 IHttpActionResult 接口的类实例。

现在,如果模型无效,而不是抛出异常,请使用辅助方法 BadRequest()。

// POST /api/customers
[HttpPost]
public IHttpActionResult CreateCustomer(CustomerDTO customerDto)
{
    if (!ModelState.IsValid)
        return BadRequest();

    var customer = Mapper.Map<CustomerDTO, Customer>(customerDto);
    _context.Customers.Add(customer);
    _context.SaveChanges();

    // Here we make our CustomerDto completely fill, because after
    // adding customerDto to Customer table (id is assigned to it)
    // & Now we assigned this id to customerDto
    customerDto.Id = customer.Id;

    return Created(new Uri(Request.RequestUri + "/" + customer.Id),
        customerDto);
}

正如我们所见,如果 ModelState 无效,它将返回 BadRequest;如果 customer 已添加,我们将返回带有此资源 ID 的 Uri,并使用 Created() 以及最终创建的新对象。

看,我们创建了一个新资源,现在状态是 201 Created。如果我们看 location 选项卡,

那是新创建客户的 URI。这是 RESTful 约定的一部分。因此,在 Web API 中,我们倾向于使用 IHttpActionResult 作为操作的返回类型。

现在,让我们对这个 Web API 的其余操作进行更改。这是我们 API 的完整代码。

public class CustomersController : ApiController
{
    private readonly ApplicationDbContext _context;

    public CustomersController()
    {
        _context = new ApplicationDbContext();
    }

    // GET /api/customers
    public IHttpActionResult GetCustomers()
    {
        return Ok(_context.Customers.ToList()
            .Select(Mapper.Map<Customer, CustomerDTO>));
    }

    // GET /api/customers/1
    public IHttpActionResult GetCustomer(int id)
    {
        var customer = _context.Customers.SingleOrDefault(x => x.Id == id);

        // This is part of the RESTful Convention
        if (customer == null)
            return NotFound();

        return Ok(Mapper.Map<Customer, CustomerDTO>(customer));
    }

    // POST /api/customers
    [HttpPost]
    public IHttpActionResult CreateCustomer(CustomerDTO customerDto)
    {
        if (!ModelState.IsValid)
            return BadRequest();

        var customer = Mapper.Map<CustomerDTO, Customer>(customerDto);
        _context.Customers.Add(customer);
        _context.SaveChanges();

        // Here we make our CustomerDto completely fill, because after
        // adding customerDto to Customer table (id is assigned to it)
        // & Now we assigned this id to customerDto
        customerDto.Id = customer.Id;

        return Created(new Uri(Request.RequestUri + "/" + customer.Id),
            customerDto);
    }
    
    // PUT /api/customers/1
    [HttpPut]
    public IHttpActionResult UpdateCustomer(int id, CustomerDTO customerDto)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest();
        }
 
        var custmr = _context.Customers.SingleOrDefault(x => x.Id == id);
 
        // Might be user sends invalid id.
        if (custmr == null)
        {
            return NotFound();
        }
 
        Mapper.Map<customerdto, customer="">(customerDto, custmr);
 
        _context.SaveChanges();
        return Ok(custmr);
    }
    
    // Delete /api/customers/1
    [HttpDelete]
    public IHttpActionResult DeleteCustomer(int id)
    {
        var custmr = _context.Customers.SingleOrDefault(x => x.Id == id);
 
        // Might be user sends invalid id.
        if (custmr == null)
        {
            return NotFound();
        }
 
        _context.Customers.Remove(custmr);
        // Now the object is marked as removed in memory
 
        // Now it is done
        _context.SaveChanges();
 
        return Ok(custmr);
    }
}</customerdto,>

我在这里提一下这一点,正如您所见,UpdateCustomer 中有两个参数。如果参数是原始类型,例如 int id,那么我们将这个参数放在路由 URL 中或与查询字符串一起。如果我们想初始化我们的复杂类型,例如我们这里有 CustomerDTO,那么我们将始终在 Postman 中从请求正文中初始化它。所以不要对此感到困惑。

现在,让我们通过 Postman 更新和删除 JSON 对象。如果您关注 UpdateCustomer 操作参数,这里我们有 1st 参数是记录 ID,2nd 参数是 Customer 域模型类对象。

看,它与请求标头中的 ID 一起工作,因为我们的实体是完整的。

但是如果我们不提供请求标头中的 ID,我们将收到错误。

并且 exceptionMessage 是“对象的键信息的一部分属性‘Id’无法修改。”实际上,这个异常发生在这一行,

Mapper.Map<CustomerDTO, Customer>(customerDto, custmr);

因为 customerDto 不包含 ID,但 custmr(这是 Customer 模型类的对象变量)有一个 Id 属性。在这里,我们需要告诉 Automapper 在映射到 customerDto 到 custmr 时忽略 Id。所以,回到 Mapping Profile。

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        Mapper.CreateMap<Customer, CustomerDTO>();
        Mapper.CreateMap<CustomerDTO, Customer>()
            .ForMember(c => c.Id, opt => opt.Ignore());
    }
}

看,现在它正在工作。

消费 Web API

在正确测试 API 后,现在是时候使用 API 了。我最想在这里提到的一点是。现在我们的 API 已经准备好了,您可以在任何客户端中使用它。在这里,我们为您提供了一个使用 Visual Studio 应用程序的示例。如果您与我们一起构建了这个 API,那么您可以使用 JQuery Ajax 在 PHP、Python、任何框架应用程序中使用它。现在我们将使用 JQuery 调用我们的 API。看这个屏幕,这里我展示了一些客户。

现在,当用户点击删除按钮时,我们想要删除这一行。因此,如果您了解我们如何呈现项目,那么显然是使用了 foreach 循环。因此,在 Delete 锚标记点击时,我们需要记录 ID 来将此 ID 传递给 Web API Delete 操作,并在成功时删除该行。

@foreach (var customer in Model)
{
    <tr>
        <td>@Html.ActionLink(customer.Name, "Edit", "Customers", new { id = customer.Id }, null)</td>
        @if (customer.Birthdate != null)
        {
            <td>
                @customer.Birthdate
            </td>
        }
        else
        {
            <td>Not Available</td>
        }
        <td>
            <button data-customer-id="@customer.Id" class="btn btn-link js-delete">Delete</button>
        </td>
    </tr>
}

这是 HTML。现在我想通过 ajax 调用我的 API。

@section scripts{
    <script>
        $(document).ready(function() {
            $('#customers .js-delete').on('click',
                function () {
                    var button = $(this);
                    if (confirm('Are you sure you want to delete this client?')) {
                        $.ajax({
                            url: '/api/customers/' + button.attr('data-customer-id'),
                            method: 'DELETE',
                            success: function() {
                                button.parents('tr').remove();
                            }
                        })
                    }
                });
        });
    </script>
}

这就是我们使用 ajax 和 api 的方式。现在您可能会想,在这里我只是将 ID 传递给 customers API 并定位 Delete 操作,然后在成功事件中直接删除该行。您可能会以不同的方式考虑这种情况,因为每个开发人员都有自己的口味。

您可能会想,首先我们使用 Delete 方法删除记录,然后从 Web API 的 GetCustomers() 方法获取所有记录,然后通过 JQuery 的 each 循环渲染所有这些项。但这种情况会花费太多时间和精力。看,当我点击 Delete 锚标记并在浏览器中检查结果时,状态是 200 ok。这意味着一切正常,我们的代码(Delete 操作)正如我们所期望的那样工作。因此,我们不再需要再次验证数据库中有多少项,并通过 each 循环来渲染它们。

让您的场景简单化,并像我在这里一样删除记录。

结论

因此,结论是,当您使用 Web API 时,始终遵循 RESTful 约定。Web API 比基于 SOAP 的 Web 服务轻量得多。它们是跨平台的。RESTful Http 动词在插入、删除、更新、获取记录方面对应用程序大有帮助。这里我们看到了如何使用 Postman,它有两个不同的窗格,如请求标头和响应标头。大多数时候,开发人员会对如何使用 Web API 操作与 JQuery Ajax 感到困惑。这里我们也使用了 API 操作。

 

© . All rights reserved.