ASP.NET Post API Call doesnt find the controller route. Why? - c#

I want to make an Post api call. the get method works without any problems, but the post call doesnt find the route. idk why...
Here's the Controller
[Authorize(Roles = AppRoles.Supervisor)]
[Route("api/[controller]/[action]")]
[ApiController]
public class SupportUserManagementController : ControllerBase
{
private readonly SupportUserService _supportUsersService;
public SupportUserManagementController(SupportUserService supportUserService)
{
this._supportUsersService = supportUserService;
}
// GET: api/GetSupportUsersListAsync
[HttpGet]
[ActionName("Test2")]
[Authorize(Roles = AppRoles.User)]
[ProducesResponseType(typeof(IEnumerable<ScopeSupportUsers>), StatusCodes.Status200OK)]
[SwaggerOperation("GetSupportUsers")]
public async Task<IEnumerable<ScopeSupportUsers>> GetSupportUsers(int id)
{
var result = await _supportUsersService.GetSupportUsersListAsync(id);
return result;
}
[HttpPost]
[ActionName("Test3")]
[Authorize(Roles = AppRoles.User)]
[ProducesResponseType(typeof(Guid?), StatusCodes.Status200OK)]
[SwaggerOperation("CreateSupportUsers")]
public async Task<Guid?> CreateSupportUsers(int id, ScopeSupportUsers user)
{
var existingUser = await GetSupportUsers(id);
var matches = existingUser.Where(u => u.Name == user.Name);
if (matches.Count() != 0)
{
return Guid.Empty;
}
var resultGuid = await _supportUsersService.CreateSupportUserAsync(id, user);
if (resultGuid != null)
{
var resultCertificate = await SetCertificate_1Async(id, user, (Guid)resultGuid);
if (resultCertificate == true)
return resultGuid;
}
return null;
}
Why does this work:
using var client = await httpClientHelper.GetHttpClientWithAccessToken();
string uri = $"{_serviceClientOptions.Value.BetriebstoolServiceAddress}/api/SupportUserManagement/Test2?id={selectedScope}";
supportUserResult = await client.GetFromJsonAsync<IEnumerable<ScopeSupportUsers>>(uri);
And this doesnt work?
using var client = await httpClientHelper.GetHttpClientWithAccessToken();
string uri = $"{_serviceClientOptions.Value.BetriebstoolServiceAddress}/api/SupportUserManagement/Test3?id={selectedScopeToCopyTo}";
var response = await client.PostAsJsonAsync<ScopeSupportUsers>(uri , user);
If i am debugging the GET works fine but at the POST Method it doesnt find the "way" to the controller"
This Breakpoint never reached :(

Related

How to pass Data from action to action using mvc and not in router

i have an action inside of users and i want that action to return the user to another action in another controller but not in the router parameter, Here is a sample
public IActionResult LoginCheck(UserForm user)
{
AuthUser auth = new AuthUser(_context);
var result = auth.IsLoggedIn(user.Email, user.Password);
if(result.isfound==false)
{
return NotFound();
}
result.User.IsAuth = true;
return RedirectToAction("Home","Index",result.User);
}
public async Task<IActionResult> Index(User user)
{
if(user.IsAuth == false)
{
return Unauthorized();
}
just part of the code
Home index did not use the incoming user as it was sent as router parameters i think
Welcome to stackoverflow!
You can use TempData to achieve that.
public IActionResult LoginCheck(UserForm user)
{
AuthUser auth = new AuthUser(_context);
var result = auth.IsLoggedIn(user.Email, user.Password);
if(result.isfound==false)
{
return NotFound();
}
result.User.IsAuth = true;
TempData["user"] = result.User;
return RedirectToAction("Home","Index");
}
Then you can get it in the other action
public async Task<IActionResult> Index()
{
if(TempData["user"] == null)
{
return Unauthorized();
}else{
var someUser= (User)TempData["user"];
}
}
But I do not recommend using TempData for sensitive data.
You can use second action as method:
public async Task<IActionResult> LoginCheck(UserForm user)
{
AuthUser auth = new AuthUser(_context);
var result = auth.IsLoggedIn(user.Email, user.Password);
if(result.isfound==false)
{
return NotFound();
}
result.User.IsAuth = true;
return await Index(result.User);
}
second action
[NonAction] // Indicates that a controller method is not an action method.
public async Task<IActionResult> Index(User user)
{
if(user == null)
{
return Unauthorized();
}
else{
var someUser= user;
}
}
Use redirection make browser to handle this transfer and it is slower.

Blazor WASM : error while ReadFromJsonAsync <List<Object>> Post crud

I have this Error
The Json value could not be converted to
System.Collections.Genereic.List
1[Blazor_fresh_project.Shared.Feedback]. Path: $ | LineNumber: 0 |
BytePositionInLine: 1.
when I'm trying to CreateObj in this method :
public async Task<List<Feedback>> CreateFeedback(Feedback feedback)
{
var resulte = await _httpClient.PostAsJsonAsync($"api/feedback",feedback);
string content = Newtonsoft.Json.JsonConvert.SerializeObject(resulte);
Console.WriteLine("Here is THE CONTENT " +content);
var feedbacks = await resulte.Content.ReadFromJsonAsync<List<Feedback>>();
return feedbacks;
}
This error happen at line :
var feedbacks = await resulte.Content.ReadFromJsonAsync<List<Feedback>>();
The console write :
Console debug
Do you have any suggestions or tips for debugging this kind of error?
Edit : api/feedback request
namespace Blazor_fresh_project.Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class FeedbackController : ControllerBase
{
List<Feedback> Feedbacks = new List<Feedback> {
new Feedback{Id=1,Name="arthur",Description="I think this is great",DateOfPost=DateTime.Now,Power=10},
new Feedback{Id=2,Name="Mario",Description=" coming soon",DateOfPost=DateTime.Now,Power=8},
new Feedback{Id=3,Name="Chipolo",Description="I think this is great",DateOfPost=DateTime.Now,Power=17},
new Feedback{Id=4,Name="Coco",Description=" coming soon",DateOfPost=DateTime.Now,Power=12},
new Feedback{Id=5,Name="Marguerite",Description="I think this is great",DateOfPost=DateTime.Now,Power=6},
new Feedback{Id=6,Name="Carine",Description=" coming soon",DateOfPost=DateTime.Now,Power=4}
};
[HttpGet]
public async Task<IActionResult> GetFeedbacks()
{
return Ok(Feedbacks);
}
[HttpGet("{id}")]
public async Task<IActionResult> GetSingleFeedback(int id)
{
var feedback = Feedbacks.FirstOrDefault(f => f.Id == id);
if (feedback == null)
return NotFound("this feedback wasn't found");
return Ok(feedback);
}
[HttpPost]
public async Task<IActionResult> CreateFeedback(Feedback feedback)
{
feedback.Id = Feedbacks.Max(h => h.Id + 1);
Feedbacks.Add(feedback);
return Ok(feedback);
}
}
}
namespace Blazor_fresh_project.Client.Services
{
public class FeedbackService : IFeedbackService
{
private HttpClient _httpClient;
public FeedbackService(HttpClient httpClient)
{
_httpClient = httpClient;
}
[Authorize]
public async Task<List<Feedback>> GetFeedbacks()
{
return await _httpClient.GetFromJsonAsync<List<Feedback>>("api/feedback");
}
public async Task<Feedback> GetFeedback(int id)
{
return await _httpClient.GetFromJsonAsync<Feedback>($"api/feedback/{id}");
}
[Authorize]
public async Task<List<Feedback>> CreateFeedback(Feedback feedback)
{
var resulte = await _httpClient.PostAsJsonAsync($"api/feedback",feedback);
string content = Newtonsoft.Json.JsonConvert.SerializeObject(resulte);
Console.WriteLine("Here is THE CONTENT " +content);
var feedbacks = await resulte.Content.ReadFromJsonAsync<List<Feedback>>();
return feedbacks;
}
}
}
The 'Console' screenshot shows us a payload of a single Feedback item, the request-in-a-browser shows a list of Feedbacks.
Your code is doing a POST, the browser does a GET. Apparently you have an endpoint with different return types for GET and POST.
Post the (relevant) code of your controller if you need more help.
OK, so indeed you have. You can change your controller or what looks more logical, your client:
public async Task<Feedback> CreateFeedback(Feedback feedback)
{
var resulte = await _httpClient.PostAsJsonAsync($"api/feedback",feedback);
var feedback = await resulte.Content.ReadFromJsonAsync<Feedback>();
return feedback;
}
and adapt the calling code accordingly.

Can't get the header value from HTTP header in Asp.Net Core 2.0

I have an MVC controller that aims to read the user's info from HTTP header. The header contains user info that returns from a single sign on (SiteMinder). SiteMinder redirects the user to the company login page and returns back to my app along with cookie and HTTP header. The HTTP header contains user's info. My controller is supposed to get those info and display it in the navigation bar.
Here is the controller code:
[HttpGet]
public async Task<IActionResult> GetUser()
{
var person = Request.Headers["HTTP_JHED_UID"].ToString();
if (repository.GetJhedUser(person) != null)
{
var user = await repository.GetUser(person);
var userDto = mapper.Map<User, UserForDisplayDto>(user);
return Ok(userDto);
}
else
{
return null;
}
}
And here is my corresponded repository:
public string GetJhedUser(string value)
{
return context.Users.Where(x => x.JHED_ID == value).ToString();
}
public async Task<User> GetUser(string id, bool includeRelated = true)
{
if(!includeRelated)
return await context.Users.FindAsync(id);
return await context.Users
.SingleOrDefaultAsync(s => s.JHED_ID == id);
}
I receive 500 server error. I am sure that the header has those values.
EDIT: Here is an image of debugging. Even I tried with "Date" the value is nothing. Please note that I refactored my codes to #Nkosi's code below
How to get those user's info (in this case just username) from header so that I can display in my HTML template?
Do not return null from a controller action.
Check that the header actually exists before trying to access it.
Refactor the action to be coded a little more defensively.
[HttpGet]
public async Task<IActionResult> GetUser() {
//was the header provided?
var headerValue = Request.Headers["HTTP_JHED_UID"];
if(headerValue.Any() == false) return BadRequest(); //401
//does the person exist?
var person = headerValue.ToString();
if(repository.GetJhedUser(person) == null) return NotFound(); //404
var user = await repository.GetUser(person);
var userDto = mapper.Map<User, UserForDisplayDto>(user);
return Ok(userDto); //200
}
The repository code for GetJhedUser has a problem as well because calling to string on the linq expression is not doing what you think it does.
I would go further to suggest refactoring GetJhedUser to what it is actually checking
public bool JhedUserExists(string value) {
return context.Users.FirstOrDefault(x => x.JHED_ID == value) != null;
}
this results in the action looking like this
[HttpGet]
public async Task<IActionResult> GetUser() {
//was the header provided?
var headerValue = Request.Headers["HTTP_JHED_UID"];
if(headerValue.Any() == false) return BadRequest(); //401
//does the person exist?
var person = headerValue.ToString();
if(repository.JhedUserExists(person) == false) return NotFound(); //404
var user = await repository.GetUser(person);
var userDto = mapper.Map<User, UserForDisplayDto>(user);
return Ok(userDto); //200
}

separation of layers when performing CRUD operations

I am confused on where my deserialization logic should go.
I have a controller that returns data to the client specifically for a GET operation:
public accountscontroller:apicontroller
{
[HttpGet]
[Route("", Name = "GetAccount")]
public async Task<IHttpActionResult> GetAccount()
{
var query = Request.RequestUri.PathAndQuery.Split('/')[2];
var response = await _accountService.GetAccount(query);
if (response == null)
{
return NotFound();
}
return Ok(response);
}
//morestuff
}
and the AccountService.GetAccount code is the following:
public class AccountService
{
public async Task<Account> GetAccount(string query)
{
var task = await Client.HTTPCLIENT.GetAsync(Client.HTTPCLIENT.BaseAddress + query);
var jsonString = await task.Content.ReadAsStringAsync();
var value = JsonConvert.DeserializeObject<RootObject>(jsonString);
return value.value.FirstOrDefault();
}
//morestuff
}
as you can see, the deserialization is handled in the AccountService, not the AccountsController
however, if we look at the POST operation:
public class AccountController
{
[HttpPost]
[Route("", Name = "CreateAccount")]
public async Task<IHttpActionResult> CreateAccount([FromBody] JObject account)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var response = await _accountService.Create(account);
var newAccount = await response.Content.ReadAsAsync<object>();
return Ok(newAccount);
}
and the underlying Create method within the AccountService:
public async Task<HttpResponseMessage> Create(JObject account)
{
var request = new HttpRequestMessage(HttpMethod.Post, Client.HTTPCLIENT.BaseAddress + "accounts")
{
Content = new StringContent(account.ToString(), Encoding.UTF8, "application/json")
};
var response = await Client.HTTPCLIENT.SendAsync(request);
var uri = new Uri(response.Headers.GetValues("OData-EntityId").FirstOrDefault());
return await Client.HTTPCLIENT.GetAsync(uri);
}
you will see that in fact the deserialization happens on the controller level.
How can I encapsulate the deserialization logic for CRUD operations, such as GET/PUT/POST for consistency?

WebAPI2 : [DELETE] Method not allowed in CODE but in Fiddler it is working

I tested my WebAPI2 (DELETE) in Fiddler and it is working fine but in my code had an error of Method not Allowed.
This is my Code :
public async Task<bool> deleteUser(int id)
{
string URI = "http://api.danubeco.com/api/userapps";
using (var client = new HttpClient())
{
var response = await client.DeleteAsync(String.Format("{0}/{1}", URI, id));
var myobject = await response.Content.ReadAsStringAsync();
return Convert.ToBoolean(myobject);
}
}
// DELETE: api/userapps/5
[ResponseType(typeof(userapp))]
public IHttpActionResult Deleteuserapp(int id)
{
userapp userapp = db.userapps.Find(id);
if (userapp == null)
{
return NotFound();
}
db.userapps.Remove(userapp);
db.SaveChanges();
return Ok(userapp);
}
Try adding something like this:
config.Routes.MapHttpRoute(
name: "YourControllerApi",
routeTemplate: "api/{controller}",
defaults: new { controller = "YourControler", action = "Delete", id = RouteParameter.Optional }
);
Of course you'll need to replace "YourController with the name of your controller class, and you may need to tweak the routeTemplate (this one assumes you'll call YourURL/api/YourController.
I really don't know if this is a good practice but i modified the code like this.
// DELETE: api/userapps/5
[HttpGet]
[Route("api/userapps/deluser/{id}")]
[ActionName("deluser")]
[ResponseType(typeof(bool))]
public bool Deleteuserapp(int id)
{
userapp userapp = db.userapps.Find(id);
if (userapp == null)
{
return false;
}
db.userapps.Remove(userapp);
db.SaveChanges();
return true;
}
var response = await client.GetAsync(String.Format("{0}/{1}", URI,
and used GetAsync rather than DeleteAsync.

Categories