如何重寫WebApi的壹些默認規則?最近為什麽要改變SOA框架?是公司第壹次接觸這種技術(之前也有,先不理會)。感覺不錯,所以想自己折騰壹下,實現壹個簡單的SOA框架。
我是用mvc開發的,印象中好像WebApi和Mvc是壹樣的。我就這樣預置開始玩WebApi,然後就被虐的找不到北了。
被濫用的原因是Mvc和WebApi在細節上還是有點區別的,比如:
在Mvc中,控制器中的所有公共* * *方法壹般都可以響應POST方法,但在WebApi中不行。在Mvc中,Action方法中的參數可以來自Url或Form,但不能來自WebApi。具體的規則好像是,除非妳給參數加上[FromBody],否則,永遠不會從表單中獲取這個參數。這是我所知道的兩種技術最大的區別。其他的沒有被發現或者關註。也有可能這些不同是因為我不會用。畢竟我接觸WebApi的時間不長。如果我犯了壹些錯誤,請糾正我。
我查了很多關於這兩個區別的資料,卻找不到解決的辦法。第壹個還好,加個功能就行,第二個好像即使加了[FromBody]也不行,感覺就是壹堆限制。然後,既然有那麽多讓我不爽的事情,我就改造壹下吧。
轉型的目標如下:
不再限制控制器必須以控制器結尾。其實沒必要這樣,但是真的很難受。所有方法都可以響應所有請求的方法。如果有相同方法名的方法,那麽首先需要特征來區分Url中的參數,然後區分主體中的參數。從主體獲取時,假設主體中的數據首先是壹個表單參數。如果不把獲取主體中數據的目標定為json或者xml數據,微軟為什麽要這樣設計WebApi?也許有它的原因。
目標好定,做起來真的是大事。壹開始想參考公司的SOA框架的實現,但是因為是用OWIN技術托管的,看了公司的框架好像沒有用這個。總之看了半天不明白從何下手,反而越來越迷茫。畢竟不是完全壹樣的技術,還是自己做吧。
好了,廢話那麽多,言歸正傳。首先,我們來做個鏈接。沒有這篇文章,我不可能成功轉型:blogs . com/beginor/archive/2012/03/22/2411496 . html。
事實上,互聯網上有許多OWIN主機。我主要是貼代碼,不然後面幾節寫不出來。
[assembly:owl startup(type of(startup)]//在托管IIS時使用這句話。功能是。Net會找到啟動類來啟動整個服務namespace xinchen . SOA . server { public class Startup { public void configuration(IAPP生成器App Builder){ http configuration config = new http configuration();配置。routes . MapHttPRoute(name:" default API ",route template:" { controller }/{ action } ");配置。services . Add(type of(ValueProviderFactory),new MyValueProviderFactory());//自定義參數查找實現第三個目標config . services . replace(type of(ihttpcontroller選擇器),new controller選擇器(config));//用戶自定義控制器查找實現第壹個目標config . services . replace(type of(ihttpartitionselector),new httppartitionselector());//自定義動作查找實現第二個目標appBuilder。use webapi(config);}}}省略了壹些不重要的代碼。服務。Add和Replace可以從字面上理解它們的意思,但是我沒有試過是否有必要這麽寫。
對控制器的限制公共類控制器選擇器:ihttpcontroller選擇器{ httpconfiguration _ config字典& ltstring,HttpControllerDescriptor & gt_ desriptors =新詞典& ltstring,HttpControllerDescriptor & gt(StringComparer。普通案件);公共控制器選擇器(http configuration config){ _ config = config;} void init controllers(){ if(_ descriptors。計數& lt= 0){ lock(_ descriptor){ if(_ descriptor。計數& lt= 0) { var assemblies = AppDomain。CurrentDomain.GetAssemblies()。其中(x = & gt!十.全球程序集緩存和。& amp!x . is dynamic);var controllerTypes =新列表<。Type & gt();foreach(程序集中的變量ass){ controller types。AddRange(ass。GetExportedTypes()。其中(x = & gttypeof(ApiController)。IsAssignableFrom(x)));} var descriptors =新詞典& ltstring,HttpControllerDescriptor & gt();foreach(controllerTypes中的var controller type){ var descriptor = new HttpControllerDescriptor(_ config,controller type。名稱,controller type);_描述符。添加(描述符。控制器名,描述符);} } } } }公共字典& ltstring,HttpControllerDescriptor & gtGetControllerMapping(){ init controllers();return _ desriptors}公共系統。web . http . controllers . httpcontrollerdescriptor select controller(System。Net.Http.HttpRequestMessage請求){ init controllers();var routeData = request。GetRouteData();var controllerName = Convert。ToString(routeData。values . Get(" controller "));If(字符串。isnullwhitespace(控制器名稱)){拋出新參數異常(字符串。format("在路由信息中找不到控制器");} return _ desriptors。get(controller name);}}這個其實比較簡單。在測試中,似乎WebApi沒有調用GetControllerMapping方法,而是直接調用了SelectController方法。在最後壹個方法中,有兩個Get方法調用。Get只是封裝了從字典中嘗試TryGetValue的函數。InitControllers方法是從所有當前程序集中查找繼承ApiController的類,並在找到它們後緩存它們。這段代碼整體上相對簡單。
對操作的限制public class http actions elector:ihttpactionselector { public I lookup
打破;默認值:var http method = controller context。Request .方法;var filterdMethods =方法。其中(x = & gt{ var verb = x . GetCustomAttribute & lt;AcceptVerbsAttribute & gt();if(verb = = null){ throw new httpresponse exception(controller context。request . CreateErrorResponse(System。在控制器“+ControllerContext”中找到多個名為“+actionName+”的方法。控制器描述符。ControllerName+",請考慮給這些方法添加AcceptVerbsAttribute屬性");}返回動詞。http methods . Contains(http method);});if (filterdMethods。count()& gt;1){ throw new httpresponse exception(controller context)。request . CreateErrorResponse(System。在控制器“+ControllerContext”中找到多個名為“+actionName+”的方法。控制器描述符。ControllerName+",以及這些方法的AcceptVerbsAttribute都包含"+httpMethod。ToString()+",這是重復的");} else if (filterdMethods。count()& lt;= 0){ throw new httpresponse exception(controller context)。request . CreateErrorResponse(System。在控制器“+ControllerContext”中找到多個名為“+actionName+”的方法。控制器描述符。ControllerName+",但它們都沒有配置為響應"+httpMethod。ToString()+" request "));} method = filterdMethods。FirstOrDefault();
打破;}返回新的ReflectedHttpActionDescriptor(controller context。ControllerDescriptor,方法);} } get action映射方法很簡單,所有的動作方法都是從控制器類型中找到並返回的。
SelectAction方法比較復雜,實際上是第二個目標的邏輯。代碼中其實有很多難點。
很難限制行動的參數。我花了很長時間才成功,現在還有坑。
公共類ActionValueBinder:DefaultActionValueBinder { protected override httpparametertbinding GetParameterBinding(HttpParameterDescriptor parameter er){ ParameterBindingAttribute parameter attribute = parameter。ParameterBinderAttributeif(parameter binder attribute = = null){ parameter bindingrulescollection parameter binding rules = parameter。配置