This tutorial builds a web API for managing a list of “to-do” items. A user interface (UI) isn’t created.
The following diagram shows the basic design of the app.
-
The client is whatever consumes the web API (mobile app, browser, etc.). This tutorial doesn’t create a client. Postman or curl is used as the client to test the app.
- A model is an object that represents the data in the app. In this case, the only model is a to-do item. Models are represented as C# classes, also known as Plain Old CLR Object (POCOs).
- A controller is an object that handles HTTP requests and creates the HTTP response. This app has a single controller.
- To keep the tutorial simple, the app doesn’t use a persistent database. The sample app stores to-do items in an in-memory database.
Create the project
Follow these steps in Visual Studio:
- From the File menu, select New > Project.
- Select the ASP.NET Core Web Application template. Name the project TodoApi and click OK.
- In the New ASP.NET Core Web Application – TodoApi dialog, choose the ASP.NET Core version. Select the API template and click OK. Do not select Enable Docker Support.
Launch the app
In Visual Studio, press CTRL+F5 to launch the app. Visual Studio launches a browser and navigates to http://localhost:<port>/api/values
, where <port>
is a randomly chosen port number. Chrome, Microsoft Edge, and Firefox display the following output:
1 2 |
[<span class="hljs-string">"value1"</span>,<span class="hljs-string">"value2"</span>] |
If using Internet Explorer, you’ll be prompted to save a values.json file.
Add a model class
A model is an object representing the data in the app. In this case, the only model is a to-do item.
In Solution Explorer, right-click the project. Select Add > New Folder. Name the folder Models.
Note
The model classes can go anywhere in the project. The Models folder is used by convention for model classes.
In Solution Explorer, right-click the Models folder and select Add > Class. Name the class TodoItemand click Add.
Update the TodoItem
class with the following code:
1 2 3 4 5 6 7 8 9 10 |
<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoApi.Models</span> { <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TodoItem</span> { <span class="hljs-keyword">public</span> <span class="hljs-keyword">long</span> Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } <span class="hljs-keyword">public</span> <span class="hljs-keyword">bool</span> IsComplete { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } } } |
The database generates the Id
when a TodoItem
is created.
Create the database context
The database context is the main class that coordinates Entity Framework functionality for a given data model. This class is created by deriving from the Microsoft.EntityFrameworkCore.DbContext
class.
In Solution Explorer, right-click the Models folder and select Add > Class. Name the class TodoContext and click Add.
Replace the class with the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore; <span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoApi.Models</span> { <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TodoContext</span> : <span class="hljs-title">DbContext</span> { <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TodoContext</span>(<span class="hljs-params">DbContextOptions<TodoContext> options</span>) : <span class="hljs-title">base</span>(<span class="hljs-params">options</span>) </span>{ } <span class="hljs-keyword">public</span> DbSet<TodoItem> TodoItems { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } } } |
Register the database context
In this step, the database context is registered with the dependency injection container. Services (such as the DB context) that are registered with the dependency injection (DI) container are available to the controllers.
Register the DB context with the service container using the built-in support for dependency injection. Replace the contents of the Startup.cs file with the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<span class="hljs-keyword">using</span> Microsoft.AspNetCore.Builder; <span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc; <span class="line-highlight"><span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;</span> <span class="hljs-keyword">using</span> Microsoft.Extensions.DependencyInjection; <span class="line-highlight"><span class="hljs-keyword">using</span> TodoApi.Models;</span> <span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoApi</span> { <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Startup</span> { <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureServices</span>(<span class="hljs-params">IServiceCollection services</span>) </span>{ <span class="line-highlight"> services.AddDbContext<TodoContext>(opt => </span> <span class="line-highlight"> opt.UseInMemoryDatabase(<span class="hljs-string">"TodoList"</span>));</span> services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">IApplicationBuilder app</span>) </span>{ app.UseMvc(); } } } |
The preceding code:
- Removes the unused code.
- Specifies an in-memory database is injected into the service container.
Add a controller
In Solution Explorer, right-click the Controllers folder. Select Add > New Item. In the Add New Itemdialog, select the API Controller Class template. Name the class TodoController, and click Add.
Replace the class with the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc; <span class="hljs-keyword">using</span> System.Collections.Generic; <span class="hljs-keyword">using</span> System.Linq; <span class="hljs-keyword">using</span> TodoApi.Models; <span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoApi.Controllers</span> { [<span class="hljs-meta">Route(<span class="hljs-string">"api/[controller]"</span>)</span>] [<span class="hljs-meta">ApiController</span>] <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TodoController</span> : <span class="hljs-title">ControllerBase</span> { <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> TodoContext _context; <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TodoController</span>(<span class="hljs-params">TodoContext context</span>) </span>{ _context = context; <span class="hljs-keyword">if</span> (_context.TodoItems.Count() == <span class="hljs-number">0</span>) { _context.TodoItems.Add(<span class="hljs-keyword">new</span> TodoItem { Name = <span class="hljs-string">"Item1"</span> }); _context.SaveChanges(); } } } } |
The preceding code defines an API controller class without methods. In the next sections, methods are added to implement the API. The class is annotated with an [ApiController]
attribute to enable some convenient features. For information on features enabled by the attribute, see Annotate class with ApiControllerAttribute.
The controller’s constructor uses Dependency Injection to inject the database context (TodoContext
) into the controller. The database context is used in each of the CRUD methods in the controller. The constructor adds an item to the in-memory database if one doesn’t exist.
Get to-do items
To get to-do items, add the following methods to the TodoController
class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[<span class="hljs-meta">HttpGet</span>] <span class="hljs-keyword">public</span> ActionResult<List<TodoItem>> GetAll() { <span class="hljs-keyword">return</span> _context.TodoItems.ToList(); } [<span class="hljs-meta">HttpGet(<span class="hljs-string">"{id}"</span>, Name = <span class="hljs-string">"GetTodo"</span>)</span>] <span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult<TodoItem> <span class="hljs-title">GetById</span>(<span class="hljs-params"><span class="hljs-keyword">long</span> id</span>) </span>{ <span class="hljs-keyword">var</span> item = _context.TodoItems.Find(id); <span class="hljs-keyword">if</span> (item == <span class="hljs-literal">null</span>) { <span class="hljs-keyword">return</span> NotFound(); } <span class="hljs-keyword">return</span> item; } |
These methods implement the two GET methods:
GET /api/todo
GET /api/todo/{id}
Here’s a sample HTTP response for the GetAll
method:
1 2 3 4 5 6 7 8 |
[ { <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Item1"</span>, <span class="hljs-attr">"isComplete"</span>: <span class="hljs-literal">false</span> } ] |
Later in the tutorial, I’ll show how the HTTP response can be viewed with Postman or curl.
Routing and URL paths
The [HttpGet]
attribute denotes a method that responds to an HTTP GET request. The URL path for each method is constructed as follows:
- Take the template string in the controller’s
Route
attribute:
1 2 3 4 5 6 7 8 |
<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoApi.Controllers</span> { <span class="line-highlight"> [<span class="hljs-meta">Route(<span class="hljs-string">"api/[controller]"</span>)</span>]</span> [<span class="hljs-meta">ApiController</span>] <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TodoController</span> : <span class="hljs-title">ControllerBase</span> { <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> TodoContext _context; |
- Replace
[controller]
with the name of the controller, which is the controller class name minus the “Controller” suffix. For this sample, the controller class name is TodoController and the root name is “todo”. ASP.NET Core routing is case insensitive. - If the
[HttpGet]
attribute has a route template (such as[HttpGet("/products")]
, append that to the path. This sample doesn’t use a template. For more information, see Attribute routing with Http[Verb] attributes.
In the following GetById
method, "{id}"
is a placeholder variable for the unique identifier of the to-do item. When GetById
is invoked, it assigns the value of "{id}"
in the URL to the method’s id
parameter.
1 2 3 4 5 6 7 8 9 10 11 |
<span class="line-highlight">[<span class="hljs-meta">HttpGet(<span class="hljs-string">"{id}"</span>, Name = <span class="hljs-string">"GetTodo"</span>)</span>]</span> <span class="line-highlight"><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult<TodoItem> <span class="hljs-title">GetById</span>(<span class="hljs-params"><span class="hljs-keyword">long</span> id</span>)</span> </span>{ <span class="hljs-keyword">var</span> item = _context.TodoItems.Find(id); <span class="hljs-keyword">if</span> (item == <span class="hljs-literal">null</span>) { <span class="hljs-keyword">return</span> NotFound(); } <span class="hljs-keyword">return</span> item; } |
Name = "GetTodo"
creates a named route. Named routes:
- Enable the app to create an HTTP link using the route name.
- Are explained later in the tutorial.
Return values
The GetAll
method returns a collection of TodoItem
objects. MVC automatically serializes the object to JSON and writes the JSON into the body of the response message. The response code for this method is 200, assuming there are no unhandled exceptions. Unhandled exceptions are translated into 5xx errors.
In contrast, the GetById
method returns the ActionResult<T> type, which represents a wide range of return types. GetById
has two different return types:
- If no item matches the requested ID, the method returns a 404 error. Returning NotFound returns an HTTP 404 response.
- Otherwise, the method returns 200 with a JSON response body. Returning
item
results in an HTTP 200 response.
Launch the app
In Visual Studio, press CTRL+F5 to launch the app. Visual Studio launches a browser and navigates to http://localhost:<port>/api/values
, where <port>
is a randomly chosen port number. Navigate to the Todo
controller at http://localhost:<port>/api/todo
.
Implement the other CRUD operations
In the following sections, Create
, Update
, and Delete
methods are added to the controller.
Create
Add the following Create
method:
1 2 3 4 5 6 7 8 9 |
[<span class="hljs-meta">HttpPost</span>] <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Create</span>(<span class="hljs-params">TodoItem item</span>) </span>{ _context.TodoItems.Add(item); _context.SaveChanges(); <span class="hljs-keyword">return</span> CreatedAtRoute(<span class="hljs-string">"GetTodo"</span>, <span class="hljs-keyword">new</span> { id = item.Id }, item); } |
The preceding code is an HTTP POST method, as indicated by the [HttpPost] attribute. MVC gets the value of the to-do item from the body of the HTTP request.
The CreatedAtRoute
method:
- Returns a 201 response. HTTP 201 is the standard response for an HTTP POST method that creates a new resource on the server.
- Adds a Location header to the response. The Location header specifies the URI of the newly created to-do item. See 10.2.2 201 Created.
- Uses the “GetTodo” named route to create the URL. The “GetTodo” named route is defined in
GetById
:
1 2 3 4 5 6 7 8 9 10 11 |
<span class="line-highlight">[<span class="hljs-meta">HttpGet(<span class="hljs-string">"{id}"</span>, Name = <span class="hljs-string">"GetTodo"</span>)</span>]</span> <span class="line-highlight"><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult<TodoItem> <span class="hljs-title">GetById</span>(<span class="hljs-params"><span class="hljs-keyword">long</span> id</span>)</span> </span>{ <span class="hljs-keyword">var</span> item = _context.TodoItems.Find(id); <span class="hljs-keyword">if</span> (item == <span class="hljs-literal">null</span>) { <span class="hljs-keyword">return</span> NotFound(); } <span class="hljs-keyword">return</span> item; } |
Use Postman to send a Create request
- Start the app.
- Open Postman.
- Update the port number in the localhost URL.
- Set the HTTP method to POST.
- Click the Body tab.
- Select the raw radio button.
- Set the type to JSON (application/json).
- Enter a request body with a to-do item resembling the following JSON:
1 2 3 4 5 |
{ <span class="hljs-attr">"name"</span>:<span class="hljs-string">"walk dog"</span>, <span class="hljs-attr">"isComplete"</span>:<span class="hljs-literal">true</span> } |
- Click the Send button.
Click the Headers tab in the Response pane and copy the Location header value:
The Location header URI can be used to access the new item.
Update
Add the following Update
method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[<span class="hljs-meta">HttpPut(<span class="hljs-string">"{id}"</span>)</span>] <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Update</span>(<span class="hljs-params"><span class="hljs-keyword">long</span> id, TodoItem item</span>) </span>{ <span class="hljs-keyword">var</span> todo = _context.TodoItems.Find(id); <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span>) { <span class="hljs-keyword">return</span> NotFound(); } todo.IsComplete = item.IsComplete; todo.Name = item.Name; _context.TodoItems.Update(todo); _context.SaveChanges(); <span class="hljs-keyword">return</span> NoContent(); } |
Update
is similar to Create
, except it uses HTTP PUT. The response is 204 (No Content). According to the HTTP specification, a PUT request requires the client to send the entire updated entity, not just the deltas. To support partial updates, use HTTP PATCH.
Use Postman to update the to-do item’s name to “walk cat”:
Delete
Add the following Delete
method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[<span class="hljs-meta">HttpDelete(<span class="hljs-string">"{id}"</span>)</span>] <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Delete</span>(<span class="hljs-params"><span class="hljs-keyword">long</span> id</span>) </span>{ <span class="hljs-keyword">var</span> todo = _context.TodoItems.Find(id); <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span>) { <span class="hljs-keyword">return</span> NotFound(); } _context.TodoItems.Remove(todo); _context.SaveChanges(); <span class="hljs-keyword">return</span> NoContent(); } |
The Delete
response is 204 (No Content).
Use Postman to delete the to-do item:
Call the Web API with jQuery
In this section, an HTML page is added that uses jQuery to call the Web API. jQuery initiates the request and updates the page with the details from the API’s response.
Configure the project to serve static files and to enable default file mapping. This is accomplished by invoking the UseStaticFiles and UseDefaultFiles extension methods in Startup.Configure. For more information, see Static files.
1 2 3 4 5 6 7 |
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">IApplicationBuilder app</span>) </span>{ <span class="line-highlight"> app.UseDefaultFiles();</span> <span class="line-highlight"> app.UseStaticFiles();</span> app.UseMvc(); } |
Add an HTML file, named index.html, to the project’s wwwroot directory. Replace its contents with the following markup:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
<span class="hljs-meta"><!DOCTYPE html></span> <span class="hljs-tag"><<span class="hljs-name">html</span>></span> <span class="hljs-tag"><<span class="hljs-name">head</span>></span> <span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>></span> <span class="hljs-tag"><<span class="hljs-name">title</span>></span>To-do CRUD<span class="hljs-tag"></<span class="hljs-name">title</span>></span> <span class="hljs-tag"><<span class="hljs-name">style</span>></span><span class="css"> <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type='submit']</span>, <span class="hljs-selector-tag">button</span>, <span class="hljs-selector-attr">[aria-label]</span> { <span class="hljs-attribute">cursor</span>: pointer; } <span class="hljs-selector-id">#spoiler</span> { <span class="hljs-attribute">display</span>: none; } <span class="hljs-selector-tag">table</span> { <span class="hljs-attribute">font-family</span>: Arial, sans-serif; <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid; <span class="hljs-attribute">border-collapse</span>: collapse; } <span class="hljs-selector-tag">th</span> { <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#0066CC</span>; <span class="hljs-attribute">color</span>: white; } <span class="hljs-selector-tag">td</span> { <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid; <span class="hljs-attribute">padding</span>: <span class="hljs-number">5px</span>; } </span><span class="hljs-tag"></<span class="hljs-name">style</span>></span> <span class="hljs-tag"></<span class="hljs-name">head</span>></span> <span class="hljs-tag"><<span class="hljs-name">body</span>></span> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>To-do CRUD<span class="hljs-tag"></<span class="hljs-name">h1</span>></span> <span class="hljs-tag"><<span class="hljs-name">h3</span>></span>Add<span class="hljs-tag"></<span class="hljs-name">h3</span>></span> <span class="hljs-tag"><<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"javascript:void(0);"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span> <span class="hljs-attr">onsubmit</span>=<span class="hljs-string">"addItem()"</span>></span> <span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"add-name"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"New to-do"</span>></span> <span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Add"</span>></span> <span class="hljs-tag"></<span class="hljs-name">form</span>></span> <span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"spoiler"</span>></span> <span class="hljs-tag"><<span class="hljs-name">h3</span>></span>Edit<span class="hljs-tag"></<span class="hljs-name">h3</span>></span> <span class="hljs-tag"><<span class="hljs-name">form</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"my-form"</span>></span> <span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"edit-id"</span>></span> <span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"edit-isComplete"</span>></span> <span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"edit-name"</span>></span> <span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Edit"</span>></span> <span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"closeInput()"</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Close"</span>></span>✖<span class="hljs-tag"></<span class="hljs-name">a</span>></span> <span class="hljs-tag"></<span class="hljs-name">form</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"counter"</span>></span><span class="hljs-tag"></<span class="hljs-name">p</span>></span> <span class="hljs-tag"><<span class="hljs-name">table</span>></span> <span class="hljs-tag"><<span class="hljs-name">tr</span>></span> <span class="hljs-tag"><<span class="hljs-name">th</span>></span>Is Complete<span class="hljs-tag"></<span class="hljs-name">th</span>></span> <span class="hljs-tag"><<span class="hljs-name">th</span>></span>Name<span class="hljs-tag"></<span class="hljs-name">th</span>></span> <span class="hljs-tag"><<span class="hljs-name">th</span>></span><span class="hljs-tag"></<span class="hljs-name">th</span>></span> <span class="hljs-tag"><<span class="hljs-name">th</span>></span><span class="hljs-tag"></<span class="hljs-name">th</span>></span> <span class="hljs-tag"></<span class="hljs-name">tr</span>></span> <span class="hljs-tag"><<span class="hljs-name">tbody</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"todos"</span>></span><span class="hljs-tag"></<span class="hljs-name">tbody</span>></span> <span class="hljs-tag"></<span class="hljs-name">table</span>></span> <span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://code.jquery.com/jquery-3.3.1.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span> <span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"site.js"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span> <span class="hljs-tag"></<span class="hljs-name">body</span>></span> <span class="hljs-tag"></<span class="hljs-name">html</span>></span> |
Add a JavaScript file, named site.js, to the project’s wwwroot directory. Replace its contents with the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
<span class="hljs-keyword">const</span> uri = <span class="hljs-string">'api/todo'</span>; <span class="hljs-keyword">let</span> todos = <span class="hljs-literal">null</span>; <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCount</span>(<span class="hljs-params">data</span>) </span>{ <span class="hljs-keyword">const</span> el = $(<span class="hljs-string">'#counter'</span>); <span class="hljs-keyword">let</span> name = <span class="hljs-string">'to-do'</span>; <span class="hljs-keyword">if</span> (data) { <span class="hljs-keyword">if</span> (data > <span class="hljs-number">1</span>) { name = <span class="hljs-string">'to-dos'</span>; } el.text(data + <span class="hljs-string">' '</span> + name); } <span class="hljs-keyword">else</span> { el.html(<span class="hljs-string">'No '</span> + name); } } $(<span class="hljs-built_in">document</span>).ready(<span class="hljs-function"><span class="hljs-keyword">function</span> () </span>{ getData(); }); <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>() </span>{ $.ajax({ <span class="hljs-attr">type</span>: <span class="hljs-string">'GET'</span>, <span class="hljs-attr">url</span>: uri, <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{ $(<span class="hljs-string">'#todos'</span>).empty(); getCount(data.length); $.each(data, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">key, item</span>) </span>{ <span class="hljs-keyword">const</span> checked = item.isComplete ? <span class="hljs-string">'checked'</span> : <span class="hljs-string">''</span>; $(<span class="hljs-string">'<tr><td><input disabled="true" type="checkbox" '</span> + checked + <span class="hljs-string">'></td>'</span> + <span class="hljs-string">'<td>'</span> + item.name + <span class="hljs-string">'</td>'</span> + <span class="hljs-string">'<td><button onclick="editItem('</span> + item.id + <span class="hljs-string">')">Edit</button></td>'</span> + <span class="hljs-string">'<td><button onclick="deleteItem('</span> + item.id + <span class="hljs-string">')">Delete</button></td>'</span> + <span class="hljs-string">'</tr>'</span>).appendTo($(<span class="hljs-string">'#todos'</span>)); }); todos = data; } }); } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addItem</span>() </span>{ <span class="hljs-keyword">const</span> item = { <span class="hljs-string">'name'</span>: $(<span class="hljs-string">'#add-name'</span>).val(), <span class="hljs-string">'isComplete'</span>: <span class="hljs-literal">false</span> }; $.ajax({ <span class="hljs-attr">type</span>: <span class="hljs-string">'POST'</span>, <span class="hljs-attr">accepts</span>: <span class="hljs-string">'application/json'</span>, <span class="hljs-attr">url</span>: uri, <span class="hljs-attr">contentType</span>: <span class="hljs-string">'application/json'</span>, <span class="hljs-attr">data</span>: <span class="hljs-built_in">JSON</span>.stringify(item), <span class="hljs-attr">error</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">jqXHR, textStatus, errorThrown</span>) </span>{ alert(<span class="hljs-string">'here'</span>); }, <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">result</span>) </span>{ getData(); $(<span class="hljs-string">'#add-name'</span>).val(<span class="hljs-string">''</span>); } }); } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deleteItem</span>(<span class="hljs-params">id</span>) </span>{ $.ajax({ <span class="hljs-attr">url</span>: uri + <span class="hljs-string">'/'</span> + id, <span class="hljs-attr">type</span>: <span class="hljs-string">'DELETE'</span>, <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">result</span>) </span>{ getData(); } }); } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">editItem</span>(<span class="hljs-params">id</span>) </span>{ $.each(todos, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">key, item</span>) </span>{ <span class="hljs-keyword">if</span> (item.id === id) { $(<span class="hljs-string">'#edit-name'</span>).val(item.name); $(<span class="hljs-string">'#edit-id'</span>).val(item.id); $(<span class="hljs-string">'#edit-isComplete'</span>).val(item.isComplete); } }); $(<span class="hljs-string">'#spoiler'</span>).css({ <span class="hljs-string">'display'</span>: <span class="hljs-string">'block'</span> }); } $(<span class="hljs-string">'.my-form'</span>).on(<span class="hljs-string">'submit'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> () </span>{ <span class="hljs-keyword">const</span> item = { <span class="hljs-string">'name'</span>: $(<span class="hljs-string">'#edit-name'</span>).val(), <span class="hljs-string">'isComplete'</span>: $(<span class="hljs-string">'#edit-isComplete'</span>).is(<span class="hljs-string">':checked'</span>), <span class="hljs-string">'id'</span>: $(<span class="hljs-string">'#edit-id'</span>).val() }; $.ajax({ <span class="hljs-attr">url</span>: uri + <span class="hljs-string">'/'</span> + $(<span class="hljs-string">'#edit-id'</span>).val(), <span class="hljs-attr">type</span>: <span class="hljs-string">'PUT'</span>, <span class="hljs-attr">accepts</span>: <span class="hljs-string">'application/json'</span>, <span class="hljs-attr">contentType</span>: <span class="hljs-string">'application/json'</span>, <span class="hljs-attr">data</span>: <span class="hljs-built_in">JSON</span>.stringify(item), <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">result</span>) </span>{ getData(); } }); closeInput(); <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; }); <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">closeInput</span>() </span>{ $(<span class="hljs-string">'#spoiler'</span>).css({ <span class="hljs-string">'display'</span>: <span class="hljs-string">'none'</span> }); } |
A change to the ASP.NET Core project’s launch settings may be required to test the HTML page locally. Open launchSettings.json in the Properties directory of the project. Remove the launchUrl
property to force the app to open at index.html—the project’s default file.
There are several ways to get jQuery. In the preceding snippet, the library is loaded from a CDN. This sample is a complete CRUD example of calling the API with jQuery. There are additional features in this sample to make the experience richer. Below are explanations around the calls to the API.
Get a list of to-do items
To get a list of to-do items, send an HTTP GET request to /api/todo.
The jQuery ajax function sends an AJAX request to the API, which returns JSON representing an object or array. This function can handle all forms of HTTP interaction, sending an HTTP request to the specified url
. GET
is used as the type
. The success
callback function is invoked if the request succeeds. In the callback, the DOM is updated with the to-do information.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
$(<span class="hljs-built_in">document</span>).ready(<span class="hljs-function"><span class="hljs-keyword">function</span> () </span>{ getData(); }); <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>() </span>{ $.ajax({ <span class="hljs-attr">type</span>: <span class="hljs-string">'GET'</span>, <span class="hljs-attr">url</span>: uri, <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{ $(<span class="hljs-string">'#todos'</span>).empty(); getCount(data.length); $.each(data, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">key, item</span>) </span>{ <span class="hljs-keyword">const</span> checked = item.isComplete ? <span class="hljs-string">'checked'</span> : <span class="hljs-string">''</span>; $(<span class="hljs-string">'<tr><td><input disabled="true" type="checkbox" '</span> + checked + <span class="hljs-string">'></td>'</span> + <span class="hljs-string">'<td>'</span> + item.name + <span class="hljs-string">'</td>'</span> + <span class="hljs-string">'<td><button onclick="editItem('</span> + item.id + <span class="hljs-string">')">Edit</button></td>'</span> + <span class="hljs-string">'<td><button onclick="deleteItem('</span> + item.id + <span class="hljs-string">')">Delete</button></td>'</span> + <span class="hljs-string">'</tr>'</span>).appendTo($(<span class="hljs-string">'#todos'</span>)); }); todos = data; } }); } |
Add a to-do item
To add a to-do item, send an HTTP POST request to /api/todo/. The request body should contain a to-do object. The ajax function is using POST
to call the API. For POST
and PUT
requests, the request body represents the data sent to the API. The API is expecting a JSON request body. The accepts
and contentType
options are set to application/json
to classify the media type being received and sent, respectively. The data is converted to a JSON object using JSON.stringify
. When the API returns a successful status code, the getData
function is invoked to update the HTML table.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addItem</span>() </span>{ <span class="hljs-keyword">const</span> item = { <span class="hljs-string">'name'</span>: $(<span class="hljs-string">'#add-name'</span>).val(), <span class="hljs-string">'isComplete'</span>: <span class="hljs-literal">false</span> }; $.ajax({ <span class="hljs-attr">type</span>: <span class="hljs-string">'POST'</span>, <span class="hljs-attr">accepts</span>: <span class="hljs-string">'application/json'</span>, <span class="hljs-attr">url</span>: uri, <span class="hljs-attr">contentType</span>: <span class="hljs-string">'application/json'</span>, <span class="hljs-attr">data</span>: <span class="hljs-built_in">JSON</span>.stringify(item), <span class="hljs-attr">error</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">jqXHR, textStatus, errorThrown</span>) </span>{ alert(<span class="hljs-string">'here'</span>); }, <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">result</span>) </span>{ getData(); $(<span class="hljs-string">'#add-name'</span>).val(<span class="hljs-string">''</span>); } }); } |
Update a to-do item
Updating a to-do item is very similar to adding one, since both rely on a request body. The only real difference between the two in this case is that the url
changes to add the unique identifier of the item, and the type
is PUT
.
1 2 3 4 5 6 7 8 9 10 11 |
$.ajax({ <span class="hljs-attr">url</span>: uri + <span class="hljs-string">'/'</span> + $(<span class="hljs-string">'#edit-id'</span>).val(), <span class="hljs-attr">type</span>: <span class="hljs-string">'PUT'</span>, <span class="hljs-attr">accepts</span>: <span class="hljs-string">'application/json'</span>, <span class="hljs-attr">contentType</span>: <span class="hljs-string">'application/json'</span>, <span class="hljs-attr">data</span>: <span class="hljs-built_in">JSON</span>.stringify(item), <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">result</span>) </span>{ getData(); } }); |
Delete a to-do item
Deleting a to-do item is accomplished by setting the type
on the AJAX call to DELETE
and specifing the item’s unique identifier in the URL.
1 2 3 4 5 6 7 |
$.ajax({ <span class="hljs-attr">url</span>: uri + <span class="hljs-string">'/'</span> + id, <span class="hljs-attr">type</span>: <span class="hljs-string">'DELETE'</span>, <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">result</span>) </span>{ getData(); } }); |
No #1 Recommended ASP.NET Core Hosting
ASPHostPortal.com
ASPHostPortal.com is the leading provider of Windows hosting and affordable ASP.NET MVC Hosting. ASPHostPortal proudly working to help grow the backbone of the Internet, the millions of individuals, families, micro-businesses, small business, and fledgling online businesses. ASPHostPortal has ability to support the latest Microsoft and ASP.NET technology, such as: WebMatrix, WebDeploy, Visual Studio 2015, .NET 5/ASP.NET 4.5.2, ASP.NET MVC 6.0/5.2, Silverlight 6 and Visual Studio Lightswitch, ASPHostPortal guarantees the highest quality product, top security, and unshakeable reliability, carefully chose high-quality servers, networking, and infrastructure equipment to ensure the utmost reliability.
HostForLIFE.eu
HostForLIFE.eu guarantees 99.9% uptime for their professional ASP.NET MVC hosting and actually implements the guarantee in practice. HostForLIFE.eu is the service are excellent and the features of the web hosting plan are even greater than many hosting. HostForLIFE.eu offer IT professionals more advanced features and the latest technology. Relibility, Stability and Performance of servers remain and TOP priority. Even basic service plans are equipped with standard service level agreements for 99.99% uptime. Advanced options raise the bar to 99.99%. HostForLIFE.eu revolutionized hosting with Plesk Control Panel, a Web-based interface that provides customers with 24×7 access to their server and site configuration tools.
DiscountService.com.au
DiscountService.com.au is The Best and Cheap ASP.NET MVC Hosting. DiscountService.com.au was established to cater to an under served market in the hosting industry web hosting for customers who want excellent service. DiscountService.com.au guarantees the highest quality product, top security, and unshakeable reliability, carefully chose high-quality servers, networking, and infrastructure equipment to ensure the utmost reliability. DiscountService.com.au has ability to support the latest Microsoft and ASP.NET technology, such as: WebMatrix, WebDeploy, Visual Studio 2015, .NET 5/ASP.NET 4.5.2, ASP.NET MVC 6.0/5.2, Silverlight 6 and Visual Studio Lightswitch. DiscountService.com.au is devoted to offering the best Windows hosting solution for you.