最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

c# - ASP.NET Core server not receiving params from Angular frontend post call - Stack Overflow

matteradmin6PV0评论

I'm creating a user registration form in Angular, here is the ts

import { Component } from '@angular/core';
import { AuthService } from '../_services/auth.service';

@Component({
  selector: 'app-registration',
  templateUrl: './registrationponent.html',
  styleUrl: './registrationponent.css'
})
export class RegistrationComponent {
  form: any = {
    email: null,
    password: null,
    accountType: 1,
    name: null,
    address: null,
    phone: null
  };
  isSuccessful = false;
  isSignUpFailed = false;
  errorMessage = '';

  constructor(private authService: AuthService) { }

  onSubmit(): void {
    const { email, password, accountType, name, address, phone } = this.form;

    this.authService.register(email, password, accountType, name, address, phone).subscribe({
      next: data => {
        console.log(data);
        this.isSuccessful = true;
        this.isSignUpFailed = false;
      },
      error: err => {
        this.errorMessage = err.error.message;
        this.isSignUpFailed = true;
      }
    });
  }

}

On submit calls my authService register method (below) which should call the register-account endpoint on my API

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AccountType } from '../_classes/AccountType';
import { RegisterRequest } from '../_DTOs/RegisterRequest';

const AUTH_API = 'https://localhost:7033/api/account/';

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  constructor(private http: HttpClient) { }

  register(email: string, password: string, accountType: AccountType, name: string, address: string, phone: string): Observable<any> {
    const request: RegisterRequest = {
      email: email,
      password: password,
      accountType: accountType,
      name: name,
      address: address,
      phone: phone
    }

    return this.http.post(
      AUTH_API + 'register-account',
      {
        request
      },
      httpOptions
    );
  }
}

With a breakpoint in my AccountController, the method never seems to be hit. Here is the controller

using AML.Server.Interfaces;
using AML.Server.Models;
using Microsoft.AspNetCore.Mvc;

namespace AML.Server.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AccountController : ControllerBase
    {
        private readonly IAccountRepository _accountRepository;

        public AccountController(IAccountRepository accountRepository)
        {
            this._accountRepository = accountRepository;
        }

        [HttpPost]
        [Route("register-account")]
        public async Task<bool> RegisterAccount(RegisterRequest request)
{
    bool success = false;

    if (request.Email == "[email protected]")
    {
        success = true;
    }

    // Logic going to repo & return success response
    return success;
}
    }
}

It throws a 400 bad response, the response I receive in DevTools is

{
    "type": ".5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "errors": {
        "name": [
            "The name field is required."
        ],
        "email": [
            "The email field is required."
        ],
        "phone": [
            "The phone field is required."
        ],
        "address": [
            "The address field is required."
        ],
        "password": [
            "The password field is required."
        ]
    },
    "traceId": "00-ef5889b3c6e2444528b8799e51a3107b-8ca9bab2705e4cc0-00"
}

It seems that the parameters are not making it through, but I don't know how to resolve the issue. Does anybody have any ideas?

Edit - Additional potentially helpful info

Request payload

{"request":{"email":"[email protected]","password":"testtest","accountType":1,"name":"Jordan Abc","address":"123 Fake Street","phone":"07123456789"}}

Registration form html

<app-navbar></app-navbar>
<div class="font-weight-bold">
  <h3 class="title-text">Registration</h3>
</div>
<div class="content col-md-12">
  <div class="registration-form">
    @if (!isSuccessful) {
    <form name="form"
          (ngSubmit)="f.form.valid && onSubmit()"
          #f="ngForm"
          novalidate>
      <div class="form-group">
        <label for="email">Email</label>
        <input type="email"
               class="form-control"
               name="email"
               [(ngModel)]="form.email"
               required
               email
               #email="ngModel"
               [ngClass]="{ 'is-invalid': f.submitted && email.errors }" />
        @if (email.errors && f.submitted) {
        <div class="invalid-feedback">
          @if (email.errors['required']) {
          <div>Email is required</div>
          }
          @if (email.errors['email']) {
          <div>Email must be a valid email address</div>
          }
        </div>
        }
      </div>
      <div class="form-group">
        <label for="password">Password</label>
        <input type="password"
               class="form-control"
               name="password"
               [(ngModel)]="form.password"
               required
               minlength="6"
               #password="ngModel"
               [ngClass]="{ 'is-invalid': f.submitted && password.errors }" />
        @if (password.errors && f.submitted) {
        <div class="invalid-feedback">
          @if (password.errors['required']) {
          <div>Password is required</div>
          }
          @if (password.errors['minlength']) {
          <div>Password must be at least 6 characters</div>
          }
        </div>
        }
      </div>
      <div class="form-group">
        <label for="name">Name</label>
        <input type="text"
               class="form-control"
               name="name"
               [(ngModel)]="form.name"
               required
               minlength="1"
               maxlength="30"
               #name="ngModel"
               [ngClass]="{ 'is-invalid': f.submitted && name.errors }" />
        @if (name.errors && f.submitted) {
        <div class="invalid-feedback">
          @if (name.errors['required']) {
          <div>Name is required</div>
          }
          @if (name.errors['minlength']) {
          <div>Name is required</div>
          }
          @if (name.errors['maxlength']) {
          <div>Name must be at most 30 characters</div>
          }
        </div>
        }
      </div>
      <div class="form-group">
        <label for="address">Address</label>
        <input type="text"
               class="form-control"
               name="address"
               [(ngModel)]="form.address"
               required
               minlength="1"
               maxlength="75"
               #address="ngModel"
               [ngClass]="{ 'is-invalid': f.submitted && address.errors }" />
        @if (address.errors && f.submitted) {
        <div class="invalid-feedback">
          @if (address.errors['required']) {
          <div>Address is required</div>
          }
          @if (address.errors['minlength']) {
          <div>Address is required</div>
          }
          @if (address.errors['maxlength']) {
          <div>Address must be at most 75 characters</div>
          }
        </div>
        }
      </div>
      <div class="form-group">
        <label for="phone">Phone Number</label>
        <input type="tel"
               class="form-control"
               name="phone"
               [(ngModel)]="form.phone"
               required
               pattern="[0-9]{11}"
               #phone="ngModel"
               [ngClass]="{ 'is-invalid': f.submitted && phone.errors }" />
        @if (phone.errors && f.submitted) {
        <div class="invalid-feedback">
          @if (phone.errors['required']) {
          <div>Phone Number is required</div>
          }
          @if (phone.errors['tel']) {
          <div>Valid UK Phone Number is required</div>
          }
          @if (phone.errors['pattern']) {
          <div>Valid UK Phone Number is required (No spaces)</div>
          }
        </div>
        }
      </div>
      <div class="form-group">
        <button class="btn btn-primary btn-block">Register</button>
      </div>

      @if (f.submitted && isSignUpFailed) {
      <div class="alert alert-warning">
        Signup failed!<br />{{ errorMessage }}
      </div>
      }
    </form>
    } @else {
    <div class="alert alert-success">Your registration is successful!</div>
    }
  </div>
</div>

proxy.conf.js

const { env } = require('process');

const target = env.ASPNETCORE_HTTPS_PORT ? `https://localhost:${env.ASPNETCORE_HTTPS_PORT}` :
    env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'https://localhost:7033';

const PROXY_CONFIG = [
  {
    context: [
      "/api/*"
    ],
    target,
    secure: false,
    
  }
]

module.exports = PROXY_CONFIG;

I'm creating a user registration form in Angular, here is the ts

import { Component } from '@angular/core';
import { AuthService } from '../_services/auth.service';

@Component({
  selector: 'app-registration',
  templateUrl: './registrationponent.html',
  styleUrl: './registrationponent.css'
})
export class RegistrationComponent {
  form: any = {
    email: null,
    password: null,
    accountType: 1,
    name: null,
    address: null,
    phone: null
  };
  isSuccessful = false;
  isSignUpFailed = false;
  errorMessage = '';

  constructor(private authService: AuthService) { }

  onSubmit(): void {
    const { email, password, accountType, name, address, phone } = this.form;

    this.authService.register(email, password, accountType, name, address, phone).subscribe({
      next: data => {
        console.log(data);
        this.isSuccessful = true;
        this.isSignUpFailed = false;
      },
      error: err => {
        this.errorMessage = err.error.message;
        this.isSignUpFailed = true;
      }
    });
  }

}

On submit calls my authService register method (below) which should call the register-account endpoint on my API

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AccountType } from '../_classes/AccountType';
import { RegisterRequest } from '../_DTOs/RegisterRequest';

const AUTH_API = 'https://localhost:7033/api/account/';

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  constructor(private http: HttpClient) { }

  register(email: string, password: string, accountType: AccountType, name: string, address: string, phone: string): Observable<any> {
    const request: RegisterRequest = {
      email: email,
      password: password,
      accountType: accountType,
      name: name,
      address: address,
      phone: phone
    }

    return this.http.post(
      AUTH_API + 'register-account',
      {
        request
      },
      httpOptions
    );
  }
}

With a breakpoint in my AccountController, the method never seems to be hit. Here is the controller

using AML.Server.Interfaces;
using AML.Server.Models;
using Microsoft.AspNetCore.Mvc;

namespace AML.Server.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AccountController : ControllerBase
    {
        private readonly IAccountRepository _accountRepository;

        public AccountController(IAccountRepository accountRepository)
        {
            this._accountRepository = accountRepository;
        }

        [HttpPost]
        [Route("register-account")]
        public async Task<bool> RegisterAccount(RegisterRequest request)
{
    bool success = false;

    if (request.Email == "[email protected]")
    {
        success = true;
    }

    // Logic going to repo & return success response
    return success;
}
    }
}

It throws a 400 bad response, the response I receive in DevTools is

{
    "type": "https://tools.ietf./html/rfc9110#section-15.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "errors": {
        "name": [
            "The name field is required."
        ],
        "email": [
            "The email field is required."
        ],
        "phone": [
            "The phone field is required."
        ],
        "address": [
            "The address field is required."
        ],
        "password": [
            "The password field is required."
        ]
    },
    "traceId": "00-ef5889b3c6e2444528b8799e51a3107b-8ca9bab2705e4cc0-00"
}

It seems that the parameters are not making it through, but I don't know how to resolve the issue. Does anybody have any ideas?

Edit - Additional potentially helpful info

Request payload

{"request":{"email":"[email protected]","password":"testtest","accountType":1,"name":"Jordan Abc","address":"123 Fake Street","phone":"07123456789"}}

Registration form html

<app-navbar></app-navbar>
<div class="font-weight-bold">
  <h3 class="title-text">Registration</h3>
</div>
<div class="content col-md-12">
  <div class="registration-form">
    @if (!isSuccessful) {
    <form name="form"
          (ngSubmit)="f.form.valid && onSubmit()"
          #f="ngForm"
          novalidate>
      <div class="form-group">
        <label for="email">Email</label>
        <input type="email"
               class="form-control"
               name="email"
               [(ngModel)]="form.email"
               required
               email
               #email="ngModel"
               [ngClass]="{ 'is-invalid': f.submitted && email.errors }" />
        @if (email.errors && f.submitted) {
        <div class="invalid-feedback">
          @if (email.errors['required']) {
          <div>Email is required</div>
          }
          @if (email.errors['email']) {
          <div>Email must be a valid email address</div>
          }
        </div>
        }
      </div>
      <div class="form-group">
        <label for="password">Password</label>
        <input type="password"
               class="form-control"
               name="password"
               [(ngModel)]="form.password"
               required
               minlength="6"
               #password="ngModel"
               [ngClass]="{ 'is-invalid': f.submitted && password.errors }" />
        @if (password.errors && f.submitted) {
        <div class="invalid-feedback">
          @if (password.errors['required']) {
          <div>Password is required</div>
          }
          @if (password.errors['minlength']) {
          <div>Password must be at least 6 characters</div>
          }
        </div>
        }
      </div>
      <div class="form-group">
        <label for="name">Name</label>
        <input type="text"
               class="form-control"
               name="name"
               [(ngModel)]="form.name"
               required
               minlength="1"
               maxlength="30"
               #name="ngModel"
               [ngClass]="{ 'is-invalid': f.submitted && name.errors }" />
        @if (name.errors && f.submitted) {
        <div class="invalid-feedback">
          @if (name.errors['required']) {
          <div>Name is required</div>
          }
          @if (name.errors['minlength']) {
          <div>Name is required</div>
          }
          @if (name.errors['maxlength']) {
          <div>Name must be at most 30 characters</div>
          }
        </div>
        }
      </div>
      <div class="form-group">
        <label for="address">Address</label>
        <input type="text"
               class="form-control"
               name="address"
               [(ngModel)]="form.address"
               required
               minlength="1"
               maxlength="75"
               #address="ngModel"
               [ngClass]="{ 'is-invalid': f.submitted && address.errors }" />
        @if (address.errors && f.submitted) {
        <div class="invalid-feedback">
          @if (address.errors['required']) {
          <div>Address is required</div>
          }
          @if (address.errors['minlength']) {
          <div>Address is required</div>
          }
          @if (address.errors['maxlength']) {
          <div>Address must be at most 75 characters</div>
          }
        </div>
        }
      </div>
      <div class="form-group">
        <label for="phone">Phone Number</label>
        <input type="tel"
               class="form-control"
               name="phone"
               [(ngModel)]="form.phone"
               required
               pattern="[0-9]{11}"
               #phone="ngModel"
               [ngClass]="{ 'is-invalid': f.submitted && phone.errors }" />
        @if (phone.errors && f.submitted) {
        <div class="invalid-feedback">
          @if (phone.errors['required']) {
          <div>Phone Number is required</div>
          }
          @if (phone.errors['tel']) {
          <div>Valid UK Phone Number is required</div>
          }
          @if (phone.errors['pattern']) {
          <div>Valid UK Phone Number is required (No spaces)</div>
          }
        </div>
        }
      </div>
      <div class="form-group">
        <button class="btn btn-primary btn-block">Register</button>
      </div>

      @if (f.submitted && isSignUpFailed) {
      <div class="alert alert-warning">
        Signup failed!<br />{{ errorMessage }}
      </div>
      }
    </form>
    } @else {
    <div class="alert alert-success">Your registration is successful!</div>
    }
  </div>
</div>

proxy.conf.js

const { env } = require('process');

const target = env.ASPNETCORE_HTTPS_PORT ? `https://localhost:${env.ASPNETCORE_HTTPS_PORT}` :
    env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'https://localhost:7033';

const PROXY_CONFIG = [
  {
    context: [
      "/api/*"
    ],
    target,
    secure: false,
    
  }
]

module.exports = PROXY_CONFIG;
Share Improve this question edited Nov 18, 2024 at 22:46 JordanChester asked Nov 18, 2024 at 20:56 JordanChesterJordanChester 1399 bronze badges 13
  • 1 Your TS code sends a JSON object (to verify: see network panel) but this is not what your controller expects. To change this, create a dto and use this as the single controller parameter, roughly public record RegisterParams(string Email, string Password, ...) and then RegisterAccount(RegisterParams params). Not tested, that why I'm posting in a comment. – Christoph Lütjen Commented Nov 18, 2024 at 21:41
  • @ckarakoc That may well be a separate issue which I've corrected, still not correcting this problem though – JordanChester Commented Nov 18, 2024 at 21:42
  • @JordanChester does it hit the function now? – ckarakoc Commented Nov 18, 2024 at 21:45
  • @ckarakoc if there is a validation error, the function won't be called. The pipeline can't extract the method parameters and so the function can't be called and you'll see the 400 bad request response. – Christoph Lütjen Commented Nov 18, 2024 at 21:49
  • @JordanChester, why not just create a DtO instead? public class RegisterAccountDto { public string Email { get; set; } public string Password { get; set; } public AccountType AccountType { get; set; } public string Name { get; set; } public string Address { get; set; } public string Phone { get; set; } } and put that in your parameters. – ckarakoc Commented Nov 18, 2024 at 21:50
 |  Show 8 more comments

1 Answer 1

Reset to default 2

In your ts file please apply the following changes:

register(email: string, password: string, accountType: AccountType, name: string, address: string, phone: string): Observable<any> {
    const request: RegisterRequest = {
      email: email,
      password: password,
      accountType: accountType,
      name: name,
      address: address,
      phone: phone
    }

    return this.http.post(
      AUTH_API + 'register-account',
      request,
      httpOptions
    );
  }

You don't need to wrap your request model into {..}, because it wraps it into additional model (what you can see in you json request).

Then as it was suggested please create a data model and add it to your API: data mode:

public class RegisterRequest 
{
  public string Email { get; set; }
  public string Password { get; set; }
  public string Name{ get; set; }
  public string Address { get; set; }
  public string Phone { get; set; }
  public AccountType AccountType { get; set; }
  //public int AccountType { get; set; } // alternative way to test it
}

In your controller:

[HttpPost("register-account")]
public async Task<bool> RegisterAccount(RegisterRequest request)
{
    bool success = false;

    if (request.Email == "[email protected]")
    {
        success = true;
    }

    // Logic going to repo & return success response
    return success;
}
Post a comment

comment list (0)

  1. No comments so far