1.WebApi是什么
ASP.NET Web API 是一种框架,用于轻松构建可以由多种客户端(包括浏览器和移动设备)访问的 HTTP 服务。ASP.NET Web API 是一种用于在 .NET Framework 上构建 RESTful 应用程序的理想平台。
可以把WebApi看成Asp.Net项目类型中的一种,其他项目类型诸如我们熟知的WebForm项目,Windows窗体项目,控制台应用程序等。
WebApi类型项目的最大优势就是,开发者再也不用担心客户端和服务器之间传输的数据的序列化和反序列化问题,因为WebApi是强类型的,可以自动进行序列化和反序列化,一会儿项目中会见到。
1 安装
一、如果是新建项目最简单,文件=>新建=>项目=>Web=> ASP.NET Web 应用程序,在下方同时勾选Web Forms 和 Web API 核心引用即可,webfroms核心和WebAPI核心的应用程序就创建好了。
如果没有去卸载的修改器中,右键------------修改后下载安装
下载安装后打开
二、如果是原有的项目上增加WebAPI,只要将相关的包引用即可。
1.这里先创建WebForms 应用程序
在电脑上创建Web站点:
-
打开控制面板,选择并进入“程序”,双击“打开或关闭Windows服务”,在弹出的窗口中选择“Internet信息服务”下面所有地选项,点击确定后,开始更新服务。
-
更新完成后,打开浏览器,输入“http://localhost/”回车,如果此时出现IIS7欢迎界面,说明Web服务器已经搭建成功。
-
当web服务器搭建成功后,我们下一步所要做的就是把我们开发的网站安装到Web服务器的目录中。一般情况下,当Web服务器安装完成后,会创建路径“%系统根目录%inetpub/wwwroot”,将我们开发的网站COPY到该路径下。即可实现本地访问该网站。
-
设置防火墙,让局域网当其它计算机也能访问本地网站资源。具体方法:打开控制面板,选择“系统和安全”,点击“允许程序通过Windows防火墙”,在弹出的对话框中勾选“万维网服务HTTP”右侧的两个复选框,最后点击确定退出。
-
在局域网中其它计算机上,打开浏览器,输入 “http://Web服务器的IP地址/”按回车键,就可以访问服务器上的资源”。 经过以上步骤的设置,局域网中的其它用户就可以通过浏览器访问你所共享的web资源了!
了解和测试
2.Webfroms项目创建完成后,需要用到VS的NuGet包管理器。右击引用,选择 管理NuGet程序包。
选择 浏览,搜索WebAPI,选择第一个Microsoft.AspNet.WebApi;点击右边的安装后点击确定,后选择我接受,等到输出显示成功,则安装完成。
3.右击Web项目,添加名为App_Start的文件夹,在App_Start文件夹下创建名为WebApiConfig的cs文件。
清理命名空间,将类更改为static类型,添加必要代码,缺少引用的自行引用。
完整代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; namespace WebFormsDemo { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服务 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } }
4.需要在Global.asax文件下的Application_Start方法中注册一下WebAPI,这里需要引用System.Web.Http;完整代码如下:
protected void Application_Start(object sender, EventArgs e) { // 在应用程序启动时运行的代码 GlobalConfiguration.Configure(WebApiConfig.Register); }
5.接下来让我们来测试一下,新建一个Controller
6.浏览器访问http://localhost:27650/api/values/get?id=1,测试通过。
三、使用OWIN来作为宿主启动Webapi
上述是使用Global方式启动WebAPI,如果项目中使用的SignalR,就必须使用OWIN来作为宿主,虽然网上有教程Global也可以启动SignalR(在中Application_Start方法加上一句 RouteTable.Routes.MapHubs();),但是微软早在2014年6月就对其声明了过时,建议使用Owin Startup Class的方式启动SignalR。(http://go.microsoft.com/fwlink/?LinkId=320578)
1.废话不多说,新建Startup类
2.直接在Configuration 方法下新建一个ConfigureWebapi方法,完整代码如下:
/// <summary> /// 配置Webapi /// </summary> /// <param name="app"></param> public void ConfigureWebapi(IAppBuilder app) { //创建一个HTTP的实例配置 HttpConfiguration config = new HttpConfiguration(); //映射路由 config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); //将配置注入OWIN管道中 app.UseWebApi(config); }
3.我们发现,有错误信息IAppBuilder中未包含UseWebApi的定义,原因是缺少Self-Host寄宿支持,在程序包管理器控制台,中输入以下指令:
Install-Package Microsoft.AspNet.WebApi.OwinSelfHost
4.安装完成后错误提示消失
5.移除Global中的启动方式,并将ConfigureWebapi方法初始化。
6.让我们来测试一下,http://localhost:27650/api/values/get?id=1,报错误404.
7.原因是还缺少一个名为 Microsoft.Owin.Host.SystemWeb 的包,这个包提供了Owin服务运行ASP.NET 网络请求管道。在程序包管理器控制台,中输入以下指令:
install-package Microsoft.Owin.Host.SystemWeb
8.让我们再来测试一下,浏览器中输入http://localhost:27650/api/values/get?id=1,测试通过。
最后,值得一提的是官方的教程大多都使用隐式类型var 关键字,有网友说使用隐式类型的好处有
1.它有利于更好地为本地变量命名。
2. 它有利于设计更好的API。
3. 它促使对变量进行初始化。
4. 它消除了代码的混乱。
5. 它不需要using指示符。
楼主还没有深刻的体会和研究,不敢在这里妄加解释。还在学习中,下面是微软官方的文档,大家感受一下。
4项目代码:
服务器端:
using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WebAccount.DBModle;
using WebAccount.Enity;
using LitJson;
using System.IO;
//账户登录控制器
namespace WebAccount.Controllers.Api
{
public class AccountController : ApiController
{
public object JsonMapper { get; private set; }
// GET: api/Account get 请求,在没参数时,会默认调用这个方法
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET: api/Account/5 -- 客户端传过ID参数,服务会调用此方法
public AccountEnity Get(int id)
{
AccountEnity account = new AccountEnity();
return AccountDBModle.Instance.GetAccountEnity(id);
}
// POST: api/Account 客户端传来JSON字符串--会掉用此方法
public RetValue Post([FromBody]string value)
{
RetValue ret = new RetValue();
try
{
JsonData jsondata = LitJson.JsonMapper.ToObject(value);
//JsonData jsondata = Jso
int type = Convert.ToInt32(jsondata["type"].ToString());
string name = jsondata["username"].ToString();
string pwd = jsondata["pwd"].ToString();
if (type == 0) // 注册
{
ret.Data = AccountDBModle.Instance.Register(name, pwd);
}
else //登陆
{
}
}
catch (Exception E)
{
ret.HasError = true;
ret.ErrorMsg = E.Message;
}
return ret;
}
// PUT: api/Account/5 没有使用
public void Put(int id, [FromBody]string value)
{
}
// DELETE: api/Account/5 没有使用
public void Delete(int id)
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebAccount.Enity
{
public class AccountEnity // mySQl 数据库操作实体
{
public int Id { get; set; }
public string Name { get; set; }
public string Pwd{ get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebAccount
{
public class RetValue // 错误返回实体
{
public bool HasError;
public string ErrorMsg;
public Object Data;
}
}
sing System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using WebAccount.Enity;
using System.Configuration;
namespace WebAccount.DBModle //modle 层处理数据的业务逻辑 连接数据库,给控制器返回数据
{
public class AccountDBModle
{
public static Object loce_Object = new object();
private static AccountDBModle instance;
public static AccountDBModle Instance
{
get
{
if(instance == null)
{
lock (loce_Object)
{
if(instance== null)
{
instance = new AccountDBModle();
}
}
}
return instance;
}
}
private const string constr = "Data Source=.;Initial Catalog=DBaccount;Integrated Security=True";
// private string constr = ConfigurationManager.ConnectionStrings["con"].ToString();
// @"server=.;database=E:\REGISTER\REGISTER\APP_DATA\USER.MDF;User ID=sa;Password=123";//连接字体串
public AccountEnity GetAccountEnity (int id)
{
try
{
using (SqlConnection con = new SqlConnection(constr))
{
con.Open(); // 事务回滚放置事务出现问题
SqlCommand cmd = new SqlCommand("Account_Get", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure; //存储过程---
cmd.Parameters.Add(new SqlParameter("@Id", id));
// 如果关闭查询数据库也关闭
using (SqlDataReader dr = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection))
{
if (dr.HasRows)
{
while (dr.Read()) {
AccountEnity enity = new AccountEnity();
enity.Id = dr["Id"] is DBNull ? 0 : Convert.ToInt32(dr["Id"]);
enity.Name = dr["Name"] is DBNull ? string.Empty : Convert.ToString(dr["Name"]);
enity.Pwd = dr["Pwd"] is DBNull ? string.Empty : Convert.ToString(dr["Pwd"]);
return enity;
}
}
}
}
}catch (Exception e)
{
Console.Write("xxxxxxxxxxxxxxx");
}
return null;
}
public int Register(string Name ,string Pwd )
{
int userID = -1;
try
{
using (SqlConnection con = new SqlConnection(constr))
{
con.Open(); // 事务回滚放置事务出现问题
SqlCommand cmd = new SqlCommand("Account_Regists", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure; //存储过程---
cmd.Parameters.Add(new SqlParameter("@Name", Name));
cmd.Parameters.Add(new SqlParameter("@Pwd", Pwd));
// 如果关闭查询数据库也关闭
// userID = (int)cmd.ExecuteScalar(); //
userID = Convert.ToInt32(cmd.ExecuteScalar().ToString());
}
return userID;
}
catch (Exception e)
{
Console.Write("xxxxxxxxxxxxxxx");
return userID;
}
}
}
}
客户端:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// HTTP 通讯管理通讯类
public class NetWorkHttp : MonoSingleton<NetWorkHttp>
{
private System.Action<CallBackArgs> m_CallbackAction;
private CallBackArgs m_CallBackArgs;
private bool m_IsBusy = false;
// 只读
public bool M_IsBusy
{
get { return m_IsBusy; }
}
void Start () {
m_CallBackArgs = new CallBackArgs();
}
// Update is called once per frame
void Update () {
}
public void SendDate( string url, System.Action<CallBackArgs> CallbackAction, string json= null,bool isPost =false)
{
if (m_IsBusy) return;
m_IsBusy = true;
m_CallbackAction = CallbackAction;
if (isPost)
{
PostUrl(url, json);
}
else
{
GetUrl(url);
}
}
/// <summary>
/// Get请求
/// </summary>
/// <param name="url"></param>
public void GetUrl(string url)
{
WWW data = new WWW(url);
StartCoroutine(Request(data));
}
private IEnumerator Request (WWW data)
{
yield return data;
m_IsBusy = false;
if (string.IsNullOrEmpty(data.error)) //没有报错
{
if (data.text == "null") // 数据库返回字符串表示空
{
if (m_CallbackAction != null)
{
m_CallBackArgs.isError = true;
m_CallBackArgs.json = data.text;
m_CallBackArgs.errorMsg = data.error;
m_CallbackAction(m_CallBackArgs);
Debug.Log("没请求到数据");
}
}
else {
if (m_CallbackAction != null)
{
m_CallBackArgs.isError = false;
m_CallBackArgs.json = data.text;
m_CallBackArgs.errorMsg = "没错";
m_CallbackAction(m_CallBackArgs);
Debug.Log(data.text);
}
}
}
else
{
if(m_CallbackAction != null)
{
// 给参数赋值
m_CallBackArgs.isError = true;
m_CallBackArgs.errorMsg = data.error;
m_CallBackArgs.json = data.text;
m_CallbackAction(m_CallBackArgs);
Debug.Log(data.error+"直接请求错误");
}
}
}
// 使用JSON 传送数据
/// <summary>
/// POST 请求
/// </summary>
/// <param name="url"></param>
/// <param name="json"></param>
public void PostUrl(string url,string json)
{
WWWForm form = new WWWForm(); //定义表单,添加值发送 数据名称数据的值
form.AddField("",json); // fromBODY ----
WWW data = new WWW(url,form);
StartCoroutine(Request(data));
}
public class CallBackArgs
{
public bool isError; // 是否有错
public string errorMsg;// 错误原因
public string json; //JSON 数据
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LitJson;
// 测试类-------------具体等登录UI方面的-实现的时候,就是客户端进行是否空等逻辑,
// 发送服务器,客户端更具回调判断是否成功--此处只做测试
public class Thttp : MonoBehaviour {
// Use this for initialization
void Start() {
if (!NetWorkHttp.Instance.M_IsBusy)
{
//NetWorkHttp.Instance.SendDate(GlobalConfig.WebAccountURL + "api/account?id=2", GetCallBack);
//NetWorkHttp.Instance.SendDate("http://192.168.1.125:8080/api/account?id=1", GetCallBack);
}
if (!NetWorkHttp.Instance.M_IsBusy)
{
JsonData jsondata = new JsonData();
jsondata["type"] = 0; /// 0 注册 1 登录
jsondata["username"] = "xxx";
jsondata["pwd"] = "";
NetWorkHttp.Instance.SendDate("http://192.168.1.125:8080/api/account", PostCallBack, isPost: true, json: jsondata.ToJson());//?id = 10
}
}
// Update is called once per frame
void Update () {
}
public void GetCallBack(NetWorkHttp.CallBackArgs arg)
{
if (arg.isError) {
Debug.Log(arg.isError);
}
else
{
AccountEntity entity = JsonMapper.ToObject<AccountEntity>(arg.json);
Debug.Log(entity.Name);
}
}
public void PostCallBack(NetWorkHttp.CallBackArgs arg)
{
if (arg.isError)
{
Debug.Log(arg.isError);
Debug.Log(arg.errorMsg);
}
else
{
Debug.Log(arg.json);
RetValue retValue = JsonMapper.ToObject<RetValue>(arg.json);
if (!retValue.HasError) {
Debug.Log("用户编号" + retValue.Data);
}
else
{
}
}
}
}