ASP.NetCore API controller does not call my method in my Controller - asp.net-core

I create an API Controller in my ASP.NET core web api project.
[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
public MyData Method1(string Id)
{
Console.WriteLine("here");
return null;
}
public MyData Method2()
{
Console.WriteLine("here");
return null;
}
}
I set breakpoints in each method and load these urls in my browser:
https://localhost:44357/test/Method1/1343a
https://localhost:44357/test/Method2
And in my Startup.cs, I have
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
Can you please help me why my API controller does not get invoked when I load ^ urls in browser?
I read https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-6.0 , I think those method should get called.
Thank you for your help.

First check by adding verb over method [HTTPPOST] or [HTTPGET].
Also your starup.cs code looks like as written below:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
You controller Code:
[ApiController]
[Route("api/[controller]")]
public class TestController : ControllerBase
{
[HttpGet]
[Route("method1")]
public MyData Method1(string Id)
{
Console.WriteLine("here");
return null;
}
[HttpGet]
[Route("method2")]
public MyData Method2()
{
Console.WriteLine("here");
return null;
}
}
Now call you API like :
https://localhost:portno/api/test/method1/abc
https://localhost:portno/api/test/method2

Please change your route to include the action like below
[ApiController]
[Route("[controller]/[action]")]
public class TestController : ControllerBase
{
public MyData Method1(string Id)
{
Console.WriteLine("here");
return null;
}
public MyData Method2()
{
Console.WriteLine("here");
return null;
}
}

in Asp.net Api you need route for each Action:
[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
[HttpGet("[Action]/{Id}")]
public MyData Method1(string Id)
{
Console.WriteLine("here");
return null;
}
[HttpGet("[Action]")]
public MyData Method2()
{
Console.WriteLine("here");
return null;
}
}

For Net Core 6.0 change this in your Program.cs
`var services = builder.Services;
services.AddControllers();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.Run();`
and [Route("methodname")] use this attribute above your action method.

Related

http post action not reached in ASP.NET Core 3.1 web API controller

I have this controller
[ApiController]
[Route("api/[controller]")]
public class PlanningController: ControllerBase
{
public async Task<IActionResult> SaveTest([FromBody] TestData data)
{
return Ok(data);
}
public class TestData
{
public int Id { get; set; }
public string Name { get; set; }
}
This in Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseCors("default");
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.Run(context => context.Response.WriteAsync("Planificador API iniciada"));
}
I put a break point in the return but when I post this in postman
nothing happens in my controller the break point is not reached.
I don't understand the response received in postman
In VS 2022 I see this
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request
starting HTTP/1.1 POST
http://localhost:5001/api/planning/saveTest application/json 34
Microsoft.AspNetCore.Hosting.Diagnostics[1]
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request finished in 8.3968ms 200
Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished in 8.3968ms 200
Any idea, please?
Thanks
Nothing happens in my controller the break point is not reached.I
don't understand the response received in postman
Well, because of using [Route("planning")] before your PlanningController it is certainly overriding your application standard routing. So, your controller route has been changed. Thus, you shouldn't manipulate this routing [Route("api/[controller]")]
Correct Way:
[Route("api/[controller]")]
[ApiController]
public class PlanningController : ControllerBase
{
[HttpPost]
[Route("saveTest")]
public async Task<IActionResult> SaveTest([FromBody] TestData data)
{
return Ok(data);
}
}
Update:
Stratup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "TestWebAPIProject", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TestWebAPIProject v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Output:
Note: I would highly recommend you to have a look on our official document for Custom route constraints
Solved...
The problem was tha in my controller I was injected IFileProvider wrong
Unable to resolve service for type 'Microsoft.Extensions.FileProviders.IFileProvider' while attempting to activate my controller

.NET Core API Endpoint gives 404 only in deployed version

I am building a .NET Core (3.1) Web API which is being hosted in IIS.
I have 2 endpoints:
/api/status
/api/widget/config/{id}
Both endpoints work perfectly when running locally. The /api/status endpoint works in my deployed version too. But the other endpoint gives a 404 error in the deployed version. As it works locally, I believe this to be an issue with how it is deployed. Please can you help me understand the issue?
Here are my 2 controllers code:
[Route("api/[controller]")]
[ApiController]
public class StatusController : ControllerBase
{
[HttpGet]
public ActionResult Get()
{
return Ok("API is available");
}
}
and
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
private readonly IWidgetService service;
public WidgetController(IWidgetService _service)
{
service = _service;
}
[HttpGet]
[Route("~/api/[controller]/[action]/{id}")]
public ActionResult Config(Guid id)
{
return Ok(service.GetWidgetConfig(id));
}
}
and below is my Program.cs and Startup.cs:
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
SeedDatabase.Initialize(services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occured seeding the DB");
}
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel();
webBuilder.UseContentRoot(Directory.GetCurrentDirectory());
webBuilder.UseIIS();
webBuilder.UseStartup<Startup>();
});
and
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(opts => opts.UseSqlServer(Configuration.GetConnectionString("sqlConnection"),
options => options.MigrationsAssembly("MyProject")));
services.AddIdentity<ApplicationUser, IdentityRole>(opt =>
{
opt.Password.RequiredLength = 8;
opt.Password.RequireDigit = true;
opt.Password.RequireUppercase = true;
opt.Password.RequireNonAlphanumeric = true;
opt.SignIn.RequireConfirmedAccount = false;
opt.SignIn.RequireConfirmedAccount = false;
opt.SignIn.RequireConfirmedPhoneNumber = false;
}).AddEntityFrameworkStores<ApplicationDbContext>();
services.AddScoped<IWidgetService, WidgetService>();
services.AddCors(o => o.AddPolicy("CorsPolicy", builder => {
builder
.WithMethods("GET", "POST")
.AllowAnyHeader()
.AllowAnyOrigin();
}));
services.AddMvc()
.AddNewtonsoftJson(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors("CorsPolicy");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Change your controller code to this:
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
private readonly IWidgetService service;
public WidgetController(IWidgetService _service)
{
service = _service;
}
[HttpGet("Config/{id}")]
public ActionResult Config(Guid id)
{
return Ok(service.GetWidgetConfig(id));
}
}
Change your code like below:-
Startup.cs
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Controller:-
[ApiController]
[Route("api/[controller]")]
public class WidgetController : ControllerBase
{
private readonly IWidgetService service;
public WidgetController(IWidgetService _service)
{
service = _service;
}
[HttpGet("Config/{id}")]
public ActionResult Config(Guid id)
{
return Ok(service.GetWidgetConfig(id));
}
}
Also try your write connection string in appsettings.Development.json file.
It will resolve your issue.

LinkGenerator.GetUriByAction not following the custom route

That's the controller:
[ApiController]
[Route("api/[controller]")
public class MarketController : ControllerBase
{
[HttpGet("{id}/picture")
public async Task<IActionResult> GetPictureAsync(Guid id)
{
...
}
}
I'm using LinkGenerator to create a Absolute URI from GetPictureAsync. And set the Startup class to start HttpContextAccessor as DI.
// Startup.cs
...
public void ConfigureServices(IServiceCollection services)
{
...
services.AddHttpContextAccessor();
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapDefaultControllerRoute();
});
}
And in my custom class I use that way:
public class CustomClass
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly LinkGenerator _linkGenerator;
public CustomClass(IHttpContextAccessor httpContextAccessor,
LinkGenerator linkGenerator)
{
_httpContextAccessor = httpContextAccessor;
_linkGenerator = linkGenerator;
}
public void SomeMethod()
{
var uri = _linkGenerator.GetUriByAction(_httpContextAccessor.HttpContext, "GetPicture", "Markets", new { id = id });
}
}
The problem is because LinkGenerator is not following the custom route sample that I set in GetPicture method.
The LinkGenerator generates the following value:
https://localhost:5051/Markets/GetPicture/00748d23-afa7-4efb-b67b-77f68fdc44d5
But it should generate:
https://localhost:5051/api/Markets/00748d23-afa7-4efb-b67b-77f68fdc44d5/picture
The reason is you use wrong controller name in SomeMethod. Follow the steps you provided, I reproduced your issue.
You should use Market, not Markets.
Because your controller name is MarketController.
After test it,it works for me.

.net core 5.0.2 and jwt => response 401 Unauthorized

I am following an video tutorial for identity server 4 with web api's.
And Im not sure when I went wrong.
Im getting 401 Unauthorized when I try to call api with bearer token.
In previos step, without authorization, my api worked.
This is my api controller in my TablesReach.API project:
...
namespace TablesReach.Controllers
{
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
private readonly DataContext _context;
public UsersController(DataContext context)
{
_context = context;
}
// GET: api/Users
[HttpGet]
public async Task<ActionResult<IEnumerable<User>>> GetUsers()
{
return await _context.Users.ToListAsync();
}
...
this is my Startup.cs of my api project:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(opts =>
{
opts.Authority = "http://localhost:5000";
opts.RequireHttpsMetadata = false;
opts.ApiName = "TablesReachApi";
});
services.AddDbContext<DataContext>(opts => opts.UseInMemoryDatabase("UNWDb"));
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseAuthentication();
}
}
My other project TablesReach.IdentityServer is host on localhost:5000
and Im being able to get bearer token, so I assume that this project is quite OK.
identityServer startup.cs class:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiScopes(Config.GetAllApiResources())
.AddInMemoryClients(Config.GetClients());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//else
//{
// app.UseExceptionHandler("/Home/Error");
// // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
// app.UseHsts();
//}
//app.UseHttpsRedirection();
//app.UseStaticFiles();
//app.UseRouting();
//app.UseAuthorization();
//app.UseEndpoints(endpoints =>
//{
// endpoints.MapControllerRoute(
// name: "default",
// pattern: "{controller=Home}/{action=Index}/{id?}");
//});
app.UseIdentityServer();
}
}
and Config.cs:
public class Config
{
public static IEnumerable<ApiScope> GetAllApiResources()
{
return new List<ApiScope>
{
new ApiScope("TablesReachApi", "Api for solution")
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = { "TablesReachApi" }
}
};
}
}
Note: When I remove annotation [Authorize] from my api controller I can reach my method.
For some middleware, order matters. Authentication and authorization, for example, can't go in the order that you have put them in the API. Microsoft has some clear documentation on this for you to read here..

How to add an Action with a DateTime parameter?

I want to add an Action to my Invoices controller which has a DateTime parameter:
Here is my Controller with my action:
[Route("api/[controller]")]
public class InvoicesController : Controller
{
private readonly IInvoiceRepository _repository;
private readonly ILogger<InvoicesController> _logger;
public InvoicesController(IInvoiceRepository repository, ILogger<InvoicesController> logger)
{
_repository = repository;
_logger = logger;
}
[HttpGet]
public IActionResult FilterBy(DateTime date)
{
try
{
return Ok(_repository.GetInvoicesByDate(date));
}
catch (Exception ex)
{
string errorMessage = "Failed to get invoices by date";
_logger.LogError("{0} {1}", errorMessage, ex);
return BadRequest(errorMessage);
}
}
}
I had in the startup.cs file this line:
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc(routes =>
routes.MapRoute(
name: "getInvoicesByDate",
template: "api/Invoices/{action}/{date:DateTime}",
defaults: new { controller = "Invoices", action = "FilterBy" }));
}
What's wrong in my code ? Thank you
UPDATE
I would like an URL this: format http://domain/api/invoices/filterby/2017-01-01
hm..
I think it is not typical route and parameter with ASP.NET WebAPI, I am also not sure it's WebSite or WebAPI.
It works for me (url format like: domain/api/invoices/filterby/2017-01-01):
[Route("api/[controller]")]
public class InvoicesController : Controller
{
[HttpGet("[action]/{date}")]
public IActionResult FilterBy(DateTime date)
{
try
{
return Ok(date);
}
catch (Exception ex)
{
string errorMessage = "Failed to get invoices by date";
return BadRequest(errorMessage);
}
}
}
--
In my opinion, I would like to make it simple: only use route attribute with WebAPI.
only use app.UseMvc(); in Startup.cs
add route attribute in controller:
Finally, make sure your WebAPI url with parameter(HTTP GET)
http://localhost:xxxx/api/Invoices/FilterBy?date=2017-01-01