www.2527.com_澳门新葡8455手机版_新京葡娱乐场网址_
做最好的网站

WebAPI设置路由和参数贰,多版本和Filter

2019-05-02 15:05 来源:未知

一.方面已经教大家怎么样修改全局路由了,那么修改完后大家在post请求的要如此使用,个中model模型笔者就暗中同意你应该早就建好了,未有开创的话请看上一部分

一、关于API的参数
a) Web API在WebApiConfig.cs中配备了路由模板,暗中认可为"api/{controller}/{id}",那与MVC路由模板的分别在于未有{action},会依赖请求格局来找到相应的不二等秘书诀,只要三个Action标注了[HttpGet],那么不管Action的称谓怎样,Get请求都会被路由到那么些Action。
b)如果有GET请求为http:/***/api/Controller?user="u一"&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请求那样写在U汉兰达I中,但参数相比较多时最佳封装起来,通过Request Body传递,同时在参数上标识[FromBody]。一样的那一个符号也只好利用3回。对于POST方法public string Login二(int i,[FromBody]LoginModel model,string us) 来讲,请求是在url中传送的i和us参数的次第不限。
d)也能够依样画葫芦MVC的路由模板,配置为"api/{controller}/{action}/{id}",那样使用格局越来越直观,但不可能依照请求方式自行对应,且不吻合REST风格。
二、WebAPI的多版本管理
偶尔在晋级API的同时供给保留旧版本的API,区别的UBMWX伍L请求例外版本的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;
  }

今天,依照AngularJS贰的壮士指南教程走了1回,教程网站是。

Post方法的参数,假使提交的请求体需假若phoneNum=1二三&password=1二三这么的格式。假诺用string AddNew(string phoneNum, string password)那种平凡参数会有为数不少的坑(参考《C#进阶体系—— WebApi 接口参数不再质疑:传参详解》),所以不用用。都用模子对象,public string AddNew二(LoginModel model),也得以参数标注[FromBody]:public string AddNew2([FromBody]LoginModel model)。(只好有2个参数标注FromBody)。

  public override HttpControllerDescriptor SelectController(HttpRequestMessage request) {

在步骤达成后,又更进一步,在英勇增加和删除改的时候,直接调用.net core的WebApi来得以落成后台数据的操作,替换教程中的模拟WebApi格局。在替换.net core WebApi时,依旧碰到了部分坑的,这里记录一下。

图片 1图片 2

    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;
  }
}

先来看一下WebApi和AngularJS的源代码:

[HttpPost]
        public bool Login4(LoginModel model)//也可以参数标注[FromBody]LoginModel model
        {
            if (model.phoneNum == "123" && model.password == "123")
            {
                return true;
            }
            else
            {
                return false;
            }
        }

接下来在WebApiConfig中安插多个路由模板:
config.Routes.MapHttpRoute(
          name: "DefaultApiv1",
          routeTemplate: "api/v1/{controller}/{id}",
          defaults: new { id = RouteParameter.Optional }
      );

WebApi

View Code

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

图片 3图片 4

图片 5

谈到底将IHttpControllerSelector用写好的VersionControllerSelector替换就足以了
config.Services.Replace(typeof(IHttpControllerSelector), new VersionControllerSelector(config));

 1     [Route("api/[controller]")]
 2     public class ValuesController : Controller
 3     {
 4         private List<Hero> heroes;
 5 
 6         public ValuesController()
 7         {
 8             heroes = GetHeroes()
 9 
10         }
11 
12         [HttpGet]
13         public IEnumerable<Hero> Get()
14         {
15             return heroes;
16         }
17 
18         [HttpGet("{id}")]
19         public Hero Get(int id)
20         {
21             return heroes.Single(h => h.Id == id);
22         }
23 
24         [HttpGet]
25         [Route("GetList")]
26         public IEnumerable<Hero> GetList(string key)
27         {
28             return heroes.Where(h => h.Name.Contains(key));
29         }
30 
31         [HttpPost]
32         public void Post([FromBody]Hero info)
33         {
34             Hero hero = new Hero();
35 
36             hero.Id = heroes.Max(h => h.Id)   1;
37             hero.Name = info.Name;
38 
39             AddHeroes(hero);
40         }
41 
42         [HttpPut("{id}")]
43         public void Put(int id, [FromBody]Hero hero)
44         {
45             Hero x = heroes.Single(h => h.Id == id);
46 
47             x.Name = hero.Name;
48 
49             UpdateHeroes(x);
50         }
51 
52         [HttpDelete("{id}")]
53         public void Delete(int id)
54         {
55             Hero hero = heroes.Single(h => h.Id == id);
56             RemoveHeroes (hero);
57         }
58 }

二.由此自定义路由规则来捕获参数

三、Filter
和MVC的Filter的写法基本类似,成效也一近年来后,提供AOP作用。但住户直接遵照异步方式写的。
a) IAuthorizationFilter的为主选择
public class MyAuthFilter : IAuthorizationFilter {
  public bool AllowMultiple => true;

View Code

WebAPI可以通过[Route]和[RoutePrefix]源于定义路由,[RoutePrefix]作用于Controller,[Route]功能于Action,壹旦四个Controller或许Action设置了[Route]、[RoutePrefix]那么设置的routeTemplate讲在 那个Controller恐怕Action中就不起功能了。

  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;

 

(1)[Route]自定义路由

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

AngularJS

图片 6图片 7

读书材料:如鹏网.net提升班

图片 8图片 9

[Route("Login/{phoneNum}/{password}")]
        [HttpGet]
        public string Login5(string phoneNum, string password)
        {
            return string.Format("Login5-->phoneNum:{0},password:{1}", phoneNum, password);
        }
 1     getHeroes(): Promise<Hero[]> {
 2         return this.http.get(this.heroUrl).toPromise().then(response => response.json() as Hero[]).catch(this.handleError);
 3     }
 4 
 5     getHero(id: number): Promise<Hero> {
 6         return this.getHeroes().then(heroes => heroes.find(hero => hero.id === id));
 7     }
 8 
 9     getHeroesSlowly(): Promise<Hero[]> {
10         return new Promise<Hero[]>(resolve =>
11             setTimeout(resolve, 2000)) // delay 2 seconds
12             .then(() => this.getHeroes());
13     }
14 
15     updateHero(hero: Hero): Promise<Hero> {
16         const url = `${this.heroUrl}/${hero.id}`;
17         return this.http
18             .put(url, JSON.stringify(hero), { headers: this.headers })
19             .toPromise()
20             .then(() => hero)
21             .catch(this.handleError);
22     }
23 
24     addHero(heroName: string): Promise<Hero> {
25         return this.http
26             .post(this.heroUrl, JSON.stringify({ name: name }), { headers: this.headers })
27             .toPromise()
28             .then(response => response.json())
29             .catch(this.handleError);
30     }
31 
32     deleteHero(heroId: number): Promise<void> {
33         const url = `${this.heroUrl}/${heroId}`;
34         return this.http
35             .delete(url, { headers: this.headers })
36             .toPromise()
37             .then(() => null)
38             .catch(this.handleError);
39     }
40 
41     search(term: string): Observable<Hero[]> {
42         return this.http.get(`${this.heroUrl}/GetList?key=${term}`).map((r: Response) => r.json() as Hero[]);
43     }
44 
45     private handleError(error: any): Promise<any> {
46         console.error('An error occurred', error); // for demo purposes only
47         return Promise.reject(error.message | error);
48     }

View Code

View Code

图片 10

 

(二)每一种方法都[Route]自定义太费力,[RoutePrefix]功用于Controller适用内部装有办法

1、跨域访问(Cors)难题

图片 11图片 12

在建好WebApi站点,运行运营,1切符合规律。大家仅呈现前五个Action,结果如下:

//当然每个Action都设定api/Login很麻烦,可以在Controller上标注[RoutePrefix("api/Login")](路径不能以/结尾)
    [RoutePrefix("api/Login")]
    public class LoginController : ApiController
    {
        [HttpGet]
        public string LoginAction(string phoneNum, string password)
        {
            return string.Format("Login-->phoneNum:{0},password:{1}", phoneNum, password);
        }
    }

图片 13

View Code

图片 14

 图片 15

可是,在AngularJS客户端,出现了难题,分界面未有其他英豪辈出。

 

图片 16

总结:

再查Chrome的调整台,开采了难题所在,WebApi的Access-Control-Allow-Origin没有开,也正是跨域访问不经过。

一.如若运用 Post 请求,那么就须要种种方法都宣示二个参数对应的类,参数前可标注[FromBody]。

图片 17

二.一旦运用 Get 请求,那么参数相比较轻松,但是急需专注防备缓存(使用 ajax 的话加上多少个当下时间或许 随机数的参数,使用 HttpClient 等急需禁止使用缓存)。

跨域访问,就是JS访问其余网站的新闻。比方这里的AngularJS的

三.借使用 Get 格局,参数既能够用一般参数也足以用模子类参数,须要专注防止缓存;如 果 用 Post 方 式 , 参 数 壹 定 要 用 模 型 类 , 客 户 端 既 可 以 用 ContentType=” application/x-www-form-urlencoded”提交表单,也足以用 ContentType=”application/json”提交。

1     getHeroes(): Promise<Hero[]> {
2         return this.http.get(this.heroUrl).toPromise().then(response => response.json() as Hero[]).catch(this.handleError);
3     }

4.路由设置的话根据项目情状设置,适合的才是好的,切记不要搞得太乱。

格局中,调用heroUrl(WebApi网址)。AngularJS的网址是,而WebApi的网站是。只要协议、域名、端口有别的2个差别,都被用作是见仁见智的域。默许情状下是不帮助直接跨域访问的。为了在WebiApi中加进跨域访问,大家要在WebApi的Startup.cs中开拓Access-Control-Allow-Origin:

 

1         public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
2         {
3             app.UseCors(builder =>
4             {
5                 builder.AllowAnyOrigin();
6             });
7 
8             app.UseMvc();
9         }

 

现在程序访问符合规律。

图片 18

笔者们查看AngularJS网址的network意况,在values的headers—Response Headers中有Access-Control-Allow-Origin: **的字样,这样就消除了眼前出现的"No Access-Control-Allow-Origin header is present…*"错误。

图片 19

 

再持续测试,又冒出难题了,此次是在创新时

图片 20

错误音信如下:

图片 21

我们都曾经张开Access-Control-Allow-Origin,怎么还报错:"No Access-Control-Allow-Origin header is present…"?大家回过来看AngularJS,调用的是Update:

1     updateHero(hero: Hero): Promise<Hero> {
2         const url = `${this.heroUrl}/${hero.id}`;
3         return this.http
4             .put(url, JSON.stringify(hero), { headers: this.headers })
5             .toPromise()
6             .then(() => hero)
7             .catch(this.handleError);
8     }

 

对应WebApi,此番调用的是Put方法

1         [HttpPut("{id}")]
2         public void Put(int id, [FromBody]Hero hero)
3         {
4             Hero x = heroes.Single(h => h.Id == id);
5 
6             x.Name = hero.Name;
7 
8             UpdateHeroes(hero.Name);
9         }

是或不是由于Method不对啊,在此之前都以Post、Get,这一次是Put。趁早,一不做,2不休,在WebApi的Startup.cs中,写成如下:

 1         public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 2         {
 3             app.UseCors(builder =>
 4             {
 5                 builder.AllowAnyOrigin();
 6                 builder.AllowAnyHeader();
 7                 builder.AllowAnyMethod();
 8             });
 9 
10             app.UseMvc();
11         }

 

同意全体Origin、Header和Method。这一次通透到底解决,运营平常化。

贰、Update方法,必须采用类

骨子里下面Update时,依旧碰着了一部分难题的。便是根据最开首的次序,大家在WebApi的Put方法中,传入的是勇于名称name,而不是Hero对象。

1         [HttpPut("{id}")]
2         public void Put(int id, [FromBody]string name)
3         {
4             Hero x = heroes.Single(h => h.Id == id);
5 
6             x.Name = name;
7 
8             UpdateHero(x);
9         }

同时AngularJS中如下:

1     updateHero(hero: Hero): Promise<Hero> {
2         const url = `${this.heroUrl}/${hero.id}`;
3         return this.http
4             .put(url, JSON.stringify({name: name}), { headers: this.headers })
5             .toPromise()
6             .then(() => hero)
7             .catch(this.handleError);
8     }

 

在程序运营时,我们修改第二叁号硬汉:

图片 22

翻看network,提交也是name: "Bombasto111一"。

图片 23

可是,在WebApi中,调节和测试情形下:

图片 24

Id没非常,可是name是null。[FromBody]渴求前台传入的是Json串,然后交给到Action中。那时,Angular传入的是{name: "Bombasto111一"},通过FromBody转变后,是二个object,而不是二个string,因而name的值是null。

假诺想用string name情势,AngularJS将要写成:

1     updateHero(hero: Hero): Promise<Hero> {
2         const url = `${this.heroUrl}/${hero.id}`;
3         return this.http
4             .put(url, JSON.stringify(hero.name), { headers: this.headers })
5             .toPromise()
6             .then(() => hero)
7             .catch(this.handleError);
8     }

 

再看network

图片 25

WebApi调节和测试景况如下图,name有值,1切解决。

图片 26

 

也得以运用Hero作为参数的章程,就像大家文书档案最开始提供的代码同样。

1     updateHero(hero: Hero): Promise<Hero> {
2         const url = `${this.heroUrl}/${hero.id}`;
3         return this.http
4             .put(url, JSON.stringify(hero), { headers: this.headers })
5             .toPromise()
6             .then(() => hero)
7             .catch(this.handleError);
8     }

 

        [HttpPut("{id}")]
        public void Put(int id, [FromBody]Hero hero)
        {
            Hero x = heroes.Single(h => h.Id == id);

            x.Name = hero.Name;

            UpdateHeroes(x);
        }

 

 

叁、路由改换

我们在做Hero Search的时候,又要在后台WebApi中编辑依据入眼字查询的办法

1         [HttpGet]
2         public IEnumerable<Hero> GetList(string key)
3         {
4             return heroes.Where(h => h.Name.Contains(key));
5         }

 

假如只有这样写,整个WebApi都倒霉用了。在调用Get时,出现了可喜的500荒谬。

图片 27

而调用Get(int id)方法,正是localhost:六千/api/values/11时,一切平常。那是为什么吧?

因为依据微软的主意,若是有五个一样Method(举个例子HttpGet)的秘诀,WebApi路由就无法分别了。这里,Get()和GetList(string key)都是[HttpGet],路由都以localhost:四千/api/values。而Get(int id)方法由于写的是[HttpGet("{id}")],网站是localhost:5000/api/values/11,与Get()路由分歧。由此,为了减轻Get()和GetList(string key),大家在getlist方法上增添钦赐路由的章程。举例这里便是

1         [HttpGet]
2         [Route("GetList")]
3         public IEnumerable<Hero> GetList(string key)
4         {
5             return heroes.Where(h => h.Name.Contains(key));
6         }

 

在AngularJS中,就能够应用localhost:四千/api/values/GetList?key=XXXX的格局调用,程序如下:

1     search(term: string): Observable<Hero[]> {
2         return this.http.get(`${this.heroUrl}/GetList?key=${term}`).map((r: Response) => r.json() as Hero[]);
3     }

 

当然了,假如想更进一步,需要再修改总体路由方式,扩张Action。那就须要在Controller上平添[Route("api/[controller]/[action]/")]的写法,并且将Action的[Route]删除。

[Route("api/[controller]/[action]/")]

public class ValuesController : Controller

 

此次是确实缓和了。

图片 28

图片 29

TAG标签:
版权声明:本文由澳门新葡8455手机版发布于计算机编程,转载请注明出处:WebAPI设置路由和参数贰,多版本和Filter