.Net Core 2.0 Web API controller not working and getting 404 - api

I have something very very strange. I have 2 controllers. UploadController and AccountController. Theye were both working, and now when I try the AccountController it give error 404. ik don't get it.
This is how my AccountController looks like:
namespace CoreAngular.Controllers
{
//[Authorize]
[Produces("application/json")]
[Route("api/account")]
public class AccountController : Controller
{
private IRepository repository;
public AccountController(IDatabaseClient<DocumentClient> client)
: this ( new UserRepository(client))
{
}
public AccountController(IRepository repository)
{
this.repository = repository;
}
[HttpGet]
public async Task<ActionResult> Get(string id)
{
var start = DateTime.Now.TimeOfDay;
if (string.IsNullOrEmpty(id))
{
return BadRequest();
}
var user = await repository.GetAsync(id);
if (user == null)
{
return NotFound();
}
var userDTO = new UserGetDTO()
{
image = Convert.ToBase64String(user.image.image),
id = user.id,
time = DateTime.Now.Subtract(start).Millisecond
};
return Ok(userDTO);
}......
Do I miss something here? I know I comentet out the [Authorize], but i just wanted to try to connect.

You should specify route template in HttpGet attribute:
[HttpGet("{id}")]
public async Task<ActionResult> Get(string id)
{
// ...
}

Related

When send Parameter pagenumber to web api by post man action not working or recognize?

I work on .net core 6 web api I face issue when
send paramter pagenumber on url by post man
action not catched by break point debug .
so what is issue and How to solve It ?
i try with url
https://localhost:7235/api/items/pageNumber=1
[HttpGet("{pageNumber}")]
public async Task<IActionResult> GetAll(int pageNumber)
{
}
it return error 200 bad Request .
but i try with url below
https://localhost:7235/api/items/
[HttpGet]
[Route("")]
public async Task<IActionResult> GetAll(int pageNumber)
{
}
it working hit controller success and return data success fromitems controller action get all .
so What is issue please and How to solve it ?
Updated post not working
[HttpGet("{pageNumber}")]
public async Task<IActionResult> GetAll(int pageNumber)
{
}
for this action you need to use this url:
https://localhost:7235/api/items/1
not working and it give me error 500 internal server error
all controller items
using DomainModel.Entities;
using DomainModel.Pagination;
using DomainModel.ViewModel;
using k8s.Models;
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Service.Contract;
using Service.Features.CustomerFeatures.Commands;
using Service.Features.CustomerFeatures.Queries;
namespace WebApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ItemsController : Controller
{
private readonly IitemService _iitem;
private readonly IPageHelper<ItemsViewModel> _pageHelper;
public ItemsController(IitemService iitem, IPageHelper<ItemsViewModel> pageHelper)
{
_iitem = iitem;
_pageHelper = pageHelper;
}
[HttpPost]
public async Task<IActionResult> Create(Items item)
{
await _iitem.AddAsync(item);
return Ok();
}
[HttpGet("{pageNumber}")]
public async Task<IActionResult> GetAll(int pageNumber)
{
var allitems = _iitem.GetAllItems();
var result = _pageHelper.GetPage(allitems.AsQueryable(), pageNumber);
var itemsdata = new ItemsPageViewModel
{
items = result.Items,
Pager = result.Pager
};
return Ok(itemsdata);
}
[HttpGet("{id}")]
public async Task<IActionResult> GetById(int id)
{
var details = await _iitem.GetByIdAsync(id);
return Ok(details);
}
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
await _iitem.DeleteAsync(id);
return Ok();
}
[HttpPut("{id}")]
public async Task<IActionResult> Update(int id, Items item)
{
if (id != item.Id)
{
return BadRequest();
}
await _iitem.UpdateAsync(id, item);
return Ok();
}
}
}
The error you are actually getting is
AmbiguousMatchException: The request matched multiple endpoints.
This is because you have two actions that have the same route:
// for this action you need to use this url:
// https://localhost:7235/api/items/1
[HttpGet("{pageNumber}")]
public async Task<IActionResult> GetAll(int pageNumber)
{
var allitems = _iitem.GetAllItems();
var result = _pageHelper.GetPage(allitems.AsQueryable(), pageNumber);
var itemsdata = new ItemsPageViewModel
{
items = result.Items,
Pager = result.Pager
};
return Ok(itemsdata);
}
// for this action you ALSO need to use this url:
// https://localhost:7235/api/items/1
[HttpGet("{id}")]
public async Task<IActionResult> GetById(int id)
{
var details = await _iitem.GetByIdAsync(id);
return Ok(details);
}
Both actions are HttpGet and both use the same route:
https://localhost:7235/api/items/x
you need to change the route for one of them.
Routing to controller actions in ASP.NET Core

Aspnet.Core Empty structures2

I have a hybrid web application that has WordPress as the root site with an aspnet core web application as a virtual directory. The IIS structure looks something like:
Within the aspnet core site, when I redirect to a page or use tag helpers the url includes "/web/blahblah" which makes sense. However, I don't want that. How do I force the aspnet core site to ignore the virtual directory path and generate urls like "/blahblah" without web?
NOT ADMIN(f)
1. AccountController
namespace FiorelloTask.Controllers
{
public class AccountController : Controller
{
private UserManager<AppUser> _userManager;
private SignInManager<AppUser> _signInManager;
private RoleManager<IdentityRole> _roleManager;
public AccountController(UserManager<AppUser> userManager,SignInManager<AppUser>signInManager,
RoleManager<IdentityRole> roleManager)
{
_userManager = userManager;
_signInManager = signInManager;
_roleManager = roleManager;
}
public IActionResult Index()
{
return View();
}
public IActionResult Register()
{
return View();
}
[HttpPost]
[AutoValidateAntiforgeryToken]
public async Task< IActionResult> Register(RegisterVM register)
{
if(!ModelState.IsValid) return View();
AppUser newUser = new AppUser()
{
Fullname = register.FullName,
UserName = register.UserName,
Email = register.Email
};
IdentityResult result =await _userManager.CreateAsync(newUser,
register.Password);
if (!result.Succeeded)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error.Description);
}
return View(register);
}
await _userManager.AddToRoleAsync(newUser, Roles.Admin.ToString());
await _signInManager.SignInAsync(newUser, true);
return RedirectToAction("index","home");
}
public IActionResult Login()
{
return View();
}
[HttpPost]
[AutoValidateAntiforgeryToken]
public async Task<IActionResult> Login(LoginVM login,string ReturnUrl)
{
if (!ModelState.IsValid) return View();
AppUser dbUser=await _userManager.FindByEmailAsync(login.Email);
if (dbUser==null)
{
ModelState.AddModelError("", "email or password wrong");
return View(login);
}
SignInResult result = await _signInManager.PasswordSignInAsync(dbUser, login.Password,
login.RememberMe , true);
if (result.IsLockedOut)
{
ModelState.AddModelError("", "your account is lockout");
return View(login);
}
if (!result.Succeeded)
{
ModelState.AddModelError("", "email or password wrong");
return View(login);
}
foreach (var item in await _userManager.GetRolesAsync(dbUser))
{
if (item.Contains(Roles.Admin.ToString()))
{
return RedirectToAction("index", "dashboard", new { area = "adminF" });
}
}
if (ReturnUrl==null)
{
return RedirectToAction("index", "home");
}
return Redirect(ReturnUrl);
}
public async Task<IActionResult> Logout()
{
await _signInManager.SignOutAsync();
return RedirectToAction("index", "home");
}
public async Task CreateRole()
{
foreach (var item in Enum.GetValues(typeof(Roles)))
{
if (!await _roleManager.RoleExistsAsync(item.ToString()))
{
await _roleManager.CreateAsync(new IdentityRole { Name = item.ToString() });
}
}
}
}
}
DefaultWebSite (hosts WordPress) | +- web (virtual direcotry that hosts the aspnet core site) Within the aspnet core site, when I redirect to a page or use tag helpers the url includes "/web/blahblah" which makes sense. However, I don't want that. How do I force the aspnet core site to ignore the virtual directory path and generate urls like "/blahblah" without web?
2.BasketController
public class BasketController : Controller
{
private AppDbContext _context;
public BasketController(AppDbContext context)
{
_context = context;
}
public IActionResult Index()
{
return View();
}
public async Task<IActionResult> AddBasket(int?id)
{
if (id == null) return NotFound();
Product dbProduct = await _context.Products.FindAsync(id);
if (dbProduct == null) return NotFound();
List<BasketProduct> products;
string existBasket = Request.Cookies["basket"];
if (existBasket == null)
{
products = new List<BasketProduct>();
}
else
{
products = JsonConvert.DeserializeObject<List<BasketProduct>>(Request.Cookies
["basket"]);
}
BasketProduct existBasketProduct = products.FirstOrDefault(p => p.Id==dbProduct.Id);
if (existBasketProduct==null)
{
BasketProduct basketProduct = new BasketProduct();
basketProduct.Id = dbProduct.Id;
basketProduct.Name = dbProduct.Name;
basketProduct.Count = 1;
products.Add(basketProduct);
}
else
{
if (dbProduct.Count<=existBasketProduct.Count)
{
TempData["Fail"] = "not enough count";
return RedirectToAction("index", "home");
}
else
{
existBasketProduct.Count++;
}
}
Response.Cookies.Append("basket", JsonConvert.SerializeObject(products), new
CookieOptions { MaxAge = TimeSpan.FromMinutes(30) });
return RedirectToAction("Index","Home");
}
public IActionResult Basket()
{
List<BasketProduct> products=JsonConvert.DeserializeObject<List<BasketProduct>>
(Request.Cookies["basket"]);
List<BasketProduct> updateProducts = new List<BasketProduct>();
foreach (var item in products)
{
Product dbProduct = _context.Products.FirstOrDefault(p=>p.Id==item.Id);
BasketProduct basketProduct = new BasketProduct()
{
Id =dbProduct.Id,
Price=dbProduct.Price,
Name=dbProduct.Name,
ImageUrl=dbProduct.ImageUrl,
Count=item.Count
};
updateProducts.Add(basketProduct);
}
return View(updateProducts);
}
public IActionResult RemoveItem(int? id)
{
if (id == null) return NotFound();
string basket = Request.Cookies["basket"];
List<BasketProduct> products =
JsonConvert.DeserializeObject<List<BasketProduct>>(basket);
BasketProduct existProduct = products.FirstOrDefault(p => p.Id == id);
if (existProduct == null) return NotFound();
products.Remove(existProduct);
Response.Cookies.Append("basket",
JsonConvert.SerializeObject(products),
new CookieOptions { MaxAge=TimeSpan.FromMinutes(20)});
return RedirectToAction(nameof(basket));
}
public IActionResult Plus(int? id)
{
if (id == null) return NotFound();
string basket = Request.Cookies["basket"];
List<BasketProduct> products =
JsonConvert.DeserializeObject<List<BasketProduct>>(basket);
BasketProduct existProduct = products.FirstOrDefault(p => p.Id == id);
if (existProduct == null) return NotFound();
Product dbProduct = _context.Products.FirstOrDefault(p => p.Id == id);
if (dbProduct.Count>=existProduct.Count)
{
existProduct.Count++;
}
else
{
TempData["Fail"] = "not enough count";
return RedirectToAction("Basket", "Basket");
}
Response.Cookies.Append(
"basket",
JsonConvert.SerializeObject(products),
new CookieOptions { MaxAge = TimeSpan.FromMinutes(20) });
return RedirectToAction(nameof(Basket));
}
public IActionResult Minus(int? id)
{
if (id == null) return NotFound();
string basket = Request.Cookies["basket"];
List<BasketProduct> products =
JsonConvert.DeserializeObject<List<BasketProduct>>(basket);
BasketProduct existProduct = products.FirstOrDefault(p => p.Id == id);
if (existProduct == null) return NotFound();
if (existProduct.Count>1)
{
existProduct.Count--;
}
else
{
RemoveItem(existProduct.Id);
return RedirectToAction(nameof(Basket));
}
Response.Cookies.Append(
"basket",
JsonConvert.SerializeObject(products),
new CookieOptions { MaxAge = TimeSpan.FromMinutes(20) });
return RedirectToAction(nameof(Basket));
}
}
DefaultWebSite (hosts WordPress) | +- web (virtual direcotry that hosts the aspnet core site) Within the aspnet core site, when I redirect to a page or use tag helpers the url includes "/web/blahblah" which makes sense. However, I don't want that. How do I force the aspnet core site to ignore the virtual directory path and generate urls like "/blahblah" without web?
1. HomeController
- public class HomeController : Controller
{
private AppDbContext _context;
public HomeController(AppDbContext context)
{
_context=context;
}
public IActionResult Index()
{
HomeVM homeVm = new HomeVM();
homeVm.sliders= _context.Sliders.ToList();
homeVm.pageIntro= _context.PageIntros.FirstOrDefault();
homeVm.categories = _context.Categories.ToList();
return View(homeVm);
}
}
DefaultWebSite (hosts WordPress) | +- web (virtual direcotry that hosts the aspnet core site) Within the aspnet core site, when I redirect to a page or use tag helpers the url includes "/web/blahblah" which makes sense. However, I don't want that. How do I force the aspnet core site to ignore the virtual directory path and generate urls like "/blahblah" without web?
- 4-PRODUCT CONTROLLER
namespace FiorelloTask.Controllers
{
[Authorize]
public class ProductController : Controller
{
private AppDbContext _context;
public ProductController(AppDbContext context)
{
_context = context;
}
[Authorize]
public IActionResult Index()
{
ViewBag.ProductCount = _context.Products.Count();
List<Product> products = _context.Products.Include(p => p.Category).Take(2).ToList();
return View(products);
}
public IActionResult LoadMore(int skip)
{
List<Product> products = _context.Products.Include(p => p.Category).Skip(skip).Take(2).ToList();
return PartialView("_ProductPartial", products);
}
public IActionResult SearchProduct(string search)
{
List<Product> products = _context.Products.Where(p => p.Name.ToLower().Contains(search.ToLower())).Take(10).ToList();
return PartialView("_Search", products);
}
}
}
DefaultWebSite (hosts WordPress) | +- web (virtual direcotry that hosts the aspnet core site) Within the aspnet core site, when I redirect to a page or use tag helpers the url includes "/web/blahblah" which makes sense. However, I don't want that. How do I force the aspnet core site to ignore the virtual directory path and generate urls like "/blahblah" without web?
In this line docker run -it --rm -p 5000:80 --name aspnetcore_sample aspnetapp you are mapping the internal port (within the docker container) of 5000 to an external port (outside of the container) of 80. Meaning, when you browse to the ip address given to your container, it forwards your request to port 5000
- AppDbContext
public class AppDbContext:IdentityDbContext<AppUser>
{
public AppDbContext(DbContextOptions<AppDbContext>options):base(options)
{
}
public DbSet<Slider> Sliders { get; set; }
public DbSet<PageIntro> PageIntros { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Bio> Bios { get; set; }
public DbSet<Blog> Blogs { get; set; }
I have a hybrid web application that has WordPress as the root site with an aspnet core web application as a virtual directory. The IIS structure looks something like:
Within the aspnet core site, when I redirect to a page or use tag helpers the url includes "/web/blahblah" which makes sense. However, I don't want that. How do I force the aspnet core site to ignore the virtual directory path and generate urls like
-ViewComponents
- public class FooterViewComponent:ViewComponent
{
private AppDbContext _context;
public FooterViewComponent(AppDbContext context)
{
_context = context;
}
public async Task<IViewComponentResult> InvokeAsync()
{
Bio bio = _context.Bios.FirstOrDefault();
return View(await Task.FromResult(bio));
}
}
I have a hybrid web application that has WordPress as the root site with an aspnet core web application as a virtual directory. The IIS structure looks something like:
- HeaderViewComponent
public class HeaderViewComponent:ViewComponent
{
private UserManager<AppUser> _userManager;
private AppDbContext _context;
public HeaderViewComponent(AppDbContext context,UserManager<AppUser> userManager)
{
_context = context;
_userManager = userManager;
}
public async Task<IViewComponentResult> InvokeAsync()
{
int totalCount = 0;
if (Request.Cookies["basket"]!=null)
{
List<BasketProduct> products = JsonConvert.DeserializeObject<List<BasketProduct>>
(Request.Cookies["basket"]);
foreach (var item in products)
{
totalCount += item.Count;
}
}
ViewBag.BasketLength = totalCount;
Bio bio = _context.Bios.FirstOrDefault();
if (User.Identity.IsAuthenticated)
{
AppUser currentUser = await _userManager.FindByNameAsync(User.Identity.Name);
ViewBag.Fullname = currentUser.Fullname;
}
return View(await Task.FromResult(bio));
}
}
#JamieTaylor you are right, but that's not what the message "now listening on ..." says. That message is talking about the internal port inside the container, which, as you correctly say, is mapped to the port 5000 outside the container
- ProductsViewComponent
public class ProductsViewComponent:ViewComponent
{
private AppDbContext _context;
public ProductsViewComponent(AppDbContext context)
{
_context = context;
}
public async Task<IViewComponentResult> InvokeAsync()
{
List<Product> products = _context.Products.Include(p => p.Category).Take(8).ToList();
return View(await Task.FromResult(products));
}
}

404 Not found when calling Web API using Attribute routing

I am trying to get a call to an attribute route in my ASP.NET Web API 5.27 to work but Im getting a 404 Not Found error. I have searched extensively for this.
My app is a Xamarin.Forms developed with VS2019.
The call works in the browser of real the testing device but not from the app.
Here is my setup:
public class OrdersController : ApiController
{
private readonly OrdersDbContext db = new OrdersDbContext();
// GET: api/Orders/5
[ResponseType(typeof(Order))]
[Route("Order/{Id}")]
[HttpGet]
public async Task<IHttpActionResult> GetOrder(int Id)
{
var order = await db.Orders.Where(w => w.OrderId == Id).Select(s => s)
.FirstAsync();
if (order == null)
{
return NotFound();
}
return Ok(order);
}
}
public class DataService : IDataService
{
readonly HttpClient _client;
public DataService()
{
_client = new HttpClient()
{
BaseAddress = new Uri(Constants.BaseUrl)
};
}
public async Task<Order> GetNewOrder(NewOrderDetails details)
{
var uri = $"Order/1";
var response = await _client.GetStringAsync(uri);
var order = JsonConvert.DeserializeObject<Order>(response);
return order;
}
}

IdentityResult to ActionResult

Is there an easy way to convert an IdentityResult to an IActionResult taking into account errors?
IdentityResult is just a class which tells you if an ASP.NET (Core) Identity operation succeeded or not and in case of an error offers you error messages and is unrelated to MVC Action's results which implement IActionResult interface.
If you use WebApi/RestApi controllers , you'd translate it to something like
public IActionResult SomeActionName()
{
IdentityResult result = ...; // some identity operation
// all is okay, return http code 200
if(result.Success)
return Ok();
// error happened, return http code 400 + errors as json
return BadRequest(result.Errors);
}
Or if you are really lazy, write your own IActionResult:
public class IdentityActionResult : IActionResult
{
private readonly IdentityResult identityResult;
public IdentityActionResult(IdentityResult identityResult)
{
this.identityResult = identityResult;
}
public Task ExecuteResultAsync(ActionContext context)
{
IActionResult actionResult = null;
if(identityResult.Success)
{
actionResult = new OkResult();
}
else
{
actionResult = new BadRequestObjectResult(identityResult.Errors);
}
return actionResult.Execute(context);
}
}
Of course this can be further optimized so that you don't have to create two IActionResult objects per request, but that's an exercise left up to you ;)
You can write an extension method for IdentityResult which returns ObjectResult something like this:
public static class IdentityResultExtension
{
public static ObjectResult ToObjectResult(this IdentityResult result)
{
//
return new ObjectResult(result);
}
}
then use it in action:
public IActionResult YourAction()
{
IdentityResult result;
return result.ToObjectResult();
}

WebApi for Email delivery

I created a Web API controller inside my ASP.NET MVC 4 Website to specifically send emails so that I can consume it for this purpose and eventually provide it to other consumers (Mobile, etc).
Everything is working fine but I want to use it asynchronously, altough it's not working that way, my website blocks until the work is finished.
I have a regular Controller where I call a helper class that calls the API.
Controller Code :
[HttpPost]
public async Task<ActionResult> ContactUs(ContactUsModel model)
{
ExternalApiCalls extApi = new ExternalApiCalls();
await extApi.PostContactUs(model).ConfigureAwait(false);
return RedirectToAction("ContactUsSuccess", "Account");
}
Helper Class Code :
public class ExternalApiCalls
{
public HttpClient client { get; set; }
public ExternalApiCalls()
{
client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:10239/");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task PostContactUs(ContactUsModel model)
{
try
{
var response = await client.PostAsJsonAsync("api/WAPIMail", model).ConfigureAwait(false);
}
catch (HttpRequestException ex)
{
}
catch (System.FormatException)
{
}
finally
{
}
}
}
Web API Controller :
public class WAPIMailController : ApiController
{
public void PostContactUs(ContactUsModel model)
{
// Send Email Here
}
}
Thanks a lot for your help
I finally managed how to do it..
For brevity's sake, I am showing oversimplified code, see below:
Controller :
[HttpPost]
public ActionResult ContactUs(ContactUsModel model)
{
new ExternalApiCalls().MailContactUs(model);
return RedirectToAction("ContactUsSuccess", "Account");
}
Helper Class :
public void MailContactUs(ContactUsModel model)
{
client.PostAsJsonAsync("api/WAPIMail/MailContactUs", model).ConfigureAwait(false);
}
Web API Controller :
[HttpPost]
public void MailContactUs(ContactUsModel model)
{
//Email Logic Here
}