Im making a WebApi core project for school and everything seemed fine until i decided to start up the project to test it. When I start it up this error appears https://imgbbb.com/images/2020/01/16/error.png
Here's everything that my project consists of:
And here's the controller code:
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using webapi3.Models;
using webapi3.Models.Repository;
using RouteAttribute = Microsoft.AspNetCore.Components.RouteAttribute;
namespace webapi3.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class EmployeeController : ControllerBase
{
private readonly IDataRepository<Employee> _dataRepository;
public EmployeeController(IDataRepository<Employee> dataRepository)
{
_dataRepository = dataRepository;
}
// GET: api/Employee
[HttpGet]
public IActionResult Get()
{
IEnumerable<Employee> employees = _dataRepository.GetAll();
return Ok(employees);
}
// GET: api/Employee/5
[HttpGet("{id}", Name = "Get")]
public IActionResult Get(long id)
{
Employee employee = _dataRepository.Get(id);
if (employee == null)
{
return NotFound("The Employee record couldn't be found.");
}
return Ok(employee);
}
// POST: api/Employee
[HttpPost]
public IActionResult Post([FromBody] Employee employee)
{
if (employee == null)
{
return BadRequest("Employee is null.");
}
_dataRepository.Add(employee);
return CreatedAtRoute(
"Get",
new { Id = employee.EmployeeId },
employee);
}
// PUT: api/Employee/5
[HttpPut("{id}")]
public IActionResult Put(long id, [FromBody] Employee employee)
{
if (employee == null)
{
return BadRequest("Employee is null.");
}
Employee employeeToUpdate = _dataRepository.Get(id);
if (employeeToUpdate == null)
{
return NotFound("The Employee record couldn't be found.");
}
_dataRepository.Update(employeeToUpdate, employee);
return NoContent();
}
// DELETE: api/Employee/5
[HttpDelete("{id}")]
public IActionResult Delete(long id)
{
Employee employee = _dataRepository.Get(id);
if (employee == null)
{
return NotFound("The Employee record couldn't be found.");
}
_dataRepository.Delete(employee);
return NoContent();
}
}
}
If anyone helps me id be very gratheful! Thanks in advance!
Try changing [controller] to "Employee" in [Route("api/[controller]")]. Check this example from Microsoft 1
Replace [controller] with the name of the controller, which by convention is the controller class name minus the "Controller" suffix. For this sample, the controller class name is TodoItemsController, so the controller name is "TodoItems". ASP.NET Core routing is case insensitive.
Another option, check your Startup.cs file (post it here so we can check if everything is alright). And check this example explaining Attribute Route in .NET Attribute Routing
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Attribute routing.
config.MapHttpAttributeRoutes();
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Related
I am trying to create an API and trying to access it via chrome, expecting it to return the list of Items
public class ProductController : ApiController
{
Product product = new Product();
List<Product> productList = new List<Product>();
[HttpGet]
public HttpResponseMessage GetTheProduct(int id)
{
this.productList.Add(new Product {Id = 111,Name= "sandeep" });
return Request.CreateResponse(HttpStatusCode.OK, this.productList.FirstOrDefault(p => p.Id == 111));
}
}
I have not added route so wanna run it using default route but when i am running it, am getting
No HTTP resource was found that matches the request
URI 'http://localhost:65098/api/GetTheProduct()'.
No type was found that matches the controller named
'GetTheProduct()'.
Suggest me what all things are required to make it work.
If using default routes then configuration may look like this
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
This would mean that routing is using convention-based routing with the following route template "api/{controller}/{id}"
Your controller in its current state is not following the convention. This results in requests not being matched in the route tables which result in the Not Found issues being experienced.
Refactor the controller to follow the convention
public class ProductsController : ApiController {
List<Product> productList = new List<Product>();
public ProductsController() {
this.productList.Add(new Product { Id = 111, Name = "sandeep 1" });
this.productList.Add(new Product { Id = 112, Name = "sandeep 2" });
this.productList.Add(new Product { Id = 113, Name = "sandeep 3" });
}
//Matched GET api/products
[HttpGet]
public IHttpActionResult Get() {
return Ok(productList);
}
//Matched GET api/products/111
[HttpGet]
public IHttpActionResult Get(int id) {
var product = productList.FirstOrDefault(p => p.Id == id));
if(product == null)
return NotFound();
return Ok(product);
}
}
Finally based on the route template configured then the controller expects a request that looks like
http://localhost:65098/api/products/111.
To get a single product that matches the provided id if it exists.
Reference Routing in ASP.NET Web API
I just started working with ApiController. I'm trying to do an HTTP GET sending an ID, but it is not working.
My ApiController:
[Route("api/Test")]
public class TestController : ApiController
{
private myEntity db = new myEntity();
[HttpGet]
public HttpResponseMessage GetAll()
{
// Get a list of customers
IEnumerable<Customer> customers = db.Customers.ToList();
// Write the list of customers to the response body
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, customers);
return response;
}
[HttpGet]
public HttpResponseMessage GetById(int id)
{
// Get Customer by id
Customer customer = db.Customers.Where(x => x.Id == id).FirstOrDefault();
HttpResponseMessage response;
if (customer == null)
{
response = Request.CreateResponse(HttpStatusCode.NotFound);
return response;
} else
{
response = Request.CreateResponse(HttpStatusCode.OK, customer);
}
return response;
}
When I run it in the browser, the GetAll method work perfectly. However, when I try GetById:
http://localhost:53198/api/Test/1
It returns:
No HTTP resource was found that matches the request URI http://localhost:53198/api/Test/1
Does anyone know what I am doing wrong?
If using attribute routing you would need to make a few changes to make sure that action routes are distinct to avoid any route conflicts.
[RoutePrefix("api/Test")]
public class TestController : ApiController {
private myEntity db = new myEntity();
//GET api/Test
[HttpGet]
[Route("")]
public IHttpActionResult GetAll() {
// Get a list of customers
var customers = db.Customers.ToList();
// Write the list of customers to the response body
return OK(customers);
}
//GET api/Test/1
[HttpGet]
[Route("{id:int}")]
public IHttpActionResult GetById(int id) {
// Get Customer by id
Customer customer = db.Customers.Where(x => x.Id == id).FirstOrDefault();
if (customer == null) {
return NotFound();
}
return Ok(customer);
}
}
This assumes that attribute routing is enabled
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Attribute routing.
config.MapHttpAttributeRoutes();
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Reference Attribute Routing in ASP.NET Web API 2
You can do either
http://localhost:53198/api/Test/GetById/1 (as DavidG mentioned)
or
http://localhost:53198/api/Test/1
and changing your code to
[HttpGet]
[Route("{id:int}")]
public HttpResponseMessage GetById(int id)
I've found many topic and suggestions on this and I think I've tried all of the combinations.
I had a working application that is going to grow larger so I decided to make use of areas. I sloughed through that and can access the controllers but then the application fails when it tries to return data to a view. I created a test data context, classes, etc. then to be sure that it wasn't something that I did wrong when moving into areas.
It's probably best to work through the somewhat smaller test situation and then apply what works to the larger actual application.
My link from _Layout.cshtml:
<li>#Html.ActionLink("Test", "Index", "testclasses")</li>
My model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Tracking.Areas.test.Models
{
public class testclass
{
public int ID { get; set; }
}
}
My testAreaRegistration:
using System.Web.Mvc;
namespace Tracking.Areas.test
{
public class testAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "test";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"test_default",
//"test/{controller}/{action}/{id}",
"test/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
}
My test controller:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
using System.Net;
using System.Web;
using System.Web.Mvc;
using Tracking.Areas.test.Models;
using Tracking.DAL.Test;
namespace Tracking.Areas.test.Controllers
{
[RouteArea("test")]
public class testclassesController : Controller
{
private testcontext db = new testcontext();
// GET: test/testclasses
public async Task<ActionResult> Index()
{
return View(await db.spas.ToListAsync());
}
// GET: test/testclasses/Details/5
public async Task<ActionResult> Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
testclass testclass = await db.spas.FindAsync(id);
if (testclass == null)
{
return HttpNotFound();
}
return View(testclass);
}
// GET: test/testclasses/Create
public ActionResult Create()
{
return View();
}
// POST: test/testclasses/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include = "ID")] testclass testclass)
{
if (ModelState.IsValid)
{
db.spas.Add(testclass);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(testclass);
}
// GET: test/testclasses/Edit/5
public async Task<ActionResult> Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
testclass testclass = await db.spas.FindAsync(id);
if (testclass == null)
{
return HttpNotFound();
}
return View(testclass);
}
// POST: test/testclasses/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "ID")] testclass testclass)
{
if (ModelState.IsValid)
{
db.Entry(testclass).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(testclass);
}
// GET: test/testclasses/Delete/5
public async Task<ActionResult> Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
testclass testclass = await db.spas.FindAsync(id);
if (testclass == null)
{
return HttpNotFound();
}
return View(testclass);
}
// POST: test/testclasses/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteConfirmed(int id)
{
testclass testclass = await db.spas.FindAsync(id);
db.spas.Remove(testclass);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
My RouteConfig file
namespace Tracking
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
My Global.asax.cs file
namespace Tracking
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
}
I've tried with and without [RouteArea("test")] in the controller; I've tried multiple options with adding a controller to the area registration file, removing the area name from in front of controller in the area registration file, and many other combinations.
The code finds the controller and model as I put breakpoints in those and reach them - when it attempts to return the view I get the error message about the index view not being found in the standard locations - it doesn't search within the areas at all.
Thanks!
I think you have an inconsistence in your "convention over configuration" setup. Might be helpful to add the error message and your solution structure. You should check, for example, that the Index.cshtml is found in the Areas\test\Views\testclasses folder. The only thing that I see at a first glance is that you didn't modify your action link to include the area. You should try:
#Html.ActionLink("Test", "Index", "testclasses", new { Area = "test" }, new{})
P.S.> I would recommend using camel case notation for the class names and areas... you know, for the clean code sake. Not to mention that you never know when you might stumble upon a case sensitive convention....
I'm new to Web Api (I'm probably missing something very straightforward here) I have a Web Api project with ProductsController.cs that has a property of type List<Product> and I simply want to call the Api in the browser eg localhost/api/products/1 or /api/products/getproduct/1 to retrieve the product response for the specified Id in the url but I cannot get it to retrieve any data. I get a 'not found' error each time. What am I missing to make it find the data and retrieve the response?
I have tried the following:
public IHttpActionResult Get(int id)
{
var product = products.FirstOrDefault(p => p.Id == id);
if (product == null)
{
return NotFound();
}
else
{
return Ok(product);
}
}
And even the following which still returns not found:
public string Get(int id)
{
return "product test";
}
Make sure the the routing is configured properly
WebApiConfig.cs
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Attribute routing.
config.MapHttpAttributeRoutes();
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
From there you have two options of routing to the action.
Convention-based.
public class ProductsController : ApiController {
//...constructor code removed for brevity
[HttpGet] // Matches GET api/products
public IHttpActionResult GetAllProducts() {
return Ok(products);
}
[HttpGet] // Matches GET api/products/1
public IHttpActionResult GetProduct(int id) {
var product = products.FirstOrDefault(p => p.Id == id);
if (product == null) {
return NotFound();
}
return Ok(product);
}
}
or Attribute routing
[RoutePrefix("api/products")]
public class ProductsController : ApiController {
//...constructor code removed for brevity
[HttpGet]
[Route("")] // Matches GET api/products
public IHttpActionResult GetAllProducts() {
return Ok(products);
}
[HttpGet]
[Route("{id:int}")] // Matches GET api/products/1
public IHttpActionResult GetProduct(int id) {
var product = products.FirstOrDefault(p => p.Id == id);
if (product == null) {
return NotFound();
}
return Ok(product);
}
}
I am new in web api.
i am sure i am doing something wrong for which my action is not getting called.
this is my action
public IEnumerable<Customer> GetCustomersByCountry(string country)
{
return repository.GetAll().Where(
c => string.Equals(c.Country, country, StringComparison.OrdinalIgnoreCase));
}
when i am calling this action this way http://localhost:38762/api/customer/GetCustomersByCountry/Germany
the error is thrown, and error message is
{"Message":"No HTTP resource was found that matches the request URI
'http://localhost:38762/api/customer/GetCustomersByCountry/Germany'.","MessageDetail":"No
action was found on the controller 'Customer' that matches the
request."}
tell me where i made the mistake ? thanks
Web config routes are
config.Routes.MapHttpRoute(
name: "WithActionApi",
routeTemplate: "api/{controller}/{action}/{customerID}"
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
EDIT : Full code added
public class CustomerController : ApiController
{
static readonly ICustomerRepository repository = new CustomerRepository();
public IEnumerable<Customer> GetAllCustomers()
{
return repository.GetAll();
}
public Customer GetCustomer(string customerID)
{
Customer customer = repository.Get(customerID);
if (customer == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return customer;
}
//[ActionName("GetCustomersByCountry")]
public IEnumerable<Customer> GetCustomersByCountry(string country)
{
return repository.GetAll().Where(
c => string.Equals(c.Country, country, StringComparison.OrdinalIgnoreCase));
}
public HttpResponseMessage PostCustomer(Customer customer)
{
customer = repository.Add(customer);
var response = Request.CreateResponse<Customer>(HttpStatusCode.Created, customer);
string uri = Url.Link("DefaultApi", new { customerID = customer.CustomerID });
response.Headers.Location = new Uri(uri);
return response;
}
public void PutProduct(string customerID, Customer customer)
{
customer.CustomerID = customerID;
if (!repository.Update(customer))
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
public void DeleteProduct(string customerID)
{
Customer customer = repository.Get(customerID);
if (customer == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
repository.Remove(customerID);
}
}
just tell me when controller will have multiple get whose parameter name is different then how could i handle the situation.
thanks
Given CustomerController like
public class CustomerController : ApiController {
[HttpGet]
public IEnumerable<Customer> GetCustomersByCountry(string country) {
return repository.GetAll().Where(
c => string.Equals(c.Country, country, StringComparison.OrdinalIgnoreCase));
}
}
a convention-based route can look like this
config.Routes.MapHttpRoute(
name: "CustomerApi",
routeTemplate: "api/customer/{action}/{countryId}",
default: new { controller = "Customer"}
);
which will map http://localhost:38762/api/customer/GetCustomersByCountry/Germany
The problem with your route is that your parameter name in the route template does not match.
Another option could be to use attribute routing
Attribute Routing in ASP.NET Web API 2
[RoutePrefix("api/customer")]
public class CustomerController : ApiController {
//GET api/customer/country/germany
[HttpGet, Route("country/{country}")]
public IEnumerable<Customer> GetCustomersByCountry(string country) {
return repository.GetAll().Where(
c => string.Equals(c.Country, country, StringComparison.OrdinalIgnoreCase));
}
}
with this configuration
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Web API routes
config.MapHttpAttributeRoutes();
// Other Web API configuration not shown.
}
}
Remove "Get" from the action in the url. Just keep CustomersByCountry instead of GetCustomersByCountry. So the url should be http://localhost:38762/api/customer/CustomersByCountry/Germany.