• Web API的参数、多版本和Filter


    一、关于API的参数
    a) Web API在WebApiConfig.cs中配置了路由模板,默认为"api/{controller}/{id}",这与MVC路由模板的区别在于没有{action},会根据请求方式来找到对应的方法,只要一个Action标注了[HttpGet],那么不管Action的名称如何,Get请求都会被路由到这个Action。
    b)如果有GET请求为http:/***/api/Controller?user="u1"&pwd="p1",按照默认的路由配置,有效的GET方法可以是public string Login(string user, string pwd)。也可以使用[FromUri],但GET方法改为public string Login([FromUri]LoginModel model) ,将参数封装为Model并添加FromUri,FromUri只能标注一个参数,经试验也可以在使用FromUri的同时使用多个参数。
    c)对于Post、Put请求,也可以像Get请求那样写在URI中,但参数比较多时最好封装起来,通过Request Body传递,同时在参数上标记[FromBody]。同样的这个标记也只能使用一次。对于POST方法public string Login2(int i,[FromBody]LoginModel model,string us) 来说,请求是在url中传递的i和us参数的顺序不限。
    d)也可以模仿MVC的路由模板,配置为"api/{controller}/{action}/{id}",这样使用方式更加直观,但无法根据请求方式自动对应,且不符合REST风格。
    二、WebAPI的多版本管理
    有时在升级API的同时需要保留旧版本的API,不同的URL请求不同版本的API。这时可以将不同版本的API部署在不同的服务器或域名。或者放在同一个项目中,然后使用IHttpControllerSelector来区分不同的版本,代码如下:
    public class VersionControllerSelector : DefaultHttpControllerSelector {
      private HttpConfiguration _config;
      public VersionControllerSelector(HttpConfiguration configuration) : base(configuration) {
        _config = configuration;
      }
      public override IDictionary<string, HttpControllerDescriptor> GetControllerMapping() {
        Dictionary<string, HttpControllerDescriptor> dict = new Dictionary<string, HttpControllerDescriptor>();
        foreach (var asm in _config.Services.GetAssembliesResolver().GetAssemblies()) {
          //获取所有继承自ApiController的非抽象类
          var controllerTypes = asm.GetTypes().Where(t => !t.IsAbstract && typeof(ApiController).IsAssignableFrom(t)).ToArray();
          foreach (var ctrlType in controllerTypes) {
            //从namespace中提取版本号
            var match = Regex.Match(ctrlType.Namespace, @"_8._1_WebAPI.Controllers.v(d+)");
            if (match.Success) {
              string verNum = match.Groups[1].Value;
              string ctrlName = Regex.Match(ctrlType.Name, "(.+)Controller").Groups[1].Value;
              string key = ctrlName + "v" + verNum;
              dict[key] = new HttpControllerDescriptor(_config, ctrlName, ctrlType);
            }
          }
        }
        return dict;
      }

      public override HttpControllerDescriptor SelectController(HttpRequestMessage request) {

        var controllers = GetControllerMapping();
        //获取路由数据
        var routeData = request.GetRouteData();
        //从路由中获取当前Controller的名称
        var controllerName = (string)routeData.Values["controller"];
        //从url中获取版本号
        string verNum = Regex.Match(request.RequestUri.PathAndQuery, @"api/v(d+)").Groups[1].Value;
        //从报文头获取版本号
        //string verNum = request.Headers.GetValues("ApiVersion").Single();
        string key = controllerName + "v" + verNum;
        return controllers.ContainsKey(key) ? controllers[key] : null;
      }
    }

    然后在WebApiConfig中配置两个路由模板:
    config.Routes.MapHttpRoute(
              name: "DefaultApiv1",
              routeTemplate: "api/v1/{controller}/{id}",
              defaults: new { id = RouteParameter.Optional }
          );

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

    最后将IHttpControllerSelector用写好的VersionControllerSelector替换就可以了
    config.Services.Replace(typeof(IHttpControllerSelector), new VersionControllerSelector(config));

    三、Filter
    和MVC的Filter的写法基本类似,作用也一致,提供AOP功能。但人家直接按照异步形式写的。
    a) IAuthorizationFilter的基本使用
    public class MyAuthFilter : IAuthorizationFilter {
      public bool AllowMultiple => true;

      public async Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) {
        IEnumerable<string> values;
        if (actionContext.Request.Headers.TryGetValues("UserName", out values)) {
          var userName = values.FirstOrDefault();
          if (!userName.Equals("admin")) {
            return new HttpResponseMessage(HttpStatusCode.Unauthorized);
          }
        }
        else {
          return new HttpResponseMessage(HttpStatusCode.Unauthorized);
        }
        return await continuation();
      }
    }
    b) IExceptionFilter的基本使用
    public class ExceptionFilter : IExceptionFilter {
      public bool AllowMultiple => false;

      public async Task ExecuteExceptionFilterAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken) {
        using (StreamWriter writer = File.AppendText("d:/err.txt")) {
          await writer.WriteLineAsync(actionExecutedContext.Exception.ToString());
        }
      }
    }


    学习资料:如鹏网.net提高班http://www.rupeng.com/News/10/4603.shtml

  • 相关阅读:
    eclipse导入项目后出现红色叉号
    java.lang.ArithmeticException: Non-terminating decimal expansion
    IDEA 2020 注册码
    最新调查:游戏女性玩家群体达3亿!这意味着什么,嘻嘻......
    Linux安装配置Nginx服务器
    mysql/mariadb 远程登陆
    redis 集群 新增 master 节点 与 slave 挂靠命令
    RedisCluster 集群 之 Ruby 安装
    Linux CentOS 7 关闭防火墙
    springcloud 与 springboot 对应关系
  • 原文地址:https://www.cnblogs.com/zhixin9001/p/7745530.html
Copyright © 2020-2023  润新知