"
 
 
 
ASP.NET (snapshot 2017) Microsoft documentation and samples

Creating Backend Services for Native Mobile Applications

By Steve Smith

Mobile apps can easily communicate with ASP.NET Core backend services.

View or download sample backend services code

The Sample Native Mobile App

This tutorial demonstrates how to create backend services using ASP.NET Core MVC to support native mobile apps. It uses the Xamarin Forms ToDoRest app as its native client, which includes separate native clients for Android, iOS, Windows Universal, and Window Phone devices. You can follow the linked tutorial to create the native app (and install the necessary free Xamarin tools), as well as download the Xamarin sample solution. The Xamarin sample includes an ASP.NET Web API 2 services project, which this article’s ASP.NET Core app replaces (with no changes required by the client).

To Do Rest application running on an Android smartphone
To Do Rest application running on an Android smartphone

Features

The ToDoRest app supports listing, adding, deleting, and updating To-Do items. Each item has an ID, a Name, Notes, and a property indicating whether it’s been Done yet.

The main view of the items, as shown above, lists each item’s name and indicates if it is done with a checkmark.

Tapping the + icon opens an add item dialog:

Add item dialog
Add item dialog

Tapping an item on the main list screen opens up an edit dialog where the item’s Name, Notes, and Done settings can be modified, or the item can be deleted:

Edit item dialog
Edit item dialog

This sample is configured by default to use backend services hosted at developer.xamarin.com, which allow read-only operations. To test it out yourself against the ASP.NET Core app created in the next section running on your computer, you’ll need to update the app’s RestUrl constant. Navigate to the ToDoREST project and open the Constants.cs file. Replace the RestUrl with a URL that includes your machine’s IP address (not localhost or 127.0.0.1, since this address is used from the device emulator, not from your machine). Include the port number as well (5000). In order to test that your services work with a device, ensure you don’t have an active firewall blocking access to this port.

Creating the ASP.NET Core Project

Create a new ASP.NET Core Web Application in Visual Studio. Choose the Web API template and No Authentication. Name the project ToDoApi.

New ASP.NET Web Application dialog with Web API project template selected
New ASP.NET Web Application dialog with Web API project template selected

The application should respond to all requests made to port 5000. Update Program.cs to include .UseUrls("http://*:5000") to achieve this:

[!code-csharpMain]

   1:  using System.IO;
   2:  using Microsoft.AspNetCore.Hosting;
   3:   
   4:  namespace ToDoApi
   5:  {
   6:      public class Program
   7:      {
   8:          public static void Main(string[] args)
   9:          {
  10:              var host = new WebHostBuilder()
  11:                  .UseKestrel()
  12:                  .UseUrls("http://*:5000")
  13:                  .UseContentRoot(Directory.GetCurrentDirectory())
  14:                  .UseIISIntegration()
  15:                  .UseStartup<Startup>()
  16:                  .Build();
  17:   
  18:              host.Run();
  19:          }
  20:      }
  21:  }

[!NOTE] Make sure you run the application directly, rather than behind IIS Express, which ignores non-local requests by default. Run dotnet run from a command prompt, or choose the application name profile from the Debug Target dropdown in the Visual Studio toolbar.

Add a model class to represent To-Do items. Mark required fields using the [Required] attribute:

[!code-csharpMain]

   1:  using System.ComponentModel.DataAnnotations;
   2:   
   3:  namespace ToDoApi.Models
   4:  {
   5:      public class ToDoItem
   6:      {
   7:          [Required]
   8:          public string ID { get; set; }
   9:   
  10:          [Required]
  11:          public string Name { get; set; }
  12:   
  13:          [Required]
  14:          public string Notes { get; set; }
  15:   
  16:          public bool Done { get; set; }
  17:      }
  18:  }

The API methods require some way to work with data. Use the same IToDoRepository interface the original Xamarin sample uses:

[!code-csharpMain]

   1:  using System.Collections.Generic;
   2:  using ToDoApi.Models;
   3:   
   4:  namespace ToDoApi.Interfaces
   5:  {
   6:      public interface IToDoRepository
   7:      {
   8:          bool DoesItemExist(string id);
   9:          IEnumerable<ToDoItem> All { get; }
  10:          ToDoItem Find(string id);
  11:          void Insert(ToDoItem item);
  12:          void Update(ToDoItem item);
  13:          void Delete(string id);
  14:      }
  15:  }

For this sample, the implementation just uses a private collection of items:

[!code-csharpMain]

   1:  using System.Collections.Generic;
   2:  using System.Linq;
   3:  using ToDoApi.Interfaces;
   4:  using ToDoApi.Models;
   5:   
   6:  namespace ToDoApi.Services
   7:  {
   8:      public class ToDoRepository : IToDoRepository
   9:      {
  10:          private List<ToDoItem> _toDoList;
  11:   
  12:          public ToDoRepository()
  13:          {
  14:              InitializeData();
  15:          }
  16:   
  17:          public IEnumerable<ToDoItem> All
  18:          {
  19:              get { return _toDoList; }
  20:          }
  21:   
  22:          public bool DoesItemExist(string id)
  23:          {
  24:              return _toDoList.Any(item => item.ID == id);
  25:          }
  26:   
  27:          public ToDoItem Find(string id)
  28:          {
  29:              return _toDoList.FirstOrDefault(item => item.ID == id);
  30:          }
  31:   
  32:          public void Insert(ToDoItem item)
  33:          {
  34:              _toDoList.Add(item);
  35:          }
  36:   
  37:          public void Update(ToDoItem item)
  38:          {
  39:              var todoItem = this.Find(item.ID);
  40:              var index = _toDoList.IndexOf(todoItem);
  41:              _toDoList.RemoveAt(index);
  42:              _toDoList.Insert(index, item);
  43:          }
  44:   
  45:          public void Delete(string id)
  46:          {
  47:              _toDoList.Remove(this.Find(id));
  48:          }
  49:   
  50:          private void InitializeData()
  51:          {
  52:              _toDoList = new List<ToDoItem>();
  53:   
  54:              var todoItem1 = new ToDoItem
  55:              {
  56:                  ID = "6bb8a868-dba1-4f1a-93b7-24ebce87e243",
  57:                  Name = "Learn app development",
  58:                  Notes = "Attend Xamarin University",
  59:                  Done = true
  60:              };
  61:   
  62:              var todoItem2 = new ToDoItem
  63:              {
  64:                  ID = "b94afb54-a1cb-4313-8af3-b7511551b33b",
  65:                  Name = "Develop apps",
  66:                  Notes = "Use Xamarin Studio/Visual Studio",
  67:                  Done = false
  68:              };
  69:   
  70:              var todoItem3 = new ToDoItem
  71:              {
  72:                  ID = "ecfa6f80-3671-4911-aabe-63cc442c1ecf",
  73:                  Name = "Publish apps",
  74:                  Notes = "All app stores",
  75:                  Done = false,
  76:              };
  77:   
  78:              _toDoList.Add(todoItem1);
  79:              _toDoList.Add(todoItem2);
  80:              _toDoList.Add(todoItem3);
  81:          }
  82:      }
  83:  }

Configure the implementation in Startup.cs:

[!code-csharpMain]

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using Microsoft.AspNetCore.Builder;
   5:  using Microsoft.AspNetCore.Hosting;
   6:  using Microsoft.Extensions.Configuration;
   7:  using Microsoft.Extensions.DependencyInjection;
   8:  using Microsoft.Extensions.Logging;
   9:  using ToDoApi.Interfaces;
  10:  using ToDoApi.Services;
  11:   
  12:  namespace ToDoApi
  13:  {
  14:      public class Startup
  15:      {
  16:          public Startup(IHostingEnvironment env)
  17:          {
  18:              var builder = new ConfigurationBuilder()
  19:                  .SetBasePath(env.ContentRootPath)
  20:                  .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
  21:                  .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
  22:                  .AddEnvironmentVariables();
  23:              Configuration = builder.Build();
  24:          }
  25:   
  26:          public IConfigurationRoot Configuration { get; }
  27:   
  28:          // This method gets called by the runtime. Use this method to add services to the container.
  29:          public void ConfigureServices(IServiceCollection services)
  30:          {
  31:              // Add framework services.
  32:              services.AddMvc();
  33:   
  34:              services.AddSingleton<IToDoRepository,ToDoRepository>();
  35:          }
  36:   
  37:          // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  38:          public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  39:          {
  40:              loggerFactory.AddConsole(Configuration.GetSection("Logging"));
  41:              loggerFactory.AddDebug();
  42:   
  43:              app.UseMvc();
  44:          }
  45:      }
  46:  }

At this point, you’re ready to create the ToDoItemsController.

[!TIP] Learn more about creating web APIs in Building Your First Web API with ASP.NET Core MVC and Visual Studio.

Creating the Controller

Add a new controller to the project, ToDoItemsController. It should inherit from Microsoft.AspNetCore.Mvc.Controller. Add a Route attribute to indicate that the controller will handle requests made to paths starting with api/todoitems. The [controller] token in the route is replaced by the name of the controller (omitting the Controller suffix), and is especially helpful for global routes. Learn more about routing.

The controller requires an IToDoRepository to function; request an instance of this type through the controller’s constructor. At runtime, this instance will be provided using the framework’s support for dependency injection.

[!code-csharpMain]

   1:  using System;
   2:  using Microsoft.AspNetCore.Http;
   3:  using Microsoft.AspNetCore.Mvc;
   4:  using ToDoApi.Interfaces;
   5:  using ToDoApi.Models;
   6:   
   7:  namespace ToDoApi.Controllers
   8:  {
   9:      [Route("api/[controller]")]
  10:      public class ToDoItemsController : Controller
  11:      {
  12:          private readonly IToDoRepository _toDoRepository;
  13:   
  14:          public ToDoItemsController(IToDoRepository toDoRepository)
  15:          {
  16:              _toDoRepository = toDoRepository;
  17:          }
  18:   
  19:          [HttpGet]
  20:          public IActionResult List()
  21:          {
  22:              return Ok(_toDoRepository.All);
  23:          }
  24:   
  25:          [HttpPost]
  26:          public IActionResult Create([FromBody] ToDoItem item)
  27:          {
  28:              try
  29:              {
  30:                  if (item == null || !ModelState.IsValid)
  31:                  {
  32:                      return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
  33:                  }
  34:                  bool itemExists = _toDoRepository.DoesItemExist(item.ID);
  35:                  if (itemExists)
  36:                  {
  37:                      return StatusCode(StatusCodes.Status409Conflict, ErrorCode.TodoItemIDInUse.ToString());
  38:                  }
  39:                  _toDoRepository.Insert(item);
  40:              }
  41:              catch (Exception)
  42:              {
  43:                  return BadRequest(ErrorCode.CouldNotCreateItem.ToString());
  44:              }
  45:              return Ok(item);
  46:          }
  47:   
  48:          [HttpPut]
  49:          public IActionResult Edit([FromBody] ToDoItem item)
  50:          {
  51:              try
  52:              {
  53:                  if (item == null || !ModelState.IsValid)
  54:                  {
  55:                      return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
  56:                  }
  57:                  var existingItem = _toDoRepository.Find(item.ID);
  58:                  if (existingItem == null)
  59:                  {
  60:                      return NotFound(ErrorCode.RecordNotFound.ToString());
  61:                  }
  62:                  _toDoRepository.Update(item);
  63:              }
  64:              catch (Exception)
  65:              {
  66:                  return BadRequest(ErrorCode.CouldNotUpdateItem.ToString());
  67:              }
  68:              return NoContent();
  69:          }
  70:   
  71:          [HttpDelete("{id}")]
  72:          public IActionResult Delete(string id)
  73:          {
  74:              try
  75:              {
  76:                  var item = _toDoRepository.Find(id);
  77:                  if (item == null)
  78:                  {
  79:                      return NotFound(ErrorCode.RecordNotFound.ToString());
  80:                  }
  81:                  _toDoRepository.Delete(id);
  82:              }
  83:              catch (Exception)
  84:              {
  85:                  return BadRequest(ErrorCode.CouldNotDeleteItem.ToString());
  86:              }
  87:              return NoContent();
  88:          }
  89:      }
  90:   
  91:      public enum ErrorCode
  92:      {
  93:          TodoItemNameAndNotesRequired,
  94:          TodoItemIDInUse,
  95:          RecordNotFound,
  96:          CouldNotCreateItem,
  97:          CouldNotUpdateItem,
  98:          CouldNotDeleteItem
  99:      }
 100:   
 101:  }

This API supports four different HTTP verbs to perform CRUD (Create, Read, Update, Delete) operations on the data source. The simplest of these is the Read operation, which corresponds to an HTTP GET request.

Reading Items

Requesting a list of items is done with a GET request to the List method. The [HttpGet] attribute on the List method indicates that this action should only handle GET requests. The route for this action is the route specified on the controller. You don’t necessarily need to use the action name as part of the route. You just need to ensure each action has a unique and unambiguous route. Routing attributes can be applied at both the controller and method levels to build up specific routes.

[!code-csharpMain]

   1:  using System;
   2:  using Microsoft.AspNetCore.Http;
   3:  using Microsoft.AspNetCore.Mvc;
   4:  using ToDoApi.Interfaces;
   5:  using ToDoApi.Models;
   6:   
   7:  namespace ToDoApi.Controllers
   8:  {
   9:      [Route("api/[controller]")]
  10:      public class ToDoItemsController : Controller
  11:      {
  12:          private readonly IToDoRepository _toDoRepository;
  13:   
  14:          public ToDoItemsController(IToDoRepository toDoRepository)
  15:          {
  16:              _toDoRepository = toDoRepository;
  17:          }
  18:   
  19:          [HttpGet]
  20:          public IActionResult List()
  21:          {
  22:              return Ok(_toDoRepository.All);
  23:          }
  24:   
  25:          [HttpPost]
  26:          public IActionResult Create([FromBody] ToDoItem item)
  27:          {
  28:              try
  29:              {
  30:                  if (item == null || !ModelState.IsValid)
  31:                  {
  32:                      return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
  33:                  }
  34:                  bool itemExists = _toDoRepository.DoesItemExist(item.ID);
  35:                  if (itemExists)
  36:                  {
  37:                      return StatusCode(StatusCodes.Status409Conflict, ErrorCode.TodoItemIDInUse.ToString());
  38:                  }
  39:                  _toDoRepository.Insert(item);
  40:              }
  41:              catch (Exception)
  42:              {
  43:                  return BadRequest(ErrorCode.CouldNotCreateItem.ToString());
  44:              }
  45:              return Ok(item);
  46:          }
  47:   
  48:          [HttpPut]
  49:          public IActionResult Edit([FromBody] ToDoItem item)
  50:          {
  51:              try
  52:              {
  53:                  if (item == null || !ModelState.IsValid)
  54:                  {
  55:                      return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
  56:                  }
  57:                  var existingItem = _toDoRepository.Find(item.ID);
  58:                  if (existingItem == null)
  59:                  {
  60:                      return NotFound(ErrorCode.RecordNotFound.ToString());
  61:                  }
  62:                  _toDoRepository.Update(item);
  63:              }
  64:              catch (Exception)
  65:              {
  66:                  return BadRequest(ErrorCode.CouldNotUpdateItem.ToString());
  67:              }
  68:              return NoContent();
  69:          }
  70:   
  71:          [HttpDelete("{id}")]
  72:          public IActionResult Delete(string id)
  73:          {
  74:              try
  75:              {
  76:                  var item = _toDoRepository.Find(id);
  77:                  if (item == null)
  78:                  {
  79:                      return NotFound(ErrorCode.RecordNotFound.ToString());
  80:                  }
  81:                  _toDoRepository.Delete(id);
  82:              }
  83:              catch (Exception)
  84:              {
  85:                  return BadRequest(ErrorCode.CouldNotDeleteItem.ToString());
  86:              }
  87:              return NoContent();
  88:          }
  89:      }
  90:   
  91:      public enum ErrorCode
  92:      {
  93:          TodoItemNameAndNotesRequired,
  94:          TodoItemIDInUse,
  95:          RecordNotFound,
  96:          CouldNotCreateItem,
  97:          CouldNotUpdateItem,
  98:          CouldNotDeleteItem
  99:      }
 100:   
 101:  }

The List method returns a 200 OK response code and all of the ToDo items, serialized as JSON.

You can test your new API method using a variety of tools, such as Postman, shown here:

Postman console showing a GET request for todoitems and the body of the response showing the JSON for three items returned
Postman console showing a GET request for todoitems and the body of the response showing the JSON for three items returned

Creating Items

By convention, creating new data items is mapped to the HTTP POST verb. The Create method has an [HttpPost] attribute applied to it, and accepts a ToDoItem instance. Since the item argument will be passed in the body of the POST, this parameter is decorated with the [FromBody] attribute.

Inside the method, the item is checked for validity and prior existence in the data store, and if no issues occur, it is added using the repository. Checking ModelState.IsValid performs model validation, and should be done in every API method that accepts user input.

[!code-csharpMain]

   1:  using System;
   2:  using Microsoft.AspNetCore.Http;
   3:  using Microsoft.AspNetCore.Mvc;
   4:  using ToDoApi.Interfaces;
   5:  using ToDoApi.Models;
   6:   
   7:  namespace ToDoApi.Controllers
   8:  {
   9:      [Route("api/[controller]")]
  10:      public class ToDoItemsController : Controller
  11:      {
  12:          private readonly IToDoRepository _toDoRepository;
  13:   
  14:          public ToDoItemsController(IToDoRepository toDoRepository)
  15:          {
  16:              _toDoRepository = toDoRepository;
  17:          }
  18:   
  19:          [HttpGet]
  20:          public IActionResult List()
  21:          {
  22:              return Ok(_toDoRepository.All);
  23:          }
  24:   
  25:          [HttpPost]
  26:          public IActionResult Create([FromBody] ToDoItem item)
  27:          {
  28:              try
  29:              {
  30:                  if (item == null || !ModelState.IsValid)
  31:                  {
  32:                      return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
  33:                  }
  34:                  bool itemExists = _toDoRepository.DoesItemExist(item.ID);
  35:                  if (itemExists)
  36:                  {
  37:                      return StatusCode(StatusCodes.Status409Conflict, ErrorCode.TodoItemIDInUse.ToString());
  38:                  }
  39:                  _toDoRepository.Insert(item);
  40:              }
  41:              catch (Exception)
  42:              {
  43:                  return BadRequest(ErrorCode.CouldNotCreateItem.ToString());
  44:              }
  45:              return Ok(item);
  46:          }
  47:   
  48:          [HttpPut]
  49:          public IActionResult Edit([FromBody] ToDoItem item)
  50:          {
  51:              try
  52:              {
  53:                  if (item == null || !ModelState.IsValid)
  54:                  {
  55:                      return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
  56:                  }
  57:                  var existingItem = _toDoRepository.Find(item.ID);
  58:                  if (existingItem == null)
  59:                  {
  60:                      return NotFound(ErrorCode.RecordNotFound.ToString());
  61:                  }
  62:                  _toDoRepository.Update(item);
  63:              }
  64:              catch (Exception)
  65:              {
  66:                  return BadRequest(ErrorCode.CouldNotUpdateItem.ToString());
  67:              }
  68:              return NoContent();
  69:          }
  70:   
  71:          [HttpDelete("{id}")]
  72:          public IActionResult Delete(string id)
  73:          {
  74:              try
  75:              {
  76:                  var item = _toDoRepository.Find(id);
  77:                  if (item == null)
  78:                  {
  79:                      return NotFound(ErrorCode.RecordNotFound.ToString());
  80:                  }
  81:                  _toDoRepository.Delete(id);
  82:              }
  83:              catch (Exception)
  84:              {
  85:                  return BadRequest(ErrorCode.CouldNotDeleteItem.ToString());
  86:              }
  87:              return NoContent();
  88:          }
  89:      }
  90:   
  91:      public enum ErrorCode
  92:      {
  93:          TodoItemNameAndNotesRequired,
  94:          TodoItemIDInUse,
  95:          RecordNotFound,
  96:          CouldNotCreateItem,
  97:          CouldNotUpdateItem,
  98:          CouldNotDeleteItem
  99:      }
 100:   
 101:  }

The sample uses an enum containing error codes that are passed to the mobile client:

[!code-csharpMain]

   1:  using System;
   2:  using Microsoft.AspNetCore.Http;
   3:  using Microsoft.AspNetCore.Mvc;
   4:  using ToDoApi.Interfaces;
   5:  using ToDoApi.Models;
   6:   
   7:  namespace ToDoApi.Controllers
   8:  {
   9:      [Route("api/[controller]")]
  10:      public class ToDoItemsController : Controller
  11:      {
  12:          private readonly IToDoRepository _toDoRepository;
  13:   
  14:          public ToDoItemsController(IToDoRepository toDoRepository)
  15:          {
  16:              _toDoRepository = toDoRepository;
  17:          }
  18:   
  19:          [HttpGet]
  20:          public IActionResult List()
  21:          {
  22:              return Ok(_toDoRepository.All);
  23:          }
  24:   
  25:          [HttpPost]
  26:          public IActionResult Create([FromBody] ToDoItem item)
  27:          {
  28:              try
  29:              {
  30:                  if (item == null || !ModelState.IsValid)
  31:                  {
  32:                      return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
  33:                  }
  34:                  bool itemExists = _toDoRepository.DoesItemExist(item.ID);
  35:                  if (itemExists)
  36:                  {
  37:                      return StatusCode(StatusCodes.Status409Conflict, ErrorCode.TodoItemIDInUse.ToString());
  38:                  }
  39:                  _toDoRepository.Insert(item);
  40:              }
  41:              catch (Exception)
  42:              {
  43:                  return BadRequest(ErrorCode.CouldNotCreateItem.ToString());
  44:              }
  45:              return Ok(item);
  46:          }
  47:   
  48:          [HttpPut]
  49:          public IActionResult Edit([FromBody] ToDoItem item)
  50:          {
  51:              try
  52:              {
  53:                  if (item == null || !ModelState.IsValid)
  54:                  {
  55:                      return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
  56:                  }
  57:                  var existingItem = _toDoRepository.Find(item.ID);
  58:                  if (existingItem == null)
  59:                  {
  60:                      return NotFound(ErrorCode.RecordNotFound.ToString());
  61:                  }
  62:                  _toDoRepository.Update(item);
  63:              }
  64:              catch (Exception)
  65:              {
  66:                  return BadRequest(ErrorCode.CouldNotUpdateItem.ToString());
  67:              }
  68:              return NoContent();
  69:          }
  70:   
  71:          [HttpDelete("{id}")]
  72:          public IActionResult Delete(string id)
  73:          {
  74:              try
  75:              {
  76:                  var item = _toDoRepository.Find(id);
  77:                  if (item == null)
  78:                  {
  79:                      return NotFound(ErrorCode.RecordNotFound.ToString());
  80:                  }
  81:                  _toDoRepository.Delete(id);
  82:              }
  83:              catch (Exception)
  84:              {
  85:                  return BadRequest(ErrorCode.CouldNotDeleteItem.ToString());
  86:              }
  87:              return NoContent();
  88:          }
  89:      }
  90:   
  91:      public enum ErrorCode
  92:      {
  93:          TodoItemNameAndNotesRequired,
  94:          TodoItemIDInUse,
  95:          RecordNotFound,
  96:          CouldNotCreateItem,
  97:          CouldNotUpdateItem,
  98:          CouldNotDeleteItem
  99:      }
 100:   
 101:  }

Test adding new items using Postman by choosing the POST verb providing the new object in JSON format in the Body of the request. You should also add a request header specifying a Content-Type of application/json.

Postman console showing a POST and response
Postman console showing a POST and response

The method returns the newly created item in the response.

Updating Items

Modifying records is done using HTTP PUT requests. Other than this change, the Edit method is almost identical to Create. Note that if the record isn’t found, the Edit action will return a NotFound (404) response.

[!code-csharpMain]

   1:  using System;
   2:  using Microsoft.AspNetCore.Http;
   3:  using Microsoft.AspNetCore.Mvc;
   4:  using ToDoApi.Interfaces;
   5:  using ToDoApi.Models;
   6:   
   7:  namespace ToDoApi.Controllers
   8:  {
   9:      [Route("api/[controller]")]
  10:      public class ToDoItemsController : Controller
  11:      {
  12:          private readonly IToDoRepository _toDoRepository;
  13:   
  14:          public ToDoItemsController(IToDoRepository toDoRepository)
  15:          {
  16:              _toDoRepository = toDoRepository;
  17:          }
  18:   
  19:          [HttpGet]
  20:          public IActionResult List()
  21:          {
  22:              return Ok(_toDoRepository.All);
  23:          }
  24:   
  25:          [HttpPost]
  26:          public IActionResult Create([FromBody] ToDoItem item)
  27:          {
  28:              try
  29:              {
  30:                  if (item == null || !ModelState.IsValid)
  31:                  {
  32:                      return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
  33:                  }
  34:                  bool itemExists = _toDoRepository.DoesItemExist(item.ID);
  35:                  if (itemExists)
  36:                  {
  37:                      return StatusCode(StatusCodes.Status409Conflict, ErrorCode.TodoItemIDInUse.ToString());
  38:                  }
  39:                  _toDoRepository.Insert(item);
  40:              }
  41:              catch (Exception)
  42:              {
  43:                  return BadRequest(ErrorCode.CouldNotCreateItem.ToString());
  44:              }
  45:              return Ok(item);
  46:          }
  47:   
  48:          [HttpPut]
  49:          public IActionResult Edit([FromBody] ToDoItem item)
  50:          {
  51:              try
  52:              {
  53:                  if (item == null || !ModelState.IsValid)
  54:                  {
  55:                      return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
  56:                  }
  57:                  var existingItem = _toDoRepository.Find(item.ID);
  58:                  if (existingItem == null)
  59:                  {
  60:                      return NotFound(ErrorCode.RecordNotFound.ToString());
  61:                  }
  62:                  _toDoRepository.Update(item);
  63:              }
  64:              catch (Exception)
  65:              {
  66:                  return BadRequest(ErrorCode.CouldNotUpdateItem.ToString());
  67:              }
  68:              return NoContent();
  69:          }
  70:   
  71:          [HttpDelete("{id}")]
  72:          public IActionResult Delete(string id)
  73:          {
  74:              try
  75:              {
  76:                  var item = _toDoRepository.Find(id);
  77:                  if (item == null)
  78:                  {
  79:                      return NotFound(ErrorCode.RecordNotFound.ToString());
  80:                  }
  81:                  _toDoRepository.Delete(id);
  82:              }
  83:              catch (Exception)
  84:              {
  85:                  return BadRequest(ErrorCode.CouldNotDeleteItem.ToString());
  86:              }
  87:              return NoContent();
  88:          }
  89:      }
  90:   
  91:      public enum ErrorCode
  92:      {
  93:          TodoItemNameAndNotesRequired,
  94:          TodoItemIDInUse,
  95:          RecordNotFound,
  96:          CouldNotCreateItem,
  97:          CouldNotUpdateItem,
  98:          CouldNotDeleteItem
  99:      }
 100:   
 101:  }

To test with Postman, change the verb to PUT. Specify the updated object data in the Body of the request.

Postman console showing a PUT and response
Postman console showing a PUT and response

This method returns a NoContent (204) response when successful, for consistency with the pre-existing API.

Deleting Items

Deleting records is accomplished by making DELETE requests to the service, and passing the ID of the item to be deleted. As with updates, requests for items that don’t exist will receive NotFound responses. Otherwise, a successful request will get a NoContent (204) response.

[!code-csharpMain]

   1:  using System;
   2:  using Microsoft.AspNetCore.Http;
   3:  using Microsoft.AspNetCore.Mvc;
   4:  using ToDoApi.Interfaces;
   5:  using ToDoApi.Models;
   6:   
   7:  namespace ToDoApi.Controllers
   8:  {
   9:      [Route("api/[controller]")]
  10:      public class ToDoItemsController : Controller
  11:      {
  12:          private readonly IToDoRepository _toDoRepository;
  13:   
  14:          public ToDoItemsController(IToDoRepository toDoRepository)
  15:          {
  16:              _toDoRepository = toDoRepository;
  17:          }
  18:   
  19:          [HttpGet]
  20:          public IActionResult List()
  21:          {
  22:              return Ok(_toDoRepository.All);
  23:          }
  24:   
  25:          [HttpPost]
  26:          public IActionResult Create([FromBody] ToDoItem item)
  27:          {
  28:              try
  29:              {
  30:                  if (item == null || !ModelState.IsValid)
  31:                  {
  32:                      return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
  33:                  }
  34:                  bool itemExists = _toDoRepository.DoesItemExist(item.ID);
  35:                  if (itemExists)
  36:                  {
  37:                      return StatusCode(StatusCodes.Status409Conflict, ErrorCode.TodoItemIDInUse.ToString());
  38:                  }
  39:                  _toDoRepository.Insert(item);
  40:              }
  41:              catch (Exception)
  42:              {
  43:                  return BadRequest(ErrorCode.CouldNotCreateItem.ToString());
  44:              }
  45:              return Ok(item);
  46:          }
  47:   
  48:          [HttpPut]
  49:          public IActionResult Edit([FromBody] ToDoItem item)
  50:          {
  51:              try
  52:              {
  53:                  if (item == null || !ModelState.IsValid)
  54:                  {
  55:                      return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
  56:                  }
  57:                  var existingItem = _toDoRepository.Find(item.ID);
  58:                  if (existingItem == null)
  59:                  {
  60:                      return NotFound(ErrorCode.RecordNotFound.ToString());
  61:                  }
  62:                  _toDoRepository.Update(item);
  63:              }
  64:              catch (Exception)
  65:              {
  66:                  return BadRequest(ErrorCode.CouldNotUpdateItem.ToString());
  67:              }
  68:              return NoContent();
  69:          }
  70:   
  71:          [HttpDelete("{id}")]
  72:          public IActionResult Delete(string id)
  73:          {
  74:              try
  75:              {
  76:                  var item = _toDoRepository.Find(id);
  77:                  if (item == null)
  78:                  {
  79:                      return NotFound(ErrorCode.RecordNotFound.ToString());
  80:                  }
  81:                  _toDoRepository.Delete(id);
  82:              }
  83:              catch (Exception)
  84:              {
  85:                  return BadRequest(ErrorCode.CouldNotDeleteItem.ToString());
  86:              }
  87:              return NoContent();
  88:          }
  89:      }
  90:   
  91:      public enum ErrorCode
  92:      {
  93:          TodoItemNameAndNotesRequired,
  94:          TodoItemIDInUse,
  95:          RecordNotFound,
  96:          CouldNotCreateItem,
  97:          CouldNotUpdateItem,
  98:          CouldNotDeleteItem
  99:      }
 100:   
 101:  }

Note that when testing the delete functionality, nothing is required in the Body of the request.

Postman console showing a DELETE and response
Postman console showing a DELETE and response

Common Web API Conventions

As you develop the backend services for your app, you will want to come up with a consistent set of conventions or policies for handling cross-cutting concerns. For example, in the service shown above, requests for specific records that weren’t found received a NotFound response, rather than a BadRequest response. Similarly, commands made to this service that passed in model bound types always checked ModelState.IsValid and returned a BadRequest for invalid model types.

Once you’ve identified a common policy for your APIs, you can usually encapsulate it in a filter. Learn more about how to encapsulate common API policies in ASP.NET Core MVC applications.





Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23
Link to this page: //www.vb-net.com/AspNet-DocAndSamples-2017/aspnetcore/mobile/native-mobile-backend.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>