Web API PUT 400 Bad Request - asp.net-web-api

I have a HttpPut annotated Insert method in a controller and when I want to insert a new dto with it it returns a Bad Request 400 error.
public class BaseDto
{
public int Id { get; set; }
...
}
public class ModelDto : BaseDto
{
public string Name { get; set; }
...
}
[Produces("application/json")]
[Route("api/[controller]")]
public class ExampleController : MyControlle
{
...
[HttpPut]
public IActionResult Insert([FromBody] ModelDto model)
{
_service.Insert(model, _user);
return Ok();
}
}
I tried it with an API client in Edge with this URL:
http://localhost:52073/api/Example
with this JSON:
``
{
"award_Id":1,
"nameOfTheAwardee":"zgghjggf",
"titleOfTheAwardee":"XXX",
"reasonForAwarding":"zzhfhf",
"numberOfDecision":"876",
"yearOfAwarding":"2022"
}
``

Related

Web Api take an array from front

The question is very simple :-).
I'm a beginner.
Data comes to the controller (WebApi).
If you put an object.
[HttpPost]
public async Task<IActionResult> AddOrder(Object [] orderR)
ValueKind = Object : "{"product":{"id":"72ae28f2-4ad3-4e97-5a7b-
08d8db1aac26","code":"666666","name":"test6","price":6,"category":"test6","orrderItems":"320d57eb-
3333-45d2-f497-08d8d66a0d39"},"quality":1}"
ValueKind = Object : "{"product":{"id":"72ae28f2-4ad3-4e97-5a7b-
08d8db1aac26","code":"666666","name":"test6","price":6,"category":"test6","orrderItems":"320d57eb-
3333-45d2-f497-08d8d66a0d39"},"quality":1}"
ValueKind = Object : "{"product":{"id":"72ae28f2-4ad3-4e97-5a7b-
08d8db1aac26","code":"666666","name":"test6","price":6,"category":"test6","orrderItems":"320d57eb-
3333-45d2-f497-08d8d66a0d39"},"quality":1}"
I created a class.
public class OrderR
{
public Guid ID { get; set; }
public Guid orrderItems { get; set; }
public string CODE { get; set; }
public string NAME { get; set; }
public int PRICE { get; set; }
public string CATEGORY { get; set; }
}
I am trying to get an array.
[HttpPost]
public async Task<IActionResult> AddOrder(OrderR[] orderR)
But get null.
What am I doing wrong?
How is it correct?
Create new class:
public class Order
{
public OrderR Product { get; set; }
public int Quality { get; set; }
}
and change your action to this:
[HttpPost]
public async Task<IActionResult> AddOrder(Order[] orders)
{
.... your code
}
it was tested in Postman using this data:
[
{"product":{"id":"72ae28f2-4ad3-4e97-5a7b-08d8db1aac26","code":"666666","name":"test1","price":6,"category":"test6","orrderItems":"320d57eb-3333-45d2-f497-08d8d66a0d39"},"quality":1},
{"product":{"id":"72ae28f2-4ad3-4e97-5a7b-08d8db1aac26","code":"666666","name":"test2","price":6,"category":"test6","orrderItems":"320d57eb-3333-45d2-f497-08d8d66a0d39"},"quality":1},
{"product":{"id":"72ae28f2-4ad3-4e97-5a7b-08d8db1aac26","code":"666666","name":"test3","price":6,"category":"test6","orrderItems":"320d57eb-3333-45d2-f497-08d8d66a0d39"},"quality":1}
]
and everything works fine. If you want to test it in Postman too, add [FromBody] to the action input parameter:
[HttpPost]
public async Task<IActionResult> AddOrder([FromBody] Order[] orders)
{
return Ok(orders);
}

Multiple Endpoints in same controller with different parameter

Been years since I had to do this and the heat must be getting to me!
I have my home controller:
public ActionResult Index(string param1, string param2, string param3)
{
return View();
}
public IActionResult Index()
{
return View();
}
I have 1 Index.cshtml page.
In my startup,cs:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}");
endpoints.MapControllerRoute(
name: "default2",
pattern: "{controller=Home}/{action=Index}/{param1}/{param2}/{param3}");
});
The error I get is:
**{"error":"APP: The request matched multiple endpoints.
public class HomeController : Controller
{
// hits when navigating to https://localhost:5001/one/two/three
[HttpGet("{param1}/{param2}/{param3}")]
public IActionResult Index(string param1, string param2, string param3)
{
return View();
}
// hits when navigating to https://localhost:5001/
public IActionResult Index()
{
return View();
}
}
and in Startup#Configure
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
I tried this,
using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Routing;
namespace RouteTemplateProvider.Controllers
{
public class RouteWithParamAttribute : Attribute, IRouteTemplateProvider
{
public string Template => "{param1}/{param2}/{param3}";
public int? Order { get; set; }
public string Name { get; set; }
}
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[RouteWithParam]
public string Index(string param1, string param2, string param3)
{
return "Index with param";
}
public string Index()
{
return "Index no param";
}
}
}

InvalidOperationException While Using the Existing DB in MVC Core

I tried to use the existing database in my application but every time I hit the view it says
An unhandled exception occurred while processing the
InvalidOperationException: Unable to resolve service for type
'BookStore.Models.BookStoreContext' while attempting to activate
'BookStore.Models.UsersRepo'
Context
namespace BookStore.Models
{
public partial class BookStoreContext : DbContext
{
public BookStoreContext()
{
}
public BookStoreContext(DbContextOptions<BookStoreContext> options)
: base(options)
{
}
public virtual DbSet<Users> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\V11.0;Database=BookStore;Trusted_Connection=True;");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasAnnotation("ProductVersion", "2.2.3-servicing-35854");
modelBuilder.Entity<Users>(entity =>
{
entity.HasKey(e => e.UserId);
entity.Property(e => e.UserId).HasColumnName("User_ID");
entity.Property(e => e.Password)
.IsRequired()
.HasMaxLength(50);
entity.Property(e => e.UserName)
.IsRequired()
.HasColumnName("User_Name")
.HasMaxLength(50);
});
}
}
}
User Repository
namespace BookStore.Models
{
public class UsersRepo : IUser
{
private readonly BookStoreContext _bookStoreContext;
public UsersRepo(BookStoreContext bookStoreContext)
{
_bookStoreContext = bookStoreContext;
}
public void AddUser(Users users)
{
_bookStoreContext.Users.Add(users);
_bookStoreContext.SaveChanges();
}
}
}
User Model
public partial class Users
{
public long UserId { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public int Type { get; set; }
}
public interface IUser
{
void AddUser(Users users);
}
User Controller
public class UsersController : Controller
{
private readonly IUser _userRepo;
public UsersController(IUser userRepo)
{
_userRepo = userRepo;
}
[HttpGet]
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult Index(Users users)
{
_userRepo.AddUser(users);
return RedirectToAction("UserAddedSuccessfully");
}
public IActionResult UserAddedSuccessfully()
{
return View();
}
}
I tried this one and it is perfectly working
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<BookStoreContext>();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}

How to send array of custom object as a multiform data content to asp.net web api via postman?

How to properly send array of custom objects to asp.net web api via Postman? What I have done is:
Custom class:
public class SystemConsumerConfiguration
{
public int SystemId { get; }
public Uri CallbackUrl { get; }
public SystemConsumerConfiguration()
{
}
public SystemConsumerConfiguration(int systemId, Uri callbackUrl)
{
SystemId = systemId;
CallbackUrl = callbackUrl;
}
}
View model in REST API:
public class PostDigitalPostSubscriptionConfiguration
{
public IReadOnlyList<SystemConsumerConfiguration> SystemsModel { get; set; }
public IFormFile Certificate { get; set; }
public PostDigitalPostSubscriptionConfiguration()
{
}
}
And now, I make a request in Postman
The problem is, that model is bound with default values:
Forgot to have public setters in SystemConsumerConfiguration.
Should be like this:
public class SystemConsumerConfiguration
{
public int SystemId { get; set; }
public Uri CallbackUrl { get; set; }
public SystemConsumerConfiguration()
{
}
public SystemConsumerConfiguration(int systemId, Uri callbackUrl)
{
SystemId = systemId;
CallbackUrl = callbackUrl;
}
}
Answered in:
Default value in an asp.net mvc view model

Set a ASP.NET WEB.API model property to be read-only for consumers of the API?

What's the best way of ensuring that a property of a model can only be set by the ASP.NET WEB.API service? To a consumer of the service, that property is read-only.
For example:
public class MyModel
{
[Required]
public string CanBeSetByConsumer { get; set; }
// Can only be set by the service
public int Id { get; set; }
}
public class MyModelController : ApiController
{
public MyModel Get(int id)
{
// get MyModel by Id
return new MyModel();
}
public MyModel Post(MyModel myData)
{
// save myData to a store and generate an ID
// return myData with ID populated with a 201 Created
}
}
In the above example, the consumer of the API can POST:
{
"CanBeSetByConsumer" : "SomeValue"
}
The consumer can also GET:
{
"Id" : 1234,
"CanBeSetByConsumer" : "SomeValue"
}
What I would like to do is return a 400 BAD REQUEST if the client POSTs:
{
"Id" : 1234,
"CanBeSetByConsumer" : "SomeValue"
}
Here is one way to do it. Note that the POST model does not contain the Id property.
public class MyGetModel
{
[Required]
public string CanBeSetByConsumer { get; set; }
public int Id { get; set; }
}
public class MyPostModel
{
[Required]
public string CanBeSetByConsumer { get; set; }
}
public class MyModelController : ApiController
{
public MyGetModel Get(int id)
{
// get MyModel by Id
return new MyGetModel();
}
public MyGetModel Post(MyPostModel myData)
{
// save myData to a store and generate an ID
// return myGetData with ID populated with a 201 Created
}
}
Then if you have a lot of shared properties, you can have both of these inherit from an abstract class MyModel.
Another way to do it could be to add an action filter to the post action. In that action filter class, you would override the OnActionExecuting method, inspect the POST values collection for a value under the Id key, and set your 400 BAD REQUEST response there.
public class PreventIdValueAttribute
: System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// check request for id value, and if present,
// set the result to a 400 bad request HttpResponseMessage
}
}
[PreventIdValue]
public MyModel Post(MyModel myData)
{
// save myData to a store and generate an ID
// return myData with ID populated with a 201 Created
}
Note that with the second option, your MyModel instance will still have an Id value in the Post action, but its value will be zero.

Resources