C
C#17mo ago
Ysehporp

✅ Sending an HTTP Exception in Web API

I am having some trouble with sending an HTTP exception in web api as it seems how its dont has changed over the course of different .net versions. There seems to be an issue of what return type I have, but I found examples online where people were able to do it with an ActionResult. I found examples which implemented it like this but it will not compile for me because it cannot convert the return type.
[HttpPost]
[Route("login")]
public ActionResult<String> login(Login req)
{

LoginReturn r = new LoginReturn();
Account query = (from m in msgDB.accounts
where m.userID == req.username
select m).FirstOrDefault<Account>();
if (query!= null)
{

}
else
{
//Why doesn't this compile?
return new HttpStatusCodeResult(HttpStatusCode.NotFound, "No user exists with that ID");
}
r.userID = req.username;
r.token = "Fake Token";

return JsonConvert.SerializeObject(r);

}
[HttpPost]
[Route("login")]
public ActionResult<String> login(Login req)
{

LoginReturn r = new LoginReturn();
Account query = (from m in msgDB.accounts
where m.userID == req.username
select m).FirstOrDefault<Account>();
if (query!= null)
{

}
else
{
//Why doesn't this compile?
return new HttpStatusCodeResult(HttpStatusCode.NotFound, "No user exists with that ID");
}
r.userID = req.username;
r.token = "Fake Token";

return JsonConvert.SerializeObject(r);

}
I have also tried what is shown on the learn microsoft page where it says essentially to do
throw new HttpResponseException(HttpStatusCode.NotFound);
throw new HttpResponseException(HttpStatusCode.NotFound);
However doing so causes my server to encounter an unhandled exception and cease to work. What is the correct way of doing this in .net 6???
26 Replies
Pobiega
Pobiega17mo ago
return NotFound(...) Also, this should probably be an async method, given that you are accessing a database in it
Ysehporp
Ysehporp17mo ago
What dependency is NotFound under?
Ysehporp
Ysehporp17mo ago
I will take this into consideration and bring this up with my group at the next meeting
Pobiega
Pobiega17mo ago
can you show the controller declaration?
[ApiController]
[Route("[controller]")]
public class ExampleController : ControllerBase
[ApiController]
[Route("[controller]")]
public class ExampleController : ControllerBase
NotFound is a method from ControllerBase also, this worries me: return JsonConvert.SerializeObject(r); its newtonsoft, and you are doing response serialization manually
Ysehporp
Ysehporp17mo ago
Aha! Okay, yes my issue was with the controller base being an ambigious reference because of another solution I attempted earlier Thank you so much!!! NotFound exists now and I can get it
Pobiega
Pobiega17mo ago
with .net 5 and above, its recommended to use the built in json serializer (STJ) instead of newtonsoft, unless you actively need a feature only newtonsoft has and you shouldnt be manually doing the serialization in 99% of cases its better to just return the object
Ysehporp
Ysehporp17mo ago
As far as the manual serialization goes its because my front end dev wants to do some weird stuff Oh hmmm I see will that manually seriallize it into json?
Pobiega
Pobiega17mo ago
automatically, but yes 😛
Ysehporp
Ysehporp17mo ago
err autmoatically i mean weiiird we had some issues with that which is why we switched to doing it this way. Tho i wouldn't put it past something having been wrong in the front end when we tried it notLikeMokoko2
Pobiega
Pobiega17mo ago
so you'd set your response type to be ActionResult<LoginReturn> well the way you have it right now you are returning a json string, containing json ie, your return will be...
"{ \"userId\": \"123\" }"
"{ \"userId\": \"123\" }"
instead of returning actual json
Ysehporp
Ysehporp17mo ago
@.@ Wow thats a blunder Its a miracle it works rn...
Pobiega
Pobiega17mo ago
feel free to doublecheck but thats what it looks like to me unless you've disabled the automatic response serializer in the pipeline
Ysehporp
Ysehporp17mo ago
hmmm maybe I have cause looking at my response it seems to be received as just json
Pobiega
Pobiega17mo ago
can you share your Program.cs without exposing any secrets?
Ysehporp
Ysehporp17mo ago
Getting things seriallized properly was a headache a few months ago and I don't remember everything we did to sort it out Sure lemme grab it, this is just a long term project for college so
Pobiega
Pobiega17mo ago
ah
Ysehporp
Ysehporp17mo ago
using Microsoft.EntityFrameworkCore;
using SMPBackEndAPI.Controllers;
using SMPBackEndAPI.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder => { builder.WithOrigins("*").WithMethods("POST").WithHeaders("*"); });
});

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
/*builder.Services.AddDbContext<MessageContext>(
o => o.UseNpgsql(builder.Configuration.GetConnectionString("SMPDB")));
*/
builder.Services.AddDbContext<MessageContext>(
o => o.UseNpgsql(builder.Configuration.GetConnectionString("SMPDB")));

var app = builder.Build();


//// middlewares
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpLogging();
app.UseHttpsRedirection();
app.UseCors();
app.UseAuthorization();


app.MapControllers();
app.Seed();
app.Run();
using Microsoft.EntityFrameworkCore;
using SMPBackEndAPI.Controllers;
using SMPBackEndAPI.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder => { builder.WithOrigins("*").WithMethods("POST").WithHeaders("*"); });
});

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
/*builder.Services.AddDbContext<MessageContext>(
o => o.UseNpgsql(builder.Configuration.GetConnectionString("SMPDB")));
*/
builder.Services.AddDbContext<MessageContext>(
o => o.UseNpgsql(builder.Configuration.GetConnectionString("SMPDB")));

var app = builder.Build();


//// middlewares
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpLogging();
app.UseHttpsRedirection();
app.UseCors();
app.UseAuthorization();


app.MapControllers();
app.Seed();
app.Run();
Pobiega
Pobiega17mo ago
hm I see nothing touching the serializer at all
Ysehporp
Ysehporp17mo ago
Hmmm... I'll look into it a bit more and bring that up at my next meeting as well. Thanks so much for all the help, I really appreciate it. It's so hard to find good advice for this on the internet because .net stuff has changed so much over time. You're a life saver
Pobiega
Pobiega17mo ago
okay it wont be stringwrapped but its still wrong
Pobiega
Pobiega17mo ago
Pobiega
Pobiega17mo ago
[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
[HttpPost]
public ActionResult<string> Test()
{
var x = new SampleRecord(123, "Steve");

return JsonSerializer.Serialize(x);
}
}

record SampleRecord(int UserId, string Username);
[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
[HttpPost]
public ActionResult<string> Test()
{
var x = new SampleRecord(123, "Steve");

return JsonSerializer.Serialize(x);
}
}

record SampleRecord(int UserId, string Username);
the content-type is text/plain and this is what it looks like with my suggested changes
Pobiega
Pobiega17mo ago
Pobiega
Pobiega17mo ago
[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
[HttpPost]
public ActionResult<SampleRecord> Test()
{
var x = new SampleRecord(123, "Steve");

return x;
}
}

public record SampleRecord(int UserId, string Username);
[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
[HttpPost]
public ActionResult<SampleRecord> Test()
{
var x = new SampleRecord(123, "Steve");

return x;
}
}

public record SampleRecord(int UserId, string Username);
properties are using camelCase names, as is standard in web. content-type is application/json, as it should be and my code doesnt need to bother with serializing, which leads to less code 🙂
Ysehporp
Ysehporp17mo ago
Amazing!!! Thanks so much!!!
Pobiega
Pobiega17mo ago
You can /close the thread if you don't have any further questions.