How to send an object to MVC controller using AngularJS - c#

I have an object, I need to send it to my MVC controller;
object:
params = {Id: 1, UserAge: 32 }
// Angular $htttp
function test() {
var request = $http.post('/user/updateuser/', params);
return request;
}
c# - controller
public class User
{
public int Id { get; set; }
public int UserAge { get; set; }
}
[HttpPost]
public void UpdateUser(User user)
{
//user Id and user age is always zero.
}
UserId and UserAge is always 0 i'm not sure what i'm missing.

Try to add [FromBody] attribute before the input parameter:
public void UpdateUser([FromBody]User user) {}

Related

Can you use ModelBinding with a GET request?

I'm curious if it's possible to bind a query string that is passed in with a GET request to a Model.
For example, if the GET url was https://localhost:1234/Users/Get?age=30&status=created
Would it be possible on the GET action to bind the query parameters to a Model like the following:
[HttpGet]
public async Task<JsonResult> Get(UserFilter filter)
{
var age = filter.age;
var status = filter.status;
}
public class UserFilter
{
public int age { get; set; }
public string status { get; set; }
}
I am currently using ASP.NET MVC and I have done quite a bit of searching but the only things I can find are related to ASP.NET Web API. They suggest using the [FromUri] attribute but that is not available in MVC.
I just tested the this, and it does work (at least in .net core 3.1)
[HttpGet("test")]
public IActionResult TestException([FromQuery]Test test)
{
return Ok();
}
public class Test
{
public int Id { get; set; }
public string Yes { get; set; }
}
You can can create an ActionFilterAttribute where you will parse the query parameters, and bind them to a model. And then you can decorate your controller method with that attribute.
For example
public class UserFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var controller = actionContext.ControllerContext.Controller as CustomApiController;
var queryParams = actionContext.Request.GetQueryNameValuePairs();
var ageParam = queryParams.SingleOrDefault(a => a.Key == "age");
var statusParam = queryParams.SingleOrDefault(a => a.Key == "status");
controller.UserFilter = new UserFilter {
Age = int.Parse(ageParam.Value),
Status = statusParam.Value
};
}
}
The CustomApiController (inherits from your current controller) and has a UserFilter property so you can keep the value there. You can also add null checks in case some of the query parameters are not sent with the request..
Finally you can decorate your controller method
[HttpGet]
[UserFilter]
public async Task<JsonResult> Get()
{
var age = UserFilter.age;
var status = UserFilter.status;
}

Controller Query Parameter (not in action)

I'm trying to make a api like the OPENBANKPROJECT. Such as
/api/banks/{BANK_ID}/atms/{ATM_ID} etc. I guess banks and atm is a different controller
I want get a global (api/Claim/{id}/Detail/[action] i need this {id}) parameter before before [action] initialize (maybe in constructor).
How do i get this {id} before [action] initialize?
[Route("api/Claim/{id}/Detail/[action]")]
public class ClaimDetailController
{
int _id; // assignment {id}
public ClaimDetailController(IClaimDetailService claimDetailService)
{
`Need Query Id before execute action`
}
[HttpPost]
public async Task<BaseResponse> ClaimDetailInfoPolicy(ClaimDetailKeyModel model)
{
return `codes with _id`;
}
}
public class ClaimDetailKeyModel
{
public long FileNo { get; set; }
public long RecourseNo { get; set; }
}
Solution was simple :)
[ApiController]
[Route("api/Claim/{claimId}/Detail/[action]/")]
public class ClaimDetailController
{
[FromRoute(Name = "claimId")]
public int Id { get; set; }
public ClaimDetailController(IClaimDetailService claimDetailService)
{
`bla bla`
}
[HttpPost]
public async Task<BaseResponse> ClaimDetailInfoPolicy(ClaimDetailKeyModel model)
{
return `codes with Id`
}
}
Add this id to your request handler.
[HttpPost]
public async Task<BaseResponse> ClaimDetailInfoPolicy(int id, ClaimDetailKeyModel model)
{
return `codes`;
}

Angular POST request received in NET Core Api as Null

Im POSTing some data via Angular 6, but my Core API keeps returning nulls:
Request:
{"id":0,"name":"test","weight":2,"frequency":2,"activityTypeModelId":3}
Response:
{id: 0, name: null, weight: 0, frequency: 0, activityTypeModelId: 0}
Controller:
[HttpPost("[action]")]
public IActionResult Add([FromForm]Model model)
{
return new JsonResult(model);
}
Angular, using HttpClient:
add(Model: model) {
return this.http.post(this.addUrl, model);
}
API Model:
public class Model
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int Weight { get; set; }
public int Frequency { get; set; }
public int ActivityTypeModelId { get; set; }
}
TS Model:
export class Model{
id?: number;
name?: string;
weight?: number;
frequency?: number;
activityTypeModelId?: number;
}
Everything works fine when I'm using Postman. I already tried with [FromBody]. Where is the problem?
I dont know why, but this fixed my issue:
I created a header:
const header = new HttpHeaders()
.set('Content-type', 'application/json');
Changed the POST function by adding a header and JSON.Stringyfy the object:
add(model: Model): Observable<Model> {
const body = JSON.stringify(c);
return this.http.post<Model>(this.addUrl, body, { headers: header} );
}
Changed [FromForm] to [FromBody].
Adding JSON.stringify(model) in the parameters of the http.post was not working.
JSON that is working with the CORE Api:
{"name":"test","weight":2,"activityTypeModelId":15}
JSON that is not working with the CORE Api:
{name:"test",weight:2,activityTypeModelId:15}
Without the header I encountered a 415 error from the API.
Try
return this.http.post(this.addUrl, JSON.stringify(model) );
I think that, in .NET Core 2.1 is (see https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-2.1)
HttpPost("[action]")]
//see that I put [FromBody]
public IActionResult Add([FromBody]Model model)
{
//OK is one of several IActionResult
return OK(model);
}
I had this issue and the problem was that I was trying to bind to an interface:
[HttpPost("[action]")]
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK]
public bool SaveResponse([FromBody]ISaveRequestViewModel request) =>
Service.SaveResponse(request.Responses);
I fixed it by changing it to a class:
[HttpPost("[action]")]
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK]
public bool SaveResponse([FromBody]SaveRequestViewModel request) =>
Service.SaveResponse(request.Responses);
This model also had to use classes instead of interfaces:
public class SaveRequestViewModel
{
public List<IQuestionResponseViewModel> Responses { get; set; }
}
Became
public class SaveRequestViewModel
{
public List<QuestionResponseViewModel> Responses { get; set; }
}
I guess the model binder just doesn't work with interfaces.

How to get and post common data to each request made to the web api

I have created a simple webapi service with few get/post methods, these methods are having some input parameters that client is passing while making call to it, other than these parameter I have some common parameters that has to pass in each request made to the web api, currently I added in every web api method as input parameter that is passing by client along with other input parameters. I am looking for a way where I don'n need to add these common parameters on every webapi method, I want to get these common parameters commonly under webapi.
This is my sample api controller
public class MessageController : ApiController
{
//companyID is a common parameter that is required to pass every web api method
public IHttpActionResult GetMessage(string messageCode, int companyID)
{
Message msg = null;
MesssageManager msgManager = null;
try
{
if(string.IsNullOrEmpty(messageCode))
{
throw new Exception("Plase pass the messageCode in order to get the message.");
}
msgManager = new MesssageManager();
List<Message> messages = msgManager.GetMessages(companyID);
msg = messages.FirstOrDefault(o => o.Code.Equals(messageCode, StringComparison.InvariantCultureIgnoreCase));
return Ok(msg);
}
catch (Exception)
{
throw;
}
finally
{
msgManager = null;
}
}
public IHttpActionResult GetWarningMessage(string warningCode, int companyID)
{
//doing actual stuff to get the data
}
public IHttpActionResult GetMthod1(string param1, int companyID)
{
//doing actual stuff to get the data
}
public IHttpActionResult GetMthod2(string param1, int companyID)
{
//doing actual stuff to get the data
}
[HttpPost]
public IHttpActionResult SaveMessage(string message, int companyID)
{
//doing actual stuff to get the data
}
}
In above controller "companyID" is a common parameter that has to pass in each request.
Please suggest me implementation in web api to get the common parameters, and how to pass it from client using HttpClient.
If the companyID is some kind of indentification/authentication parameter you could add the companyId to the request headers. Implement an authenticationfilter and grab the companyId from the headers. However, you still need some kind of short term persisting mechanism (session, cache, scoped DI container etc.) where the authentication filter would store the parameter and the controller method would get the parameter from.
At the end you need to pass the parameter from the client to the server each time it is required. You need to figure out if it's less hassle to put it into the headers or pass it as a parameter to the method. If the companyId varies from request to request I'd add it to each method. If the companyId is "static" for at least a duration of a session then I'd put it into the headers and would try to make sure, that the client automatically adds the appropriate companyId to the request headers (i.e. like you would handle user tokens).
Please refer below line
https://www.codeproject.com/Tips/574576/How-to-implement-a-custom-IPrincipal-in-ASP-NET-MV
We can add additional attribute in CustomPrincipalSerializedModel like below
public interface ICustomPrincipal : System.Security.Principal.IPrincipal
{
string FirstName { get; set; }
string LastName { get; set; }
int CompanyId { get;set; }
}
public class CustomPrincipal : ICustomPrincipal
{
public IIdentity Identity { get; private set; }
public CustomPrincipal(string username)
{
this.Identity = new GenericIdentity(username);
}
public bool IsInRole(string role)
{
return Identity != null && Identity.IsAuthenticated &&
!string.IsNullOrWhiteSpace(role) && Roles.IsUserInRole(Identity.Name, role);
}
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get { return FirstName + " " + LastName; } }
public int CompanyId { get;set; }
}
public class CustomPrincipalSerializedModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int CompanyId { get;set; }
}
https://www.codeproject.com/Tips/574576/How-to-implement-a-custom-IPrincipal-in-ASP-NET-MV
We can get from header or cookies or use Custom identity principals

Web Api add a location to a user

I want to add a location to a user (My userDto has a list of location he wants to visit)
[HttpPut]
[Route("{id:guid}/location/")]
public IHttpActionResult AddLocationToUser(Guid idUser , LocationDto location)
{
_userLogic.AddLocationToUser(idUser, location);
return Ok();
}
it's ok to make a Put ? (because I have a function who just add a location to a list in user and then I want to update ) but how my route should look like ???
It's ok [Route("{id:guid}/location/")] ??
I pass the userId from session , but It's ok to send the whole location in PUT??
Since it is adding/creating a record, you want to use HttpPost. For LocationDto, you want to use [FromBody].
For example,
[HttpPost]
[Route("{id:guid}/location")]
public IHttpActionResult AddLocationToUser(Guid id, [FromBody] LocationDto location)
{
_userLogic.AddLocationToUser(id, location);
return Ok();
}
I second #Win's suggestion of using HttpPost. If you are using Web Api 2, then the following is another alternative.
Controller:
public class LocationController : ApiController
{
UserLogic _userLogic;
public LocationController()
{
_userLogic = new UserLogic();
}
public void PostLocationToUser(LocationViewModel locationViewModel)
{
_userLogic.AddLocationToUser(locationViewModel.UserId, locationViewModel.Location);
}
}
View Model:
public class LocationViewModel
{
public Guid UserId { get; set; }
public Location Location { get; set; }
}
public class Location
{
public string Latitude { get; set; }
public string Longitude { get; set; }
}
JSON:
var input = {
UserId: "11111111-1111-1111-1111-111111111111",
Location: {
Latitude: "anotherLatitude",
Longitude: "anotherLongitude"
}
};
I used the default Web Api routing, the url is "/api/Location", and the PostLocationToUser returns a status code of 204 (no content).

Categories