Rodney Wormsbecher
Rodney Wormsbecher

Reputation: 927

angular 5 send POST to .net core 2, payload empty

I have made a simple angular 5 spa with a .net core 2 backend api. I am trying to send a POST request to register my user but for some reason it fails to inject my payload properties in the post call resulting in the auth controller which is unable to parse the dto object from a null instance. I expect that the error is in my angular code but I checked the official documentation and cannot see what I am doing wrong. Below I will describe my code:

PS: As there are so many parts for such a simple HTTP call I also included the project here: download the source code

My register component calls the 'authService.register' method which does the call:

import { AuthService } from './../_services/auth.service';
import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';

@Component({
  selector: 'app-register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit {

  model: any = [];
  @Input() valuesFromHome: any;
  @Output() cancelRegister = new EventEmitter();

  constructor(private authService: AuthService) { }

  ngOnInit() {
  }

  register() {
    console.log(this.model);
    this.authService.register(this.model).subscribe(() => {
      console.log('registration successful');
    }, error => {
      console.log(error);
    });
  }

  cancel() {
    this.cancelRegister.emit(false);
    console.log('cancelled');
  }

}

Here is the auth.service

import { Http, Headers, RequestOptions, Response } from '@angular/http';
import { Injectable } from '@angular/core';
import 'rxjs/add/operator/map';

@Injectable()
export class AuthService {

    baseUrl = 'http://localhost:5000/api/auth';
    userToken: any;

    constructor(private http: Http) { }

    login(model: any) {
        return this.http.post(this.baseUrl + '/login', model, this.requestOptions()).map((response: Response) => {
            const user = response.json();

            if (user) {
                localStorage.setItem('token', user.tokenString);
                this.userToken = user.tokenString;
            }
        });
    }

    register(model: any) {
        console.log('model before the call', model);
        return this.http.post(this.baseUrl + '/register', model, this.requestOptions());
    }

    private requestOptions() {
        const headers = new Headers({'Content-type': 'application/json'});
        return new RequestOptions({headers: headers});
    }


}

When making a post the "model before the call" log will execute just fine with the correct model:

enter image description here

When we check the request however it is empty: enter image description here

Next when I debug my auth controller gets hit and when using postman the data is inserted, but via my SPA it gives an error 'registerDto cannot be null'.

using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using DatingApp.API.Data;
using DatingApp.API.Dtos;
using DatingApp.API.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;

namespace DatingApp.API.Controllers
{
    [AllowAnonymous]
    [Route("api/[controller]")]
    public class AuthController : Controller
    {
        private readonly IAuthRepository _repository;
        private readonly IConfiguration _config;
        public AuthController(IAuthRepository repository, IConfiguration config)
        {
            this._config = config;
            this._repository = repository;
        }



        [HttpPost("register")]
        public async Task<IActionResult> Register([FromBody] userForRegisterDto registerDto)
        {

            registerDto.Username = registerDto.Username.ToLower();

            if (await _repository.UserExists(registerDto.Username))
            {
                ModelState.AddModelError("Username", "USername already exists");
            }

            if (!ModelState.IsValid)
                return BadRequest(ModelState);

            var userToCreate = new User
            {
                UserName = registerDto.Username
            };

            var createUser = await _repository.Register(userToCreate, registerDto.Password);

            return StatusCode(201);
        }



        [HttpPost("login")]
        public async Task<IActionResult> Login([FromBody] UserForLoginDto userForLoginDto)
        {
            var userFromRepo = await _repository.Login(userForLoginDto.UserName.ToLower(), userForLoginDto.Password);

            if (userFromRepo == null)
            {
                return Unauthorized();
            }

            // generate token
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(_config.GetSection("AppSettings:Token").Value);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[] {
                    new Claim(ClaimTypes.NameIdentifier, userFromRepo.Id.ToString()),
                    new Claim(ClaimTypes.Name, userFromRepo.UserName)
                }),
                Expires = DateTime.Now.AddDays(1),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
                    SecurityAlgorithms.HmacSha512)
            };

            var token = tokenHandler.CreateToken(tokenDescriptor);
            var tokenString = tokenHandler.WriteToken(token);

            return Ok(new { tokenString });

        }

    }
}

The userForRegisterDto

using System.ComponentModel.DataAnnotations;

namespace DatingApp.API.Dtos
{
    public class userForRegisterDto
    {
        [Required]
        public string Username { get; set; }

        [Required]
        [StringLength(8, MinimumLength = 4, ErrorMessage = "You must specify a password between 4 and 8 characters")]
        public string Password { get; set; }


    }
}

I checked the Angular documentation and the parameters all match up. The docs can be found here: https://angular.io/guide/http

The model:

namespace DatingApp.API.Models
{
    public class User
    {
        public int Id { get; set; }
        public string UserName { get; set; }
        public byte[] PasswordHash { get; set; }
        public byte[] PasswordSalt { get; set; }

    }
}

Upvotes: 0

Views: 1426

Answers (1)

Eman Z
Eman Z

Reputation: 167

Try

replacing model:any = [], with model:any = {};

You're creating an array not an object.

Upvotes: 3

Related Questions