国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

如何改寫(xiě)WebApi部分默認(rèn)規(guī)則

2019-11-17 02:13:59
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

如何改寫(xiě)WebApi部分默認(rèn)規(guī)則

為什么要改

最近公司在推廣SOA框架,第一次正經(jīng)接觸這種技術(shù)(之前也有但還是忽略掉吧),感覺(jué)挺好,就想自己也折騰一下,實(shí)現(xiàn)一個(gè)簡(jiǎn)單的SOA框架

用過(guò)mvc進(jìn)行開(kāi)發(fā),印象之中WebApi和Mvc好像是一樣的,帶著這樣的預(yù)設(shè)開(kāi)始玩WebApi,然后被虐得找不到著北。

被虐的原因,是Mvc和WebApi在細(xì)節(jié)上差別還是有點(diǎn)大,例如:

  1. 在Mvc中,一個(gè)Controller中的所有公共方法一般情況下可以響應(yīng)POST方法,而WebApi中不行
  2. 在Mvc中,一個(gè)Action方法中的參數(shù)即可來(lái)自Url,也可以來(lái)自Form,而WebApi中不是這樣,具體的規(guī)則好像是除非你在參數(shù)中加了[FromBody],否則這個(gè)參數(shù)永遠(yuǎn)也無(wú)法從Form中獲取

這是這兩種技術(shù)我知道的最大的差別,其他的沒(méi)發(fā)現(xiàn)或者說(shuō)是沒(méi)注意,也有可能這些差別是因?yàn)槲也粫?huì)用,畢竟接觸WebApi時(shí)間不長(zhǎng)。如果我有些地方說(shuō)錯(cuò)了,請(qǐng)指正。

就這兩個(gè)不同點(diǎn),我查了很多資料,也沒(méi)有辦法解決,第一個(gè)還好,加個(gè)特性就行了,第二個(gè)的話好像就算加了[FromBody]也還是不行,感覺(jué)就是一堆限制。接著,既然這么多讓我不爽的地方,那我就來(lái)改造它吧。

改造的目標(biāo),有以下幾個(gè):

  1. 不再限制控制器必須以Controller結(jié)尾,其實(shí)這個(gè)并不是必須,只是被限制著確實(shí)不太舒服
  2. 所有方法可以響應(yīng)所有的請(qǐng)求方法,如果存在方法名相同的方法,那么才需要特性來(lái)區(qū)分
  3. Action中的參數(shù)優(yōu)先從Url中獲取,再?gòu)腂ody中獲取,從Body中獲取的時(shí)候,優(yōu)先假設(shè)Body中的數(shù)據(jù)是表單參數(shù),若不是則將Body中的數(shù)據(jù)當(dāng)作json或xml數(shù)據(jù)進(jìn)行獲取

定下了目標(biāo)之后,感覺(jué)微軟為什么要這樣設(shè)計(jì)WebApi呢,或許它有它的道理。

目標(biāo)好定,做起來(lái)真是頭大,一開(kāi)始想?yún)⒖脊镜腟OA框架的實(shí)現(xiàn),但因?yàn)槲矣昧薕WIN技術(shù)來(lái)進(jìn)行宿主,而看了公司的框架好像不是用的這個(gè),總之就是看了半天沒(méi)看懂應(yīng)該從哪個(gè)地方開(kāi)始,反而是越看越糊,畢竟不是完全一樣的技術(shù),所以還是自己弄吧。

OK,廢話了這么多,進(jìn)入正題吧。首先來(lái)一個(gè)鏈接,沒(méi)了這個(gè)文章我就不可能改造成功:http://www.survivalescaperooms.com/beginor/archive/2012/03/22/2411496.html

OWIN宿主

其實(shí)這個(gè)網(wǎng)上很多,我主要是為了貼代碼,不然的話下面幾小節(jié)寫(xiě)不下去

  1. [assembly: OwinStartup(typeof(Startup))]//這句是在IIS宿主的時(shí)候使用的,作用是.Net會(huì)查找Startup類來(lái)啟動(dòng)整個(gè)服務(wù)
  2. namespace Xinchen.SOA.Server
  3. {
  4. public class Startup
  5. {
  6. public void Configuration(IAppBuilder appBuilder)
  7. {
  8. HttpConfiguration config = new HttpConfiguration();
  9. config.Routes.MapHttPRoute(
  10. name: "DefaultApi",
  11. routeTemplate: "{controller}/{action}"
  12. );
  13. config.Services.Add(typeof(ValueProviderFactory), new MyValueProviderFactory());//自定義參數(shù)查找,實(shí)現(xiàn)第三個(gè)目標(biāo)
  14. config.Services.Replace(typeof(IHttpControllerSelector), new ControllerSelector(config));//自定義控制器查找,實(shí)現(xiàn)第一個(gè)目標(biāo)
  15. config.Services.Replace(typeof(IHttpActionSelector), new HttpActionSelector());//自定義Action查找,實(shí)現(xiàn)第二個(gè)目標(biāo)
  16. appBuilder.UseWebApi(config);
  17. }
  18. }
  19. }

省略了部分不太重要的代碼,Services.Add和Replace從字面就能明白是什么意思,但我沒(méi)有試過(guò)是否必須要像上面那樣寫(xiě)才行

對(duì)控制器的限制

  1. public class ControllerSelector : IHttpControllerSelector
  2. {
  3. HttpConfiguration _config;
  4. IDictionary<string, HttpControllerDescriptor> _desriptors = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
  5. public ControllerSelector(HttpConfiguration config)
  6. {
  7. _config = config;
  8. }
  9. void InitControllers()
  10. {
  11. if (_desriptors.Count <= 0)
  12. {
  13. lock (_desriptors)
  14. {
  15. if (_desriptors.Count <= 0)
  16. {
  17. var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(x => !x.GlobalAssemblyCache && !x.IsDynamic);
  18. var controllerTypes = new List<Type>();
  19. foreach (var ass in assemblies)
  20. {
  21. controllerTypes.AddRange(ass.GetExportedTypes().Where(x => typeof(ApiController).IsAssignableFrom(x)));
  22. }
  23. var descriptors = new Dictionary<string, HttpControllerDescriptor>();
  24. foreach (var controllerType in controllerTypes)
  25. {
  26. var descriptor = new HttpControllerDescriptor(_config, controllerType.Name, controllerType);
  27. _desriptors.Add(descriptor.ControllerName, descriptor);
  28. }
  29. }
  30. }
  31. }
  32. }
  33. public IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
  34. {
  35. InitControllers();
  36. return _desriptors;
  37. }
  38. public System.Web.Http.Controllers.HttpControllerDescriptor SelectController(System.Net.Http.HttpRequestMessage request)
  39. {
  40. InitControllers();
  41. var routeData = request.GetRouteData();
  42. var controllerName = Convert.ToString(routeData.Values.Get("controller"));
  43. if (string.IsNullOrWhiteSpace(controllerName))
  44. {
  45. throw new ArgumentException(string.Format("沒(méi)有在路由信息中找到controller"));
  46. }
  47. return _desriptors.Get(controllerName);
  48. }
  49. }

這個(gè)其實(shí)比較簡(jiǎn)單,測(cè)試中WebApi好像沒(méi)調(diào)用GetControllerMapping方法,直接調(diào)用了SelectController方法,最后一個(gè)方法中有兩個(gè)Get方法調(diào)用,Get只是把從字典獲取值的TryGetValue功能給封裝了一下,InitControllers方法是從當(dāng)前所有的程序集中找繼承了ApiController的類,找到之后緩存起來(lái)。這段代碼整體比較簡(jiǎn)單。

對(duì)Action的限制

  1. public class HttpActionSelector : IHttpActionSelector
  2. {
  3. public ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor)
  4. {
  5. var methods = controllerDescriptor.ControllerType.GetMethods();
  6. var result = new List<HttpActionDescriptor>();
  7. foreach (var method in methods)
  8. {
  9. var descriptor = new ReflectedHttpActionDescriptor(controllerDescriptor, method);
  10. result.Add(descriptor);
  11. }
  12. return result.ToLookup(x => x.ActionName);
  13. }
  14. public HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
  15. {
  16. var actionDescriptor = new ReflectedHttpActionDescriptor();
  17. var routeData = controllerContext.RouteData;
  18. object action = string.Empty;
  19. if (!routeData.Values.TryGetValue("action", out action))
  20. {
  21. throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(System.Net.HttpStatusCode.NotFound, "在路由中未找到action"));
  22. }
  23. string actionName = action.ToString().ToLower();
  24. var methods = controllerContext.ControllerDescriptor.ControllerType.GetMethods().Where(x => x.Name.ToLower() == actionName);
  25. var count = methods.Count();
  26. MethodInfo method = null;
  27. switch (count)
  28. {
  29. case 0:
  30. throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(System.Net.HttpStatusCode.NotFound, "在控制器" + controllerContext.ControllerDescriptor.ControllerName + "中未找到名為" + actionName + "的方法"));
  31. case 1:
  32. method = methods.FirstOrDefault();
  33. break;
  34. default:
  35. var httpMethod = controllerContext.Request.Method;
  36. var filterdMethods = methods.Where(x =>
  37. {
  38. var verb = x.GetCustomAttribute<AcceptVerbsAttribute>();
  39. if (verb == null)
  40. {
  41. throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(System.Net.HttpStatusCode.NotFound, "在控制器" + controllerContext.ControllerDescriptor.ControllerName + "中找到多個(gè)名為" + actionName + "的方法,請(qǐng)考慮為這些方法加上AcceptVerbsAttribute特性"));
  42. }
  43. return verb.HttpMethods.Contains(httpMethod);
  44. });
  45. if (filterdMethods.Count() > 1)
  46. {
  47. throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(System.Net.HttpStatusCode.NotFound, "在控制器" + controllerContext.ControllerDescriptor.ControllerName + "中找到多個(gè)名為" + actionName + "的方法,并且這些方法的AcceptVerbsAttribute都含有" + httpMethod.ToString() + ",發(fā)生重復(fù)"));
  48. }
  49. else if (filterdMethods.Count() <= 0)
  50. {
  51. throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(System.Net.HttpStatusCode.NotFound, "在控制器" + controllerContext.ControllerDescriptor.ControllerName + "中找到多個(gè)名為" + actionName + "的方法,但沒(méi)有方法被配置為可以響應(yīng)" + httpMethod.ToString() + "請(qǐng)求"));
  52. }
  53. method = filterdMethods.FirstOrDefault();
  54. break;
  55. }
  56. return new ReflectedHttpActionDescriptor(controllerContext.ControllerDescriptor, method);
  57. }
  58. }

GetActionMapping方法很簡(jiǎn)單,從控制器類型中找到所有的Action方法并返回

SelectAction方法相對(duì)復(fù)雜,其實(shí)就是第二個(gè)目標(biāo)的邏輯,代碼看起來(lái)比較多其實(shí)并有很難的地方。

對(duì)Action的參數(shù)的限制

這一塊比較難,我試了很久才成功,而且還有坑

  1. public class ActionValueBinder : DefaultActionValueBinder
  2. {
  3. protected override HttpParameterBinding GetParameterBinding(HttpParameterDescriptor parameter)
  4. {
  5. ParameterBindingAttribute parameterBinderAttribute = parameter.ParameterBinderAttribute;
  6. if (parameterBinderAttribute == null)
  7. {
  8. ParameterBindingRulesCollection parameterBindingRules = parameter.Configuratio
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 龙口市| 山东| 甘泉县| 三台县| 海原县| 宁都县| 岳西县| 富顺县| 大同市| 株洲市| 乌恰县| 衡水市| 天镇县| 彭阳县| 盐山县| 乐山市| 枞阳县| 军事| 米泉市| 信宜市| 无棣县| 广宁县| 永德县| 涡阳县| 泸西县| 山丹县| 阿荣旗| 南阳市| 兴山县| 石棉县| 景德镇市| 汤阴县| 北票市| 博野县| 探索| 黑山县| 泾阳县| 乌拉特前旗| 临朐县| 漯河市| 金溪县|