- ASP.net tutorials:
1. Create simple web api
- Create Model
- Create Controller
- Define simple routing
2. Access web service
- Access web service from browser
- Display web service data in browser with JavaScript/jQuery
- Access web service from .net client - WebRequest
- Access web service from .net client - HttpClient
3. Other
- JSON or XML
- Invoking web methods from Fiddler
- Routing to method with attributes
- Calling delete with http GET verb
- Multiple GET methods
REST stands for REpresentational State Transfer
The concept represent an approach how data can be manipulated via webservice. REST leverages http verbs:
GET - retrieve item(s)
POST - add an item
PUT - update an item
DELETE - delete an item
Code examples: Service (VS 2010) | Client (VS 2012) Web Api official site
ASP.net tutorials:
Tutorial on asp.net for Visual Studio 2012 (with sources, get only)
ASP. NET Web API Tutorial 02: CRUD Operations (with sources)
1. Create simple web api
In Visual Studio 2010 select New Project, Web, ASP.net Empty Web Application
Right click on the solution, Add >> New Folder, name it Controllers
Right click on the solution, Add >> New Folder, name it Models
Right click on the Models folder, Add >> Class New Folder, name it Person
Create Model
C# public class Person { public String Name; public int Height; }
Create Controller
Right click on References, Add Reference, System.Web.Http
Right click on References, Add Reference, System.Net.Http 2.0
Right click on the Controllers folder, Add > Add New Class, name it PersonsController
.
C# public class PersonsController : System.Web.Http.ApiController { static Person[] s_persons = new Person[] { new Person() { Name = "John", Height=180}, new Person() { Name = "Paul", Height=170} }; public IEnumerable<Person> Get() { return s_persons.ToArray(); } public Person Get(int id) { return s_persons.Where(p => p.Id == id).FirstOrDefault(); } public System.Net.Http.HttpResponseMessage Post(Person newPerson) { s_persons.Add(newPerson); // pass back to the caller success and new id (if database is used) System.Net.Http.HttpResponseMessage result = new System.Net.Http.HttpResponseMessage(HttpStatusCode.OK); result.Headers.Location = new Uri("http://localhost:34460/api/persons/" + Convert.ToString(newPerson.Id)); // Id field would be autogenerated if database is used
return result; } public void Put(Person personArg) { Person person = m_persons.Where(p => p.Id == personArg.Id).FirstOrDefault(); person = personArg; } public void Delete(int id) { Person person = m_persons.Where(p => p.Id == id).FirstOrDefault(); s_persons.Remove(person); } }
Define simple routing
Create App_Start folder.
Create WebApiConfig.cs under the folder.
http://myserver/api/persons will return list of all persons, because persons will be interpreted as PersonsController and a method starting with Get with no arguments will be used to return the data. {id} maps to id argument (in Get(int id)).
C# using System.Web.Http; namespace WebApiSimple { public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } }Create Global.asax file in the root of the project
C# <%@ Application Codebehind="Global.asax.cs" Inherits="WebApiSimple.WebApiApplication" Language="C#" %>and Global.asax.cs as well. These files will register mapping defined in WebApiConfig when the application starts.
C#
namespace WebApiSimple
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
WebApiConfig.Register (System.Web.Http.GlobalConfiguration.Configuration);
}
}
}
2. Access web service
Access web service from browser
Hit F5 in Visual Studio to start the web service
Open your web browser
type: http://myserver/api/persons to get list of persons
type: http://myserver/api/persons/1 to get person #1
Display web service data in browser with JavaScript/jQuery
HTML <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.0.3.min.js"></script> <script> function listAllPeople() { $.getJSON('api/persons').done( function (people) { $.each(people, function (key, person) { $('<li>', { text: person.Id + " " + person.Name } ).appendTo( $('#persons') ); }); } ); } <script>
Access web service from .net client - WebRequest
- Create a console app
- Inlude model.cs in the project
C# HttpWebRequest myHttpWebRequest = (HttpWebRequest)HttpWebRequest.Create("http://localhost:34460/api/persons"); myHttpWebRequest.Method = "GET"; myHttpWebRequest.Credentials = System.Net.CredentialCache.DefaultCredentials; myHttpWebRequest.ContentType = "application/json"; myHttpWebRequest.Accept = "application/json"; HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse(); // data in JSON format System.IO.StreamReader myStreamReader = new System.IO.StreamReader(myHttpWebResponse.GetResponseStream()); string responseData = myStreamReader.ReadToEnd(); // deserialize the data var p1 = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<Person[]>(responseData);
Access web service from .net client - HttpClient
- Create console app
- Include model.cs in the projects
- Right click on References, Add Reference, System.Net.Http 2.0 (for HttpClient)
- add reference to System.Net.Http.Formatting 4.0 (ReadAsAsync) As HttpClient calls are asynchronous, async-await" is used.
C#
static void Main()
{
string baseAddress = "http://localhost:34460/";
CallWebService(baseAddress + "api/persons").Wait();
}
static async Task CallWebService(string baseAddress)
{
HttpClientHandler handler = new HttpClientHandler();
handler.UseDefaultCredentials = true; // needed for Windows authentication
using (HttpClient client = new System.Net.Http.HttpClient(handler))
{
client.BaseAddress = new Uri(baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// get all items
HttpResponseMessage httpResponseMsg = await client.GetAsync("");
if (httpResponseMsg.IsSuccessStatusCode)
{
Person[] person = await httpResponseMsg.Content.ReadAsAsync<Person[]>();
}
// get one item
httpResponseMsg = await client.GetAsync(baseAddress+"/1");
if (httpResponseMsg.IsSuccessStatusCode)
{
Person person = await httpResponseMsg.Content.ReadAsAsync<Person>();
}
// add new - Post
Person newPerson = new Person() { Id=3, Name = "George" };
httpResponseMsg = await client.PostAsJsonAsync("", newPerson);
if (!httpResponseMsg.IsSuccessStatusCode) { return; }
Uri newlyAddedPersonUrl = httpResponseMsg.Headers.Location;
// update existing
newPerson.Name = "Ringo";
await client.PutAsJsonAsync(newlyAddedPersonUrl, newPerson);
// delete existing
await client.DeleteAsync(newlyAddedPersonUrl);
}
}
3. Other
JSON or XML
JSON [{"Name":"John","Id":1},{"Name":"Paul","Id":2}]If you want to get data in XML, you need to change the http header:
C# client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
XML <ArrayOfPerson xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/WebApiSimple.Models"> <Person><Id>1</Height><Name>John</Name></Person> <Person><Id>2</Height><Name>Paul</Name></Person></ArrayOfPerson>
Invoking web methods from Fiddler
-Navigate to Composer tab
-Select "POST" verb
-Enter web service address, e.g. http://myserver/api/persons
-In the Request body section, enter [{"Name": "John","Id":1}]
-Click "Execute"
If you set a break point in the Post() method, the Visual Studio will stop the web service execution there.
Routing to method with attributes
C# [HttpGet] public IEnumerable<Person> RetrieveAll() {... } [HttpPost] public System.Net.Http.HttpResponseMessage Add(Person newPerson) {...} [HttpPut] public void Update(Person personArg) { ... } [HttpDelete] public void Remove(int id) { ... }
Calling delete with http GET verb
C# // enables http://localhost:34460/apiaction/persons3/delete/1 config.Routes.MapHttpRoute( name: "ActionApi", routeTemplate: "apiaction/{controller}/{action}/{id}", // prefix "apiaction" is different in order to avoid conflict with api/persons/1 and api/persons/action defaults: new { id = RouteParameter.Optional } ); .... [HttpGet] public void Delete(int id) { Person person = s_persons.Where(p => p.Id == id).FirstOrDefault(); s_persons.Remove(person); }
Multiple GET methods
C# public Person GetOne(int id) { return s_persons.Where(p => p.Id == id).FirstOrDefault(); } public Person GetByName(string name) { return s_persons.Where(p => p.Name == name).FirstOrDefault(); }You can call GetByName either http://myserver/api/persons3?name=john or http://myserver/apiaction2/persons3/getbyname/john. The latter requires routing like below:
C# config.Routes.MapHttpRoute( name: "ActionApi2", routeTemplate: "apiaction2/{controller}/{action}/{name}", defaults: new { id = RouteParameter.Optional } );because web api maps {name} to the name of the method argument "name". If you change the argument to name1, the web api will not be able to route the apiaction2/persons3/getbyname/john. http://myserver/api/persons3?name=john will be then routed to GetAll() method that does not have any argument.