c# webapi2 实用详解

本文介绍webapi的使用知识

  1. 发布webapi的问题前端

    配置问题
        webapi的项目要前端访问,须要在web.config配置文件中添加以下配置
        在system.webServer节点下面添加
            <modules runAllManagedModulesForAllRequests="true" />
            <httpProtocol>
            <customHeaders>
                <add name="Access-Control-Allow-Origin" value="*" />
                <add name="Access-Control-Allow-Headers" value="*" />
                <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE" />
            </customHeaders>
            </httpProtocol>
        在Global.asax.cs文件中添加
            GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
  2. 最基础的demoios

    public class ProductsController : ApiController
    {
        MyTest[] tests = new MyTest[]
        {
            new MyTest {Id = 1, Name = "苹果", Category = "水果", Price = 10},
            new MyTest {Id = 2, Name = "番茄", Category = "蔬菜", Price = 5},
            new MyTest {Id = 3, Name = "猪肉", Category = "肉类", Price = 20}
        };
        public IEnumerable<MyTest> GetAllProducts()
        {
            return tests;
        }
        public IHttpActionResult GetProduct(int id)
        {
            var product = tests.FirstOrDefault(p => p.Id == id);
            if(product == null)
            {
                return NotFound();
            }
            return Ok(product);
        }
    }
    将程序编译好,而后发布出去就能够经过以下方式请求数据
    var axiosInstance = window.axios.create({
        baseURL: "http://192.168.31.198:8888/api",
        timeout: 5000
    })
    // 或者是products/2 获取具体某一条数据
    axiosInstance.get("products").then(function (res) {
        debugger
    }).catch(function (err) {
        console.log(err);
    })
  3. 控制器中方法的返回值web

    返回void 
        若是一个get方法写成
            public void GetAllProducts(){}
            那么HTTP响应状态码是204,表示没有返回内容
    返回HttpResponseMessage
        若是返回的是HttpResponseMessage对象,那么请求的HTTP响应信息就是HttpResponseMessage对象
        public HttpResponseMessage GetAllProducts()
        {
            // 建立HttpResponseMessage对象,而且将返回值设置为 叶家伟
            HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "叶家伟"); 
            // 设置响应的返回内容,StringContent用来返回字符串的Json对象
            response.Content = new StringContent(@"{""a"": ""1""}", Encoding.UTF8); 
            // 设置响应头的缓存控制
            response.Headers.CacheControl = new CacheControlHeaderValue
            {
                NoCache = false
            };
            return response;
        }
        能够直接设置  HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, tests);
        将tests可枚举对象做为返回结果
    返回IHttpActionResult
        IHttpActionResult是HttpResponseMessage的生产工厂
        若是一个控制器的方法返回一个IHttpActionResult,那么会自动调用ExecuteAsync方法建立HttpResponseMessage
        ApiController提供了不少的内置生产IHttpActionResult类型的函数,方便调用,好比OK,NotFound等
    其余类型的返回值    
        用户能够返回值类型和引用类型,web api使用媒体序列化器解析返回值类型,默认支持的数据格式有
        xml,json,bson,form-urlencoded,若是有其余类型须要本身手动的建立
        public MyTest[] GetAllProducts()
        {
            return tests;
        }
  4. 建立webapi文档页正则表达式

    首先,安装 Install-Package Microsoft.AspNet.WebApi.HelpPage
    而后,在Global.asax文件中的Application_Start方法下添加
        AreaRegistration.RegisterAllAreas();
    而后,在Areas/HelpPage/App_Start/HelpPageConfig.cs,开启
        config.SetDocumentationProvider(new XmlDocumentationProvider(
        HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml")));
    在项目属性的生成中开启XML documentation file 添加 App_Data/XMLDocument.xml
    最后发布,将相关的资源包含到项目中来,而后生成,完事儿了发布便可
    剩下的就是写注释了
  5. 路由json

    控制器中的方法能够使用 GET,POST,PUT和DELETE 开头的命名规则,来指定具体请求对应的方法
    固然,你也能够选择修饰符的方式来指定方法,支持的修饰符 HttpGet, HttpPut, HttpPost, or HttpDelete
        [HttpPost]
        public MyTest[] AllProducts()
        {
            return tests;
        }
        使用 [AcceptVerbs("GET", "HEAD")] 这种写法,能够支持多种http请求,而且还能够使用GET,POST,PUT和DELETE以外的方式
    另外若是你想把具体的方法的名称也加到请求的url中,那么能够配合上面的修饰符形式,结合下面的方法实现
        首先,将WebApiConfig.cs文件中的配置改为
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
            还能够这样配置
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{action}/{id}",
                defaults: new { controller = "Department", id = RouteParameter.Optional }
            ); // 表示若是api知足routeTemplate那么使用Department控制器匹配,若是不知足则执行其余的路由匹配规则
        控制器中的方法的写法
            [HttpPost]
            public MyTest[] AllProducts()
            {
                return tests;
            }
        url的请求方式
            post("products/AllProducts")
    若是,想无视某个方法,添加 [NonAction] 便可
  6. 路由配置axios

    路由模板,也就是路由配置中的routeTemplate选项
        "api/{controller}/yejiawei/{action}/{id}"
        其中使用花括号包裹的是占位符,能够有多个占位符
    路由参数默认值,是路由配置中的defaults参数,用来给方法的参数指定默认值
        new { id = RouteParameter.Optional } 表示id这个字段在匹配的时候能够有,也能够没有
        new { id = 2 } 表示id这个字段能够有也能够没有,可是若是没有会自动设置为2
        new { id = @"\d+" } 能够使用正则限定id能够的值
    建立路由匹配规则的方式
        除了使用config.Routes.MapHttpRoute方法建立路由规则外,还能够使用以下的方式
            IHttpRoute myRoute = config.Routes.CreateRoute(
                "api/{controller}/yejiawei/{id}",
                new { id = RouteParameter.Optional },
                null
            );
            config.Routes.Add("MyRoute", myRoute);
        MapHttpRoute方法的参数除了上面将到的name,routeTemplate,defaults还有以下的参数
            constraints 使用正则表达式,限定传参的要求
                constraints: new { id = @"/d+"}
            handler 每一个请求的分发函数
    路由字典
        var routeData = Request.GetRouteData();
        IDictionary<string, object> routes = routeData.Values;
        foreach(KeyValuePair<string, object> item in routes)
        {
            Console.WriteLine("Key: {0}, Value{1}", item.Key, item.Value);
        }
        路由匹配到的全部占位符都保存在上面的routes里面,
        若是一个占位符被设置成 RouteParameter.Optional 那么若是这个占位符没有提供的话,就不会添加到路由占位符对象里面
        defaults选项中也能够包含routeTemplate中不存在的占位符,这样能够保存一些额外的信息
    路由参数的获取方式
        默认状况下简单的数据类型从URL中获取,复杂的数据类型从请求体中获取
  7. 基于路由属性的控制器方法api

    上面咱们讲的都是基于约定的路由,由于路由规则都是在配置文件中预先定义好的,能够使用路由属性更加灵活的配置请求
    路由配置文件中
        config.MapHttpAttributeRoutes(); 这段代码就是属性路由的配置,当方法没有配置属性路由,默认使用基于约定的路由
    使用例子
        [Route("yejiawei/{id}/haha")]
        [HttpPost]
        public int AllProducts(int id)
        {
            return id;
        }
        匹配的路由 yejiawei/3/haha 注意api已经不须要了
    能够给控制器添加路由前缀
        [RoutePrefix("yejiawei")]
        那么控制器的方法只须要简写成 
            [Route("{id}/haha")] 便可
        若是有的控制器方法的前缀不一致能够使用~重写
            [Route("~/api/{id}/haha")]
        还能够添加路由约束
            [Route("{id:int}/haha")]
            支持的路由约束还有不少,自行查阅
        添加可选的路由参数
            [Route("{id:int?}/haha")] 控制器的方法要设置默认值
        添加路由参数默认值
            [Route("{id:int=2}/haha")]
  8. 路由参数跨域

    参数名称必须相同,不区分大小写
    get请求
        值类型参数从url中获取
            public string GetDepartments(string str)
            {
                return str;
            }
            符合的api
            Departments?str=bbb
    post请求
        值类型参数默认从url中获取
            public string PostDepartments(string str)
            {
                return str;
            }
            符合的api
            Departments?str=ccc
        引用类型的参数默认从请求体中获取
            public class Demo
            {
                public string Name { get; set; }
                public string Sex { get; set; }
            }
            [Route("yejiawei/Departments")]
            public Demo PostDepartments(Demo obj)
            {
                return obj;
            }
            符合的api
                axios.post("yejiawei/Departments", {
                    Name: "yejiawei",
                    Sex: "女"
                }).then( (res) => { debugger }).catch( (err) => {console.log(err);})
            注意:应用类型的参数,只能存在一个,put方法的处理方式和post一致
    若是想修改默认的参数获取规则,能够使用 
        [FromUri] 可让引用类型的属性从uri中的参数获取
            public class Demo
            {
                public string Name { get; set; }
                public string Sex { get; set; }
            }
            public Demo GetDepartments([FromUri] Demo obj)
            {
                return obj;
            }
            匹配的api以下
            axiosInstance.get("api/Departments", {
                params: {
                    Name: "yejiawei",
                    Sex: "女"
                }
            })
        [FromBody] 可让值类型从请求体中获取
            [Route("yejiawei/BodyTest")]
            public string Post ([FromBody] string name)
            {
                return name;
            }
            匹配的api以下
            axiosInstance.post("yejiawei/BodyTest", "=yejiawei")
            若是你不想上面这种奇怪的写法,能够参考以下
                首先定义一个类
                    public class Test
                    {
                        public string Name { get; set; }
                    }
                控制器方法改为以下
                    [Route("yejiawei/BodyTest")]
                    public string Post ([FromBody] Test name)
                    {
                        return name.Name;
                    }
                符合的api写法
                    axiosInstance.post("yejiawei/BodyTest", { name: "yejiawei" })
            注意:
                [FromBody] 只能使用于一个参数
  9. webapi跨域解决缓存

    使用开局介绍的配置只能简单的解决get,post不带请求体这类的跨域请求,若是想完全的跨域,请看下面
    第一步,安装 Install-Package Microsoft.AspNet.WebApi.Cors
    第二步,在WebApiConfig.cs中添加 
        config.EnableCors();
    第三步,在会被跨域的控制器上添加 
        [EnableCors(origins: "http://mywebclient.azurewebsites.net", headers: "*", methods: "*")]
        origins对应前端发请求的地址
    第四步,注释掉本文开头所说配置中的
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="*" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE" />
        干掉上面这三句句话,此时你的跨域配置已经ok了
    注:
        [EnableCors] 能够单独给一个控制器方法使用
        [DisableCors] 能够给一个单独的控制器方法禁用跨域
        开启全局跨域
            让任何一个控制器都支持跨域,只须要将上面的第二步改为
            var cors = new EnableCorsAttribute("http://localhost:3000", "*", "*");
            config.EnableCors(cors);
        设置规则的顺序
            Action > Controller > Global
        origins参数详解
            origins支持一逗号分隔,写多个跨域地址,也能够支持通配符 * 
        methods参数
            methods参数用来指定具体的http方法,能够以逗号分隔写多个,也支持通配符
        headers参数不须要手动配置,写成通配符便可
  10. 请求和响应的数据格式化app

    MIME类型指定了数据的基本格式
    在HTTP请求中 
        Accept头指定了客户端指望获得的数据格式
        Content-Type指定了请求发送的数据格式
    Web Api根据Content-Type头指定的格式类型,将请求的数据转化成对应的CLR对象,同时根据Accept头将响应的结果序列化成对应的数据格式,Web Api 内置支持JSON, XML, BSON, form-urlencoded 序列化器,这就是说这几种格式的数据Web Api会自动处理
    因此仅仅改变Content-Type和Accept就能够方便的序列化请求或者响应的数据
    媒体类型格式序列化器
        webapi可以自动识别而且处理JSON和XML数据格式,是由于Web API包含如下的内置媒体格式化器
        媒体格式化器类 
            JsonMediaTypeFormatter 处理的MIME类型 application/json, text/json 用来处理JSON格式化
            XmlMediaTypeFormatter  处理的MIME类型 application/xml, text/json 用来处理XML格式化
            FormUrlEncodedMediaTypeFormatter 处理的MIME类型 application/x-www-form-urlencoded 处理HTML表达URL编码的数据
            JQueryMvcFormUrlEncodedFormatter 处理的MIME类型 application/x-www-form-urlencoded 处理模型绑定的HTML表单URL编码的数据
        访问全部的媒体格式化器
            [Route("yejiawei/MIMEType")]
            public IEnumerable<string> Get()
            {
                IList<string> formatters = new List<string>();
                foreach(var item in GlobalConfiguration.Configuration.Formatters)
                {
                    formatters.Add(item.ToString());
                }
                return formatters.AsEnumerable<string>();
            }  
        单独访问指定的媒体格式化器
            GlobalConfiguration.Configuration.Formatters.JsonFormatter.GetType().FullName
            GlobalConfiguration.Configuration.Formatters.FormUrlEncodedFormatter.GetType().FullName
    webapi 处理Json格式的数据默认使用 PascalCase, 能够设置成支持camelCase的
        在WebApiConfig.cs中添加以下代码
        config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
  11. WebApi过滤器

    过滤器能够在控制器方法调用以前和以后执行
    简单的一个用法
        先建立一个实现ActionFilterAttribute的类
            public class LogAttribute : ActionFilterAttribute
            {
                public LogAttribute()
                {
                }
                public override void OnActionExecuting(HttpActionContext actionContext)
                {
                    Trace.WriteLine(string.Format("Action Method {0} executing at {1}", actionContext.ActionDescriptor.ActionName, DateTime.Now.ToShortDateString()), "Web API Logs");
                }
                public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
                {
                    Trace.WriteLine(string.Format("Action Method {0} executed at {1}", actionExecutedContext.ActionContext.ActionDescriptor.ActionName, DateTime.Now.ToShortDateString()), "Web API Logs");
                }
            }
        而后在控制器类的头部添加属性 [Log] 便可,当控制器调用方法时,OnActionExecuting会执行,当方法调用完毕之后OnActionExecuted会执行
  12. WebApi使用注意点

    在写post,put请求以前,要先使用 ModelState.IsValid 判断一下,传进来的引用类型参数是否包含有效值
相关文章
相关标签/搜索