I´m trying to make a simple api on .net core 3.1, I deleted the wheather thing that comes from default. I put a new starting point but despite many efforts and changes, I still get an 404
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
In properties, start explorer:
api/Servicio/GetServicio/tecnico/Pedro/semanaDelAno/8
Controller
[Route("api/Servicio")]
public class ServicioController : Controller
{
private readonly ApplicationDbContext _context;
public ServicioController(ApplicationDbContext context)
{
_context = context;
}
// POST: api/PostServicio
[HttpPost]
public async Task<ActionResult<Servicio>> PostServicio(Servicio servicio)
{
_context.Servicio.Add(servicio);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetServicio), new { id = servicio.Id }, servicio);
}
// GET: api/GetServicio/5
//[HttpGet("{tecnico}/{semanaDelAno}")]
[HttpGet("GetServicio/{tecnico}/{semanaDelAno}")]
public async Task<ActionResult<Servicio>> GetServicio(string tecnico, int semanaDelAno)
{
var servicio = await _context.Servicio.FirstOrDefaultAsync(i => i.Tecnico == tecnico && i.SemanaDelAno == semanaDelAno);
if (servicio == null)
{
return NotFound();
}
return servicio;
}
Assuming tecnico=Pedro and semanaDelAno=8, you have to use this url
~/api/Servicio/GetServicio/Pedro/8
for GetServicio action:
[HttpGet("GetServicio/{tecnico}/{semanaDelAno}")]
public async Task<ActionResult<Servicio>> GetServicio(string tecnico, int semanaDelAno)
{
.... your code
}
Related
I am attempting to create a web application that is capable of searching an itunes API. It will require a database so I am using Entity framework and have a context file called SearchCountContext.cs. Inside this file I have a constructor which I need to use inside of my controller to manipulate data, the problem I am having is that I do not know how to call this method since it takes in 1 parameter DbContextOptions<ItunesSearchDBEntities> options and do not know what argument I need to pass in when invoking. Can someone help me figure this out?
SearchCountContext.cs:
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
namespace ItunesMVC.DataAccess
{
public partial class ItunesSearchDBEntities : DbContext
{
public ItunesSearchDBEntities(DbContextOptions<ItunesSearchDBEntities> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.UseCollation("utf8mb4_0900_ai_ci")
.HasCharSet("utf8mb4");
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
public DbSet<SearchCount> SearchCounts { get; set; }
}
}
HomeController.cs:
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using ItunesMVC.Models;
namespace ItunesMVC.Controllers;
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public ActionResult Index()
{
ViewBag.SearchCounts = new DataAccess.ItunesSearchDBEntities().SearchCounts.OrderByDescending(a => a.Count).Take(25).ToList(); //Error here
return View();
}
public IActionResult Privacy()
{
return View();
}
[HttpGet]
public ActionResult Search(string Term)
{
try
{
var result = API.ItunesSearchAPI.Search(Term);
ViewBag.value = Term;
return View(result);
}
catch (Exception)
{
throw;
}
}
[HttpGet]
public ActionResult CountAndGO(string URL, string SearchTerm)
{
DataAccess.ItunesSearchDBEntities db = new DataAccess.ItunesSearchDBEntities();
//Finding the term in database.
var _term = db.SearchCounts.Where(a => a.Term == SearchTerm.ToLower()).FirstOrDefault();
if (_term != null)
{
//If term is present Count is added
_term.Count++;
db.Entry(_term).State = System.Data.EntityState.Modified;
}
else
{
//Term is saved in database
db.SearchCounts.Add(new SearchCount() { Term = SearchTerm.ToLower(), Count = 1 });
}
db.SaveChanges();
if (URL == null || URL == "")
return RedirectToAction("NoURL");
return Redirect(URL);
}
public ActionResult NoURL()
{
return View();
}
}
In your startup.cs or where you are registering your dependencies you may want to register an instance of your context (ItunesSearchDBEntities) by calling
services.AddDbContext<SimulationsDbContext>(d =>
{
d.UseSqlServer(simulationsDbConnectionString);
});
Then you would be able to inject your ItunesSearchDBEntities context into the homecontroller, or even at the method level by using the [FromServices] attribute https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection?view=aspnetcore-6.0
In my application, I'm trying to build an authorization - privilege based authentication.
For better understanding here's how my privileges are named and stored in my database : "GET_USERS" , "GET_USER", "DELETE_USER" ...
What I want to do is to specify the privilege name in the authorization attribute from my base controller, but the problem is that the authorization attribute only allows constant parameters.
Here's my base Controller :
public class BaseController<T> : ControllerBase where T : class
{
protected readonly ConcreetDataContext _context;
protected readonly IBaseRepository<T> _repo;
protected readonly INotificationRepository _notificationRepo;
protected readonly IHubContext<NotificationHub> _hubContext;
protected readonly DbSet<T> _dbSet;
public BaseController(IHubContext<NotificationHub> hubContext,
ConcreetDataContext context,
IBaseRepository<T> repo,
INotificationRepository notifRepo)
{
_context = context;
_hubContext = hubContext;
_repo = repo;
_dbSet = _context.Set<T>();
_notificationRepo = notifRepo;
}
// GET: api/[items]
[HttpGet]
// HERE's THE ISSUE
[PrivilegeAuthorize("GET_"+typeof(T).Name.toUpper()] // this is not allowed
public async Task<ActionResult<IEnumerable<T>>> Get([FromQuery] GlobalParams globalParams)
{
Type t = typeof(T);
Console.WriteLine(t.Name.ToUpper());
var classes = await PagedList<T>.CreateAsync(_repo.Get(globalParams),globalParams.PageNumber,globalParams.PageSize);
Response.AddPagination(classes.CurrentPage, classes.PageSize, classes.TotalCount, classes.TotalPages);
return Ok(classes);
}
// GET: api/[items]/5
[HttpGet("{id}")]
public virtual async Task<ActionResult<T>> Get(int id)
{
var item = await this._repo.GetByID(id);
if (item == null)
{
return NotFound();
}
return item;
}
// PUT: api/[items]/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPut("{id}")]
public async Task<IActionResult> Put(int id, T item)
{
// if (id != item.ID)
// {
// return BadRequest();
// }
try
{
await this._repo.Update(item);
// Creating the notification
await this._notificationRepo.CreateNotification("Update",typeof(T).ToString(),"Updated "+typeof(T).ToString()+" with ID : "+id);
}
catch (DbUpdateConcurrencyException)
{
if (!(await Exists(id)))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/Classes
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPost]
public async virtual Task<ActionResult<T>> Post(T item)
{
await this._repo.Insert(item);
await this._notificationRepo.CreateNotification("Create",typeof(T).ToString(),"Created "+typeof(T).ToString());
return CreatedAtAction("Get", item);
}
// DELETE: api/Classes/5
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
var item = await _dbSet.FindAsync(id);
if (item == null)
{
return NotFound();
}
_dbSet.Remove(item);
await _context.SaveChangesAsync();
var notification = await this._notificationRepo.CreateNotification("Delete",typeof(T).ToString(),"Deleted "+typeof(T).ToString());
// Invoking BroadCastToUserFunction
var useID = Request.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)?.Value;
await _hubContext.Clients.User(useID).SendAsync("simo",notification);
return NoContent();
}
private async Task<bool> Exists(int id)
{
var item = await this._repo.GetByID(id);
if(item != null)
return true;
return false;
}
[HttpGet("count")]
public async Task<ActionResult<int>> Count([FromQuery] GlobalParams globalParams)
{
return await this._repo.Count(globalParams);
}
}
Thank you in advance !
As Lasse V. Karlsen pointed out in comments: "base class is compiled once, it is not compiled for each Variant, so the compiler will have to figure out what to pass as a string there once".
So I went with the following solution for the moment :
[PrivilegeAuthorize("GET_USERS")]
public override Task<ActionResult<IEnumerable<City>>> Get([FromQuery] GlobalParams globalParams)
{
return base.Get(globalParams);
}
I should override each method where I want to apply this authorization attribute.
i'm making a Web API and i want to retrieve the object created by the CreateCommand Method.
To do that, I'm using the CreateAtRoute function to call the GetCommandById function ,with the id of the created Command as parameter, but i'm getting the following error:
" System.InvalidOperationException: No route matches the supplied
values."
This is my controller:
[Route("api/commands")]
[ApiController]
public class CommandsController : Controller
{
private readonly ICommanderRepo _repository;
private readonly IMapper _mapper;
public CommandsController(ICommanderRepo repository,IMapper mapper)
{
_repository = repository;
_mapper = mapper;
}
[HttpGet]
public ActionResult <IEnumerable<CommandReadDto>> GetAllCommands()
{
var commands = _repository.GetAllCommands();
return Ok(_mapper.Map<IEnumerable<CommandReadDto>>(commands));
}
[HttpGet("{id}")]
public ActionResult <CommandReadDto> GetCommandById(int id)
{
var command = _repository.GetCommandById(id);
if(command != null)
{
return Ok(_mapper.Map<CommandReadDto>(command));
}
return NotFound();
}
[HttpPost]
public ActionResult <CommandReadDto> CreateCommand(CommandCreateDto commandCreateDto)
{
var commandModel = _mapper.Map<Command>(commandCreateDto);
_repository.CreateCommand(commandModel);
_repository.SaveChanges();
var commandReadDto = _mapper.Map<CommandReadDto>(commandModel);
var x = nameof(GetCommandById);
return CreatedAtRoute(nameof(GetCommandById), new { id = commandReadDto.Id }, commandReadDto);
}
I have already tried this (which didn't resolve the problem):
Check if the parameters of both functions match
Added to my Startup.cs : services.AddControllers(options => options.SuppressAsyncSuffixInActionNames = false); ( i saw this on a post here in stackoverflow
What might be the problem?
When using CreatedAtRoute, you'll need something like shown below. Please note the addition of a route name, and use of that route name in CreatedAtRoute.
[HttpGet("{id}", Name="GetCommand")]
public ActionResult <CommandReadDto> GetCommandById(int id)
{
... // your code here
}
[HttpPost]
public ActionResult <CommandReadDto> CreateCommand(CommandCreateDto commandCreateDto)
{
... // your code here
return CreatedAtRoute("GetCommand", new { commandReadDto.Id }, commandReadDto);
}
An alternative, is to use CreatedAtAction like shown below. With this approach, a route name is not required.
return CreatedAtAction("GetCommandById", new { commandReadDto.Id }, commandReadDto);
You should derive your API-controllers from ControllerBase instead of Controller. The latter is targeting MVC-controllers.
And I believe you should remove options.SuppressAsyncSuffixInActionNames until you actually need it.
I want to call an ASP.NET Core 2.1.0 Web API with a controller's method.
I tried following but I get an error
Cannot GET /api/remote/NewAc/test1
Code:
[Route("api/remote/{action}")]
//[Route("api/[controller]")]
[ApiController]
public class RemoteController : ControllerBase
{
private readonly MyContext _context;
public RemoteValsController(MyContext context)
{ _context = context; }
[HttpGet]
public async Task<OkObjectResult> NewAc()
{
var r = await _context.TypeOfAccounts.AnyAsync();
return Ok(new { r = true });
}
[HttpGet("{id}")]
public async Task<OkObjectResult> NewAc([FromRoute] string AccountType)
{
var r = await _context.TypeOfAccounts.AnyAsync(o => o.AccountType.ToUpper() == AccountType.ToUpper());
return Ok(new { r = !r });
}
}
Startup.cs
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
I tried both [HttpPost] and [HttpGet] but in vain.
Re-check the defined routes for the controller.
[Route("api/remote/[action]")] //<-- NOTE Token replacement in route templates
[ApiController]
public class RemoteController : ControllerBase {
private readonly MyContext _context;
public RemoteController(MyContext context) {
_context = context;
}
//GET api/remote/NewAc
[HttpGet]
public async Task<IActionResult> NewAc() {
var r = await _context.TypeOfAccounts.AnyAsync();
return Ok(new { r = true });
}
//GET api/remote/NewAc/test1
[HttpGet("{accountType}")]
public async Task<IActionResult> NewAc(string accountType) {
var r = await _context.TypeOfAccounts.AnyAsync(o => o.AccountType.ToUpper() == accountType.ToUpper());
return Ok(new { r = !r });
}
}
Reference Routing to controller actions in ASP.NET Core
First, mapped routes and attribute routing are an either/or affair. If you have route attributes involved, the route definition in your Startup is not applicable at all.
Second, you can't just throw [FromRoute] in front a param and magically have it in the route. In fact, that attribute isn't necessary at all unless there's some ambiguity about where the param value is actually supposed to come from. If you want it from the route, then it needs to be part of your route template. Simply:
[HttpGet("{id}/{AccountType}")]
public async Task<OkObjectResult> NewAc(string AccountType)
{
var r = await _context.TypeOfAccounts.AnyAsync(o => o.AccountType.ToUpper() == AccountType.ToUpper());
return Ok(new { r = !r });
}
I am working on a Url Shortener in Asp.Net Core and using MongoDB.
I currently have a working Get method and a working Create method.
I ran into an issue with my Delete method and this is the message I get:
Argument 1: cannot convert from
'MongoDB.Driver.FilterDefinition)', candidates
are: System.Threading.Tasks.Task
DeleteOneAsync(MongoDB.Driver.FilterDefinition,
System.Threading.CancellationToken)(in interface
IMongoCollection)
System.Threading.Tasks.Task
DeleteOneAsync(this
MongoDB.Driver.IMongoCollection,
System.Linq.Expressions.Expression>,
System.Threading.CancellationToken) (in class
IMongoCollectionExtensions)
The error has something to do with this ".DeleteOneAsync(filter);" in my 'ShortUrlRepository' class:
public async Task<ShortUrl> Delete(ShortUrl su)
{
var filter = Builders<Url>.Filter.Eq("Su", su);
return await _db.Urls.DeleteOneAsync(filter);
}
My ShortUrlsController class seems to be working just fine but I will post it in case:
namespace ShortenUrls.Controllers
{
[Route("api/codes")]
public class ShortUrlsController : Controller
{
private readonly ShortUrlRepository _repo;
//private readonly IShortUrlService _service;
public ShortUrlsController(ShortUrlRepository repo /*IShortUrlService service*/)
{
_repo = repo;
//_service = service;
}
[HttpGet("{id}")]
public async Task<IActionResult> Get(string id)
{
var su = await _repo.GetAsync(id);
if (su == null)
return NotFound();
return Ok(su);
}
[HttpPost]
public async Task<IActionResult> Create([FromBody] ShortUrl su)
{
await _repo.CreateAsync(su);
return Ok(su);
}
[HttpDelete("{id}")]
public async Task<IActionResult> Delete (ShortUrl su)
{
try
{
if (su == null)
return new NotFoundResult();
await _repo.Delete(su);
return Ok("Deleted Successfully");
}
catch (Exception ex)
{
return BadRequest(ex.ToString());
}
}
}
}
I have tried other remove methods but have gotten similar errors so maybe I am missing something?
If anyone can offer some suggestions I would greatly appreciate it as I am new to Asp.Net Core and I am having very little success finding a solution to this error. If I can provide anymore information please let me know.
Creating the variable 'r' and returning it solved the 'Argument 1 error':
public async Task<bool> Delete(ObjectId id)
{
var filter = Builders<ShortUrl>.Filter.Eq(x => x.Id, id);
var r = await _db.Urls.DeleteOneAsync(filter);
return r.DeletedCount > 0;
}
I made other changes that were unrelated to this error but were necessary to make the Delete method work properly. Here are the changes I had to make to my 'ShortUrlsController' class:
[HttpDelete("{id}")]
public async Task<IActionResult> Delete (string id)
{
return (await _repo.Delete(ObjectId.Parse(id)))
? (IActionResult) Ok("Deleted Successfully")
: NotFound();
}