购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(1)--后端

简介: 原文:购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(1)--后端  chsakell分享了前端使用AngularJS,后端使用ASP.NET Web API的购物车案例,非常精彩,这里这里记录下对此项目的理解。
原文: 购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(1)--后端

 


chsakell分享了前端使用AngularJS,后端使用ASP.NET Web API的购物车案例,非常精彩,这里这里记录下对此项目的理解。


文章:
http://chsakell.com/2015/01/31/angularjs-feat-web-api/
http://chsakell.com/2015/03/07/angularjs-feat-web-api-enable-session-state/

 

源码:
https://github.com/chsakell/webapiangularjssecurity


本系列共三篇,本篇是第一篇。


购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(1)--后端
购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(2)--前端,以及前后端Session
购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(3)--Idetity,OWIN前后端验证

 

■ 配置EF

 

首先搞清模型之间的关系:

 

public class Gadget
{
    public int GadgetID{get;set;}
    ...
    
    public int CategoryID{get;set;}
    public Category Category{get;set;}
}

public class Category
{
    public int CategoryID{get;set;}
    ...
    public List<Gadget> Gadgets{get;set;}
}


public class Order
{
    public int OrderID{get;set;}
    ...
    public List<Gadget> Gadgets{get;set;}
}

public class GadgetOrder
{
    public int GadgetOrderID{get;set;}
    
    public int OrderID{get;set;}
    public Order Order{get;set;}
    
    public int GadgetID{get;set;}
    public Gadget Gadget{get;set;}
}

 

以上,Category和Gadget是1对多的关系,GadgetOrder是Order和Gadget的中间表。

 

接着需要通过EF Fluent API来配置领域,需要实现EntityTypeConfiguration<TModel>这个基类。比如:

 

public class OrderConfiguration : EntityTypeConfiguration<Order>
{
    public OrderConfiguration()
    {
        Ignore(o => o.Gadgets);
    }
}

 

然后就配置上下文,继承DbContext这个基类。

 

public class StoreContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        ...
        modelBuilder.Configurations.Add(new OrderConfiguration());
    }
    
    public DbSet<Order> Orders{get;set;}
    ...
}

 

我们还希望在生成数据库的时候生成一些种子数据,需要继承DropCreateDatabaseIfModelChanges<TContext>这个泛型类。

 

public class StoreInitializer : DropCreateDatabaseIfModelChanges<StoreContext>
{
    protected override void Seed(StoreContext context)
    {
        try
        {
            GetCategoreis().ForEach(c => context.Categories.Add(c));
            ...
        }
        catch(Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    }
    
    private static List<Category> GetCategories()
    {
        ...
    }
}

 

如何调用数据库种子数据的类StoreInitializer呢?有一种方法使在项目全局文件中配置。(还有一种方法使在DbContext的构造函数中配置,还有一种在数据库迁移文件中配置,etc.)

 

void Application_Start(object sender, EventArgs e)
{
    Database.SetInitializer(new StoreIntializer());
}

 

最后,关于EF的配置部分,需要在Web.config中配置,大致如下:

 

<connectionStrings>
    <add name="ProductServiceContext" connectionString="Data Source=.;User=someusername;Password=somepassword;Initial Catalog=MyProductService;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>

 

■ CategoriesController

 

先俯瞰。

 

public class CategoriesController : ApiController
{
    private StoreContext db = new SotoreContext();
    
    ...
    
    private bool CategoryExists(int id)
    {
        return db.Categories.Count(g => g.CategoryID=id) > 0;
    }
    
    protected override void Dispose(boo disposing)
    {
        if(disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing);
    }
}

 

再细节。

 

/GET api/Categories
public IQueryable<Category> GetCategories()
{
    return db.Categories;
}

//GET api/Categories/5
[ResponseType(typeof(Category))]
public async Task<IHttpActionResult> GetCategory(int id)
{
    Category category = await db.Categories.FindAsync(id);
    if(category == null)
    {
        return NotFound();
    }
    return Ok(category);
}

//put api/Categories/5
[ResponseType(typeof(void))]
public async Task<IHttpActionResult> PutCategory(int id, Category category)
{
    if(!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    
    if(id != category.CategoryID)
    {
        return BadRequest();
    }
    
    db.Entry(category).State = EntityState.Modified;
    
    try
    {
        await db.SavheChangesAsync();
    }
    catch(DbUpdateConcurrencyException)
    {
        if(!CategoryExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }
    return StatusCode(HttpStatusCOde.NoContet);
}

//post api/Categories
[ResponseType(typeof(Category))]
public async Task<IHttpActionResult> PostCategory(Category category)
{
    if(!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    
    db.Categories.Add(category);
    await db.SaveChangesAsync();
    
    //返回到指定的路由
    return CreatedAtRoute("DefaultApi", new {id = category.CategoryID}, category);
}

//delete api/Categoreis/5
[ResponseType(typeof(Category))]
public async Task<IHttpActionResult> DeleteCategory(int id)
{
    Category category = await db.Categories.FindAsync(id);
    if(category == null)
    {
        return NotFound();
    }
    
    db.Categories.Remove(category);
    await db.SaveChangesAsync();
    return Ok(category);
}

 

■ GadgetsController

 

先俯瞰。

 

public class GadgetsController : ApiController
{
    private StoreContext db = new StoreContext();
    
    protected override void Dispose(bool disposing)
    {
        if(disposing)
        {
            db.Dispose();
        }
        
        base.Dispose(disposing);
    }
    
    private bool GadgetExists(int id)
    {
        return db.Gadgets.Count(g => g.GadgetID == ID) > 0;
    }
}

 

再细节。

 

//get api/Gadgets
public IQueryable<Gadget> GetGadgets()
{
    return db.Gadgets;
}

//get api/Gadgets/5
[ResponseType(typeof(Gadgets))]
public async Task<IHttpActionResult> GetGadget(int id)
{
    Gadget gadget = await db.Gadgets.FindAsync(id);
    if(gadget == null)
    {
        return NotFound();
    }
    return Ok(gadget);
}

//put api/Gadgets/5
[ResponseType(typeof(void))]
public async Task<IHttpActionResult> PutGadget(int id, Gadget gadget)
{
    if(!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    
    if(d != gadget.GadgetID)
    {
        return BadRequest();
    }
    
    db.Entry(gadget).State = EntityState.Modified;
    
    try
    {
        await db.SaveChangesAsync();
    }
    catch(DbUpdateConcurrencyException)
    {
        if(!GadgetExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }
}

//post api/Gadgets
[ResposneType(typeof(Gadget))]
public async Task<IHttpActionResult> PostGadget(Gadget gadget)
{
    if(!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    db.Gadgets.Add(gadget);
    await db.SaveChangesAsync();
    
    return CreatedAtRoute("DefaultApi", new {id=gadget.GadgetID}, gadget)
}

//delete api/Gadgets/5
[ResponseType(typeof(Gadget))]
public async Task<IHttpActionResult> DeleteGadget(int id)
{
    Gadget gadget = await db.Gadgets.FindAsync(id);
    if(gadget == null)
    {   
          return NotFound();
    }
    db.Gadgets.Remove(gadget);
    await db.SaveChangesAsync();
    return Ok(gadget);
}

 

■ OrdersController

 

firstly overview.

 

public class OrdersController : ApiController
{
    private StoreContext db = new StoreContext();
    
    protected override void Dispose(bool dispoing)
    {
        if(disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing);
    }
    
    private bool OrderExists(int id)
    {
        return db.Orders.Count(g => g.OrderID == id) > 0;
    }
}

 

then details.

 

// get api/Orders
public IQueryable<Order> GetOrders()
{
    return db.Orders;
}

//get api/Orders/5
[ResponseType(typeof(Order))]
public async Task<IHttpActionResult> GetOrder(int id)
{
    Order order = await db.Orders.FindAsync(id);
    if(order == null)
    {
        return NotFound();
    }
    return Ok(order);
}

//put api/Orders/5
[ResponseType(typeof(void))]
public async Task<IHttpActionResult> PutOrder(int id, Order order)
{
    if(!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    
    if(id != order.OrderID)
    {
        return BadRequest();
    }
    
    db.Entry(order).State = EntityState.Modified;
    
    try
    {
        await db.SaveChangesAsync();
    }
    catch(DbUpdateConcurrecyException)
    {
        if(!OrderExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }
    return StatusCode(HttpStatusCOde.NoContet);
}

//post api/Orders
[RequestType(typeof(Order))]
public async Task<IHttpActionResult> PostOrder(Order order)
{
    if(!ModelState.IsValid)
    {
        reuturn BadRequest(ModelState);
    }
    try
    {
        db.Orders.Add(order);
        foreach(Gadget gadget in order.Gadgets)
        {
            db.GadgetOrders.Add(new GadgetOrder{
                OrderID = order.OrderID,
                GadgetID = gadget.GadgetID
            })
        }
        
        await db.SaveChangesAsync();
    }
    catch(Exception ex)
    {
        return BadRequest(ex.Message);
    }
    return CreatedAtRoutne("Default", new {controller = "Home", action="viewOrder", id = order.orderID}, order);
}


//delete api/Orders/5
[ResponseType(typeof(Order))]
public async Task<IHttpActionResult> DeleteOrder(int id)
{
    Order order = await db.Orders.FindAsync(id);
    if(order == null)
    {
        return NotFound();
    }
    
    db.Orders.Remoe(order);
    await db.SaveChangesAsync();
    return Ok(order);
}

 

待续~~

 

目录
相关文章
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
195 4
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
729 3
|
存储 安全 关系型数据库
后端技术:构建高效稳定的现代Web应用
【10月更文挑战第5天】后端技术:构建高效稳定的现代Web应用
645 1
|
7月前
|
人工智能 搜索推荐 IDE
突破网页数据集获取难题:Web Unlocker API 助力 AI 训练与微调数据集全方位解决方案
本文介绍了Web Unlocker API、Web-Scraper和SERP API三大工具,助力解决AI训练与微调数据集获取难题。Web Unlocker API通过智能代理和CAPTCHA绕过技术,高效解锁高防护网站数据;Web-Scraper支持动态内容加载,精准抓取复杂网页信息;SERP API专注搜索引擎结果页数据抓取,适用于SEO分析与市场研究。这些工具大幅降低数据获取成本,提供合规保障,特别适合中小企业使用。粉丝专属体验入口提供2刀额度,助您轻松上手!
387 2
|
8月前
|
前端开发 Cloud Native Java
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
|
10月前
|
人工智能 前端开发 API
Gemini Coder:基于 Google Gemini API 的开源 Web 应用生成工具,支持实时编辑和预览
Gemini Coder 是一款基于 Google Gemini API 的 AI 应用生成工具,支持通过文本描述快速生成代码,并提供实时代码编辑和预览功能,简化开发流程。
673 38
Gemini Coder:基于 Google Gemini API 的开源 Web 应用生成工具,支持实时编辑和预览
|
8月前
|
XML JSON API
Understanding RESTful API and Web Services: Key Differences and Use Cases
在现代软件开发中,RESTful API和Web服务均用于实现系统间通信,但各有特点。RESTful API遵循REST原则,主要使用HTTP/HTTPS协议,数据格式多为JSON或XML,适用于无状态通信;而Web服务包括SOAP和REST,常用于基于网络的API,采用标准化方法如WSDL或OpenAPI。理解两者区别有助于选择适合应用需求的解决方案,构建高效、可扩展的应用程序。
|
9月前
|
JSON 前端开发 API
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
490 5
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
|
8月前
|
机器学习/深度学习 开发框架 API
Python 高级编程与实战:深入理解 Web 开发与 API 设计
在前几篇文章中,我们探讨了 Python 的基础语法、面向对象编程、函数式编程、元编程、性能优化、调试技巧以及数据科学和机器学习。本文将深入探讨 Python 在 Web 开发和 API 设计中的应用,并通过实战项目帮助你掌握这些技术。
|
11月前
|
Kubernetes 安全 Devops
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
277 10
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙

热门文章

最新文章