Web API
开篇首先提一下三层架构及微服务(即记录boss首次会议培训)。
三层架构
三层架构从上到下顺序为界面层(User Interface layer)、业务逻辑层(Business Logic Layer)、数据访问层(Data access layer)。
1:数据访问层:主要是对非原始数据(数据库或者文本文件等存放数据的形式)的操作层,而不是指原始数据,也就是说,是对数据库的操作,而不是数据,具体为业务逻辑层或表示层提供数据服务。可以理解为对数据库的动作(CRUD),在MVC具体为Controller层。
2:业务逻辑层:主要是针对具体的问题的操作,也可以理解成对数据层的操作,对数据业务逻辑处理,如果说数据层是积木,那逻辑层就是对这些积木的搭建。
3:界面层:主要表示WEB方式,也可以表示成WINFORM方式,WEB方式也可以表现成:aspx,如果逻辑层相当强大和完善,无论表现层如何定义和更改,逻辑层都能完善地提供服务。
微服务架构
微服务将系统分为两层:UI、Web API。与三层架构相比较,UI对应界面层,Web API对应业务逻辑层和数据访问层。这种前后端分离的方式,有利于独立开发和管理。深入理解微服务请参考:微服务架构设计
下面进入本文正题:Web API(这里我们提到Web API特指ASP.NET Web API)。
Web API是网络应用程序接口。包含了广泛的功能,网络应用通过API接口,可以实现存储服务、消息服务、计算服务等能力。。。
通俗理解Web API为处理业务逻辑和数据库动作的接口,用来执行操作,返回数据给前端。本博客例子,我们要展示笑话在页面,就需要前端显示给用户,前端显示当然要有数据,那我们的数据就通过API来提供,API就负责连接数据库,执行动作,返回数据。
那么微服务架构的Web API和常用的MVC有什么区别呢?
首先,MVC既有页面,也有数据、逻辑,而Web API只有数据、逻辑,页面由微服务的UI负责;
其次,命名空间不同,MVC在System.Web.Mvc命名空间下,Web API在ASP.NET System.Web.Http命名空间下,因此model binding/filter/routing等功能有所不同;
再次,Web API 可以根据请求报文来返回的相应数据格式。包括JSON和XML。
再再次,Web API 单独做数据请求和MVC做页面请求可以让Web前端和后台更好的解耦,减少开发难度。
最后,Web API更倾向于基于HTTP协议的服务,直接返回用户的数据请求。MVC是建站的一种框架,倾向于返回用户的页面请求。
尝试建立Web API
1.创建项目
新建Web Application项目
点击“OK”,下一步选择Web API,点击“OK”
然后项目创建成功,Controllers里面有一个ValuesController,是自动生成的一个最简单的Web API Controller。
2.添加数据实体模型
按照数据库字段在模型中添加属性。
namespace WebAPI.Jokes.Models { public class Joke { public int ID { get; set; } public string Content { get; set; } public int State { get; set; } public string Belong { get; set; } public DateTime AddDate { get; set; } } }
3.添加Web API控制器
选择空的Web API Controller
创建完成后我们可以看到这里Controller继承的并不是和MVC相同的Controller,而是ApiController.
4.在controllers文件中新建DBConnect类,用来进行数据库的连接读写操作。
首先在Web.config中添加数据库连接字符串。
<connectionStrings>
<add name="Joke" connectionString="data source=PA181;initial catalog=Joke;persist security info=True;user id=sa;password=****(此处为数据库密码);MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
</connectionStrings>
using System; using System.Collections.Generic; using System.Configuration; using System.Data.SqlClient; using System.Linq; using System.Web; using WebAPI.Jokes.Models; namespace WebAPI.Jokes.Controllers { public class DB { protected SqlConnection conn; //打开连接 public bool OpenConnection() { conn = new SqlConnection(ConfigurationManager.ConnectionStrings["Joke"].ConnectionString); try { bool result = true; if (conn.State.ToString() != "Open") { conn.Open(); } return result; } catch (SqlException ex) { return false; } } //关闭连接 public bool CloseConnection() { try { conn.Close(); return true; } catch (SqlException ex) { return false; } } //显示 public List<Joke> Select() { SqlDataReader sdr; List<Joke> list = new List<Joke>(); try { if (conn.State.ToString() == "Open") { SqlCommand cmd = new SqlCommand("Select * from Jokes", conn); sdr = cmd.ExecuteReader(); while (sdr.Read()) { Joke j = new Joke(); System.Diagnostics.Debug.WriteLine("ID:{0}\tcontent:{1}\tbelong:{2}\tstate:{3}\ttime:{4}", sdr["ID"], sdr["Content"], sdr["Belong"], sdr["State"], sdr["AddDate"]); j.ID = Convert.ToInt32(sdr["ID"]); j.Content = sdr["Content"].ToString(); j.Belong = sdr["Belong"].ToString(); j.State = Convert.ToInt32(sdr["State"]); j.AddDate = Convert.ToDateTime(sdr["AddDate"]); list.Add(j); } } } catch (Exception e) { Console.WriteLine("Joke details wrong:{0}", e); } finally { conn.Close(); } return list; } //Detail public Joke Detail(int? id) { SqlDataReader sdr; Joke j = new Joke(); System.Diagnostics.Debug.WriteLine("编号:{0}", id); string sql = "Select * from Jokes where ID = @ID"; SqlParameter[] paras = new SqlParameter[]{//参数数组 new SqlParameter("@ID",System.Data.SqlDbType.Int)}; paras[0].Value = id;//绑定ID try { if (conn.State.ToString() == "Open") { SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddRange(paras); sdr = cmd.ExecuteReader(); while (sdr.Read()) { System.Diagnostics.Debug.WriteLine("ID:{0}\tcontent:{1}\tbelong:{2}\tstate:{3}\ttime:{4}", sdr["ID"], sdr["Content"], sdr["Belong"], sdr["State"], sdr["AddDate"]); j.ID = Convert.ToInt32(sdr["ID"]); j.Content = sdr["Content"].ToString(); j.Belong = sdr["Belong"].ToString(); j.State = Convert.ToInt32(sdr["State"]); j.AddDate = Convert.ToDateTime(sdr["AddDate"]); } } } catch (Exception e) { System.Diagnostics.Debug.WriteLine("Joke select wrong:{0}", e); } finally { conn.Close(); } return j; } //Create public void Create(Joke joke) { //SqlDataReader sdr; //string sql = "insert into Jokes(Content,Belong,State,AddDate)values('" + joke.Content + "','" + joke.Belong + "','" + joke.State + "','" + joke.AddDate + "')"; string sql = "insert into Jokes(Content,Belong,State,AddDate)values(@content,@belong,@state,@time)"; SqlParameter[] paras = new SqlParameter[]{//参数数组 new SqlParameter("@content",System.Data.SqlDbType.VarChar), new SqlParameter("@belong",System.Data.SqlDbType.VarChar), new SqlParameter("@state",System.Data.SqlDbType.Int), new SqlParameter("@time",System.Data.SqlDbType.DateTime)}; paras[0].Value = joke.Content;//绑定内容 paras[1].Value = joke.Belong;//绑定署名 paras[2].Value = joke.State;//绑定状态 paras[3].Value = joke.AddDate;//绑定时间 try { if (conn.State.ToString() == "Open") { SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddRange(paras); cmd.ExecuteNonQuery(); System.Diagnostics.Debug.WriteLine("插入成功!"); } } catch (Exception e) { Console.WriteLine("Joke create wrong:{0}", e); } finally { conn.Close(); } } //Delete public int Delete(int? id) { string sql = "delete from Jokes where ID= @ID"; SqlParameter[] paras = new SqlParameter[]{//参数数组 new SqlParameter("@ID",System.Data.SqlDbType.Int)}; paras[0].Value = id;//绑定ID int i = 0; try { if (conn.State.ToString() == "Open") { SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddRange(paras); i = cmd.ExecuteNonQuery(); System.Diagnostics.Debug.WriteLine("插入成功!"); } } catch (Exception e) { Console.WriteLine("Joke create wrong:{0}", e); } finally { conn.Close(); } return i; } //update public int Update(Joke joke) { string sql = "update Jokes set Content = @content,Belong = @belong where ID= @ID"; SqlParameter[] paras = new SqlParameter[]{//参数数组 new SqlParameter("@content",System.Data.SqlDbType.VarChar), new SqlParameter("@belong",System.Data.SqlDbType.VarChar), new SqlParameter("@ID",System.Data.SqlDbType.Int)}; paras[0].Value = joke.Content;//绑定内容 paras[1].Value = joke.Belong;//绑定署名 paras[2].Value = joke.ID;//绑定ID System.Diagnostics.Debug.WriteLine("SQL语句:{0}", sql); int i = 0; try { if (conn.State.ToString() == "Open") { SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddRange(paras); i = cmd.ExecuteNonQuery(); System.Diagnostics.Debug.WriteLine("更新成功!"); } } catch (Exception e) { Console.WriteLine("Joke update wrong:{0}", e); } finally { conn.Close(); } return i; } } }
5.获取数据
新建空的Controller后,我们首先建立一个获取全部数据的方法。
public class JokesController : ApiController { private DB _db = new DB(); public List<Joke> GetJokes() { _db.OpenConnection(); return _db.Select(); } }
6.添加View
先打开HomeController,里面添加一个新的Action代码如下,因为我们要在MVC中对于JokeController添加对应的View。
public ActionResult Joke() { string apiUri = Url.HttpRouteUrl("DefaultApi",new { controller = "Joke"}); ViewBag.ApiUrl = new Uri(Request.Url, apiUri).AbsoluteUri.ToString(); return View(); }
然后右键Joke方法,Add View,选择空模板,Model选择我们建立的实体模型
然后在View中添加访问API的代码:
@section Scripts { @Scripts.Render("~/bundles/jqueryval") <script type="text/javascript" src="@Url.Content("~/Scripts/knockout-2.3.0.js")"></script> <script type="text/javascript"> $(document).ready(function () { $.getJSON('/api/jokes') .done(function (data) { $.each(data, function (key, item) { $('<li>', { text: formatItem(item) }).appendTo($('#jokes')); }); }); }) function formatItem(item) { return item.Content + ',' + item.Belong + ',' + item.AddDate; } function find() { var id = $('#jokeid').val(); $.getJSON('/api/jokes/' +id) .done(function (data) { $('#joke').text(formatItem(data)); }) .fail(function (jqXHR,textStatus,err) { $('#joke').text('Error:'+err); }); } </script> } <div> <ul id="jokes"></ul> </div> <div> <h2>Search by ID</h2> <input type="text" id="jokeid" size="5" /> <input type="button" value="Search" onclick="find();" /> <p id="joke" /> </div>
然后在_layout.cshtml中添加一个Joke页面的链接
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Home", "Index", "Home", new { area = "" }, null)</li>
<li>@Html.ActionLink("API", "Index", "Help", new { area = "" }, null)</li>
<li>@Html.ActionLink("Joke", "Joke", "Home", new { area = "" }, null)</li>
</ul>
最后,让我们运行程序看一下结果。
程序运行我们看到自建的首页面:
可以看到顶部有我们在_layout.cshtml中添加的Joke页面的链接Joke,点击Joke,跳转到Joke页面,信息已经显示出来
大功告成!
其它API如Create,Update,Delete,在JokeController中依次添加,View页面使用ajax调用API即可。