Y - cnblogs.com · 2014-07-10 · 1.1 u Þweb asp.net web api 2 ´ v + 3 Ò1-1 tcp/ip #a 1Û õ4§...
Transcript of Y - cnblogs.com · 2014-07-10 · 1.1 u Þweb asp.net web api 2 ´ v + 3 Ò1-1 tcp/ip #a 1Û õ4§...
ASP.NET Web APIASP.NET Web API Http
Controller Action ASP.NET Web API
ASP.NET Web API
ASP.NET Web API ASP.NET Web APIASP.NET Web API
CIP ASP.NET Web API 2 . 2014.7 ISBN 978-7-121-23536-8
. A . . . TP393.092
CIP 2014 127439
173 100036
787 980 1/16 45.75 908 2014 7 1 2014 7 1 2500 108.00
010 88254888 [email protected] [email protected]
010 88258888
1
Heterogeneous Web
Service Web Service
Web Web Service SOAP WSDL WS-*
Web REST Web API Windows
WCF REST Web API ASP.NET Web
API
1
ASP.NET Web API 2
2
1.1 Web
Web World Wide Web WWW W3
W3C
WWW http://www.w3.org/WWW/ The
World Wide Web (known as "WWW, "Web" or "W3") is the universe of network-accessible information, the embodiment of human knowledge
Web
Web
Web
HTTP Hypertext Hypermedia
Web HTTP HTTP Web
1.1.1 TCP/IP HTTP
TCP/IP IP TCP
TCP/IP TCP/IP TCP/IP 1-1 4
/ HyperText/HyperMedia
Hyperlink
HTML /
4 TCP/IP
4 TCP/IP
7
1.1 Web
ASP.NET Web API 2
3
1-1 TCP/IP
TCP/IP IP TCP
IP
IP
IP
Connectionless IP
IP
TCP TCP
Duplex
TCP
1
ASP.NET Web API 2
4
TCP 16 Checksum
TCP
HTTP Hypertext Transfer Protocol TCP/IP
1-1 TCP
TCP HTTP
IP IP DNS
IP TCP Port
TCP IP HTTP
80 HTTPS TLS/SSL HTTP
443
1.1.2 Web
Web HTTP
Web
Web
XML
1.1 Web
ASP.NET Web API 2
5
JSON
Media Type
MIME Multipurpose Internet Mail Extension MIME
ASCII
MIME HTTP
� text/html HTML
� text/xml application/xml XML
� text/json application/json JSON
� image/gif image/jpeg image/png GIF JPEG PNG
� audio/mp4 audio/mpeg audio/vnd.wave MP4 MPEG WAVE
� video/mp4 video/mpeg video/quicktime MP4 MPEG QUICKTIME
URI URL URN
GUID URI Web URI
Uniform Resource Identifier
URI URL
URL URI URI URL URL URI
URI
URL Uniform Resource Locator
URL
URL IP 5
http://www.artech.com:8080/images/photo.png?size=small URL
5 http www.artech.com 8080 /images/photo.png ?size=small
1
ASP.NET Web API 2
6
URL URN URI URN Uniform
Resource Name URN
URN
1.1.3 HTTP
TCP
HTTP HTTP
/ HTTP Transaction
Web HTTP
HTTP
HTTP /
CRUD Create Retrieve Update Delete HTTP
URI HTTP HTTP Method HTTP Verb
HTTP GET POST PUT DELETE HEAD
OPTIONS TRACE CONNECTION PATCH REST
Web HTTP
3
W3C
� 100~199
� 200~299
� 300~399
� 400~499
1.1 Web
ASP.NET Web API 2
7
� 500~599
1.1.4 HTTP
Web HTTP HTTP
HTTP
� HTTP HTTP
URI HTTP HTTP
� HTTP
/
HTTP
� HTTP
Chrome www.microsoft. com HTTP
HTTP HTTP
GET http://www.microsoft.com/en-us/default.aspx HTTP/1.1
GET http://www.microsoft.com/en-us/default.aspx HTTP/1.1 Host: www.microsoft.com Connection: keep-alive Cache-Control: max-age=0 User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 Cookie: ...
1
ASP.NET Web API 2
8
Host Cache-Control
User-Agent Accept Accept-Encoding
Accept-Language Accept-Charset
Web
HTTP HTTP/1.1
200 OK
Content-Type HTML
Content-Type text/html
HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Expires: -1 Vary: Accept-Encoding Server: Microsoft-IIS/7.5 X-AspNet-Version: 2.0.50727 VTag: 791897542300000000 P3P: CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI" X-Powered-By: ASP.NET Date: Wed, 18 Jan 2012 07:06:25 GMT Content-Length: 34237 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html>…</html>
1.2 RESTful Web API REST Web Service
RPC RPC REST
REST
REST Web RESTful Web API
1.2 RESTful Web API
ASP.NET Web API 2
9
1.2.1
Web Service
Web Service SOAP REST Web Service
REST REST
2014 14
2000 Roy Thomas Fielding Architectural Styles and
the Design of Network-based Software Architectures REST
5
REST REpresentational State Transfer
SOAP REST
RESTful Fielding
Fielding REST Distributed Hypermedia
System HATEOAS Hypermedia As The Engine Of Application
State
Web
Application State Web
Representation
REpresentational State
REpresentational State Transfer REST
Web Service Web API Web Service RPC SOAP
Web Service Web SOAP Web Service Web API Web Service/Web API
RESTful
1
ASP.NET Web API 2
10
1.2.2 RESTful Web API
REST
Web REST
REST REST
Lenoard Rechardson & Sam Ruby RESTful Web Services
ROA Resource Oriented Architecture
ROA Web API RESTful Web API
URI
SOAP Web Service RPC
RESTful Web API
Web
Web
Web API
URI URI
URI URI
� http://www.artech.com/employees/c001 C001
� http://www.artech.com/sales/2013/12/31 2013 12 31
� http://www.artech.com/orders/2013/q4 2013 4
URI
Addressability URI URI
URI URL URN
1.2 RESTful Web API
ASP.NET Web API 2
11
URL
URI http://www.artech.com/employees/c001
http://www.artech.com/
orders/2013/q4 Composite
URI
URL
XML URL
<movie> <name> </name> <genre> | | </genre> <directors> <add ref="http://www.artech.com/directors/taylor-hackford"> . </add> </directors> <starring> <add ref = "http://www.artech.com/actors/al-pacino"> . </add> <add ref = "http://www.artech.com/actors/keanu-reeves "> . </add> </starring> <supportingActors> <add ref = "http://www.artech.com/actors/charlize-theron "> . </add> <add ref = "http://www.artech.com/actors/jeffrey-jones "> . </add> <add ref = "http://www.artech.com/actors/connie-nielsen"> . </add> </supportingActors> <scriptWriters> <add ref = "http://www.artech.com/scriptwriters/jonathan-lemkin"> · </add> <add ref = "http://www.artech.com/scriptwriters/tony-gilroy"> · </add> </scriptWriters> <language> </language> <poster ref = "http://www.artech.com/images/the-devil-s-advocate"/>
1
ASP.NET Web API 2
12
<story>...</story> </movie>
/ Fielding REST
REST
REST Web API
CRUD Web API
Web API
Web API Web API
public class ResourceService { public IEnumerable<Resource>[] Get(); public void Create(Resource resource); public void Update(Resource resource); public void Delete(string id); }
RESTful Web API RPC SOAP Web Service
RPC Web API
Web API
Web API
CRUD / SOAP
Web Service
public class RoleService { public IEnumerable<string> GetAllRoles(); public void CreateRole(string roleName); public void DeleteRole(string roleName); public void AddRolesInUser(string userName, string[] roleNames); public void RemoveRolesFromUser(string userName, string[] roleNames); }
RESTful Web API
1.2 RESTful Web API
ASP.NET Web API 2
13
CRUD Role Assignment
Web API
Web API
public class RolesService { public IEnumerable<string> Get(); public void Create(string roleName); public void Delete(string roleName); } public class RoleAssignmentsService { public void Create(RoleAssignment roleName); public void Delete(RoleAssignment roleName); }
HTTP
RESTful Web API
Web HTTP
Web API CRUD HTTP
HTTP Web API
ASP.NET Web API Action
HTTP Action
HTTP
public class ResourceService { public IEnumerable<Resource>[] Get(); public void Post(Resource resource); public void Put(Resource resource); public void Patch(Resource resource); public void Delete(string id); public void Head(string id); public void Options(); }
7 7 HTTP
GET HEAD OPTIONS HTTP
1
ASP.NET Web API 2
14
GET
HEAD OPTIONS
HEAD
OPTIONS
HTTP
Preflight
HTTP OPTIONS
4 HTTP POST PUT PATCH DELETE
DELETE
HTTP
POST PUT
URI URI
URI
PUT URI URI POST
URI URI
PUT POST URI ID
ID PUT ID
POST
PUT http://www.artech.com/employees/300357 HTTP/1.1 ... <employee> <id>300357</id> <name> </name> <gender> <gender> <birthdate>1981-08-24</birthdate> <department>3041</department> </employee> POST http://www.artech.com/employeesHTTP/1.1 ... <employee>
1.2 RESTful Web API
ASP.NET Web API 2
15
<name> </name> <gender> <gender> <birthdate>1981-08-24</birthdate> <department>3041</department> </employee>
POST PUT PUT
URI
URI
PUT
PUT http://www.artech.com/roles/admin HTTP/1.1 ...
PUT
URI
POST PUT HTTP POST
PUT PUT
PUT
PATCH
PATCH
HTTP
7 HTTP GET HEAD OPTIONS
Side Effect 4 HTTP
Idempotent
Side Effect
Side Effect
GET HEAD OPTIONS Side
Effect
1
ASP.NET Web API 2
16
3 HTTP GET HEAD OPTIONS DELETE
PATCH PUT
POST POST
Web API HTTP
PUT PUT
LastUpdatedTime
Auditing
PUT
LastUpdatedTime
Representaion
K
Web API
Web XML
JSON
Web API
1.2 RESTful Web API
ASP.NET Web API 2
17
XML JSON
Content-Type
� URI
en en-US URI
http://www.artech.com/en/orders/2013 2013
� Content Negotiation
Accept Accept-language
Web API
URI
URI
URI URI
URI
RESTful
RESTful
HTTP
Web API
JavaScript
URI GET
1
ASP.NET Web API 2
18
� Web API
� Web API
Web API
Web API Web API
Affinity
1.3 ASP.NET Web API
ASP.NET Web API ASP.NET MVC
ASP.NET Web API ASP.NET
MVC ASP.NET Web API ASP.NET MVC
ASP.NET Web API
ASP.NET MVC
ASP.NET MVC 5
ASP.NET Web API
ASP.NET ASP.NET Web API
ASP.NET Web API
ASP.NET Web API Web
Ajax Web API CRUD S101
1.3.1
Visual Studio ASP.NET Web API
ASP.NET Web API
1.3 ASP.NET Web API
ASP.NET Web API 2
19
Visual Studio
IDE
Visual Studio
1-2
1-2
1-2 6
Web WebApp
� Common
WebApi
ConsoleApp
� WebApi HttpController Web API
Common
� WebHost ASP.NET Web ASP.NET Web API
Web Host WebApi
� SelfHost ASP.NET Web API Self Host
WebApi
1
ASP.NET Web API 2
20
� WebApp ASP.NET Web
Ajax Web API
� ConsoleApp
Web API Common
1.3.2 Web API
Web API Common
Contact Contact
ID
public class Contact { public string Id { get; set; } public string Name { get; set; } public string PhoneNo { get; set; } public string EmailAddress { get; set; } public string Address { get; set; } }
HttpController Web API WebApi ApiController
ApiController System.Web.Http.dll
%ProgramFiles%\Microsoft ASP.NET\ASP.NET Web Stack 5\Packages\
Microsoft.AspNet.WebApi.Core.5.0.0\lib\net45
Web API ContactsController Get
Post Put Delete 4 Action
Action Get ID
ASP.NET Web API Action
HTTP HTTP
public class ContactsController: ApiController { static List<Contact> contacts;
static ContactsController() { contacts = new List<Contact>();
1.3 ASP.NET Web API
ASP.NET Web API 2
21
contacts.Add(new Contact { Id = "001", Name = " ", PhoneNo = "0512-12345678", EmailAddress = "[email protected]", Address = " 328 " }); contacts.Add(new Contact { Id = "002", Name = " ", PhoneNo = "0512-23456789", EmailAddress = "[email protected]", Address = " 328 " }); } public IEnumerable<Contact> Get(string id = null) { return from contact in contacts where contact.Id == id || string.IsNullOrEmpty(id) select contact; } public void Post(Contact contact) { contact.Id = counter.ToString("D3"); contacts.Add(contact); } public void Put(Contact contact) { contacts.Remove(contacts.First(c => c.Id == contact.Id)); contacts.Add(contact); } public void Delete(string id) { contacts.Remove(contacts.First(c => c.Id == id)); } }
contacts Contacts
Controller ID 001 002
CRUD Action
1.3.3 Web Host Web API
ASP.NET Web API
ASP.NET Web API
Web API
1
ASP.NET Web API 2
22
Web Host ASP.NET Web
Web API
1-2 Web Host Web API WebHost
ASP.NET ContactsController WebApi
System.Net.Http.dll .NET Framework
3 %ProgramFiles%\Microsoft ASP.NET\ASP.NET
Web Stack 5\Packages\
� System.Web.Http.dll \Microsoft.AspNet.WebApi.Core.5.0.0\lib\net45\
� System.Net.Formatting.Http.dll \Microsoft.AspNet.WebApi.Client.5.0.0\lib\net45\
� System.Web.Http.WebHost.dll \Microsoft.AspNet.WebApi.WebHost.5.0.0\lib\net45\
� System.Net.Http.dll
ASP.NET MVC Web Host Web API ASP.NET
ASP.NET Web API
HttpController Action
Web Host
WebHost Global.asax
Application_Start api/{controller}/{id} 3
api {controller} HttpController
{id} Action ContactsController Get
id RouteParameter.Optional
public class Global : System.Web.HttpApplication { protected void Application_Start(object sender, EventArgs e) { GlobalConfiguration.Configuration.Routes.MapHttpRoute( Name : "DefaultApi", routeTemplate : "api/{controller}/{id}", defaults : new { id = RouteParameter.Optional }); } }
HttpRouteCollection
MapHttpRoute GlobalConfiguration Configuration
1.3 ASP.NET Web API
ASP.NET Web API 2
23
HttpConfiguration Routes
ASP.NET MVC
Action ASP.NET Web API Action
HTTP Action
Action {action}
Visual Studio VS 2012 VS 2013
Web IIS Express
IIS
1-3 WebHost IIS Web URL
http://localhost/WebHost
1-3 IIS Local IIS
Web API Web Host
Web API
HTTP-GET HTTP-GET
Action ContactsController Get
http://localhost/webhost/api/contacts
http://localhost/webhost/api/contacts/001
Ajax IIS Express
Web API Ajax
1
ASP.NET Web API 2
24
ID 001 1-4
1-4 Web API
1-4 Chrome XML
REST
ASP.NET Web API Accept
Chrome http://localhost/webhost/api/
contacts/001 XML Accept
application/xml ASP.NET Web API IE
Accept JSON
GET http://localhost/webhost/api/contacts/001 HTTP/1.1 Host: localhost Connection: keep-alive Cache-Control: max-age=0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
1.3 ASP.NET Web API
ASP.NET Web API 2
25
Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh-TW;q=0.4
ASP.NET Web API Fiddler
Web API HTTP 1-5 Fiddler
http://localhost/webhost/api/contacts/001 HTTP-GET application/
json Accept JSON
1-5 Fiddler Web API
PUT DELETE
ContactsController RESTful Web API
HTTP GET POST PUT DELETE
HTTP IIS PUT
DELETE
1
ASP.NET Web API 2
26
1-6 Fiddler http://localhost/webhost/api/
contacts/001 HTTP-DELETE ID 001
405 Method Not Allowed
HTTP-DELETE
1-6 IIS DELETE
IIS PUT DELETE WebDAVModule
HttpModule WebDAV Web-based Distributed Authoring and Versioning
HTTP
Web Server
WebDAV HttpModule
IIS WebDAV WebDAVModule
HTTP PUT DELETE WebDAV
HttpModule
<configuration> ... <system.webServer> <modules runAllManagedModulesForAllRequests="true"> <remove name="WebDAVModule" /> </modules> </system.webServer> </configuration>
1.3 ASP.NET Web API
ASP.NET Web API 2
27
1.3.4 Self Host Web API
WCF Web API IIS Self Host
Windows Forms WPF Windows Service
SelfHost Self Host
SelfHost WebApi
4 System.Net.Http.dll .NET
Framework 3 %ProgramFiles%\Microsoft
ASP.NET\ASP.NET Web Stack 5\Packages\
� System.Web.Http.dll \Microsoft.AspNet.WebApi.Core.5.0.0\lib\net45\
� System.Net.Formatting.Http.dll \Microsoft.AspNet.WebApi.Client.5.0.0\lib\net45\
� System.Web.Http.SelfHost.dll \Microsoft.AspNet.WebApi.SelfHost.5.0.0\lib\net45\
� System.Net.Http.dll
Web Host Web API
Self Host
HttpController
class Program { static void Main(string[] args) { Assembly.Load("WebApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); HttpSelfHostConfiguration configuration = new HttpSelfHostConfiguration("http://localhost/selfhost"); using (HttpSelfHostServer httpServer = new HttpSelfHostServer(configuration)) { httpServer.Configuration.Routes.MapHttpRoute( name : "DefaultApi", routeTemplate : "api/{controller}/{id}", defaults : new { id = RouteParameter.Optional });
1
ASP.NET Web API 2
28
httpServer.OpenAsync(); Console.Read(); } } }
ASP.NET Web API Self Host HttpSelfHostServer
ContactsController WebApi.dll
http://localhost/selfhost URL
HttpSelfHostConfiguration HttpSelfHostServer
HttpSelfHostConfiguration HttpSelfHostServer
Configuration Routes MapHttpRoute
Web Host OpenAsync HttpSelfHostServer
WCF WCF
ASP.NET Web API Web Host Self
Host HttpController WCF
ASP.NET Web API
ASP.NET Web API HttpController
HttpController IHttpController
Web Host BuildManager
Self Host HttpController
ContactsController
Web API
http://localhost/selfhost/api/contacts
http://localhost/selfhost/api/contacts/001 1-4
1.3.5 HttpClient Web API
.NET HttpClient Web API Web API
/ HttpClient
1.3 ASP.NET Web API
ASP.NET Web API 2
29
HTTP ConsoleApp HttpClient
Self Host Web API
Contact
Common HttpClient System.Net.Http.dll
System.Net.Formatting.Http.dll
Web API HttpClient Web API
HttpClient Task
async Process
await
class Program { static void Main(string[] args) { Process(); Console.Read(); } private async static void Process() { // HttpClient httpClient = new HttpClient(); HttpResponseMessage response = await httpClient .GetAsync("http://localhost/selfhost/api/contacts"); IEnumerable<Contact> contacts = await response.Content.ReadAsAsync<IEnumerable<Contact>>(); Console.WriteLine(" "); ListContacts(contacts); // Contact contact = new Contact { Name = " ", PhoneNo = "0512-34567890", EmailAddress = "[email protected]" }; await httpClient.PostAsJsonAsync<Contact>( "http://localhost/selfhost/api/contacts", contact); Console.WriteLine(" " " "); response = await httpClient.GetAsync( "http://localhost/selfhost/api/contacts"); contacts = await response.Content .ReadAsAsync<IEnumerable<Contact>> (); ListContacts(contacts);
1
ASP.NET Web API 2
30
// response = await httpClient.GetAsync( "http://localhost/selfhost/api/contacts/001"); contact = (await response.Content .ReadAsAsync<IEnumerable<Contact>> ()) .First(); contact.Name = " "; contact.EmailAddress = "[email protected]"; await httpClient.PutAsJsonAsync<Contact>( "http://localhost/selfhost/api/contacts/001", contact); Console.WriteLine(" “001” "); response = await httpClient.GetAsync( "http://localhost/selfhost/api/contacts"); contacts = await response.Content .ReadAsAsync<IEnumerable<Contact>> (); ListContacts(contacts); // await httpClient.DeleteAsync( "http://localhost/selfhost/api/contacts/002"); Console.WriteLine(" "002" "); response = await httpClient.GetAsync( "http://localhost/selfhost/api/contacts"); contacts = await response.Content .ReadAsAsync<IEnumerable<Contact>> (); ListContacts(contacts);
}
private static void ListContacts(IEnumerable<Contact> contacts) { foreach (Contact contact in contacts) { Console.WriteLine("{0,-6}{1,-6}{2,-20}{3,-10}", contact.Id, contact.Name, contact.EmailAddress, contact.PhoneNo); } Console.WriteLine(); } }
HttpClient GetAsync
http://localhost/selfhost/api/contacts GET HttpResponse
Message HttpResponseMessage Content
HttpContent ReadAsAsync<T>
Contact Contact
HttpClient PostAsJsonAsync<T> http://localhost/
1.3 ASP.NET Web API
ASP.NET Web API 2
31
selfhost/api/contacts POST
Contact JSON
http://localhost/selfhost/api/contacts/001 GET
ID 001
[email protected] HttpClient PutAsJsonAsync<T>
http://localhost/selfhost/api/contacts/001 PUT
HttpClient DeleteAsync http://localhost/selfhost/api/ contacts/002
DELETE ID 002
SelfHost ConsoleApp
HttpClient GetAsync PostAsJsonAsync PutAsJsonAsync
DeleteAsync
001 [email protected] 0512-12345678 002 [email protected] 0512-23456789
001 [email protected] 0512-12345678 002 [email protected] 0512-23456789 003 [email protected] 0512-34567890
001 002 [email protected] 0512-23456789 003 [email protected] 0512-34567890 001 [email protected] 0512-12345678
002 003 [email protected] 0512-34567890 001 [email protected] 0512-12345678
1.3.6
Web
1
ASP.NET Web API 2
32
Ajax Web Host Web API CRUD
1-7
1-7
1-8
1-8
Web 3 Web
1.3 ASP.NET Web API
ASP.NET Web API 2
33
jQuery Bootstrap KnockOut CSS
JavaScript
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title> </title> <link href="css/bootstrap.min.css" rel="stylesheet"> </head> <body> ... <script src="Scripts/jquery-1.10.2.min.js"></script> <script src="Scripts/bootstrap.min.js"></script> <script src="Scripts/knockout-3.0.0.js"></script> <script src="Scripts/viewmodel.js"></script> </body> </html>
jQuery JavaScript Bootstrap
HTML CSS JavaScript Twitter 2011 8
Web
Web Bootstrap ASP.NET MVC 5 Visual Studio
ASP.NET MVC Bootstrap CSS JavaScript
jQuery Ajax Web API
Bootstrap KnockOut Bootstrap
CSS Bootstrap JavaScript
MVVM Knockout
Knockout KO JavaScript
KO WPF/Silverlight MVVM Web
JavaScript Web MVVM
UI HTML
MVVM WPF/SL
Web MVVM Knockout KO
MVVM MVC Controller ViewModel
KO MVVM
ViewModel
1
ASP.NET Web API 2
34
View UI HTML KO
View UI <button> click
ViewModel function
1-9 View
ViewModel EventHandler ViewModel
Model View ViewModel
ViewModel ViewModel
View JavaScript UI
View View HTML
1-9 MVVM
KO 1-10
<span>
1-10
1.3 ASP.NET Web API
ASP.NET Web API 2
35
KO
ViewModel
View HTML data-bind
ViewModel ko.applyBindings
<div> <div><label> :</label><input data-bind="value: province" /></div> <div><label> :</label><input data-bind="value: city" /></div> <div><label> :</label><input data-bind="value: district"/></div> <div><label> :</label><input data-bind="value: street"/> <div><label> :</label><span data-bind="text: address"></span></div> <div><input type="button" data-bind="click: format" value=" "/></div> </div> <script type="text/javascript" > function AddressModel() { var self = this; self.province = ko.observable(" "); self.city = ko.observable(" "); self.district = ko.observable(" "); self.street = ko.observable(" 328 "); self.address = ko.observable(); self.format = function () { if (self.province() && self.city() && self.district() && self.street()){ var address = self.province() + " " + self.city() + " " + self.district() + " " + self.street(); self.address(address); } else { alert(" "); } }; self.format(); } ko.applyBindings(new AddressModel()); </script>
AddressModel
ViewModel AddressModel 5 province city district street address
4 Observable
1
ASP.NET Web API 2
36
HTML Observable ko.observable
AddressModel format
address address Observable
HTML
AddressModel 6 6 HTML province city district
street Value data-bind="value: { }"
address <span> Text data-bind="text: {
}" format click
data-bind="click: { }" ko.applyBindings
ViewModel
Web
HTML JavaScript
ViewModel JavaScript viewmodel.js
function ViewModel() { self = this; self.contacts = ko.observableArray(); // self.contact = ko.observable(); // // self.load = function () { $.ajax({ url : "http://localhost/webhost/api/contacts", type : "GET", success : function (result) { self.contacts(result); } }); }; // self.showDialog = function (data) { // Id " / " if (!data.Id) { data = { ID: "", Name: "", PhoneNo: "", EmailAddress: "",
1.3 ASP.NET Web API
ASP.NET Web API 2
37
Address: "" } } self.contact(data); $(".modal").modal('show'); }; // Web API / self.save = function () { $(".modal").modal('hide'); if (self.contact().Id) { $.ajax({ url : "http://localhost/webhost/api/contacts/" + self.contact.Id, type : "PUT", data : self.contact(), success : function () {self.load();} }); } else { $.ajax({ url : "http://localhost/webhost/api/contacts", type : "POST", data : self.contact(), success : function () {self.load();} }); } }; // self.delete = function (data) { $.ajax({ url : "http://localhost/webhost/api/contacts/" + data.Id, type : "DELETE", success : function () {self.load();} }); }; self.load(); } $(function () { ko.applyBindings(new ViewModel()); });
ViewModel ViewModel
contacts contact
contacts contact observableArray observable
1
ASP.NET Web API 2
38
4
� load Ajax Web API
contacts
� showDialog
Id
contact
<div> modal Bootstrap
� save Ajax Web API
contact
Id load
� delete Ajax Web API
load
HTML
HTML ViewModel HTML
<!-- --> <div id="content"> <table class="table table-striped"> <thead> <tr> <th> </th> <th> </th> <th> </th> <th></th> </tr> </thead> <tbody data-bind="foreach: contacts"> <tr> <td data-bind="text: Name"></td> <td data-bind="text: PhoneNo"></td> <td data-bind="text: EmailAddress"></td> <td> <a href="#" data-bind="click: $root.showDialog"> </a> <a href="#" data-bind="click: $root.delete"> </a>
1.3 ASP.NET Web API
ASP.NET Web API 2
39
</td> </tr> </tbody> </table> <a href="#" class="btn btn-primary" data-bind="click: showDialog">
</a> </div> <!-- / --> <div class="modal fade"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4 class="modal-title"> </h4> </div> <div class="modal-body form-horizontal" data-bind="with: contact"> <div class="form-group"> <label for="name" class="col-sm-2 control-label"> :</label> <div class="col-sm-10"> <input type="text" class="form-control" id="name" placeholder=" " data-bind="value:Name"> </div> </div> <div class="form-group"> <label for="phoneNo" class="col-sm-2 control-label"> :</label> <div class="col-sm-10"> <input type="text" class="form-control" id="phoneNo" placeholder=" " data-bind="value:PhoneNo"> </div> </div> <div class="form-group"> <label for="emailAddress" class="col-sm-2 control-label"> :</label> <div class="col-sm-10"> <input type="text" class="form-control" id="emailAddress" placeholder=" " data-bind="value:EmailAddress"> </div> </div> <div class="form-group"> <label for="address" class="col-sm-2 control-label"> :</label> <div class="col-sm-10"> <input type="text" class="form-control" id="address" placeholder=" " data-bind="value:Address"> </div>
1
ASP.NET Web API 2
40
</div> </div> <div class="modal-footer"> <a href="#" class="btn btn-default" data-dismiss="modal"> </a> <a href="#" class="btn btn-primary" data-bind="click: save"> </a> </div> </div> </div> </div>
<table> contacts
foreach <tbody data-bind="foreach: contacts"> <tr>
<td> text
<td data-bind="text: Name"></td>
showDialog delete
click <a href="#" data-bind="click: $root.showDialog"> </a>
$root KO
HTML foreach contacts
$root KO ViewModel
KO
with <div
data-bind="with: contact"> ViewModel contact 4
value <input type="text" data-bind="value:Name">
ViewModel / save click <
data-bind="click: save"> </a>
3
ASP.NET Web API
HttpMessageHandler
HttpMessageHandler HttpController
Action
HttpMessageHandler
Web API
3
ASP.NET Web API 2
104
3.1 HttpMessageHandler
ASP.NET Web API
HttpMessageHandler
HttpMessageHandler
3.1.1 HttpMessageHandler
ASP.NET Web API HttpMessageHandler
ASP.NET Web API ASP.NET
Web API
HttpMessageHandler
HttpMessageHandler
HttpMessageHandler System.Net.Http 2
ASP.NET Web API HttpRequestMessage HttpResponseMessage
HttpMessageHandler
public abstract class HttpMessageHandler : IDisposable { public void Dispose(); protected virtual void Dispose(bool disposing); protected abstract Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken); }
3.1 HttpMessageHandler
ASP.NET Web API 2
105
HttpMessageHandler
SendAsync Task
ASP.NET Web API
SendAsync request HttpMessageHandler
HttpRequestMessage cancellationToken
CancellationToken .NET
SendAsync
SendAsync
Task<HttpResponseMessage> HttpMessageHandler
3-1
3-1 HttpMessageHandler
HttpMessageHandler IDisposable Dispose
Dispose HttpMessageHandler
HttpMessageHandler
Dispose
public abstract class HttpMessageHandler : IDisposable {
3
ASP.NET Web API 2
106
// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {} }
3.1.2 DelegatingHandler
ASP.NET Web API HttpMessageHandler
DelegatingHandler
DelegatingHandler
HttpMessageHandler DelegatingHandler
DelegatingHandler
DelegatingHandler HttpMessageHandler
HttpMessageHandler InnerHandler
DelegatingHandler SendAsync InnerHandler
public abstract class DelegatingHandler : HttpMessageHandler { protected internal override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken); public HttpMessageHandler InnerHandler get; set; } }
ASP.NET Web API DelegatingHandler
HttpMessageHandler InnerHandler
HttpMessageHandler 3-2 ASP.NET
Web API
3.1 HttpMessageHandler
ASP.NET Web API 2
107
3-2 DelegatingHandler
3.1.3 HttpServer
ASP.NET Web API HttpMessageHandler
DelegatingHandler InnerHandler
HttpMessageHandler HttpMessageHandler HttpServer
System.Web.Http
HttpServer DelegatingHandler
Configuration Dispatcher
HttpConfiguration Dispatcher
HttpMessageHandler
public class HttpServer : DelegatingHandler { public HttpConfiguration Configuration { get; } public HttpMessageHandler Dispatcher { get; } public HttpServer(); public HttpServer(HttpMessageHandler dispatcher); public HttpServer(HttpConfiguration configuration); public HttpServer(HttpConfiguration configuration, HttpMessageHandler dispatcher); protected override void Dispose(bool disposing); protected virtual void Initialize();
3
ASP.NET Web API 2
108
protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken); }
HttpServer Configuration Dispatcher
HttpServer
HttpServer HttpConfiguration Configuration
Dispatcher HttpRoutingDispatcher
System.Web.Http.Dispatcher HttpConfiguration IDisposable
HttpServer Dispose HttpConfiguration
HttpServer
HttpServer Dispatcher Http
MessageHandler ASP.NET Web API
HttpMessageHandler
3-3 HttpMessage
Handler
3-3 HttpServer HttpRoutingDispatcher
HttpConfiguration HttpMessageHandler
HttpConfiguration
MessageHandlers HttpMessageHandler
DelegatingHandler HttpMessageHandler
3.1 HttpMessageHandler
ASP.NET Web API 2
109
DelegatingHandler
public class HttpConfiguration : IDisposable { // public Collection<DelegatingHandler> MessageHandlers { get; } }
HttpServer Initialize
SendAsync
Initialize
HttpServer S301
HttpServer
ASP.NET Web API 3
DelegatingHandler HttpMessageHandler FooHandler BarHandler
BazHandler
public class FooHandler: DelegatingHandler {} public class BarHandler : DelegatingHandler {} public class BazHandler : DelegatingHandler {}
HttpServer MyHttpServer
SendAsync MyHttpServer
HttpConfiguration
public class MyHttpServer: HttpServer { public MyHttpServer(HttpConfiguration configuration) : base(configuration) { } public new void Initialize() { base.Initialize(); } }
3
ASP.NET Web API 2
110
ApiController DemoController
GetHandlerChain DelegatingHandler
HttpMessageHandler Action Get
MyHttpServer HttpConfiguration 3 DelegatingHandler
FooHandler BarHandler BazHandler
public class DemoController : ApiController { public Tuple<IEnumerable<string>, IEnumerable<string>> Get() { HttpConfiguration configuration = new HttpConfiguration(); configuration.MessageHandlers.Add(new FooHandler()); configuration.MessageHandlers.Add(new BarHandler()); configuration.MessageHandlers.Add(new BazHandler()); MyHttpServer httpServer = new MyHttpServer(configuration); IEnumerable<string> chain1 = this.GetHandlerChain(httpServer).ToArray(); httpServer.Initialize(); IEnumerable<string> chain2 = this.GetHandlerChain(httpServer).ToArray(); return new Tuple<IEnumerable<string>, IEnumerable<string>>( chain1, chain2); }
private IEnumerable<string> GetHandlerChain(DelegatingHandler handler) { yield return handler.GetType().Name; while (null != handler.InnerHandler) { yield return handler.InnerHandler.GetType().Name; handler = handler.InnerHandler as DelegatingHandler; if (null == handler) { break; } } } }
MyHttpServer Initialize
GetHandlerChain HttpMessageHandler
Tuple<IEnumerable<string> IEnumerable<string>> Get
Tuple HttpMessageHandler HttpServer
3.1 HttpMessageHandler
ASP.NET Web API 2
111
DemoController Action Get
3-4 HttpServer
Initialize HttpMessageHandler
HttpConfiguration MessageHandlers
HttpRoutingDispatcher HttpServer
Dispatcher
3-4 HttpServer
HttpServer HttpServer
HttpConfiguration
HttpServer Configuration
HttpConfiguration
// 1 HttpConfiguration configuration = new HttpConfiguration(); configuration.MessageHandlers.Add(new FooHandler()); configuration.MessageHandlers.Add(new BarHandler()); configuration.MessageHandlers.Add(new BazHandler()); HttpServer httpServer = new HttpServer(configuration); // 2 HttpServer httpServer = new HttpServer(); httpServer.Configuration.MessageHandlers.Add(new FooHandler());
3
ASP.NET Web API 2
112
httpServer.Configuration.MessageHandlers.Add(new BarHandler ()); httpServer.Configuration.MessageHandlers.Add(new BazHandler ());
Principal
Principal Identity Permission
HttpServer SendAsync
CurrentPrincipal Principal
Principal Principal
GenericPrincipal
HttpServer SendAsync Principal
ASP.NET Web API HttpServer
MyHttpServer SendAsync
public class MyHttpServer : HttpServer { public new Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { return base.SendAsync(request, cancellationToken); } }
ApiController DemoController Action
Get MyHttpServer SendAsync
Principal Null
Artech GenericPrincipal Principal SendAsync
Principal GenericPrincipal Get
GenericPrincipal
public class DemoController : ApiController { public IEnumerable<string> Get() { MyHttpServer httpServer = new MyHttpServer(); //Thread.CurrentPrincipal == Null Thread.CurrentPrincipal = null;
3.1 HttpMessageHandler
ASP.NET Web API 2
113
HttpRequestMessage request = new HttpRequestMessage(); httpServer.SendAsync(request, new CancellationToken(false)); GenericPrincipal principal = (GenericPrincipal)Thread.CurrentPrincipal; string identity1 = string.IsNullOrEmpty(principal.Identity.Name) ? "N/A" : principal.Identity.Name; //Thread.CurrentPrincipal = Null GenericIdentity identity = new GenericIdentity("Artech"); Thread.CurrentPrincipal = new GenericPrincipal(identity, new string[0]); request = new HttpRequestMessage(); httpServer.SendAsync(request, new CancellationToken(false)); principal = (GenericPrincipal)Thread.CurrentPrincipal; string identity2 = string.IsNullOrEmpty(principal.Identity.Name) ? "N/A" : principal.Identity.Name; return new string[] { identity1, identity2 }; } }
DemoController Get 3-5
S302 Principal HttpServer
SendAsync GenericPrincipal
Principal
3-5 HttpServer Principal
HttpServer SendAsync HttpMessageHandler
SynchronizationContext Current
SynchronizationContext HttpRequest
3
ASP.NET Web API 2
114
Message
HttpRequestMessage
HttpServer HttpRequestMessage
Configuration HttpConfiguration
GetConfiguration GetSynchronizationContext HttpRequestMessage
HttpConfiguration SynchronizationContext
public static class HttpRequestMessageExtensions { // public static HttpConfiguration GetConfiguration( this HttpRequestMessage request); public static SynchronizationContext GetSynchronizationContext( this HttpRequestMessage request); }
3.1.4 HttpRoutingDispatcher HttpServer Dispatcher
HttpRoutingDispatcher HttpMessageHandler
Web API HttpController Action
HttpController Action HttpRouting
Dispatcher HttpController Action
HttpRoutingDispatcher DelegatingHandler
HttpMessageHandler HttpRoutingDispatcher
HttpConfiguration defaultHandler HttpMessage
Handler HttpRoutingDispatcher HttpController
Action
public class HttpRoutingDispatcher : HttpMessageHandler { public HttpRoutingDispatcher(HttpConfiguration configuration); public HttpRoutingDispatcher(HttpConfiguration configuration, HttpMessageHandler defaultHandler); protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken); }
3.1 HttpMessageHandler
ASP.NET Web API 2
115
ASP.NET Web API HttpContext
HttpRequestMessage
Properties
HttpServer SynchronizationContext
HttpConfiguration HttpRequestMessage
HttpRouteData HttpRequestMessage
HttpRequestMessage GetRouteData
SetRouteData HttpRouteData
public static class HttpRequestMessageExtensions { // public static IHttpRouteData GetRouteData(this HttpRequestMessage request); public static void SetRouteData(this HttpRequestMessage request, IHttpRouteData routeData); }
HttpRoutingDispatcher SendAsync HttpRequest
Message HttpRouteData HttpRouteData
HttpMessageHandler
Web Host
HttpRouteData HttpRequest
Message Self Host
HttpRoutingDispatcher HttpConfiguration
Routes HttpRequestMessage GetRouteData
GetRouteData HttpRouteData
HttpRoute HttpRoutingDispatcher HttpRouteData
HttpRequestMessage ASP.NET Web API
HttpMessageHandler GetRouteData Null
404 Not Found
3
ASP.NET Web API 2
116
HttpControllerDispatcher
HttpRoutingDispatcher
Routing Dispatching
HttpRouteData HttpRouteData
HttpMessageHandler
HttpRoutingDispatcher defaultHandler
HttpMessageHandler HttpMessageHandler
HttpControllerDispatcher System.Web.
Http.Dispatcher HttpControllerDispatcher
HttpController Action HttpControllerDispatcher
public class HttpControllerDispatcher : HttpMessageHandler { public HttpControllerDispatcher(HttpConfiguration configuration); protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken); public HttpConfiguration Configuration { get; } }
HttpControllerDispatcher ASP.NET Web API
3-6 HttpControllerDispatcher
HttpMessageHandler
HttpControllerDispatcher HttpRoutingDispatcher HttpMessageHandler
HttpControllerDispatcher HttpRoutingDispatcher
HttpMessageHandler
N DelegatingHandler + 1 HttpMessageHandler
DelegatingHandler
3.1 HttpMessageHandler
ASP.NET Web API 2
117
3-6 HttpControllerDispatcher
HttpRoutingDispatcher S303
HttpRoutingDispatcher HttpRoute
HttpRouteData HttpRouteData
HttpRequestMessage
ASP.NET Web API MyHttpRoutingDispatcher
HttpRoutingDispatcher SendAsync
public class MyHttpRoutingDispatcher : HttpRoutingDispatcher { public MyHttpRoutingDispatcher(HttpConfiguration configuration) : base(configuration) { } public new Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { return base.SendAsync(request, cancellationToken); } }
ApiController DemoController Action Get
HttpConfiguration URL wheather/ {areaCode}/
{days} HttpRoute http://www.artech. com/wheather/
010/2 URL HttpRequestMessage
3
ASP.NET Web API 2
118
public class DemoController : ApiController { public async Task<IDictionary<string, object>> Get() { HttpConfiguration configuration = new HttpConfiguration(); configuration.Routes.MapHttpRoute( "default", "wheather/{areaCode}/{days}"); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://www.artech.com/wheather/010/2"); MyHttpRoutingDispatcher dispatcher = new MyHttpRoutingDispatcher(configuration); await dispatcher.SendAsync(request, CancellationToken.None); IHttpRouteData routeData = request.GetRouteData(); return routeData.Values; } }
HttpConfiguration MyHttpRoutingDispatcher
HttpRequestMessage SendAsync
await HttpRequestMessage
GetRouteData HttpRouteData Values
DemoController Action Get
3-7 {areaCode} {days}
HttpRoutingDispatcher SendAsync
3-7 HttpRoutingDispatcher HttpRouteData
3.2 Web Host
ASP.NET Web API 2
119
RouteParameter Optional
RouteParameter
public sealed class RouteParameter { public static readonly RouteParameter Optional; }
URL
HttpRouteData
Values
HttpRoutingDispatcher SendAsync
HttpRouteData HttpRequestMessage
HttpRoutingDispatcher ASP.NET Web API
Values RouteParameter.Optional
3.2 Web Host
ASP.NET Web API HTTP
HttpRequestMessage HttpResponseMessage HttpRequestMessage
HttpMessageHandler HttpResponseMessage
Web API Web API
HttpRequestMessage HttpResponseMessage
Web Host
3.2.1 HttpControllerHandler ASP.NET Web API HttpRouting
Dispatcher Web Host
3
ASP.NET Web API 2
120
ASP.NET Web Host ASP.NET Web Web
API ASP.NET IIS
2 ASP.NET UrlRoutingModule
HttpModule HttpApplication PostResolveRequestCache
URL
RouteData UrlRoutingModule Route HttpHandler
HTTP
Web Host Web API UrlRoutingModule
HTTP HttpHandler HttpRequest
HttpRequestMessage
HttpRequestMessage HttpResponse
HttpHandler
2 Web Host
HttpRoute ASP.NET HttpWebRoute
Route HttpWebRoute RouteHandler HttpControllerRouteHandler
HttpHandler HttpControllerRouteHandler
HttpControllerRouteHandler GetHttpHandler HttpHandler
RouteData HttpControllerHandler
public class HttpControllerRouteHandler : IRouteHandler { // protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { return new HttpControllerHandler(requestContext.RouteData); } }
HttpControllerHandler System.Web.HttpTaskAsyncHandler
IHttpAsyncHandler HttpTaskAsyncHandler
3.2 Web Host
ASP.NET Web API 2
121
Task ProcessRequestAsync IHttpAsyncHandler
BeginProcessRequest Task AsyncResult
EndProcessRequest Task
public abstract class HttpTaskAsyncHandler : IHttpAsyncHandler { public virtual void ProcessRequest(HttpContext context); IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData); void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result); public abstract Task ProcessRequestAsync(HttpContext context); public virtual bool IsReusable { get; } }
HttpTaskAsyncHandler HttpControllerHandler
HttpControllerHandler RouteData HttpControllerHandler
HttpMessageHandler
public class HttpControllerHandler : HttpTaskAsyncHandler { public HttpControllerHandler(RouteData routeData) : this(routeData, GlobalConfiguration.DefaultServer) {} public HttpControllerHandler(RouteData routeData, HttpMessageHandler handler); public override Task ProcessRequestAsync(HttpContext context); }
HttpControllerRouteHandler GetHttpHandler HttpControllerHandler
Global
Configuration DefaultServer HttpMessage
Handler HttpServer HttpControllerHandler
3-8
ASP.NET HttpControllerHandler
ASP.NET ASP.NET UrlRoutingModule
Route URL
TaskWrapperAsyncResult System.Web.dll
3
ASP.NET Web API 2
122
Route RouteData RouteData Route
Route Route HttpWebRoute
3-8 HttpControllerHandler
UrlRoutingModule RouteData Route RouteHandler
RouteHandler HttpControllerRouteHandler UrlRoutingModule
RouteData HTTP RequestContext
HttpControllerRouteHandler GetHttpHandler
HttpHandler HTTP
HttpControllerRouteHandler GetHttpHandler
RequestContext RouteData HttpControllerHandler
HttpControllerHandler GlobalConfiguration
DefaultServer HttpMessageHandler
DefaultServer HttpServer HttpMessageHandler
HttpControllerHandler ProcessRequestAsync
HTTP HttpRequestMessage
RouteData HttpRouteData HostedHttpRouteData
HttpRequestMessage HttpRequestMessage
HttpServer SendAsync
HttpRequestMessage HttpRoutingDispatcher
HttpMessageHandler HttpRoute
Data HttpRouteData
3.2 Web Host
ASP.NET Web API 2
123
HttpRouteData
Web Host HttpControllerHandler HttpRequestMessage
HttpRouteData
HttpServer SendAsync Task<HttpResponseMessage>
HttpControllerHandler Task
EndProcessRequest HttpControllerHandler Task
HttpResponseMessage HttpResponse
HttpControllerHandler S304
HttpRoutingDispatcher
Web Host HttpRouteData HttpControllerHandler
HttpRoutingDispatcher
HttpControllerHandler
ASP.NET MVC HttpRouteDataTraceHandler
HttpMessageHandler HttpRequestMessage
HttpRouteData SendAsync
GetRouteData HttpRequestMessage
HttpRouteData Values
HttpResponse
public class HttpRouteDataTraceHandler: HttpMessageHandler { protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { IHttpRouteData routeData = request.GetRouteData(); foreach (var item in routeData.Values) { HttpContext.Current.Response.Write(string.Format("{0}: {1}<br/>", item.Key, item.Value)); } return Task.FromResult<HttpResponseMessage>(null); } }
3
ASP.NET Web API 2
124
HomeController Action Index ASP.NET
Web API wheather/{areaCode}/{days} HttpRoute
http://www.artech.com/wheather/010/2 HttpRequest
HttpContext HttpContext HttpContextWrapper
GetRouteData RouteData
HttpRouteDataTraceHandler RouteData
HttpControllerHandler HttpContext
ProcessRequestAsync HttpControllerHandler
public class HomeController : Controller { public void Index() { GlobalConfiguration.Configuration.Routes.MapHttpRoute( "wheather", "wheather/{areaCode}/{days}"); HttpRequest request = new HttpRequest("wheather.aspx", "http://www.artech.com/wheather/010/2", null); HttpResponse response = new HttpResponse(new StringWriter()); HttpContext context = new HttpContext(request, response); RouteData routeData = RouteTable.Routes.GetRouteData( new HttpContextWrapper(context)); HttpControllerHandler httpHandler = new HttpControllerHandler(routeData, new HttpRouteDataTraceHandler()); httpHandler.ProcessRequestAsync(context).Wait(); } }
3-9
HttpRouteDataTraceHandler SendAsync
HttpRequestMessage HttpControllerHandler RouteData
HttpRouteData HttpRequestMessage HttpRouteDataTraceHandler
RouteTable Routes ASP.NET HttpConfiguration Routes
ASP.NET Web API
3.2 Web Host
ASP.NET Web API 2
125
3-9 ASP.NET MVC
HttpServer
ASP.NET Web API HttpMessageHandler
HttpServer HttpServer
HttpControllerHandler HttpServer
GlobalConfiguration DefaultServer HttpServer
GlobalConfiguration DefaultServer HttpServer
HttpServer HttpConfiguration
GlobalConfiguration Configuration Dispatcher
HttpMessageHandler DefaultHandler HttpRoutingDispatcher
public static class GlobalConfiguration { private static Lazy<HttpConfiguration> _configuration = new Lazy<HttpConfiguration>( () => { HttpConfiguration config = new HttpConfiguration( new HostedHttpRouteCollection(RouteTable.Routes)); // return config; }); private static Lazy<HttpMessageHandler> _defaultHandler = new Lazy<HttpMessageHandler>( () => new HttpRoutingDispatcher(_configuration.Value)); private static Lazy<HttpServer> _defaultServer = new Lazy<HttpServer>(
3
ASP.NET Web API 2
126
() => new HttpServer(_configuration.Value, _defaultHandler.Value)); public static HttpConfiguration Configuration { get { return _configuration.Value; } } public static HttpMessageHandler DefaultHandler { get { return _defaultHandler.Value; } } public static HttpServer DefaultServer { get { return _defaultServer.Value; } } }
GlobalConfiguration DefaultServer DefaultHandler HttpServer
HttpRoutingDispatcher HttpMessageHandler
3.2.2 HttpMessageHandler HTTPS305
RESTful Web API HTTP
HTTP HTTP
GET POST
PUT
HTTP Proxy Gateway
HTTP
HTTP Web API
HTTP
HTTP GET POST HTTP
HTTP HTTP
HTTP X-HTTP-Method-Override
ASP.NET Web API HTTP
3.2 Web Host
ASP.NET Web API 2
127
HTTP HttpMessageHandler
HttpRequestMessage Method
HTTP HttpMessageHandler
X-HTTP-Method-Override HttpRequestMessage Method
HTTP
HttpMethodOverrideHandler DelegatingHandler
SendAsync X-HTTP-Method-Override HTTP
HttpMessageHandler
public class HttpMethodOverrideHandler: DelegatingHandler { protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { IEnumerable<string> methodOverrideHeader; if (request.Headers.TryGetValues("X-HTTP-Method-Override", out methodOverrideHeader)) { request.Method = new HttpMethod(methodOverrideHeader.First()); } return base.SendAsync(request, cancellationToken); } }
ASP.NET Web API ApiController
DemoController 4 Action Get Post Put
Delete ASP.NET Web API HTTP Action
4 Action HTTP
public class DemoController : ApiController { public string Get() { return "Get"; } public string Post() { return "Post"; } public string Put() {
3
ASP.NET Web API 2
128
return "Put"; } public string Delete() { return "Delete"; } }
Global.asax HttpMethodOverrideHandler
ASP.NET Web API IIS Express
3721
public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { GlobalConfiguration.Configuration.MessageHandlers.Add( new HttpMethodOverrideHandler()); // } }
Web API
InvokeWebApi HttpClient HTTP
Web API HTTP Web API
HttpRequestMessage HttpClient SendAsync
Web API Web API Action
HTTP X-HTTP-Method-Override
class Program { static void Main(string[] args) { HttpClient httpClient1 = new HttpClient(); HttpClient httpClient2 = new HttpClient(); HttpClient httpClient3 = new HttpClient(); HttpClient httpClient4 = new HttpClient(); httpClient3.DefaultRequestHeaders.Add("X-HTTP-Method-Override", "PUT"); httpClient4.DefaultRequestHeaders.Add("X-HTTP-Method-Override", "DELETE"); Console.WriteLine("{0,-7}{1,-24}{2,-6}", "Method", "X-HTTP-Method-Override", "Action");
3.2 Web Host
ASP.NET Web API 2
129
InvokeWebApi(httpClient1, HttpMethod.Get); InvokeWebApi(httpClient2, HttpMethod.Post); InvokeWebApi(httpClient3, HttpMethod.Post); InvokeWebApi(httpClient4, HttpMethod.Post); Console.Read(); } async static void InvokeWebApi(HttpClient httpClient, HttpMethod method) { string requestUri = "http://localhost:3721/api/demo"; HttpRequestMessage request = new HttpRequestMessage(method, requestUri); HttpResponseMessage response = await httpClient.SendAsync(request); IEnumerable<string> methodsOverride; httpClient.DefaultRequestHeaders.TryGetValues("X-HTTP-Method- Override", out methodsOverride); string actionName = response.Content.ReadAsStringAsync().Result; string methodOverride = methodsOverride == null ? "N/A" : methodsOverride.First(); Console.WriteLine("{0,-7}{1,-24}{2,-6}", method, methodOverride, actionName.Trim('"')); } }
Main 4 HttpClient httpClient1 httpClient2 httpClient3
httpClient4 X-HTTP-Method-Override httpClient3 httpClient4
HTTP PUT DELETE 4 HttpClient
InvokeWebApi Web API 4 1 GET
POST
Web API
X-HTTP-Method-Override Action
HTTP X-HTTP-Method-Override
HTTP Action
HttpMethodOverrideHandler HttpMessageHandler
Method X-HTTP-Method-Override Action POST PUT Put GET N/A Get
InvokeWebApi Web API
3
ASP.NET Web API 2
130
POST N/A Post POST DELETE Delete
3.3 Self Host
ASP.NET Web API
Web Host ASP.NET Web
API ASP.NET ASP.NET
URL HttpControllerHandler HttpHandler ASP.NET
ASP.NET Web API Self Host
3.3.1 HttpBinding
WCF Self Host Web API
Windows Form WPF Windows
Service Self Host WCF ASP.NET Web API
Binding
WCF
Endpoint ABC
Address Binding Contract WCF
Channel WCF Channel ASP.NET Web API
HttpMessageHandler
WCF Binding Binding
Binding
WCF 3 Binding ASP.NET
Web API HttpBinding Binding
3.3 Self Host
ASP.NET Web API 2
131
Binding BindingElement
Channel BindingElement BindingElement
Channel ChannelListener Channel
ChannelListener 3-10 Binding
3-10 Binding
ChannelListener Binding Open
BindingElement ChannelListener ChannelListener
BindingElement ChannelListener
ChannelListener
Channel
Channel Channel
TransportChannel MessageEncoding
Channel TransportChannel
TransportChannelListener TransportBindingElement Message
EncodingBindingElement MessageEncodingChannelListener Message
EncodingChannel
Self Host HttpBinding Binding
ChannelListener
HttpBinding System.Web.Http.SelfHost.Channels
3
ASP.NET Web API 2
132
HttpBinding
Binding
Channel BindingElement Binding
BindingElement BindingElement
ASP.NET Web API Self Host HttpBinding
BindingElement
3-11 HttpBinding BindingElement
TransportBindingElement HTTP
TransportBindingElement HttpTransportBindingElement HTTPS
TransportBindingElement HttpsTransportBindingElement
3-11 HttpBinding BindingElement
/ BindingElement 3-11
HttpMessageEncodingBindingElement HttpMessageEncodingBindingElement
System.Web.Http.SelfHost.dll
MessageEncoder /
ASP.NET Web API HttpRequestMessage HttpResponseMessage
WCF Message
Message System.ServiceModel.Channels
HttpMessageEncoder Message HttpRequestMessage
ASP.NET Web API HttpResponseMessage
Message HttpMessageEncoder
HttpMessage HttpMessage Message
3.3 Self Host
ASP.NET Web API 2
133
System.Web.Http.SelfHost.dll
HttpMessage HttpRequestMessage HttpResponseMessage
GetHttpRequestMessage GetHttpResponseMessage
HttpRequestMessage HttpResponseMessage
internal sealed class HttpMessage : Message { // public HttpMessage(HttpRequestMessage request); public HttpMessage(HttpResponseMessage response); public HttpRequestMessage GetHttpRequestMessage(bool extract); public HttpResponseMessage GetHttpResponseMessage(bool extract); }
extract
HttpRequestMessage/HttpResponseMessage True
HttpRequestMessage/HttpResponseMessage HttpMessage
Null
HttpBinding
HttpBinding ChannelListener
HTTP/HTTPS TransportChannel Message
Encoder HttpRequestMessage HttpMessage
HttpRequestMessage GetHttpRequestMessage
HttpMessage
ASP.NET Web API HttpResponse
Message HttpMessage
MessageEncoder
GetHttpResponseMessage HttpResponseMessage
HttpBinding S306
Self Host Web Web API
HttpBinding ChannelListener
ChannelListener
HttpBinding
3
ASP.NET Web API 2
134
Self Host
HttpBinding
http://127.0.0.1:3721 BuildChannelListener<IReplyChannel> Channel
Listener ChannelListener Open
ChannelListener AcceptChannel
Channel Open While
Channel ReceiveRequest
class Program { static void Main(string[] args) { Uri listenUri = new Uri("http://127.0.0.1:3721"); Binding binding = new HttpBinding(); // IChannelListener<IReplyChannel> channelListener = binding.BuildChannelListener<IReplyChannel>(listenUri); channelListener.Open(); // IReplyChannel channel = channelListener.AcceptChannel(TimeSpan.MaxValue); channel.Open(); // while (true) { // RequestContext requestContext = channel.ReceiveRequest(TimeSpan.MaxValue); PrintRequestMessage(requestContext.RequestMessage); // requestContext.Reply(CreateResponseMessage()); } } }
PrintRequestMessage
HttpMessage
GetHttpRequestMessage
3.3 Self Host
ASP.NET Web API 2
135
HttpRequestMessage HttpRequestMessage
private static void PrintRequestMessage(Message message) { MethodInfo method = message.GetType().GetMethod("GetHttpRequestMessage"); HttpRequestMessage request = (HttpRequestMessage)method.Invoke(message, new object[]{false}); Console.WriteLine("{0, -15}:{1}", "RequestUri", request.RequestUri); foreach (var header in request.Headers) { Console.WriteLine("{0, -15}:{1}", header.Key, string.Join("," ,header.Value.ToArray())); } }
Message
CreateResponseMessage
200 OK HttpResponseMessage
Content ObjectContent<Employee> MediaTypeFormatter
JsonMediaTypeFormatter Employee JSON
HttpMessage HttpResponseMessage
HttpMessage
private static Message CreateResponseMessage() { HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); Employee employee = new Employee("001","Zhang San","123456", "[email protected]"); response.Content = new ObjectContent<Employee>(employee, new JsonMediaTypeFormatter()); string httpMessageTypeName = "System.Web.Http.SelfHost.Channels.HttpMessage, System.Web.Http.SelfHost"; Type httpMessageType = Type.GetType(httpMessageTypeName); return (Message)Activator.CreateInstance(httpMessageType, new object[] { response }); } public class Employee { public string Id { get; set; }
3
ASP.NET Web API 2
136
public string Name { get; set; } public string PhoneNo { get; set; } public string EmailAddress { get; set; } public Employee(string id, string name, string phoneNo, string emailAddress) { this.Id = id; this.Name = name; this.PhoneNo = phoneNo; this.EmailAddress = emailAddress; } }
http://127.0.0.1:3721
Web API
http://127.0.0.1:3721/employees/001
001 3-12
JSON
3-12 HttpBinding
3.3.2 HttpSelfHostServer
1 ASP.NET Web API Self Host
System.Web.Http.SelfHost.HttpSelfHostServer HttpSelfHostServer
3.3 Self Host
ASP.NET Web API 2
137
HttpBinding HttpSelfHostServer ASP.NET Web API
HttpSelfHostServer HttpServer Self Host
HttpSelfHostServer HttpSelfHostServer
public sealed class HttpSelfHostServer : HttpServer { public HttpSelfHostServer(HttpSelfHostConfiguration configuration); public HttpSelfHostServer(HttpSelfHostConfiguration configuration, HttpMessageHandler dispatcher); public Task OpenAsync(); public Task CloseAsync(); protected override void Dispose(bool disposing); }
ASP.NET Web API HttpServer Configuration
HttpConfiguration HttpSelfHostServer Configuration
HttpSelfHostConfiguration HttpSelfHostConfiguration System.Web.
Http.SelfHost
HttpSelfHostServer HttpSelfHostConfiguration
HttpSelfHostConfiguration
HttpSelfHostConfiguration HttpConfiguration
HttpSelfHostConfiguration Uri
BaseAddress
public class HttpSelfHostConfiguration : HttpConfiguration { public HttpSelfHostConfiguration(Uri baseAddress); public Uri BaseAddress { get; } public HostNameComparisonMode HostNameComparisonMode { get; set; } public TransferMode TransferMode { get; set; } public int MaxBufferSize { get; set; } public int MaxConcurrentRequests { get; set; } public long MaxReceivedMessageSize { get; set; }
3
ASP.NET Web API 2
138
public TimeSpan ReceiveTimeout { get; set; } public TimeSpan SendTimeout { get; set; } public HttpClientCredentialType ClientCredentialType { get; set; } public UserNamePasswordValidator UserNamePasswordValidator { get; set; } public X509CertificateValidator X509CertificateValidator { get; set; } }
Self Host HttpBinding
HttpSelfHostConfiguration
HttpBinding HttpBinding HttpSelfHost
Configuration
public abstract class Binding : IDefaultCommunicationTimeouts { // public TimeSpan ReceiveTimeout { get; set; } public TimeSpan SendTimeout { get; set; } } public class HttpBinding : Binding, IBindingRuntimePreferences { // public HostNameComparisonMode HostNameComparisonMode { get; set; } public TransferMode TransferMode { get; set; } public long MaxBufferPoolSize { get; set; } public int MaxBufferSize { get; set; } public long MaxReceivedMessageSize { get; set; } public HttpBindingSecurity Security { get; set; } }
Binding WCF
HttpBinding Binding
3-1
3-1 HttpSelfHostConfiguration
HostNameComparisonMode
URL IPURL
System.ServiceModel.HostName ComparisonMode
3.3 Self Host
ASP.NET Web API 2
139
TransferMode MaxBufferSize
Streamed Buffered
System.ServiceModel.TransferMode
BufferedMaxBufferSize Buffered
65536 0x10000
MaxConcurrentRequests MaxReceivedMessageSize
100 655360x10000 MaxConcurrentRequests
ReceiveTimeout SendTimeout 10 1
ClientCredentialType UserNamePasswordValidator X509CertificateValidator
ClientCredentialTypeUserNamePasswordValidator
X509CertificateValidator +X.509
HttpSelfHostServer
Self Host Web API
HttpSelfHostConfiguration HttpSelfHostServer
OpenAsync HttpSelfHostServer HttpBinding
HttpSelfHostConfiguration HttpBinding
ChannelListener BeginOpen OpenAsync
HttpSelfHostServer CloseAsync
ChannelListener
ChannelListener
HttpBinding HttpMessage
3
ASP.NET Web API 2
140
HttpRequestMessage
HttpSelfHostServer HttpMessage HttpRequestMessage
HttpMessageHandler
HttpResponseMessage HttpSelfHostServer HttpMessage
HttpMessage
HttpMessage HttpResponseMessage
HttpResponseMessage 3-13
Self Host
3-13 Self Host
HttpServer HttpSelfHostServer S307
Self Host
HttpServer
HttpSelfHostServer
HttpServer HttpSelfHostServer MyHttpSelf
HostServer
HttpSelfHostServer MyHttpSelfHostServer
public class MyHttpSelfHostServer: HttpServer { public Uri BaseAddress { get; private set; } public IChannelListener<IReplyChannel> ChannelListener { get; private set; }
3.3 Self Host
ASP.NET Web API 2
141
public MyHttpSelfHostServer(HttpConfiguration configuration, Uri baseAddress) : base(configuration) { this.BaseAddress = baseAddress; } public void Open() { HttpBinding binding = new HttpBinding(); this.ChannelListener = binding .BuildChannelListener<IReplyChannel>(this.BaseAddress); this.ChannelListener.Open(); IReplyChannel channnel = this.ChannelListener.AcceptChannel(); channnel.Open(); while (true) { RequestContext requestContext = channnel .ReceiveRequest(TimeSpan.MaxValue); Message message = requestContext.RequestMessage; MethodInfo method = message.GetType().GetMethod("GetHttpRequestMessage"); HttpRequestMessage request = (HttpRequestMessage)method.Invoke(message, new object[] {true}); Task<HttpResponseMessage> processResponse = base.SendAsync(request, new CancellationTokenSource().Token); processResponse.ContinueWith(task => { string httpMessageTypeName = "System.Web.Http.SelfHost.Channels.HttpMessage, System.Web.Http.SelfHost"; Type httpMessageType = Type.GetType(httpMessageTypeName); Message reply = (Message)Activator.CreateInstance( httpMessageType, new object[] { task.Result }); requestContext.Reply(reply); }); } } public void Close() { if (null != this.ChannelListener && this.ChannelListener.State == CommunicationState.Opened) { this.ChannelListener.Close(); } } }
3
ASP.NET Web API 2
142
MyHttpSelfHostServer BaseAddress
HttpSelfHostServer MyHttpSelfHostServer
HttpConfiguration HttpSelfHostConfiguration
Open HttpBinding
ChannelListener MyHttpSelfHostServer ChannelListener
ChannelListener AccpetChannel
Channel Channel While
ReceiveRequest
HttpMessage
HttpRequestMessage SendAsync
HttpRequestMessage
SendAsync Task<HttpResponseMessage> Task
HttpResponseMessage
HttpMessage HttpMessage HttpSelfHost
Server OpenAsync CloseAsync Open
Close ChannelListener
MyHttpSelfHostServer
HttpSelfHostServer ApiController
ContactsController Action Get
ID
public class ContactsController : ApiController { private static List<Contact> contacts = new List<Contact> { new Contact{ Id="001", Name = " ", PhoneNo="123", EmailAddress="[email protected]"}, new Contact{ Id="002",Name = " ", PhoneNo="456", EmailAddress="[email protected]"} }; public IEnumerable<Contact> Get() { return contacts; }
3.3 Self Host
ASP.NET Web API 2
143
public Contact Get(string id) { return contacts.FirstOrDefault(c => c.Id == id); } } public class Contact { public string Id { get; set; } public string Name { get; set; } public string PhoneNo { get; set; } public string EmailAddress { get; set; } }
Main
HttpConfiguration http://127.0.0.1:3721
MyHttpSelfHostServer Open URL
http://127.0.0.1:3721 HttpRoute
class Program { static void Main(string[] args) { using (MyHttpSelfHostServer httpServer = new MyHttpSelfHostServer( new HttpConfiguration(), new Uri("http://127.0.0.1:3721"))) { httpServer.Configuration.Routes.MapHttpRoute( name : "DefaultApi", routeTemplate : "api/{controller}/{id}", defaults : new { id = RouteParameter.Optional }); httpServer.Open(); Console.Read(); } } }
ContactsController Action Get HttpRoute
HTTP Action URL http://127.0.0.1:
3721/api/contacts http://127.0.0.1:3721/api/contacts/001 3-14
XML MyHttpSelfHostServer
3
ASP.NET Web API 2
144
3-14 MyHttpSelfHostServer Web API
4 HttpController
Web API HttpController
Action HttpController
URI HttpController
HttpRouteData
HttpRequestMessage ASP.NET Web API
HttpController HttpController
4 HttpController
ASP.NET Web API 2
146
4.1 HttpController Visual Studio ASP.NET Web API Controller
ApiController ASP.NET Web API IHttpController
HttpController
HttpController IHttpController
IHttpController
ExecuteAsync HttpController
Task<HttpResponseMessage>
public interface IHttpController { Task<HttpResponseMessage> ExecuteAsync( HttpControllerContext controllerContext, CancellationToken cancellationToken); }
HttpController ASP.NET Web API 3
HttpRoutingDispatcher SendAsync
HttpRoutingDispatcher HttpControllerDispatcher
HttpController ExecuteAsync Task<HttpResponse
Message> 4-1 HttpController
4-1 HttpController
4.1 HttpController
ASP.NET Web API 2
147
4.1.1 HttpControllerContext
HttpMessageHandler SendAsync HttpController ExecuteAsync
HttpRequestMessage
HttpControllerContext HttpControllerContext System.Web.Http.
Controllers HttpController
HttpControllerContext
HttpConfiguration HttpRouteData
HttpRequestMessage HttpControllerContext
HttpControllerContext
public class HttpControllerContext { public HttpControllerContext(); public HttpControllerContext(HttpConfiguration configuration, IHttpRouteData routeData, HttpRequestMessage request); public HttpConfiguration Configuration { get; set; } public IHttpRouteData RouteData { get; set; } public HttpRequestMessage Request { get; set; }
public IHttpController Controller { get; set; } public HttpControllerDescriptor ControllerDescriptor { get; set; } }
HttpControllerContext HttpController
Controller HttpController
ControllerDescriptor HttpController HttpControllerDescriptor
HttpControllerDescriptor System.Web.Http.Controllers
4.1.2 HttpControllerDescriptor
HttpControllerDescriptor HttpController
HttpController HttpControllerDescriptor
HttpController ASP.NET Web API HttpController
HttpControllerDescriptor HttpController
4 HttpController
ASP.NET Web API 2
148
HttpControllerDescriptor Configuration
ControllerName ControllerType HttpConfiguration HttpController
HttpControllerDescriptor
HttpControllerDescriptor
public class HttpControllerDescriptor { public HttpControllerDescriptor(); public HttpControllerDescriptor(HttpConfiguration configuration, string controllerName, Type controllerType); public virtual IHttpController CreateController(HttpRequestMessage request);
public virtual Collection<T> GetCustomAttributes<T>() where T: class; public virtual Collection<T> GetCustomAttributes<T>(bool inherit) where T: class; public virtual Collection<IFilter> GetFilters(); public HttpConfiguration Configuration { get; set; } public string ControllerName { get; set; } public Type ControllerType { get; set; } public virtual ConcurrentDictionary<object, object> Properties { get; } }
HttpControllerDescriptor HttpController CreateController
HttpController
HttpControllerDescriptor CreateController
HttpControllerDescriptor GetCustomAttributes<T>
HttpController GetFilters
HttpController Filter Filter ASP.NET Web API
12 Filter
HttpControllerDescriptor Properties
HttpControllerDescriptor HttpRequestMessage
HttpConfiguration
4.1 HttpController
ASP.NET Web API 2
149
4.1.3 ApiController
HttpController ApiController
IHttpController HttpController
IDisposable HttpController
Dispose
public abstract class ApiController : IHttpController, IDisposable { public virtual Task<HttpResponseMessage> ExecuteAsync( HttpControllerContext controllerContext, CancellationToken cancellationToken); protected virtual void Initialize(HttpControllerContext controllerContext); public void Dispose(); protected virtual void Dispose(bool disposing); public HttpControllerContext ControllerContext { get; set; } public HttpConfiguration Configuration { get; set; } public HttpRequestMessage Request { get; set; } public IHttpRouteData RouteData { get; set; } public ModelStateDictionary ModelState { get; } public UrlHelper Url { get; set; } public IPrincipal User { get; } }
ApiController Configuration Request RouteData HttpControllerContext
ApiController HttpControllerContext
ControllerContext
ControllerContext
ApiController ModelState ModelStateDictionary
Model Action
ModelStateDictionary Url
UrlHelper UrlHelper System.Web.Http.Routing
HttpRoute URL
4 HttpController
ASP.NET Web API 2
150
ApiController User Principal 3
HttpServer Principal Null
HttpServer SendAsync GenericPrincipal
Principal User HttpServer
GenericPrincipal
ApiController Initialize
HttpControllerContext
Initialize ApiController Initialize
ExecuteAsync
ASP.NET Web API HttpController
HttpController ApiController HttpController
ExecuteAsync ApiController
InvalidOperationException
ApiController DemoController
Initialize
public class DemoController : ApiController { public new void Initialize(HttpControllerContext controllerContext) { base.Initialize(controllerContext); } }
DemoController
ExecuteAsync Initialize
DemoController controller = new DemoController(); HttpControllerContext controllerContext = new HttpControllerContext( new HttpConfiguration(), new HttpRouteData(new HttpRoute()), new HttpRequestMessage()); controller.ControllerContext = controllerContext; controller.Initialize(controllerContext); controller.ExecuteAsync(controllerContext, new CancellationToken(false));
ApiController ExecuteAsync 4-2 InvalidOperation
Cannot reuse an 'ApiController' instance. 'ApiController' has to be constructed per
4.2 HttpController
ASP.NET Web API 2
151
incoming message. Check your custom 'IHttpControllerActivator' and make sure that it will not manufacture the same instance. ApiController
ApiController
4-2 ApiController
4.2 HttpController
HttpController HttpRoutingDispatcher
HttpControllerDispatcher HttpController
HttpController
4.2.1
ASP.NET Web API HttpController AssembliesResolver
HttpController HttpController
AssembliesResolver IHttpController
AssembliesResolver IAssembliesResolver
System.Web.Http.Dispatcher
IAssembliesResolver
GetAssemblies
public interface IAssembliesResolver { ICollection<Assembly> GetAssemblies(); }
4 HttpController
ASP.NET Web API 2
152
AssembliesResolver DefaultAssembliesResolver
DefaultAssembliesResolver GetAssemblies
public class DefaultAssembliesResolver : IAssembliesResolver { public virtual ICollection<Assembly> GetAssemblies() { return AppDomain.CurrentDomain.GetAssemblies().ToList<Assembly>(); } }
DefaultAssembliesResolver AssembliesResolver Assemblies
Resolver ASP.NET Web API
ServicesContainer System.Web.Http.Controllers
ServicesContainer
ASP.NET Web API
ServicesContainer
ServicesContainer
IoC
ServicesContainer
Add AddRange Insert Replace
GetService
GetServices
public abstract class ServicesContainer : IDisposable { public void Add(Type serviceType, object service); public void AddRange(Type serviceType, IEnumerable<object> services); public void Insert(Type serviceType, int index, object service); public void InsertRange(Type serviceType, int index, IEnumerable<object> services);
4.2 HttpController
ASP.NET Web API 2
153
public void Replace(Type serviceType, object service); public void ReplaceRange(Type serviceType, IEnumerable<object> services); public abstract object GetService(Type serviceType); public abstract IEnumerable<object> GetServices(Type serviceType); public int FindIndex(Type serviceType, Predicate<object> match); public abstract bool IsSingleService(Type serviceType); public bool Remove(Type serviceType, object service); public int RemoveAll(Type serviceType, Predicate<object> match); public void RemoveAt(Type serviceType, int index); public virtual void Clear(Type serviceType); public virtual void Dispose(); }
FindIndex
IsSingleService
Remove RemoveAll RemoveAt Clear
ServicesContainer IDisposable ServicesContainer
Dispose
ASP.NET Web API HttpConfiguration
HttpConfiguration
ServicesContainer Services ASP.NET Web API
ServicesContainer
ServicesContainer DefaultServices DefaultServices
System.Web.Http.Services
public class HttpConfiguration : IDisposable { // public HttpConfiguration(HttpRouteCollection routes) { // this.Services = new DefaultServices(this); } public ServicesContainer Services { get; } }
AssembliesResolver
ASP.NET Web API AssembliesResolver
4 HttpController
ASP.NET Web API 2
154
ServicesContainer DefaultServices
AssembliesResolver DefaultAssembliesResolver
public class DefaultServices : ServicesContainer { // public DefaultServices(HttpConfiguration configuration) { // this.SetSingle<IAssembliesResolver>(new DefaultAssembliesResolver()); } }
AssembliesResolver ServicesContainer
GetService ServicesContainer
GetAssembliesResolver
public static class ServicesExtensions { // public static IAssembliesResolver GetAssembliesResolver( this ServicesContainer services); }
AssembliesResolver S401 S402
DefaultAssembliesResolver
HttpController
Self Host HttpController
HttpController
HttpController
4-3 4 Foo Bar Baz HttpController
3 Hosting 3
4.2 HttpController
ASP.NET Web API 2
155
4-3 HttpController
Foo Bar Baz 3 ApiController HttpControllerFooController BarController BazController 3
HttpController Action Get HttpControllerAssemblyQualifiedName
public class FooController : ApiController { public string Get() { return this.GetType().AssemblyQualifiedName; } } public class BarController : ApiController { public string Get() { return this.GetType().AssemblyQualifiedName; } } public class BarController : ApiController { public string Get() { return this.GetType().AssemblyQualifiedName; } }
Hosting Self Host Web APIhttp://127.0.0.1:3721 HttpSelfHostServer
URL api/{controller}/{id}
class Program {
4 HttpController
ASP.NET Web API 2
156
static void Main(string[] args) { Uri baseAddress = new Uri("http://127.0.0.1:3721"); using (HttpSelfHostServer httpServer = new HttpSelfHostServer( new HttpSelfHostConfiguration(baseAddress))) { httpServer.Configuration.Routes.MapHttpRoute( name : "DefaultApi", routeTemplate : "api/{controller}/{id}", defaults : new { id = RouteParameter.Optional }); httpServer.OpenAsync().Wait(); Console.Read(); } } }
FooController BarController
BazController Action Get 4-4
S401
HttpController
4-4 HttpController
4.2 HttpController
ASP.NET Web API 2
157
DefaultAssemblies
Resolver AssembliesResolver
<configuration> <configSections> <section name="preLoadedAssemblies" type="Hosting.PreLoadedAssembliesSettings, Hosting"/> </configSections> <preLoadedAssemblies> <add assemblyName ="Foo.dll"/> <add assemblyName ="Bar.dll"/> <add assemblyName ="Baz.dll"/> </preLoadedAssemblies> </configuration>
AssembliesResolver
PreLoadedAssembliesSettings AssemblyElementCollection Assembly
Element
public class PreLoadedAssembliesSettings: ConfigurationSection { [ConfigurationProperty("", IsDefaultCollection = true)] public AssemblyElementCollection AssemblyNames { get { return (AssemblyElementCollection)this[""]; } } public static PreLoadedAssembliesSettings GetSection() { return ConfigurationManager.GetSection("preLoadedAssemblies") as PreLoadedAssembliesSettings; } } public class AssemblyElementCollection : ConfigurationElementCollection { protected override ConfigurationElement CreateNewElement() { return new AssemblyElement(); } protected override object GetElementKey(ConfigurationElement element) { AssemblyElement serviceTypeElement = (AssemblyElement)element; return serviceTypeElement.AssemblyName;
4 HttpController
ASP.NET Web API 2
158
} } public class AssemblyElement : ConfigurationElement { [ConfigurationProperty("assemblyName", IsRequired = true)] public string AssemblyName { get { return (string)this["assemblyName"]; } set { this["assemblyName"] = value; } } }
AssembliesResolver DefaultAssembliesResolver
ExtendedDefaultAssembliesResolver ExtendedDefaultAssembliesResolverDefaultAssembliesResolver GetAssemblies
public class ExtendedDefaultAssembliesResolver : DefaultAssembliesResolver { public override ICollection<Assembly> GetAssemblies() { PreLoadedAssembliesSettings settings = PreLoadedAssembliesSettings.GetSection(); if (null != settings) { foreach (AssemblyElement element in settings.AssemblyNames) { AssemblyName assemblyName = AssemblyName.GetAssemblyName(element.AssemblyName); if(!AppDomain.CurrentDomain.GetAssemblies() .Any(assembly=>AssemblyName.ReferenceMatchesDefinition( assembly.GetName(),assemblyName))) { AppDomain.CurrentDomain.Load(assemblyName); } } } return base.GetAssemblies(); } }
Hosting ExtendedDefault Assemblies Resolver HttpConfiguration ServicesContainer
class Program {
4.2 HttpController
ASP.NET Web API 2
159
static void Main(string[] args) { Uri baseAddress = new Uri("http://127.0.0.1:3721"); using (HttpSelfHostServer httpServer = new HttpSelfHostServer( new HttpSelfHostConfiguration(baseAddress))) { httpServer.Configuration.Services.Replace( typeof(IAssembliesResolver), new ExtendedDefaultAssembliesResolver()); // } } }
FooController
BarController BazController Action Get 4-5
Action S402
4-5 AssembliesResolver HttpController
WebHostAssembliesResolver
DefaultAssembliesResolver HttpController
4 HttpController
ASP.NET Web API 2
160
HttpController
Self Host Web Host
AssembliesResolver
Web Host ASP.NET Web API
GlobalConfiguration Configuration HttpConfiguration
GlobalConfiguration Configuration
ServicesContainer AssembliesResolver
WebHostAssembliesResolver
public static class GlobalConfiguration { // static GlobalConfiguration() { _configuration = new Lazy<HttpConfiguration>(delegate { HttpConfiguration configuration = new HttpConfiguration( new HostedHttpRouteCollection(RouteTable.Routes)); configuration.Services.Replace(typeof(IAssembliesResolver), new WebHostAssembliesResolver()); // return configuration; }); // } public static HttpConfiguration Configuration { get { return _configuration.Value; } } }
WebHostAssembliesResolver System.Web.Http.WebHost.dll
WebHostAssembliesResolver GetAssemblies
BuildManager GetReferencedAssemblies
internal sealed class WebHostAssembliesResolver : IAssembliesResolver { ICollection<Assembly> IAssembliesResolver.GetAssemblies()
4.2 HttpController
ASP.NET Web API 2
161
{ return BuildManager.GetReferencedAssemblies().OfType<Assembly>() .ToList<Assembly>(); } }
BuildManager GetReferencedAssemblies
HttpController
Self Host
Web Host ASP.NET Web API HttpController
Foo.dll Bar.dll Baz.dll HttpController
4.2.2 HttpController
ServicesContainer AssembliesResolver HttpController
HttpController HttpController
TypeResolver HttpControllerTypeResolver IHttpController
TypeResolver GetControllerTypes
AssembliesResolver HttpController
public interface IHttpControllerTypeResolver { ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver); }
AssembliesResolver HttpControllerTypeResolver
HttpConfiguration ServicesContainer ServicesContainer
GetHttpControllerTypeResolver HttpController
TypeResolver
public static class ServicesExtensions { // public static IHttpControllerTypeResolver GetHttpControllerTypeResolver( this ServicesContainer services); }
HttpConfiguration DefaultServices
HttpControllerTypeResolver
4 HttpController
ASP.NET Web API 2
162
HttpControllerTypeResolver DefaultHttpControllerTypeResolver
public class DefaultServices : ServicesContainer { // public DefaultServices(HttpConfiguration configuration) { // this.SetSingle<IHttpControllerTypeResolver>( new DefaultHttpControllerTypeResolver()); } }
DefaultHttpControllerTypeResolver
DefaultHttpControllerTypeResolver Predicate<Type>
IsControllerTypePredicate
HttpController
public class DefaultHttpControllerTypeResolver : IHttpControllerTypeResolver { public DefaultHttpControllerTypeResolver(); public DefaultHttpControllerTypeResolver(Predicate<Type> predicate); public virtual ICollection<Type> GetControllerTypes( IAssembliesResolver assembliesResolver); protected Predicate<Type> IsControllerTypePredicate { get; } }
HttpController
DefaultHttpControllerTypeResolver Predicate<Type>
Predicate<Type> HttpController
HttpController
� IsVisible = true IsAbstract = false IsClass = true
� IHttpController
� Controller controller
4.2 HttpController
ASP.NET Web API 2
163
HttpController GetControllerTypesAssembliesResolver
HttpControllerDefaultHttpControllerTypeResolver HttpController
public class DefaultHttpControllerTypeResolver : IHttpControllerTypeResolver { // public virtual ICollection<Type> GetControllerTypes( IAssembliesResolver assembliesResolver) { List<Type> types = new List<Type>(); foreach (Assembly assembly in assembliesResolver.GetAssemblies()) { foreach (Type type in assembly.GetTypes()) { if (this.IsControllerTypePredicate(type)) { types.Add(type); } } } return types; } }
HttpController
HttpControllerASP.NET Web API HttpController
HttpControllerTypeCache System.Web. Http.dll
internal sealed class HttpControllerTypeCache { // internal Dictionary<string, ILookup<string, Type>> Cache { get; } }
HttpController Cache Dictionary<string, ILookup<string, Type>> Key HttpController HttpController
Controller Value ILookup<string, Type>
4 HttpController
ASP.NET Web API 2
164
HttpController Key HttpController
HttpControllerTypeCache HttpControllerTypeResolver
HttpController
HttpControllerTypeCache HttpController
4
ApiController HttpController HttpControllers1 Http
Controllers2 HttpController FooBarController FoobarController
4 HttpController FooBar
namespace HttpControllers1 { public class FooBarController : ApiController {} public class FoobarController : ApiController {} } namespace HttpControllers2 { public class FooBarController : ApiController {} public class FoobarController : ApiController {} }
HttpControllerTypeCache
HttpController Cache
Dictionary<string, ILookup<string, Type>>
class Program { static void Main(string[] args) { Type typeCacheType = Type.GetType( "System.Web.Http.Dispatcher.HttpControllerTypeCache, System.Web.Http"); object typeCache = Activator.CreateInstance(typeCacheType, new object[] { new HttpConfiguration() }); PropertyInfo cacheProperty = typeCacheType.GetProperty("Cache", BindingFlags.Instance | BindingFlags.NonPublic); Dictionary<string, ILookup<string, Type>> cachedTypes = (Dictionary<string, ILookup<string, Type>>) cacheProperty.GetValue(typeCache, null);
4.2 HttpController
ASP.NET Web API 2
165
Console.WriteLine("{0,-16}{1,-20}{2,-10}", "ControllerName", "Namespace","TypeName"); foreach (var item in cachedTypes) { foreach (string key in item.Value.Select( group => group.Key).Distinct()) { foreach (Type type in item.Value[key]) { Console.WriteLine("{0,-16}{1,-20}{2,-10}", item.Key, key, type.Name); } } } } }
4 HttpController
HttpControllerTypeCache S403 Dictionary<string, ILookup<string,
Type>> Key HttpController Controller
FooBarController FoobarController Key
Value ILookup<string, Type> Key HttpController
HttpControllers1 HttpControllers2
ControllerName Namespace TypeName FooBar HttpControllers1 FooBarController FooBar HttpControllers1 FoobarController FooBar HttpControllers2 FooBarController FooBar HttpControllers2 FoobarController
4.2.3 HttpController
AssembliesResolver HttpController
HttpController HttpController
HttpControllerSelector HttpControllerSelector
IHttpControllerSelector
public interface IHttpControllerSelector { IDictionary<string, HttpControllerDescriptor> GetControllerMapping(); HttpControllerDescriptor SelectController(HttpRequestMessage request); }
4 HttpController
ASP.NET Web API 2
166
GetControllerMapping SelectController
GetControllerMapping HttpController HttpControllerDescriptor
HttpController HttpController
SelectController HttpController HttpControllerDescriptor
DefaultHttpControllerSelector
HttpControllerSelector ServicesContainer
ServicesContainer GetHttpControllerSelector
HttpControllerSelector
public static class ServicesExtensions { // public static IHttpControllerSelector GetHttpControllerSelector( this ServicesContainer services); }
DefaultServices
HttpConfiguration DefaultHttpControllerSelector
HttpControllerSelector
public class DefaultServices : ServicesContainer { // public DefaultServices(HttpConfiguration configuration) { // this.SetSingle<IHttpControllerSelector>( new DefaultHttpControllerSelector(configuration)); } }
DefaultHttpControllerSelector IHttpController
Selector GetControllerName
HttpRequestMessage HttpController
public class DefaultHttpControllerSelector : IHttpControllerSelector { public DefaultHttpControllerSelector(HttpConfiguration configuration); public virtual IDictionary<string, HttpControllerDescriptor>
4.2 HttpController
ASP.NET Web API 2
167
GetControllerMapping(); public virtual HttpControllerDescriptor SelectController( HttpRequestMessage request); public virtual string GetControllerName(HttpRequestMessage request); }
HttpController
3 Web Host Http ControllerHandler HTTP HttpRequestMessage
ASP.NET RouteData HttpRouteDataHttpRequestMessage
Self Host HttpRoutingDispatcherASP.NET Web APIHttpRouteData HttpRouteData HttpRequestMessage
HttpRouteData HttpControllercontroller HttpRequestMessage HttpController
DefaultHttpControllerSelector GetControllerNameHttpRequestMessage HttpController
public class DefaultHttpControllerSelector : IHttpControllerSelector { // public virtual string GetControllerName(HttpRequestMessage request) { IHttpRouteData routeData = request.GetRouteData(); if (routeData == null) { return null; } string str = null; routeData.Values.TryGetValue<string>("controller", out str); return str; } }
HttpController HttpControllerDescriptor
DefaultHttpControllerSelector GetControllerMapping IDictionary
4 HttpController
ASP.NET Web API 2
168
<string, HttpControllerDescriptor> HttpController HttpController
Descriptor HttpController
public class DefaultHttpControllerSelector : IHttpControllerSelector { // private readonly HttpControllerTypeCache _controllerTypeCache; public virtual IDictionary<string, HttpControllerDescriptor> GetControllerMapping(); }
GetControllerMapping DefaultHttp
ControllerSelector HttpControllerTypeCache
HttpController GetControllerMapping HttpController
HttpControllerDescriptor
HttpController
HttpController HttpController
HttpController HttpControllerTypeCache
Dictionary<string, ILookup<string, Type>>
GetControllerMapping IDictionary<string, HttpController
Descriptor> HttpController DefaultHttpController
Selector HttpController HttpController
GetControllerMapping
HttpControllers1 FooController BarController
HttpControllers2 BarController BazController
namespace HttpControllers1 { public class FooController: ApiController {} public class BarController: ApiController {} } namespace HttpControllers2 { public class BarController: ApiController {}
4.2 HttpController
ASP.NET Web API 2
169
public class BazController: ApiController {} }
HttpController 4 DefaultHttpControllerSelector
GetControllerMapping HttpController
FooController BazController BarController
GetControllerMapping
public class DefaultHttpControllerSelector : IHttpControllerSelector { // private HttpControllerTypeCache _controllerTypeCache; private HttpConfiguration _configuration; public virtual IDictionary<string, HttpControllerDescriptor> GetControllerMapping() { Dictionary<string, HttpControllerDescriptor> mappings = new Dictionary<string, HttpControllerDescriptor>(); var keys = from item in _controllerTypeCache.Cache where item.Value.Count() == 1 select item.Key; foreach (string key in keys) { Type controllerType = _controllerTypeCache .Cache[key].First().First(); HttpControllerDescriptor descriptor = new HttpControllerDescriptor(_configuration, key, controllerType); mappings.Add(key, descriptor); } return mappings; } }
GetControllerMapping
GetControllerMapping DefaultHttp
ControllerSelector
3 ApiController HttpController
FooController BarController BazController
namespace HttpControllers {
4 HttpController
ASP.NET Web API 2
170
public class FooController : ApiController {} public class BarController : ApiController {} public class BazController : ApiController {} }
HttpConfiguration
ServicesContainer DefaultHttpControllerSelector
GetControllerMapping HttpController HttpControllerDescriptor
HttpController
class Program { static void Main(string[] args) { HttpConfiguration configuration = new HttpConfiguration(); IHttpControllerSelector controllerSelector = configuration.Services.GetHttpControllerSelector(); IDictionary<string, HttpControllerDescriptor> mappings = controllerSelector.GetControllerMapping(); Console.WriteLine("{0,-16}{1,-10}", "ControllerName", "TypeName"); foreach (var item in mappings) { Console.WriteLine("{0,-16}{1,-10}", item.Key, item.Value.ControllerType.Name); } } }
S404
HttpController
3 HttpController DefaultHttpControllerSelector
ControllerName TypeName Bar BarController Baz BazController Foo FooController
DefaultHttpControllerSelector HttpController
3 HttpController 4 HttpController Foo
Controller BazController HttpControllers1 HttpControllers2
4.2 HttpController
ASP.NET Web API 2
171
BarController
namespace HttpControllers1 { public class FooController: ApiController {} public class BarController : ApiController {} } namespace HttpControllers2 { public class BarController : ApiController {} public class BazController : ApiController {} }
S405
BarController DefaultHttpControllerSelector
BarController
ControllerName TypeName Baz BazController Foo FooController
URI HttpController
URI HttpController
HttpController ASP.NET Web API
HttpController
HttpController
HttpControllerSelector HttpController
SelectController DefaultHttpControllerSelector
SelectController GetControllerName
HttpRequestMessage HttpController
GetControllerMapping HttpControllerDescriptor
SelectController HttpController
4 HttpController
ASP.NET Web API 2
172
GetControllerName HttpController NullASP.NET Web Host ASP.NET Web
API Self HostHttpController DefaultHttpControllerSelector
HttpStatusCode.NotFound HttpResponseException404, Not Found
GetControllerMappingHttpController HttpControllerDescriptor
� AssembliesResolverHttpController
� AssembliesResolver HttpControllerHttpController
HttpController
GetControllerMappingHttpController HttpControllerTypeCache
DefaultHttpControllerSelector HttpStatusCode.NotFoundHttpResponseException InvalidOperationException
HttpController 4-6
4-6 HttpController
4.2 HttpController
ASP.NET Web API 2
173
4.2.4 HttpController
HttpControllerSelector
HttpRequestMessage HttpController HttpControllerDescriptor
HttpControllerDescriptor HttpController
HttpControllerDescriptor HttpController CreateController
CreateController HttpController
public class HttpControllerDescriptor { // public virtual IHttpController CreateController(HttpRequestMessage request); }
HttpControllerActivator
HttpController HttpControllerActivator
HttpControllerActivator IHttpControllerActivator
Create HttpRequestMessage
HttpController HttpControllerDescriptor HttpController
HttpController
public interface IHttpControllerActivator { IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType); }
ServicesContainer
HttpController ServicesContainer
GetHttpControllerActivator HttpControllerActivator
public static class ServicesExtensions { // public static IHttpControllerActivator GetHttpControllerActivator( this ServicesContainer services); }
4 HttpController
ASP.NET Web API 2
174
HttpControllerDescriptor CreateController
HttpControllerActivator Create HttpController
CreateController
public class HttpControllerDescriptor { // public virtual IHttpController CreateController(HttpRequestMessage request) { return this.Configuration.Services.GetHttpControllerActivator() .Create(request, this, this.ControllerType); } }
DefaultHttpControllerActivator
DefaultServices HttpController
Activator DefaultServices
DefaultHttpControllerActivator
public class DefaultServices : ServicesContainer { // public DefaultServices(HttpConfiguration configuration) { // this.SetSingle<IHttpControllerActivator>( new DefaultHttpControllerActivator()); } }
DefaultHttpControllerActivator Create
HttpController DefaultHttpControllerActivator
HttpController DependencyResolver
DependencyResolver
DependencyResolver IoC IoC
Dependency Injection DI IoC
IoC
4.2 HttpController
ASP.NET Web API 2
175
IoC HttpController
DependencyResolver
ASP.NET Web API IoC DependencyResolver
IDependencyResolver System.Web.Http.Dependencies
IDependencyScope BeginScope
IDependencyResolver IDependencyScope
IDisposable
public interface IDependencyResolver : IDependencyScope, IDisposable { IDependencyScope BeginScope(); } public interface IDependencyScope : IDisposable { object GetService(Type serviceType); IEnumerable<object> GetServices(Type serviceType); }
DependencyResolver BeginScope IDependencyScope
GetService GetServices
IDependencyScope IDisposable
Dispose
DependencyResolver
ServicesContainer HttpConfiguration
DependencyResolver HttpConfiguration Dependency
Resolver
public class HttpConfiguration : IDisposable { // public HttpConfiguration(HttpRouteCollection routes) { this._dependencyResolver = EmptyResolver.Instance;
}
public IDependencyResolver DependencyResolver { get
4 HttpController
ASP.NET Web API 2
176
{ return this._dependencyResolver; } set { this._dependencyResolver = value; } } }
HttpConfiguration Dependency
Resolver EmptyResolver Instance EmptyResolver
EmptyResolver System.Web.Http.dll
IoC BeginScope
GetService GetServices Null Dispose
internal class EmptyResolver : IDependencyResolver, IDependencyScope, IDisposable { public IDependencyScope BeginScope(); public void Dispose(); public object GetService(Type serviceType); public IEnumerable<object> GetServices(Type serviceType); public static IDependencyResolver Instance { get; } }
HttpRequestMessage DependencyResolver
DependencyResolver HttpConfiguration
HttpRequestMessage DependencyScope
HttpRequestMessage IDependencyScope
GetDependencyScope
public static class HttpRequestMessageExtensions { // public static IDependencyScope GetDependencyScope( this HttpRequestMessage request); }
DependencyScope
HttpRequestMessage DependencyScope
4.2 HttpController
ASP.NET Web API 2
177
HttpConfiguration DependencyResolver
DependencyScope HttpRequestMessage
DependencyScope HttpRequestMessage
DependencyResolver DefaultHttpControllerActivator
DependencyResolver DefaultHttpControllerActivator
Create HttpController
DefaultHttpControllerActivator HttpRequestMessage
GetDependencyScope DependencyResolver DependencyScope
HttpController GetService
HttpController Create
HttpController HttpController
DefaultHttpControllerActivator HttpController
public class DefaultHttpControllerActivator : IHttpControllerActivator { public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) { IDependencyScope depedencyScope = request.GetDependencyScope(); object httpController = depedencyScope.GetService(controllerType) ?? Activator.CreateInstance(controllerType); return httpController as IHttpController; } }
HttpConfiguration DependencyResolver
EmptyResolver GetService Null HttpController
HttpController
HttpController Http
Controller HttpController HttpControllerDescriptor
HttpController HttpController
HttpController HttpController
4 HttpController
ASP.NET Web API 2
178
4.2.5 HttpController
HttpController
HttpController AssembliesResolver HttpController
TypeResolver HttpController HttpControllerSelector
HttpController HttpControllerActivator IoC Dependency
Resolver
4-7 UML
HttpController ASP.NET Web API HttpController
4-7 HttpController
4.2 HttpController
ASP.NET Web API 2
179
HttpController
ASP.NET Web API HttpMessage
Handler HttpRoutingDispatcher HttpRouting
Dispatcher Self Host Web Host
ASP.NET
HttpControllerDispatcher
HttpControllerDispatcher HttpController
HttpResponseMessage HttpRoutingDispatcher HttpResponse
Message
4-8 UML HttpController HttpControllerDispatcher
HttpControllerSelector SelectController
HttpController HttpControllerDescriptor
4-8 HttpController
HttpControllerSelector DefaultHttpControllerSelector
HttpControllerTypeResolver HttpController
HttpController HttpControllerDescriptor HttpController
SelectController HttpRouteData
HttpController HttpControllerDescriptor
HttpControllerDispatcher HttpControllerDescriptor CreateController
HttpController HttpControllerDescriptor
4 HttpController
ASP.NET Web API 2
180
CreateController HttpControllerActivator
Create HttpController
DefaultHttpControllerActivator DependencyResolver
HttpController HttpController
HttpController DefaultHttpControllerActivator
HttpController
DependencyResolver EmptyResolver
HttpController Null HttpController
HttpController
HttpController
HttpController ApiController IDisposable
Dispose
HttpRequestMessage
Properties HttpRequestMessage
HttpRequestMessage Properties
Key MS_DisposableRequestResources List
<IDisposable> HttpRequestMessage Get
ResourcesForDisposal RegisterForDispose
IDisposable
public static class HttpRequestMessageExtensions { // public static IEnumerable<IDisposable> GetResourcesForDisposal( this HttpRequestMessage request); public static void RegisterForDispose(this HttpRequestMessage request, IEnumerable<IDisposable> resources); public static void RegisterForDispose(this HttpRequestMessage request, IDisposable resource); public static void DisposeRequestResources(this HttpRequestMessage request); }
4.2 HttpController
ASP.NET Web API 2
181
ASP.NET Web API HttpRequestMessage
DisposeRequestResources
Web Host 3
ASP.NET Web API HttpMessageHandler
HttpControllerHandler HTTP
HttpRequestMessage
HttpControllerHandler 3
� HttpRequestMessage DisposeRequestResources
� HttpRequestMessage Dispose
� HttpResponseMessage
Self Host 3
HttpBinding HttpMessage
HttpMessage HttpRequestMessage HttpResponseMessage
WCF Message
Close Dispose
HttpMessage Close Dispose
HttpRequestMessage HttpResponseMessage
HttpRequestMessage
Self Host HttpMessage
HttpRequestMessage 3
Foo Bar Baz DisposableObject IDisposable
Dispose
public class DisposableObject : IDisposable { public void Dispose() { Console.WriteLine("{0}.Dispose()", this.GetType().Name); }
4 HttpController
ASP.NET Web API 2
182
} public class Foo : DisposableObject {} public class Bar : DisposableObject {} public class Baz : DisposableObject {}
Main Foo
Bar Baz 3 RegisterForDispose
HttpRequestMessage HttpRequestMessage
HttpMessage Close
class Program { static void Main(string[] args) { HttpRequestMessage request = new HttpRequestMessage(); request.RegisterForDispose(new Foo()); request.RegisterForDispose(new Bar()); request.RegisterForDispose(new Baz()); Type httpMessageType = Type.GetType( "System.Web.Http.SelfHost.Channels.HttpMessage, System.Web.Http.SelfHost"); Message httpMessage = (Message)Activator.CreateInstance(httpMessageType, new object[] { request }); httpMessage.Close(); } }
RegisterForDispose HttpRequestMessage
S406
Foo.Dispose() Bar.Dispose() Baz.Dispose()
ApiController ExecuteAsync
RegisterForDispose HttpRequestMessage
ApiController HttpRequestMessage
4.3 IoC
ASP.NET Web API 2
183
4.3 IoC
Inversion of Control IoCIoC
A B BA IoC Controller
4.3.1 Unity IoCIoC Dependency Injection DI
Martin FowlerInversion of Control Containers and the Dependency Injection pattern
31 3
� Type Mapping
/ /
� Constructor Injection IoCIoC
� Property InjectionIoC
� Method InjectionIoC
IoC Castle Windsor Unity Spring.NET StructureMapNinject Unity Patterns & Practices IoCCodeplex http://unity.codeplex.com/
Unity 2.1 UnityIoC Unity
4 HttpController
ASP.NET Web API 2
184
4 IA IB IC ID
A B C D A B C D 3 IB
IC ID B
C DependencyAttribute
D Initialize InjectionMethodAttribute
A IoC
namespace UnityDemo { public interface IA {} public interface IB {} public interface IC {} public interface ID {} public class A : IA { public IB B { get; set; } [Dependency] public IC C { get; set; } public ID D { get; set; } public A(IB b) { this.B = b; } [InjectionMethod] public void Initialize(ID d) { this.D = d; } } public class B: IB{} public class C: IC{} public class D: ID{} }
Unity
Unity
<configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity. Configuration. UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> </configSections> <unity>
4.3 IoC
ASP.NET Web API 2
185
<containers> <container> <register type="UnityDemo.IA, UnityDemo" mapTo="UnityDemo.A, UnityDemo"/> <register type="UnityDemo.IB, UnityDemo" mapTo="UnityDemo.B, UnityDemo"/> <register type="UnityDemo.IC, UnityDemo" mapTo="UnityDemo.C, UnityDemo"/> <register type="UnityDemo.ID, UnityDemo" mapTo="UnityDemo.D, UnityDemo"/> </container> </containers> </unity> </configuration>
Main IoC UnityContainer
Resolve
IA A B C D Null
class Program { static void Main(string[] args) { IUnityContainer container = new UnityContainer(); UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager .GetSection(UnityConfigurationSection.SectionName); configuration.Configure(container); A a = (A)container.Resolve<IA>(); Console.WriteLine("a.B == null ? {0}", a.B == null ? "Yes" : "No"); Console.WriteLine("a.C == null ? {0}", a.C == null ? "Yes" : "No"); Console.WriteLine("a.D == null ? {0}", a.D == null ? "Yes" : "No"); } }�
Resolve<IA>
A 3
B
C D S407
a.B == null ? No a.C == null ? No a.D == null ? No
4.3.2 IoC HttpControllerActivator
IoC HttpController IoC
HttpController HttpController HttpController
4 HttpController
ASP.NET Web API 2
186
Activator IoC ASP.NET Web API HttpController
HttpControllerActivator
HttpControllerActivator IoC
IoC Unity ASP.NET Web API
UnityHttpControllerActivator UnityHttpControllerActivator Unity
UnityContainer HttpController Create
UnityContainer Resolve HttpController
public class UnityHttpControllerActivator: IHttpControllerActivator { public IUnityContainer UnityContainer { get; private set; } public UnityHttpControllerActivator(IUnityContainer unityContainer) { this.UnityContainer = unityContainer; } public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) { return (IHttpController)this.UnityContainer.Resolve(controllerType); } }
ApiController ContactsController
Action Get
id ID
public class ContactsController : ApiController { public IContactRepository Repository { get; private set; } public ContactsController(IContactRepository repository) { this.Repository = repository; } public IEnumerable<Contact> Get(string id = "") { return this.Repository.GetContacts(contact => string.IsNullOrEmpty(id) || id == contact.Id); } } public class Contact {
4.3 IoC
ASP.NET Web API 2
187
public string Id { get; set; } public string Name { get; set; } public string PhoneNo { get; set; } public string EmailAddress { get; set; } public string Address { get; set; } }
Action Repository
IContactRepository IContactRepository
GetContacts
public interface IContactRepository { IEnumerable<Contact> GetContacts(Predicate<Contact> predicate); }
DefaultContactRepository IContactRepository
public class DefaultContactRepository : IContactRepository { private static List<Contact> contacts = new List<Contact> { new Contact{ Id="001", Name = " ", PhoneNo="123", EmailAddress = "[email protected]"}, new Contact{ Id="002", Name = " ", PhoneNo="456", EmailAddress = "[email protected]"} }; public IEnumerable<Contact> GetContacts(Predicate<Contact> predicate) { return contacts.Where(contact=>predicate(contact)); } }
Global.asax UnityHttpControllerActivator
Application_Start UnityContainer
RegisterType<TFrom,TTo> IContactRepository DefaultContactRepository
UnityContainer UnityHttpControllerActivator
ServicesContainer
public class WebApiApplication: System.Web.HttpApplication { protected void Application_Start()
4 HttpController
ASP.NET Web API 2
188
{ // IUnityContainer unityContainer = new UnityContainer(); unityContainer.RegisterType<IContactRepository, DefaultContactRepository>(); GlobalConfiguration.Configuration.Services.Replace( typeof(IHttpControllerActivator), new UnityHttpControllerActivator(unityContainer)); } }
ASP.NET Web API
/api/contacts ID 001 /api/contacts/001
4-9 S408
4-9 Web API
4.3.3 IoC DependencyResolver
DefaultHttpControllerActivator DependencyResolver
HttpController HttpControllerActivator IoC Http
Controller DependencyResolver
DependencyResolver Ninject IoC
Unity Ninject IoC IoC
4.3 IoC
ASP.NET Web API 2
189
http://www.ninject.org/ Ninject
public class NinjectDependencyResolver : IDependencyResolver { private List<IDisposable> disposableServices = new List<IDisposable>(); public IKernel Kernel { get; private set; } public NinjectDependencyResolver(NinjectDependencyResolver parent) { this.Kernel = parent.Kernel; } public NinjectDependencyResolver() { this.Kernel = new StandardKernel(); } public void Register<TFrom, TTo>() where TTo : TFrom { this.Kernel.Bind<TFrom>().To<TTo>(); } public IDependencyScope BeginScope() { return new NinjectDependencyResolver(this); } public object GetService(Type serviceType) { return this.Kernel.TryGet(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { foreach (var service in this.Kernel.GetAll(serviceType)) { this.AddDisposableService(service); yield return service; } } public void Dispose() { foreach (IDisposable disposable in disposableServices) { disposable.Dispose(); } } private void AddDisposableService(object servie)
4 HttpController
ASP.NET Web API 2
190
{ IDisposable disposable = servie as IDisposable; if (null != disposable && !disposableServices.Contains(disposable)) { disposableServices.Add(disposable); } } }
NinjectDependencyResolver DependencyResolver
NinjectDependencyResolver IKernel Kernel
GetService GetServices Kernel TryGet GetAll
BeginScope NinjectDependencyResolver Kernel
Register<TFrom,TTo>
IDisposable
IDisposable
Dispose
NinjectDependencyResolver
Global.asax HttpControllerActivator Ninject
DependencyResolver ASP.NET Web API
4-9 S409
public class MvcApplication: System.Web.HttpApplication { protected void Application_Start() { // NinjectDependencyResolver dependencyResolver = new NinjectDependencyResolver(); dependencyResolver.Register<IContactRepository, DefaultContactRepository>(); GlobalConfiguration.Configuration.DependencyResolver = dependencyResolver; } }