ASP.NET core web API routing not supported in AWS HTTP API Gateway? - aws-lambda

I am trying to transfer an asp.net core web api to my first AWS HTTP API.
I have hosted the asp.net core web api project as a lambda function, and trying to match the endpoints through the API gateway.
I can access the default endpoints though my API gateway. i.e. the following endpoint can be accessed through my api gateway successfully.
[Route("api/[controller]")]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value10", "value200" };
}
...
}
But, I get a 404 not found exception if I try to access some method with a Route attribute. e.g.
[Route("api/[controller]")]
[ApiController]
public class ReportsController : ControllerBase
{
// GET api/values
[HttpGet, Route("GetReports")]
public IEnumerable<string> GetReports()
{
return new string[] { "value100", "value2000" };
}
}
with the following mapping
What am I doing wrong here?
thanks,

Related

Can't retrieve BadRequest errors when calling .NET CORE 5 Web API microservice from ASP.NET MVC project

I am trying to retrieve ModelState validation errors from a micro service built with .NET Core 5 Web API from a ASP.NET Core MVC frontend.
Say I have a model that looks like this:
public class Comment
{
public string Title { get; set; }
[Required]
public string Remarks { get; set; }
}
When I call the rest endpoint in the micro service through Swagger to update the Comment model without a remark, I get a response body like this:
{
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Remarks": [
"The Remarks field is required."
]
}
}
Awesome! This is what I expect... However, when I call this endpoint through my MVC project, I can't seem to get the actual "errors".
This is how I am calling the rest endpoint:
var client = _httpClientFactory.CreateClient("test");
HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(comment), Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PutAsync($"api/comments", httpContent);
The response object just has a statusCode of BadRequest. I want to pull the info regarding the errors (the section that says "The Remarks field is required.") but I don't see it in the Content or Headers property or anything like that.
I am new to micro services and .NET Core - am I doing something wrong? Do I need to add something to the startup.cs? Seems weird that I can get the BadRequest status but no supporting problem details.
Thanks in advance!
Be sure your web api controller is not declared with [ApiController].
Web Api Project:
//[ApiController]
[Route("api/[controller]")]
public class CommentsController : ControllerBase
{
[HttpPut]
public IActionResult Put([FromBody] Comment model)
{
if(ModelState.IsValid)
{
//do your stuff...
return Ok();
}
return BadRequest(ModelState);
}
}
Mvc Project:
HttpResponseMessage response = await client.PutAsync($"api/comments", httpContent);
var result = response.Content.ReadAsStringAsync().Result;

Bearer token: The signature is invalid - Default ASP.NET Core 2.1 Web Api template published to Azure

I created a project in VS Community 2019 (latest update) with a template for WebApi .NET Core 2.1 and published it on Azure.
I only added a client secret in the app registration in the portal to use for the call using the authorization code flow.
I was trying to make a GET call using Postman with OAuth 2.0 authorization at the url below:
https://webapi3app.azurewebsites.net/api/values
But I get an unauthorized response with the error header below:
WWW-Authenticate:"Bearer error="invalid_token", error_description="The signature is invalid""
I tried decoding the client secret to BASE64 string but in the repsonse it says that it's an invalid client secret.
I tried changing authorization data to:
- Request URL.
- Request Headers.
I tried several grant types:
- Authorization code.
- Implicit.
- Password Credentials (after changing app to public client).
I tried several scopes:
- Default Microsoft scopes url (https://graph.microsoft.com/.default).
- user.read openid profile offline_access.
- https://aldolekalive.onmicrosoft.com/WebApi3/user_impersonation.
- profile openid email https://graph.microsoft.com/Directory.Read.All https://graph.microsoft.com/User.Read
I tried setting client authentication to:
- Send as basic auth header.
- Send client credentials in body.
I tried changing the Authorize attribute to authorize based on only AzureADBearer or only AzureADJwtBearer (because apparently by default they are both enabled with the current configuration) but no luck.
etc.
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.AzureAD.UI;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
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(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// 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();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseMvc();
}
}
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
}
I expect to get a response with the body:
"value1, value2"
Per my understanding, your webapi is protected by Azure AD and now you want to call the api. To call the api you need to provide an access token.
To do this, you need to register two applications in Azure AD. One is for client App, the other one is for webapi. You can refer to my answer here.
And here is the complete sample. If you don't have an client application now, you can just register an client app in Azure portal, then use this client app to get an access token for your webapi.
I tried several scopes:
If you are using v2.0 endpoint, the scope should be api://{server_client_id}/.default.

Session Value is Always null in ASP.NET Core Web API

I am trying to store the values in session in asp.net core web api project. I have referred the below link to store the values in session.
https://andrewlock.net/an-introduction-to-session-storage-in-asp-net-core/
But i am getting null always while getting session value.
You need provide more details about your codes which doesn't work. But basically you can refer to below steps:
Add ASP.NET Core 2.0 web api application .
Install Microsoft.AspNetCore.Session NuGet package .
Modify your Startup.cs, call AddDistributedMemoryCache and AddSession methods in ConfigureServices function , and add UseSession method in Configure function :
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDistributedMemoryCache();
services.AddSession();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSession();
app.UseMvc();
}
Get/Set session in controller(using Microsoft.AspNetCore.Http;) :
[HttpGet("setSession/{name}")]
public IActionResult setsession(string name)
{
HttpContext.Session.SetString("Name", name);
return Ok("session data set");
}
[HttpGet("getSession")]
public IActionResult getsessiondata()
{
var sessionData = HttpContext.Session.GetString("Name");
return Ok(sessionData);
}
Then you could make api call to http://localhost:xxxxx/api/ControllerName/setSession/derek to set session , and call to http://localhost:xxxxx/api/ControllerName/getSession to get session data .
Following tutorial will help to set up Session values in server-side in ASP .Net Core Web API application.
Tutorial for Session in API Core

WebAPI controller not working while another one does

I have an API that works fine locally and when I move it to the live environment it doesn't.
The main POST action on the affected controller returns:
NotFound
With a test GET action I get back:
"Message": "No HTTP resource was found that matches the request URI
Strangely, when I uploaded a testController with the same test action as used in the main controller I get a proper response from the API.
This is the test that works fine:
public class TestController : ApiController
{
[AllowAnonymous]
[HttpGet]
public HttpResponseMessage helloWorld()
{
return Request.CreateResponse(HttpStatusCode.OK, "HelloWorld!");
}
}
The controller which does not work:
public class DeviceController : ApiController
{
[AllowAnonymous]
[HttpGet]
public HttpResponseMessage helloWorld() // This returns: "No HTTP resource was found that matches the request URI 'http://api.mySite.com/api/Device/helloWorld'."
{
return Request.CreateResponse(HttpStatusCode.OK, "HelloWorld!");
}
[AllowAnonymous]
[HttpPost]
public HttpResponseMessage Login([FromBody] LoginObject loginObject) // This returns: "NotFound"
{
...
}
}
Here is the web config:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Try to add explicitly declare of route like by acrion
[Route("api/Device/helloWorld")]
[AllowAnonymous]
[HttpGet]
public HttpResponseMessage helloWorld()
or
[RoutePrefix("api/Device")]
public class DeviceController : ApiController
and then
[Route("helloWorld")]
[AllowAnonymous]
[HttpGet]
public HttpResponseMessage helloWorld()
For poor sap's like myself in the future: Ensure the methods on your controller are public.
I spent some time looking for the answer to this problem in .NET 7.0 after I had made a new project (which automatically created a WeatherForecastController).
It turns out that the project had also automatically created a file named proxy.conf.js. In the file, the context: setting was set to "/weatherforecast". I changed it to "/api" instead and then changed [Route("[controller]")] to [Route("api/[controller]")] in both controller files. The controllers worked fine after that.

How to return xml or json with ASP.NET web mvc 6 depending on Accept Header

I have implemented a web api controller using ASP.NET mvc 6 and I would like to return the result of the controller as json or xml, depending on the client's Accept header. For example, if the client sends a GET request with "Accept: application/xml", then the returned response should be xml. If the header is "Accept: application/json", then it should be json. At the moment the controller always returns json. Is there a way of configuring this? Note: this question is indeed a duplicate of How to return XML from an ASP.NET 5 MVC 6 controller action. However the solution provided there did not solve my problem. The accepted answer below worked for me.
The controller is given below and is the one provided by the ASP.NET 5 web api template:
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET: api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("{id:int}")]
public string Get(int id)
{
return "value";
}
// POST api/values
[HttpPost]
public void Post([FromBody]string value)
{
}
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
Thanks for your help!
I did the research for you, you may continue alone:
needed:
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Mvc.Core": "6.0.0-rc1-final",
"Microsoft.AspNet.Mvc.Formatters.Xml": "6.0.0-rc1-final"
startup:
services.Configure<MvcOptions>(options =>
{
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
});
go on from here
another
and antoher

Resources