webapi 知识

webapi 知识什么是WebAPI 最近出去面试,被问到关于WebAPI的知识,因为项目中没有单独写过WebAPI,使用的时候是和mvc结合在一起使用的,所以,在我的印象中WebAPI和mvc是差不多的,这种答案当然不能让人满意了,于是今天做个关于WebAPI的总结,顺便梳理一下相关知识。 那么首先第一点:什么是W

什么是WebAPI

最近出去面试,被问到关于WebAPI的知识,因为项目中没有单独写过WebAPI,使用的时候是和mvc结合在一起使用的,所以,在我的印象中WebAPI和mvc是差不多的,这种答案当然不能让人满意了,于是今天做个关于WebAPI的总结,顺便梳理一下相关知识。

那么首先第一点:什么是WebAPI?

    首先我们了解一下.net framework 的框架构成,

    webapi 知识

    可以看到,WebAPI和mvc同属于B/S模板框架的一种,官方对于WebApi的定义是:WebAPI是一个框架,可以轻松构建HTTP服务,覆盖广泛的客户端,包括浏览器和移动设备,WebAPI是在.NetFramwork上构建RESTful程序的理想平台。

    这里有必要解释一下什么是RESTful: RESTful是一种设计风格,REST中的 get、post、put、delete来进行数据的增删改查,如果开发人员的应用程序符合RESTful原则,那他的服务可被称之为“Restful风格应用服务”

 为什么要使用WebAPI

然后我们了解一下:为什么要使用WebAPI?

在解释这个问题之前我们需要首先知道一下.net为外部提供接口的方式有哪些?

答:WCF、WebService、WebAp、一般处理程序。

      那来了解一下他们之间的区别:
        WebService:
            1:基于soap协议,数据格式是xml、
            2:只支持http协议、
            3:不是开源的,但是可以被任意一个了解xml的人使用、
            4:只能部署在iis上。

        WCF:
            1:基于soap协议,数据格式是xml、
            2:WCF是webservice的进化版,支持各种各样的协议,像TCP、http、https、NamedPipes、MSMQ等、
            3:不是开源的,但是可以被任意一个了解xml的人使用、
            4:可以部署在应用程序中、IIS上或者Windows服务中。

        WebAPI:
            1:是一个简单的构建http服务的新框架、
            2:在.net平台上WebAPI是一个开源的、理想的、构建RESTful服务的技术、
            3:可以使用http的所有特点,(比如URIs、request/response头、缓存、版本控制、多种内容格式)、
            4:支持mvc的特性,像路由、控制器、action、fiter、模型绑定、控制反转、依赖注入、单元测试、
            5:可以部署在应用程序中、IIS上、
            6:是一个轻量级的框架,对各种终端的支持都很好、
            7:Response可以被webAPI的MediaTypeFormatter转换成json、XML或者任何你想转换的格式。

        一般处理程序:

            一般处理程序其实就是和页面处理程序相区分开的,因为实现的是IhttpHandler接口,而且不需要继承自Page类。所以没有那么多的事件需要处理,不必消耗太多资源,所以性能方面要比aspx高。  

那么回到这个问题,为什么要使用WebApi?

        当你遇到下面这些情况的时候,就可以考虑使用webAPI来构建你的服务了;

            1:需要webservice但是不需要soap、

            2:需要在已有的WCF服务基础上建立non-soap-based http服务、

            3:只想发布一些简单的http服务,不想使用相对复杂的wcf配置、

            4:发布的服务会被限制带宽的设备访问、

            5:希望使用开源框架,关键时刻可以自己调试或者自定义一下框架。

 

最后总结一下WebAPI和MVC之间的区别:WebAPI和MVC之间有什么区别?

相信使用过mvc和webapi的同学都会觉得这两者太相似了,使用起来也差不多,但是既然是两个框架,那肯定是有区别的,我对WebAPI和MVC的区别做了一下总结:

            1:MVC主要是用来构建网站的,既关心数据也关心页面展示,而WebAPI只关心数据、

            2:WebAPI支持格式协商,客户端可以通过Accept header通知服务器期望的格式、

            3:WebApi支持Self Host,MVC目前不支持、

            4:WebAPI通过不同的http verb表达不同的动作(CRUD),MVC则通过Action名字表达动作、

            5:WebAPI内建于System.Web.Http 命名空间下,而MVC位于Systm.Web.Mvc命名空间下,因此路由等有些许不同、

            6:WebAPI非常适合构建移动客户端服务。

 WebAPI如何使用呢?

首先我们打开vs新建一个WebAPI项目,可以看到一共有这些文件夹目录

 webapi 知识

首先了解一下这些文件夹/文件的意义(按照程序启动的流程,相关的配置项就不说了),

    Global.asax:这个是程序启动的文件,内部的默认方法【Application_Start】对文件绑定、WebAPI路由、mvc控制器路由等进行注册,只会在第一个用户访问的时候运行;上网找了一下相关资料,发现可以在其中添加很多的配置方法:

webapi 知识
webapi 知识

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
 
namespace AAAAAA.WebAPI
{
    /// <summary>
    /// WebApi全局设置
    /// </summary>
    public class WebApiApplication : System.Web.HttpApplication
    {
        /// <summary>
        ///  第一个访问网站的用户会触发该方法. 通常会在该方法里定义一些系统变量
        ///  如聊天室的在线总人数统计,历史访问人数统计的初始化等等均可在这里定义.
        /// </summary>
        protected void Application_Start()
        {
            
        }
 
        /// <summary>
        /// 在应用程序关闭时运行的代码,在最后一个HttpApplication销毁之后执行
        /// 比如IIS重启,文件更新,进程回收导致应用程序转换到另一个应用程序域
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_End(object sender, EventArgs e)
        {
           
        }
 
        /// <summary>
        /// 每个用户访问网站的第一个页面时触发;
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Session_Start(object sender, EventArgs e)
        {
            string IP = this.Context.Request.UserHostAddress;
            Session["IP"] = IP;
        }
 
        /// <summary>
        /// 使用了session.abandon(),或session超时用户退出后均可触发.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Session_End(object sender, EventArgs e)
        {
            // Session["User"]; 向数据库中记录用户退出时间
        }
        /// <summary>
        /// 在每一个HttpApplication实例初始化的时候执行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_Init(object sender, EventArgs e)
        {
            
        }
 
        /// <summary>
        /// 在应用程序被关闭一段时间之后,在.net垃圾回收器准备回收它占用的内存的时候被调用。
        ///在每一个HttpApplication实例被销毁之前执行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_Disposed(object sender, EventArgs e)
        {
            
        }
 
        /// <summary>
        ///所有没有处理的错误都会导致这个方法的执行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_Error(object sender, EventArgs e)
        {
            #region 记录错误日志
            //Exception ex = Server.GetLastError().GetBaseException();
            //StringBuilder str = new StringBuilder();
            //str.Append("\r\n" + DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss"));
            //str.Append("\r\n.客户信息:");
 
 
            //string ip = "";
            //if (Request.ServerVariables.Get("HTTP_X_FORWARDED_FOR") != null)
            //{
            //    ip = Request.ServerVariables.Get("HTTP_X_FORWARDED_FOR").ToString().Trim();
            //}
            //else
            //{
            //    ip = Request.ServerVariables.Get("Remote_Addr").ToString().Trim();
            //}
            //str.Append("\r\n\tIp:" + ip);
            //str.Append("\r\n\t浏览器:" + Request.Browser.Browser.ToString());
            //str.Append("\r\n\t浏览器版本:" + Request.Browser.MajorVersion.ToString());
            //str.Append("\r\n\t操作系统:" + Request.Browser.Platform.ToString());
            //str.Append("\r\n.错误信息:");
            //str.Append("\r\n\t页面:" + Request.Url.ToString());
            //str.Append("\r\n\t错误信息:" + ex.Message);
            //str.Append("\r\n\t错误源:" + ex.Source);
            //str.Append("\r\n\t异常方法:" + ex.TargetSite);
            //str.Append("\r\n\t堆栈信息:" + ex.StackTrace);
            //str.Append("\r\n--------------------------------------------------------------------------------------------------");
            ////创建路径 
            //string upLoadPath = Server.MapPath("~/Logs/");
            //if (!System.IO.Directory.Exists(upLoadPath))
            //{
            //    System.IO.Directory.CreateDirectory(upLoadPath);
            //}
            ////创建文件 写入错误 
            //System.IO.File.AppendAllText(upLoadPath + DateTime.Now.ToString("yyyy.MM.dd") + ".log", str.ToString(), System.Text.Encoding.UTF8);
            ////处理完及时清理异常 
            //Server.ClearError();
            ////跳转至出错页面 
            //Response.Redirect("Error.html");
            #endregion
        }
 
 
        /// <summary>
        /// //每次请求时第一个出发的事件,这个方法第一个执行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_BeginRequest(object sender, EventArgs e)
        {
            var url =Request.Url.ToString();
 
        }
 
        /// <summary>
        ///在执行验证前发生,这是创建验证逻辑的起点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_AuthenticateRequest(object sender, EventArgs e)
        {
           
        }
 
        /// <summary>
        /// 当安全模块已经验证了当前用户的授权时执行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_AuthorizeRequest(object sender, EventArgs e)
        {
            
        }
 
        /// <summary>
        /// 当ASP.NET完成授权事件以使缓存模块从缓存中为请求提供服务时发生,从而跳过处理程序(页面或者是WebService)的执行。
        ///这样做可以改善网站的性能,这个事件还可以用来判断正文是不是从Cache中得到的。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_ResolveRequestCache(object sender, EventArgs e)
        {
            
        }
 
        /// <summary>
        /// 读取了Session所需的特定信息并且在把这些信息填充到Session之前执行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_AcquireRequestState(object sender, EventArgs e)
        {
           
        }
 
        /// <summary>
        /// 在合适的处理程序执行请求前调用
        ///这个时候,Session就可以用了
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_PreRequestHandlerExecute(object sender, EventArgs e)
        {
           
        }
 
 
        /// <summary>
        ///当处理程序完成对请求的处理后被调用。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_PostRequestHandlerExecute(object sender, EventArgs e)
        {
            
        }
 
        /// <summary>
        /// 释放请求状态
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_ReleaseRequestState(object sender, EventArgs e)
        {
           
        }
 
        /// <summary>
        /// 为了后续的请求,更新响应缓存时被调用
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_UpdateRequestCache(object sender, EventArgs e)
        {
            
        }
 
        /// <summary>
        /// EndRequest是在响应Request时最后一个触发的事件
        ///但在对象被释放或者从新建立以前,适合在这个时候清理代码
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_EndRequest(object sender, EventArgs e)
        {
            
        }
 
        /// <summary>
        /// 向客户端发送Http标头之前被调用
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_PreSendRequestHeaders(object sender, EventArgs e)
        {
            
        }
 
        /// <summary>
        /// 向客户端发送Http正文之前被调用
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Application_PreSendRequestContent(object sender, EventArgs e)
        {
            
        }
    }
}

View Code

    App_Start:这里面主要是程序启动的时候需要进行的一下注册文件,比如路由,文件筛选什么的;

其他的就不介绍了。

              打开框架默认提供的控制器【ValuesController】,可以看到内部提供了5个demo,分别是无参Get,带参Get,Post,Put,Delete的请求方式,其中Post和Put的例子参数都是带有【FromBody】特性,这里介绍一下【FromBody】和【FromUrl】;

    【FromBody】:强制接口从FormData中读取数据;

    【FromUrl】:强制接口从Uri中读取数据。

 

webApi的路由我们可以看到

webapi 知识

控制器之后是直接带参数的,程序是如何根据路由找到对应的接口的呢?

WebApi是遵循RESTful设计风格的,webapi会根据请求方式的不同来自动寻找对应的接口,

如果一个webAPI控制器内部对于同样的请求方式有多个接口,那么webapi默认路由会找不到对应的接口而报错,如果要遵循RESTful风格,可能需要对每个业务的接口进行控制器隔离。

那么如果需要改变这种请求方式,变成和MVC类似的请求,应该如何修改呢?

我们需要将webapi添加一个路由机制:

webapi 知识

这样我们就可以使用mvc模式的路由或者webapi默认路由进行接口的调用了。

WebApi是遵循Restful风格的,所以不建议在路由中出现action,不推荐使用和MVC控制器相同格式的路由

 

那么使用webapi有哪些地方需要注意呢?

  1. ajax中的type有四种方式:get(查询),post(修改),delete(删除),put(插入) 。
  2. 写webapi时,在后台的方法最好将特性标记号对应上[HttpGet],[HttpPost],[HttpDelete],[HttpPut]。如果不想在后台方法写特性,但也可以将方法名以Get开头,否则会报错。

    • get:若是查询数据,通过get,其实get请求会将参数拼装到url上面,而url长度是有限的
    • post:若是对原有数据新增和修改就用post,多用post即可。post不是将参数放在url上面的,而是放在表单上的。
  3. 传递的参数username名一定要相同,但是大小写可以不一样。

  4. 若是user={name:”张苏纳”,id:123,age:’19’} 然后data:user那么在后台是接收不到的,即使在页面调试时是可以看到数据。若是想接收到的话,需要在后台写成GetUserModeuri([FormUri]Users

    user)。

  5. 基于第4的另一种方法。可以将user序列化转化为一个字符窜,然后后台接收后反序列化即可得到。data:{userString:JSON.stringify(user)}

  6. (1)若是通过post请求的时候,是将数据放在from data里面的,若是传递单个参数,不要在ajax上不要写对应参数。 
    (2)只有不写id才能得到,与[formbody]无关。若是通过post传递实体,那么在后台可以直接拿到 ,不需要任何转化。 
    (3)当然也可以通过data:Json.stringify(user) contentType:’application/json’(contentType默认是json类型的)来在后台同样得到。 
    (4)若是参数包含了一个实体,还有一个字符串参数data:{“User”:user,”Info”:info}该怎么办,可以通过引用Newtonsoft.Json.Linq的JObject类型。jObject.ToObject是一个序列化方法,将josn转化为对象。

  7. dynamic动态类型,比如一个实体和一个参数放到同一个对象中,获取对象后,然后dynamic json=jData; var mm= 
    json.user,动态类型是可以直接访问属性的。

  8. put和post是一样的使用,put主要是插入数据使用。

  9. delete也是一样的。

  10. webapi最方便的是给前端使用。

WebAPI的路由

首先分析一下MVC路由和WebAPI路由的区别

在mvc里,默认的路由机制是通过URL路径去匹配控制器和Action方法的,在mvc中的默认路由定义在App_Start文件夹下的RouteConfig.cs文件下:

public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }

在webapi里,默认的路由机制是通过URL路径去匹配控制器,然后通过http的方法去匹配Action的,在WebAPI中的默认路由定义在App_Start文件夹下的WebApiConfig.cs文件下:

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服务

            // Web API 路由
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "RestFulApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }

WebApi的路由基础:

将MapHttpRoute方法转定义有4个重载的方法:

//
        // 摘要:
        //     映射指定的路由模板。
        //
        // 参数:
        //   routes:
        //     应用程序的路由的集合。
        //
        //   name:
        //     要映射的路由的名称。
        //
        //   routeTemplate:
        //     路由的路由模板。
        //
        // 返回结果:
        //     对映射路由的引用。
        public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate);
        //
        // 摘要:
        //     映射指定的路由模板并设置默认路由值。
        //
        // 参数:
        //   routes:
        //     应用程序的路由的集合。
        //
        //   name:
        //     要映射的路由的名称。
        //
        //   routeTemplate:
        //     路由的路由模板。
        //
        //   defaults:
        //     一个包含默认路由值的对象。
        //
        // 返回结果:
        //     对映射路由的引用。
        public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults);
        //
        // 摘要:
        //     映射指定的路由模板并设置默认路由值和约束。
        //
        // 参数:
        //   routes:
        //     应用程序的路由的集合。
        //
        //   name:
        //     要映射的路由的名称。
        //
        //   routeTemplate:
        //     路由的路由模板。
        //
        //   defaults:
        //     一个包含默认路由值的对象。
        //
        //   constraints:
        //     一组表达式,用于指定 routeTemplate 的值。
        //
        // 返回结果:
        //     对映射路由的引用。
        public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints);
        //
        // 摘要:
        //     映射指定的路由模板并设置默认的路由值、约束和终结点消息处理程序。
        //
        // 参数:
        //   routes:
        //     应用程序的路由的集合。
        //
        //   name:
        //     要映射的路由的名称。
        //
        //   routeTemplate:
        //     路由的路由模板。
        //
        //   defaults:
        //     一个包含默认路由值的对象。
        //
        //   constraints:
        //     一组表达式,用于指定 routeTemplate 的值。
        //
        //   handler:
        //     请求将被调度到的处理程序。
        //
        // 返回结果:
        //     对映射路由的引用。
        public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler);

看看每个参数的作用:

name:表明路由的名称,注册多个路由时保证不重复就行;

routeTemplate:路由匹配规则。默认是“api/{controller}/{id}”,前面的api是用来区分mvc路由的,不是必选项,是可变的,{controller}是控制器的占位符,{id}是形参的占位符;

defaults:一个包含默认路由值的对象,可以设置controller的默认值;

constraints:对形参的约束;

注册的路由是按照注册先后的顺序进行匹配的,注册越靠前,优先级越大

我们知道,WebApi是符合RESTful风格的,那么如果在一个控制器内部,我们需要提供多个相同的http方法,相同参数的接口我们应该怎么解决呢?

1:活用[Route(“”)]

在相同请求方法的action的前面可以加上[Route]路由特性进行区分:

/// <summary>
/// 这里可以通过http://localhost:xxxx/api/Values对这个action进行访问
/// </summary>
/// <returns></returns>
public IEnumerable<string> Get1()
{
return new string[] { "value1", "value2" };
}
/// <summary>
/// 这里可以通过http://localhost:xxxx/apis/Values/qqqqq对这个action进行访问
/// </summary>
/// <returns></returns>
[Route("apis/Values/qqqqq")]
public IEnumerable<string> Get2()
{
return new string[] { "value3", "value4" };
}

和朋友聊了一下,发现这个做法本身就和RESTful风格相抵触,所以就不深究了,一般是对action进行重载,而不是在这上面想办法

 

转自:https://www.cnblogs.com/yuchenghao/p/10598825.html

今天的文章webapi 知识分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/55657.html

(0)
编程小号编程小号
上一篇 2023-08-27
下一篇 2023-08-27

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注