asp.net core Api - insert new row in database - c#

I'm trying to create an address object in a database through an asp.net core api. I'm using Postman to invoke the method.
Class:
namespace LC.Tools.API.Controllers {
[Route("api/[controller]")]
public class MailerController : Controller
{
Data.LCToolsDbContext _context;
public MailerController(Data.LCToolsDbContext context)
{
_context = context;
}
[HttpPost]
public async Task<IActionResult> CreateAddress(int client, string name, string email)
{
Address adr = new Address() { ClientId = client, Name = name, Email = email };
_context.MailerAddresses.Add(adr);
await _context.SaveChangesAsync();
return Ok(adr);
}
} }
URL (using POST):
http://localhost:50444/api/mailer/createAddress?client=1&name=test&email=mail#mail.no
I also have a break point in the method, but it never hits. I don't get any error message, it just doesn't do anything.

You can see #Rick van den Bosch's comment but still you would like to specify the route with action. use this
[Route("api/[controller]/[action]")]

See #Ayvaras' comment. Since you're building a Web API controller, you don't have to specify the action name in your URL. The HttpPost points all POST actions to the mailer controller towards the CreateAddress method.
Your POST URL should be:
http://localhost:50444/api/mailer?client=1&name=test&email=mail#mail.no

Problem solved! Thanks Ayvaras,
[Route("api/[controller]/[action]")]
did the trick. Now that the method is found I can look into how to pass an object instead of using querystring

You are not using POST correctly.
If you use POST you should not be sending parameters through the query string, you should use the request body. Even though, if you still have to send them via query string you should use the FromQuery attribute in your action parameters.
[HttpPost]
public async Task<IActionResult> CreateAddress([FromQuery] int client, [FromQuery] string name, [FromQuery] string email)
{
Address adr = new Address() { ClientId = client, Name = name, Email = email };
_context.MailerAddresses.Add(adr);
await _context.SaveChangesAsync();
return Ok(adr);
}
Edit: Use [Route("api/[controller]/[action]")] to append the action name in your action route.

Instead of changing the controllers routing scheme, it's also possible to specify the endpoint name by doing the following
[HttpPost("createAddress")]
public async Task<IActionResult> CreateAddress(int client, string name, string email)
{
[...]
}

Related

Action method not showing in Web API, why?

I have Web API, I have written action method. but it's not correctly visible when I run the application. I cannot see SendPushNotification in the attached image.
Controller Code:
[RoutePrefix("api/OTP")]
public class OTPController : ApiController
{
public IHttpActionResult Get(int id)
{
return Ok("value");
}
[HttpGet]
public IHttpActionResult SendPushNotification(string userId, string factorId, string domain)
{
var response = _oTPRepository.SendPushNotification(userId, factorId, domain);
return Ok(response);
}
add a Route over your method, something like this:
[HttpGet]
[Route("SendPushNotification")]
public IHttpActionResult SendPushNotification(string userId, string factorId, string domain)
{
var response = _oTPRepository.SendPushNotification(userId, factorId, domain);
return Ok(response);
}
This will combine with the RoutePrefix from your controller and give you what you want.
You can call it whatever you want as well, whatever makes sense for your API.
in mentioned image second method is that for which you are actually looking for.
default routing for action methods is api/{controller_name}.
if you want to access that method as your given name you have set routing attribute above that action method.
like [Routing("api/OTP/SendPushNotification")]

Angular post request to c# web api 2 RESTful web service

I'm trying to send a http post request from angular client to C# web API 2 RESTful web service.
My client:
var userId = "123456";
var password = "654321";
const headersContent = new Headers().set('Content-Type', 'application/x-www-form-urlencoded');
var url = "http://localhost:35615/login"
this.http.post(url, {
"userId": userId,
"password": password
}, {withCredentials: true}).subscribe(res => {
console.log(res);
});
My Server:
[Route("login")]
[HttpPost]
public IHttpActionResult LoginReq([FromBody] string parameters)
{
//Deserialize the parameters.
}
My problem is the parameters var is null although the post request in the network tab in chrome includes the data.
Can someone explain me what I'm doing wrong and how can I fix it?
Thank you!
You are passing an anonymous object with properties "UserId" and "Password".
Make a Data Contract class which has those 2 properties as strings and use it in the parameters of your REST method.
public IHttpActionResult LoginReq([FromBody] User user) { ... }
If you are passing an object from your Angular POST request the Web API POST method can be changed to accept an User defined type as parameter to read it from the request body.
You can create the below user defined type in C# to bind UserId and Password properties from your angular Post request
public class UserLogin
{
public int UserId { get; set; }
public string Password { get; set; }
}
[Route("login")]
[HttpPost]
public IHttpActionResult LoginReq([FromBody] UserLogin user)
{
//Deserialize the parameters.
}
I would recommend going through this documentation to read more about parameter binding in Web API. Believe me its worth your time.
You post userId and password, but expect String parameters. Change to String userId, String password. The Modelbinder only will bind matching properties.
Just add JSON.stringify() you are sending an object to the server which expects only a string as a parameter so make it as a string and pass the value otherwise create a model with userid and password in your server side and mention that object
let obj = {
"userId": userId,
"password": password
};
this.http.post(url, JSON.stringify(obj), {withCredentials: true}).subscribe(res => {
console.log(res);
});
The above code will work with the string parameters - Going forward try to use model and pass the object from Angular
Happy Coding !!

ASP.Net WebApi change this default request method mapping with action name

I am Creating a new Web API Controller named Customer.
and this Controller has one Action named "Create"
I couldn't make this Action able to be requested via "GET" HTTP Request
in this form
http://ip:port/api/Customer/Create?userId=x&password=y
except in this method :
public class CustomerController : ApiController
{
[System.Web.Mvc.AcceptVerbs("GET", "POST")]
[System.Web.Mvc.HttpGet]
[ActionName("Create")]
public MISApiResult<List<Branch>> GetCreate(string userID, string password)
{
return new MISApiResult<List<Branch>>() { Result = new List<Branch>() { new Branch() { ID = Guid.NewGuid(), Name = "Branch1" } }, ResultCode = 1, ResultMessage = "Sucess" };
}
}
Is there any other solution to preserve the action name as "Create" as next.
public class CustomerController : ApiController
{
[System.Web.Mvc.AcceptVerbs("GET", "POST")]
[System.Web.Mvc.HttpGet]
public MISApiResult<List<Branch>> Create(string userID, string password)
{
return new MISApiResult<List<Branch>>() { Result = new List<Branch>() { new Branch() { ID = Guid.NewGuid(), Name = "Branch1" } }, ResultCode = 1, ResultMessage = "Sucess" };
}
}
Thanks.
Edit:
Sorry for not being clear at the first time.
According to this answer:
How does a method in MVC WebApi map to an http verb?
There is a default http method according to the action names, if it starts with Get it'll bemapped to GET HTTP Method be default otherwise it will be mapped to POST.
Is there a way to change this default mapping with a custom one so I could map an action named "Create" with "GET" Http Method for testing purpose since this way is faster for development
I tried to put HttpGet Attribute and AcceptVerbs("GET") and it still map the action with POST Http method.
I found a way like I said and it's to change the action method name into GetCreate and then put ActionName attribute with "Create" value.
but is there a way to change the default mapping?
Thanks again.
You can use custom route fore this action:
[HttpGet]
[Route("customer/create")]
public MISApiResult<List<Branch>> Create(string userID, string password)
Don't forget to enable attribute routing during application configuration (this should be added before default route definition):
config.MapHttpAttributeRoutes();
Though I would recommend to follow the conventions and use appropriate HTTP verbs - if you are creating a customer, then by convention you should use POST request to endpoint api/customers. Otherwise your API can be confusing for other people.
Also I would recommend to use IHttpActionResult as the return type of your method:
public IHttpActionResult Post(string userID, string password)
{
if (_userRepository.Exists(userID))
return BadRequest($"User with ID {userID} already exists");
_userRepository.Create(userID, password);
return StatusCode(HttpStatusCode.Created) // or CreatedAtRoute
}
Further reading: Attribute Routing in ASP.NET Web API 2
why dont you specify route. You actual issue is using System.Web.Mvc
use System.Web.Http instead
using System.Web.Http;
[RoutePrefix("api/Customer")]
public class CustomerController : ApiController
{
[HttpGet]
[Route("Create")]
public MISApiResult<List<Branch>> Create(string userID, string password)
{
return new MISApiResult<List<Branch>>() { Result = new List<Branch>() { new Branch() { ID = Guid.NewGuid(), Name = "Branch1" } }, ResultCode = 1, ResultMessage = "Sucess" };
}
}

How to fix - The requested resource does not support http method 'POST'

Below is WebAPI action. On googling about the below error:-
The requested resource does not support http method 'POST'
I got number of links & updated my api accordingly but still I am getting the same error.
Web api not supporting POST method
ASP.NET Web Api: The requested resource does not support http method 'GET'
[AcceptVerbs("POST")]
[HttpPost]
[Route("rename/{userId}/{type}/{title}/")]
public IHttpActionResult Rename([FromBody] int userId, [FromBody] string type, [FromBody] string title)
{
//my api stuff
}
But still when calling the above via post man throws the error.
How do I get rid of this error??
Also is it possible to fix this without using [FromBody] attribute in the method parameters list?
Any help/suggestion highly appreciated.
Thanks.
You have declared route which requires url parameters
[Route("rename/{userId}/{type}/{title}/")]
So when you send request to api/customer/rename it does not match this method. You should remove parameters which you are passing in request body from route parameters
[Route("rename")]
Make sure that you have appropriate RoutePrefix("api/customer") attribute on your controller.
Second problem is multiple [FromBody] parameters. You will get can't bind multiple parameters error. There is limitation - you can mark only one parameter as FromBody. See Sending Simple Types notes:
Web API reads the request body at most once, so only one parameter of
an action can come from the request body. If you need to get multiple
values from the request body, define a complex type.
You should create complex type which will hold all parameters
public class RenameModel
{
public int UserId { get; set; }
public string Type { get; set; }
public string Title { get; set; }
}
And change method signature to
[HttpPost]
[Route("rename")]
public IHttpActionResult Rename(RenameModel model)
And send request data as application/x-www-form-urlencoded
[Route("rename/{userId}/{type}/{title}/")]
public IHttpActionResult Rename([FromBody] int userId, [FromBody] string type, [FromBody] string title)
The last answer is correct, you're asking for these parameters in the route, but saying that you expect them in the post body. Also, usually the route would begin with a noun rather than a verb. What is it you're renaming? (i.e. [Route("users/rename/{userId}/{type}/{title}")]
Based on your initial post, try this instead:
[HttpPost]
[Route("rename/{userId}/{type}/{title}" Name = "RenameUser"]
public IHttpActionResult Rename(int userId, string type, string title)
{
_myServiceMethod.Rename(userId, type, title);
return new StatusCodeResult(HttpStatusCode.Created, this);
}
Or, if you wanted to do a post with the info in the body:
Declare your data contract:
public class User
{
public string Type { get; set; }
public string Title { get; set; }
}
Then on the endpoint:
[HttpPost]
[Route("rename/{userId}", Name = "RenameUserPost")]
public IHttpActionResult RenameUserPost(int userId, [FromBody] User userData)
{
return new StatusCodeResult(HttpStatusCode.Created, this);
}
Note that in both returns 'this' refers to your controller class that inherits from ApiController. Verified both of these in swagger, and they accept POSTs and return status codes.
Hope this helps.
I had this error for wrong string in Route string on top of my action.
[Route("api/TestReaderPercentStudyHomework/AddOrUpdate")]

ASP.NET API routing

I'm working on an ASP.NET 5 API and understand that, in order to make the API as "restful" as possible, we use Http verbs as method names.
My question is what happens if I have multiple methods that do different things and all have to be HttpPost?
Say, I have a method that I may call to update a user's first name and may have another method that I use to update the user's city. In both cases, the input parameters will be user ID (GUID) and value which is a string.
[HttpPost("id")]
public void Post([FromRoute]id, [FromBody]firstName)
{
// Change user's first name
}
[HttpPost("id")]
public void Post([FromRoute]id, [FromBody]city)
{
// Change user's city
}
How do I name my methods in this case?
To have 2 post methods that do different things, use the "ActionName" attribute.
[HttpPost("id")]
[ActionName("FirstNamePost")]
public void FirstNamePost([FromRoute]id, [FromBody]firstName)
{
// Change user's first name
}
[HttpPost("id")]
[ActionName("CityPost")]
public void CityPost([FromRoute]id, [FromBody]city)
{
// Change user's city
}
So you would call "www.mysite.com/api/citypost/1" or "www.mysite.com/api/FirstNamePost/1"
Another option would be to only have one post method and add a 3rd parameter to distinguish between a name update or city update.
You can give the controller a route prefix
[RoutePrefix("Note")]
public class NoteController
then give a specific route to whatever action
[Route("", Name = "Note")]
[HttpGet]
public async Task<IHttpActionResult> Get (string tenantName, [FromBody] TagTdo entity)
[Route("", Name = "CreateNote")]
[HttpPost]
public async Task<IHttpActionResult> Post (string tenantName, [FromBody] NoteDto entity)
[Route("Update\{id}", Name = "UpdateNote")]
[HttpPut]
public async Task<IHttpActionResult> Put(string tenantName, [FromBody] NoteDto entity)
Then the route will be:
\Note [GET]
\Note [POST]
\Note\Update\4 [PUT]
Also as a naming convention DON'T use long name in the route, break into several words with slash and http verb
Don't use GetUserContacts, use User\Contacts [GET].

Categories

Resources