ASP.NET 5 Web API RESTful CRUDs 和 Windows 10 本机应用程序






4.89/5 (20投票s)
本文将解释如何创建功能齐全的独立 ASP.NET 5 Web API,该 API 可供 Windows 10 的本机通用 Windows 运行时应用程序使用。
引言和背景
自从成为 Windows 10 Insider 以来,我一直在开发 Windows 10 应用程序,但 ASP.NET 却被搁置了很长时间,可能长达两年。ASP.NET 也收到了很多更新,所以我认为现在是时候开始研究 ASP.NET 了。ASP.NET 5 有很多很棒的功能
- 快速启动。
- 即时编译。
实际上,现在编译在你键入代码时,或者在你更改调试设置时(调试设置也要求你重新编译项目;有人可能会说“构建”)进行。 - 更短的内存基准。
- 最重要的是,XML 正在退出,JSON 正在进入框架。大多数设置现在都使用 JSON!
在本文中,我将创建一个独立的 Web API,不包含 HTML 页面,因为我不是在展示如何为你的网站创建一个小型 API,而是为你的项目创建一个功能齐全的 API(独立 API),该项目需要托管。这两者之间有一个常见的区别。
ASP.NET Web 应用程序 + Web API |
独立 Web API (无 Web 应用) |
---|---|
如果你希望为你的客户端提供两种风格,这很好。这将允许你使用 HTML 应用程序和用于客户端的 API;移动设备和软件应用程序。 |
更强大的框架,作为独立应用程序将允许你的开发人员只专注于一个部分,即 HTTP RESTful 客户端。 |
它们都托管在同一服务器、同一托管环境、同一 URL 上。 |
此选项不包括应用程序,你将只托管 API。你可以将其托管在任何地方,甚至在你自己的网络中,或将其发送给客户端以在其网络上运行! |
跨平台数据共享以及用户界面。 |
Web API 不适用于用户界面。它们是简单的基于命令的服务。 |
成本翻倍,开发人员必须维护 Web 应用程序部分和 Web API 部分的应用程序用户界面。 |
用户界面部分已移除,因此你只需专注于应用程序的逻辑。 |
表 1:ASP.NET Web 应用程序 + Web API 与单独的 ASP.NET Web API 之间的区别。
现在,让我问你几件事。你是否
- 真的需要坚持旧的 Web 编程,其中你必须维护应用程序的跨浏览器外观和感觉?IE 仍然是噩梦!
- 需要你的客户端在其机器上安装离线应用程序,以便他们可以使用漂亮的按钮运行和执行功能,并且你无需过多担心安全性?
- 想要削减你的财务预算和团队规模?
如果你的回答是肯定的,那么相信我。ASP.NET MVC 应用程序不是你所寻找的。直接创建一个小型 Web API 并将其用于你的目的。它仍然基于 ASP.NET MVC,因此你可以将你对 ASP.NET MVC 的技术知识应用于 ASP.NET Web API。Web API 带来的一些好处是
- 无需担心用户界面。你为客户端构建用户界面。大多数是简单的控制台应用程序。但 Windows Presentation Foundation、Windows Forms 也可以用于消费这些 API。这意味着,有了这些框架,图形支持会更好。
- 跨平台支持。Web API 可以被任何设备、平台、操作系统、位置和网络消费。因此,它避免了你为每个平台等编写单独的环境和服务。它托管在同一个位置,其余由网络保证。
- 与其他 Web 服务和网站相比,内存基准更小。尽管你可以编写 Web 应用程序来请求数据。但是,Web API 可以让你编写本机应用程序(性能良好!),同时获得本机体验。
另一方面,Windows 10 是一个使用相同旧 Windows 运行时技术的新操作系统。Windows 运行时允许你编写编译成本机库的应用程序,为你提供比任何其他 .NET 应用程序更好的性能。Windows 运行时是你的通用应用程序平台的核心。
在本文中,我将为每个项目创建两个项目。
- 一个 ASP.NET 5 的 Web API(独立的,不要与 Web API + Web 应用程序模板混淆)。
这将作为我们要发出请求的 API,以获取应用程序逻辑的数据。 - 一个 Windows 10 本机通用应用程序
这将是我们服务器的客户端。请注意,我们只会在这个 Windows 10 应用程序中创建用户界面。外观和感觉将遵循本机约定和主题。其余部分将在运行时由 API 捕获。
理解 ASP.NET 5 Web API 和 Windows 10
在我们开始之前,最好先了解 ASP.NET 5 在其 API 中为我们提供了什么,以及 Windows 10 将为我们提供什么。我们将分别剖析它们的几件事,并分步学习。
ASP.NET 5 Web API
ASP.NET 5 是 Microsoft 推出的 ASP.NET 新版本。Web API 已经为 ASP.NET 引入了很长时间,我们很清楚什么是 RESTful API。ASP.NET 的 Web API 允许我们使用 HTTP 动词与 API 通信。由于 ASP.NET 的 Web API 基于大部分 MVC 模式(ASP.NET MVC),你可以为每种类型定义动作方法。属性用于定位一个动作。
// HttpGet attribute notifies that this should be run if request has GET method [HttpGet] public List<string> Get() { return _list; // Suppose _list is of type List<string> with some data }
这样我们就可以为我们的客户端生成响应。另请注意,与默认 MVC 不同,我们不返回允许我们返回 View
(带或不带 Model
)的 ActionResult
。相反,我们返回本机对象,这些对象以 JSON 或 XML 格式返回。
就我个人而言,我建议使用 JSON 格式而不是 XML,因为它体积小。你应该考虑减少流量使用,体积过大的字节可能会扼杀网络或花费大量时间。这在你的应用程序中是不应该发生的。
其余代码只是 C# 和 MVC 模式的基础。我们创建一个模型,添加一些逻辑来检索数据,然后使用我们的 API 返回(或操作)数据。
Windows 10 — 通用应用程序
是时候介绍 Windows 10 了。Windows 10 只是我在标题中使用的花哨术语。实际上,我指的是使用 Windows 运行时来创建客户端。我不会使用 .NET 应用程序,如 Windows Presentation Foundation 或 Windows Forms。而是使用基于 Windows 运行时的本机通用应用程序。
Windows 运行时拥有许多有用的库供我们进行网络通信。Windows.Web.Http
命名空间就是其中之一。它在运行时应用程序中向我们公开了 HttpClient
对象。它确实类似于 .NET 框架的 HttpClient
,但性能更好,因为运行时是构建在本机代码之上的,与 .NET 框架不同。
它的用户界面也是原生的。我将使用 Windows.UI.Xaml.Controls
库在屏幕上渲染不同的控件。
只需添加几行 C# 代码即可使其成为我们 API 的客户端。接下来,我将向你展示如何创建 Web API 以及如何配置它以运行!
CRUD — 介绍
CRUD 只是创建、读取、更新和删除的缩写。具有 CRUD 功能的应用程序简单来说就是允许你执行以下操作的应用程序
- 创建一个新记录。
- 读取所有记录,或一次读取一条记录。
- 更新这些记录。
- 删除任何记录。
在我们的 API 中,我将创建相同的函数。它们将允许我们对模型执行 CRUD 功能。在编写 CRUD API 时,我没有什么秘密。它只是一个花哨的术语,仅此而已。
奖励库 — Newtonsoft.Json
由于我们将处理 JSON 数据,我建议你在处理 JSON 数据时使用 Newtonsoft.Json 库。在我的应用程序中,我也使用了这个库。相信我,它能为你省去大部分麻烦。
你可以通过运行以下 NuGet 包管理器命令从 NuGet 获取它
PM> Install-Package Newtonsoft.Json
NuGet 将为你安装包。在我随本文提供的源代码中,包已为你包含在内。
入门
希望现在你已经了解了什么是 ASP.NET 5 和什么是 Windows 10 的通用应用程序。如果了解了,你就可以继续基于这两种新技术编程一个客户端/服务器架构了!
设置环境
在我们开始之前,你需要设置你的开发环境。我希望你确保几件事
- 你有 Windows 10 吗?
编程 Windows 10 应用程序要求你使用 Windows 10 操作系统。所以,通过升级或成为 Insider 来获取一份 Windows 10! - 你有 Visual Studio 2015 吗?
编程 Windows 10 应用程序需要 Visual Studio 2015。你可以免费获得 Visual Studio Community Edition 许可证以开始编程应用程序。ASP.NET 5 也随 Visual Studio 2015 一起提供,所以 Visual Studio 2015 是必需的。
一旦你对以上问题回答“是”,请继续。在下一节中,我将解释如何创建 API 和客户端,以满足你的目的。
创建 Web API
我建议你先开发 API,而不是编写客户端代码。编写 API 将在许多方面使你受益。
- 预先设置好 API 将有助于你为客户端进行初步工作。这样你将知道 API 中提供了哪些方法,需要传递哪些参数等等。
- 你无需再次更改 API,只需确保客户端和 API 协同工作。为一个客户端编辑 API 也可能导致其他客户端(设备)出现问题。
- 你必须始终配置你的客户端与 API 协同工作,而不是反过来。你将拥有多个客户端,通过多个网络、设备和平台连接。你的 API 是静态的,它不会改变。因此,请确保你的 API 足够开放,任何人都可以连接。因此,简单的 HTTP 动词和非常清晰的动作方法就足够了。
提示:在 API 中工作时尝试创建接口和对象。这样,在收到请求时,你将能够将该请求发送到另一个后台线程或接口,该线程或接口将处理该请求,然后将数据返回给你。将所有内容硬编码在请求处理程序内部将使模型达到企业级复杂性后更难进行编辑。
在接下来的部分中,我将向你展示如何确保模型不复杂,而是一个非常简单直观的模型,能够进行进一步编程以使其变得更好! :-)
创建新的 Web API 项目
在 Visual Studio 2015(无论你使用的是哪个版本,我用的是社区版)中,创建一个新的 Web 应用程序项目。确保你选择的是 ASP.NET 5 模板而不是 ASP.NET 4 模板。在其中,选择 Web API,然后继续你的项目。
在此阶段,你的项目将只有一个控制器,在我的例子中是 ValuesController
。只需将其编辑掉,将类名更改为 UserController
,并(如果你想整理一下)将文件名更改为 UserController.cs。在创建用于处理和接受客户端请求的模型之前,保留其他所有内容不变。
创建和编辑模型
由于 Web API 主要依赖于 ASP.NET MVC,你会看到 模型-视图-控制器 模式在此处应用。同样,我们的 Web API 的控制器(回想 UserController
)和模型(我们现在要创建的)构成了该 MVC 模式的一部分。正如前面提到的,在这种情况下没有视图,因为我们只处理 HTTP 请求,不使用 HTML 渲染作为 View
。
我已经为你创建了一个我将使用的基本对象示例。一个简单的对象模型结构,User
。我还有另一个类(包含所有静态成员),它将作为我们的模型数据源。以下是它们的类图
很明显,User 拥有可用于我们数据的属性。我们可以在列表中编辑它们,为我们的数据源创建一个唯一的用户列表。此外,我们所需要的只是一个带有一些静态函数的模型,以允许我们执行操作。模型允许我们操作我们的数据源(在本文中它只是一个用户列表)。
User 类:
// Actual data model public class User { public int ID { get; set; } public string Name { get; set; } public bool Gender { get; set; } public string[] Interests { get; set; } }
模型类
// A class to work-around with out data source public class Model { // Example data source private static List<User> users = new List<User>() { new User { ID = 1, Name = "Afzaal Ahmad Zeeshan", Gender = true, Interests = new string[] { "Programming", "Songs" } }, new User { ID = 2, Name = "Shani", Gender = true, Interests = new string[] { "Eminem", "Eating" } }, new User { ID = 3, Name = "Daniyal Ahmad Rizwan", Gender = true, Interests = new string[] { "Games", "Movies" } }, new User { ID = 4, Name = "Marshall Bruce Mathers III", Gender = true, Interests = new string[] { "Rapping", "Parenting" } } }; // C part of CRUD public static void CreateUser(User user) { users.Add(user); } // R part of CRUD public static List<User> GetAll() { return users; } public static User GetUser (int id) { return users.Find(x => x.ID == id); // Find one user and return him } // U part of CRUD public static void UpdateUser(int id, User user) { users.Remove(users.Find(x => x.ID == id)); // Remove the previous User users.Add(user); } // D part of CRUD public static void DeleteUser(int id) { users.Remove(users.Find(x => x.ID == id)); // Find and remove the user } }
重新审视上面的代码,是不是很清楚每个函数的作用?没有歧义,函数和作用也很清晰。我们肯定会在控制器中使用这些函数,根据 HTTP 请求及其动词执行不同方面的操作。
除了函数之外,属性(数据源)users
也是静态的。原因在于,如果它不是静态的,每个新请求都会将数据源重新初始化为仅初始(4 个对象)列表。这将撤销我们在应用程序中执行的任何更改。实际上,这只是一个简单的内存数据源。在你的应用程序中,你将有一个数据库来支持你的应用程序。数据库将为你的项目提供其他函数和特性。在这些情况下,你甚至不需要创建这些类和对象。你将能够为你的数据库获取驱动程序或控制器。例如,SQL Server 数据库的 System.Data.SqlClient
。
API 的最后润色
现在是时候更新 API 控制器来处理请求,并将控制权传递给模型以操作应用程序状态,从而在客户端等待响应时返回响应。控制器只有 4 个方法,每种请求类型一个。
控制器的源代码是
[Route("api/[controller]")] public class UserController : Controller { // GET: api/user [HttpGet] public IEnumerable<User> Get() { return Model.GetAll(); } // GET api/user/5 [HttpGet("{id}")] public User Get(int id) { return Model.GetUser(id); } // POST api/user [HttpPost] public void Post([FromForm]string value) { var user = JsonConvert.DeserializeObject<User>(value); // Convert JSON to Users Model.CreateUser(user); // Create a new User } // PUT api/user/5 [HttpPut("{id}")] public void Put([FromForm]int id, [FromForm]string value) { var user = JsonConvert.DeserializeObject<User>(value); Model.UpdateUser(id, user); } // DELETE api/user/5 [HttpDelete("{id}")] public void Delete(int id) { Model.DeleteUser(id); } }
再看一遍,都是同样的基本功能。每种用户可能发送的请求类型都有一个。这些功能由 Http
属性处理。它告诉 API 针对哪个 HTTP 动词执行哪个方法。
请求网址 |
HTTP 动词 |
响应 |
---|---|---|
GET http://www.example.com/api/user |
GET |
|
GET http://www.example.com/api/user/1 |
GET |
|
POST http://www.example.com/api/user |
POST |
|
PUT http://www.example.com/api/user |
PUT |
|
DELETE http://www.example.com/api/user |
删除 |
|
表 2:HTTP 请求、方法和响应。
上面的表格中有很多你需要理解的东西,然后才能继续阅读更多!我在这里为你澄清几点
- 在第一种情况下(没有附加 ID),结果是一个数组。请注意,前两行的返回约定是 JSON(或 JavaScript)。在第一种情况下返回一个数组。在第二种情况下,返回一个对象的单个实例。由于空间原因,我没有用它们的正式表示法编写对象,抱歉!
- 对于 POST、PUT 和 DELETE,我返回了 void。你可以(根据你的需要)返回一个
bool
或object
以在客户端处理响应。随你便。 :-)
这样,这些请求被发送到服务器,映射到一个动作,然后执行。然后响应通过网络流式传输到客户端,客户端再将其渲染。好了,关于 API 的内容够多了,现在让我们考虑在 Windows 10 框架中编写客户端应用程序。
配置服务器设置
虽然如果你愿意继续使用默认设置,那么你可以跳过本节。但是你会发现在编辑网站配置时很方便。它将允许你使用方便的 URL 和一些其他设置。考虑转到属性页面并在调试(或 Web)下编辑设置。
在我的例子中,我将启动 URL 设置为 /api/user,并将端口更改为 1234。易于记忆。
在 Windows 10 应用程序中创建客户端
现在,在本节中,我将向你展示如何创建充当我们 API 客户端的 Windows 10 应用程序。我将创建所有模板页面,并准备好让 API 将数据填充到这些页面中。我将有几个页面和一堆逻辑表达式来实际运行逻辑。我不会展示后端如何连接,只会展示应用程序的一些高级抽象。如果你渴望测试,可以下载提供的源代码,通过构建并在自己的机器上运行来测试项目。
注意:请确保在启动 Windows 应用程序时 API 正在运行。否则,它将无法工作或更糟,开始烦扰你。
现在打开 Visual Studio 2015,为 Windows 10 创建一个新项目。你会在 Visual C# → Windows → Universal 下找到它。创建一个空应用程序。对于这样一个基本的应用程序,你不需要为复杂的框架而烦恼。
创建应用程序视图
你可以考虑为你的应用程序制作视图。在源代码中,我为我们的应用程序添加了 3 个页面。
- 视图
此页面将指代 CRUD 的读取。 - 创建或更新
此页面将用于 CRUD 的创建或更新。由于这两种形式都将提供相同的输入字段。我曾想为什么要创建两个不同的页面,只创建一个并在条件下更改它们的值!虽然很有用。:-) - 删除
最后,这将提示你删除记录。
我不会展示 XAML 标记的源代码,因为那会使文章太长而难以阅读,而且本文不是关于 XAML 或 Windows 10 的,而是更多关于使用 ASP.NET 5 Web API 和 Windows 运行时的客户端-服务器应用程序。所以,我将更多地关注 Windows 运行时 API。如果你对应用程序代码感兴趣,请下载源代码并尝试修改它。也欢迎在你自己的应用程序中分享或移植它。
成为客户端的第一步
现在是 Windows 运行时编程的主要部分。Windows 运行时不是 .NET 框架,你在 .NET 框架中熟悉的那些对象在 Windows 运行时中不可用。Windows 运行时有自己的 API 集和库。但是,.NET 框架的便携式库也适用于 Windows 运行时。
在此应用程序中,我将使用 HttpClient
对象,它是 Windows.Web.Http
命名空间下的,而不是使用 HttpClient
,它是 System.Net.Http
命名空间下的。它们是完全不同的对象,所以请不要混淆。 Windows.Web.Http.HttpClient
是一个 Windows 运行时对象,而 System.Net.Http.HttpClient
是一个 .NET 对象。由于此对象也实现了 IDisposable
,我们可以在 using
块中使用它以获得更好的结果。
大多数情况下,代码就像这样
using (var client = new HttpClient()) { /* * Send requests here * client.GetAsync(); For GET HTTP * client.PostAsync(); // For POST HTTP * Parameters are still required to be passed. **/ }
其余的只是应用程序状态逻辑,不应解释,因为它会引起一些混淆。这就是为什么我只打算粘贴与我们客户端-服务器模型中的 CRUD 操作相关的代码。
发起 CRUD 请求
在 HTTP API 中,不同的动词用于发起请求并告诉服务器该做什么。在本节中,我将向你展示如何使用特定的 HTTP 方法以及一些数据向 API 发送请求,以便服务器知道如何处理数据。你必须注意,HTTP GET 和 HTTP DELETE 请求不需要任何额外数据。你可以在 URL 中传递参数,例如 DELETE http://www.example.com/api/user/5,服务器就会知道删除 ID 为 5 的用户。PUT 和 POST 方法要求你传递一些需要保存或存储的数据。
HTTP PUT 或 HTTP POST
通常会产生疑问,既然它们都更新服务器上的内容,那么应该使用哪一个来实际实现数据存储。HTTP PUT 还是 HTTP POST。有些人使用 POST 上传数据,使用 PUT 更新数据,有些人使用 PUT 存储数据,使用 POST 更新数据。
这个歧义的实际答案是它们的幂等性,哪一个实际上是为了更新数据,哪一个存储数据。
从一个 很棒的帖子 中我得到了答案,
HTTP Post
x++
HTTP PUT
x = 5
很简单,不是吗?HTTP POST 不是幂等的,它旨在在你想要执行(比如说)向数据库添加更多记录时工作。它总是增加记录。HTTP PUT 另一方面会创建一个新记录(如果它不存在),并不断更新它(如果它已经存在)。
设置应用程序
我创建了一些应用程序属性,以便在一个应用程序中处理 API 和应用程序状态。
public static Uri BaseUri = new Uri("https://:1234/api/user"); // base API URL; UserController public static Frame RootFrame { get; set; } // RootFrame to be updated for different Views public static User ActiveUser { get; set; } // Active User to be worked with.
创建或更新用户
我首先要谈的是创建用户,创建用户采用一种表单,该表单可以重新用于更新用户。我将使用相同的页面,只做一点点改动。所以,它将同时满足我的两种目的。
创建用户
创建时,表单将为空。我们将填写详细信息,然后使用 HttpClient
将这些详细信息发送到 API。
提交后,数据通过将内容序列化为 JSON 传递给 API。
更新用户
更新用户也是类似的过程,唯一的区别是,在这种情况下,表单不会是空的。相反,应用程序会向我们显示我们可以编辑的先前数据,然后单击“更新”。
它们的源代码是相似的,这就是我之前没有分享的原因。发生的情况是,当点击按钮时(两种情况下),数据被序列化,并使用适当的 HTTP 方法向 API 发送请求。
private void Button_Click(object sender, RoutedEventArgs e) { if((sender as Button).Content.ToString() == "Cancel") { // Go to default page App.RootFrame.Navigate(typeof(MainPage)); return; // and cancel the event. } // Otherwise var user = new User { ID = Convert.ToInt32(userId.Text), Name = name.Text, Gender = (gender.IsChecked == true) ? true : false, Interests = interests.Text.Split(',') }; using(var client = new HttpClient()) { var content = JsonConvert.SerializeObject(user); if (create == null || create == true) { // Send a POST Task task = Task.Run(async () => { var data = new HttpFormUrlEncodedContent( new Dictionary<string, string> { ["value"] = content } ); await client.PostAsync(App.BaseUri, data); // sends POST request }); task.Wait(); } else { // Send a PUT Task task = Task.Run(async () => { var data = new HttpFormUrlEncodedContent( new Dictionary<string, string> { ["value"] = content, ["id"] = App.ActiveUser.ID.ToString() } ); await client.PutAsync(App.BaseUri, data); // sends PUT request }); task.Wait(); } } App.RootFrame.Navigate(typeof(MainPage)); // Finally navigate back }
读取用户
读取用户(在我看来)是 API 上最简单的任务。你发送一个请求(无需额外数据),API 返回一个用户列表。
要从 API 获取记录,请使用以下代码,
var response = ""; Task task = Task.Run(async () => { response = await client.GetStringAsync(App.BaseUri); // sends GET request }); task.Wait(); // Wait listView.ItemsSource = JsonConvert.DeserializeObject<List<User>>(response); // Bind the list
结果将是一个列表,我使用 ListView
控件来定义我自己的自定义列表布局,而不是调用默认的 ToString
。
你可以看到我们上一节中创建的新用户在那里可用。现在它没有显示太多细节,点击它(SelectionChanged
)会帮助我们。
第二个(尽管没有单独的代码)来自应用程序的 ActiveUser
属性。当选择更改时,我更改了视图,这使我能够更改视图并显示我必须显示的详细信息。
删除用户
最后也是另一个简单的任务是删除用户。它只需要一个 DELETE 请求,不需要额外数据。
点击“是”按钮后,应用程序将执行以下代码,
// Send a request to delete the user using (var client = new HttpClient()) { Task task = Task.Run(async () => { await client.DeleteAsync(App.BaseUri + "/" + App.ActiveUser.ID.ToString()); }); task.Wait(); } App.RootFrame.Navigate(typeof(MainPage));
很简单。
因此,从这个应用程序可以清楚地看出,创建消耗中央 API 的跨平台客户端实际上是多么容易。它允许我们在不同的平台上创建本机应用程序并向 API 发送 HTTP 请求。另一个好处是所有应用程序都可以拥有本机外观和感觉。我们不必费尽心力来修复 Web 应用程序中出现的跨平台和跨设备布局以及其他类似问题。
从文章中下载源代码,亲自尝试这些应用程序。你也可以将其用于自己的目的,欢迎分享。 :-)
历史
文章的第一个版本。