スキップしてメイン コンテンツに移動

[Angular][ASP.NET Core] Sending data

Intro

When I had POST data from the Angular app to ASP.NET Core app, sometimes I failed even though there hadn't been any exceptions happened.
Because I had wanted to know the reason, I tried something.

What I did

  • Set data to Request Payload and POST
  • Set data to Form Data and POST
  • Get data from ASP.NET Core

Sample Codes

ASP.NET Core

ApiController.cs


using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Files;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Models;
using UpgradeSample.Models;
using UpgradeSample.Products;

namespace UpgradeSample.Controllers
{
    public class ApiController: Controller
    {
        private readonly IProductService _productService;
        public ApiController(IProductService productService)
        {
            _productService = productService;
        }
        [HttpGet]
        [Route("/products")]
        public async Task<List<Product>> GetProducts()
        {
            return await _productService.GetProductsAsync();
        }
        [Route("/post-sample/form")]
        public UploadResult GetFormSample([FromForm] int productId, string productName)
        {
            return new UploadResult
            {
                Succeeded = (string.IsNullOrEmpty(productName) == false),
                ErrorMessage = $"ID: {productId} NAME: {productName}"
            };
        }
        [Route("/post-sample/form-class")]
        public UploadResult GetFormClassSample([FromForm] Product product)
        {
            return new UploadResult
            {
                Succeeded = (product != null),
                ErrorMessage = $"ID: {product?.ProductId} NAME: {product?.ProductName}"
            };
        }
        [Route("/post-sample/body-class")]
        public UploadResult GetBodyClassSample([FromBody] Product product)
        {
            return new UploadResult
            {
                Succeeded = (product != null),
                ErrorMessage = $"ID: {product?.ProductId} NAME: {product?.ProductName}"
            };
        }
    }
}

Product.cs


using System.ComponentModel.DataAnnotations.Schema;

namespace UpgradeSample.Models
{
    [Table("Product")]
    public class Product
    {
        [Column("ProductId")]
        public int? ProductId { get; set; }
        [Column("ProductName")]
        public string ProductName { get; set; }
    }
}

UploadResult


namespace Files
{
    public class UploadResult
    {
        public bool Succeeded { get; set; }
        public string ErrorMessage { get; set; }
    }
}

Angular

post-sample.service.ts


import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { UploadResult } from '../file-upload/upload-result';
import { Product } from '../models/product';

@Injectable({
  providedIn: 'root'
})
export class PostSampleService {
  constructor(private httpClient: HttpClient) { }
  public sendRequestPayloadClass(): Observable<UploadResult> {
    // POST grouped data as Request Payload
  }
  public sendForm(): Observable<UploadResult> {
    // POST separated data as FormData 
  }
  public sendFormClass(): Observable<UploadResult> {
    // POST grouped data as FormData
  }
  public getProducts(): Observable<Array<Product>> {
    // GET data
  }
}

post-sample.component.html


<button (click)="sendRequestPayloadClass()">RequestPayloadClass</button>
<button (click)="sendForm()">Form</button>
<button (click)="sendFormClass()">FormClass</button>
<button (click)="get()">Get</button>

post-sample.component.ts


import { Component, OnInit } from '@angular/core';
import { PostSampleService } from './post-sample.service';

@Component({
  selector: 'app-post-sample',
  templateUrl: './post-sample.component.html',
  styleUrls: ['./post-sample.component.css']
})
export class PostSampleComponent implements OnInit {
  constructor(private postSampleService: PostSampleService) { }
  ngOnInit() {
  }
  public sendRequestPayloadClass() {
    this.postSampleService.sendRequestPayloadClass()
      .subscribe(result => {
        console.log(result);
      });
  }
  public sendForm() {
    this.postSampleService.sendForm()
      .subscribe(result => {
        console.log(result);
      });
  }
  public sendFormClass() {
    this.postSampleService.sendFormClass()
    .subscribe(result => {
      console.log(result);
    });
  }
  public get() {
    this.postSampleService.getProducts()
      .subscribe(products => {
        console.log(products);
      });
  }
}

upload-result.ts


export interface UploadResult {
  succeeded: boolean;
  errorMessage: string;
}

Set data to Request Payload and POST

POST grouped data

Because I only could set single data as Request Payload, I just tried POST grouped data.

post-sample.service.ts


...
export class PostSampleService {
...
  public sendRequestPayload(): Observable<UploadResult> {
    // POST separated data as Request Payload
    const product = {
      productId: 6,
      productName: 'World'
    };
    return this.httpClient.post<UploadResult>(
      `http://localhost:5000/post-sample/body-class`,
      product, {
        headers: {
          'Content-Type': 'application/json'
        }
      }
    );
  }
...
}

I could receive data as Product class.
So I got the result like below.

{"succeeded":true,"errorMessage":"ID: 6 NAME: World"}

Send data that had partial properties

If the data hadn't had all of the properties of Product class, the ASP.NET Core app could receive as Product class.

post-sample.service.ts


...
export class PostSampleService {
...
  public sendRequestPayload(): Observable<UploadResult> {
    // POST separated data as Request Payload
    const product = {
      productId: 6,
    };
    return this.httpClient.post<UploadResult>(
      `http://localhost:5000/post-sample/body-class`,
      product, {
        headers: {
          'Content-Type': 'application/json'
        }
      }
    );
  }
...
}

result


{"succeeded":true,"errorMessage":"ID: 6 NAME: "}

Send data that had other properties

Even though the data had other properties, the ASP.NET Core app still could receive as Product class.

post-sample.service.ts


...
export class PostSampleService {
...
  public sendRequestPayload(): Observable<UploadResult> {
    // POST separated data as Request Payload
    const product = {
      productId: 6,
      product: 'Hello world'
    };
    return this.httpClient.post<UploadResult>(
      `http://localhost:5000/post-sample/body-class`,
      product, {
        headers: {
          'Content-Type': 'application/json'
        }
      }
    );
  }
...
}

result


{"succeeded":true,"errorMessage":"ID: 6 NAME: "}

Send data that had the property that had same name & different data type

How about this?

post-sample.service.ts


...
export class PostSampleService {
...
  public sendRequestPayload(): Observable<UploadResult> {
    // POST separated data as Request Payload
    const product = {
      productId: '6',
      productName: 'Hello world'
    };
    return this.httpClient.post<UploadResult>(
      `http://localhost:5000/post-sample/body-class`,
      product, {
        headers: {
          'Content-Type': 'application/json'
        }
      }
    );
  }
...
}

The result was the ASP.NET Core app hadn't been able to receive.
Because TypeScriptcould mix the data what had different data types, sometimes the problems occurred.

Did I have to add "Content-Type" to headers?

No. Because when I had sent, "Content-Type" was added by default.

Did I have to create class(or interface) to send data?

  • Angular: No
  • ASP.NET Core: Yes

Set data to Form Data and POST

POST separated data

I could send separated data by FormData.

post-sample.service.ts


...
export class PostSampleService {
...
  public sendForm(): Observable<UploadResult> {
    const formData = new FormData();
    const id = 3;
    formData.append('productId', id.toString(10));
    formData.append('productName', 'Hello world');
    return this.httpClient.post<UploadResult>(
      `http://localhost:5000/post-sample/form`,
      formData, { }
    );
  }
...
}

Send data that had partial properties

There were no problems happened.
The properties what I hadn't send had default values.

Send data that had the property that had same name & different data type

No problem.
If the data had been able to convert(ex. Angular sent '3'), ASP.NET Core app could get values.
If the converting failed, the properties had default values.

Add 'Content-Type': 'application/json' to headers?

I failed sending.
Because for sending FormData, the content type was "multipart/form-data" by default.
I also couldn't send data when I had set "application/x-www-form-urlencoded" to the content type.
I thought the controller method of ASP.NET Core also needed change to get.

POST grouped data

I couldn't send grouped data.

post-sample.service.ts


...
export class PostSampleService {
...
  public sendFormClass(): Observable<UploadResult> {
    const product = {
      productId: 4,
      productName: 'Hello world'
    };
    const formData = new FormData();
    formData.append('product', JSON.stringify(product));
    return this.httpClient.post<UploadResult>(
      `http://localhost:5000/post-sample/form-class`,
      formData, { }
    );
  }
...
}

Even though the argument hadn't been null, "ProductId" & "ProductName" was null.

I didn't know there had been any way to send grouped data with FormData.
But now, I had used RequestPayload to send grouped data.

Get data

How about the getting data from ASP.NET Core?
Were there same problems as sending data?

post-sample.service.ts


...
export class PostSampleService {
...
  public getProducts(): Observable<Array<Product>> {
    return this.httpClient.get<Array<Product>>(
      `http://localhost:5000/products`);
  }
...
}

The answer was no.
Even though I had put any types in get<T>, the return value type was as same as sent from server.

So even if I changed like below...

post-sample.service.ts


...
export class PostSampleService {
...
  public getProducts(): Observable<any> {
    return this.httpClient.get<boolean>(
      `http://localhost:5000/products`);
  }
...
}

The result was like this.
(2) [{…}, {…}]
    0:
        productId: 1
        ProductName: "Nykee Running Shoes"
        __proto__: Object
    1:
        productId: 2
        ProductName: "South Face Jacket"
        __proto__: Object
    length: 2
    __proto__: Array(0)

Resources

Angular - HttpClient
Angular - HttpClient
Model Binding in ASP.NET Core | Microsoft Docs
Custom Model Binding in ASP.NET Core | Microsoft Docs

コメント

このブログの人気の投稿

[Angular][ASP.NET Core] Upload chunked files

Intro I wanted to send files to Web application (made by ASP.NET Core). If the file size had been small, I didn't need do any special things. But when I tried to send a large file, the error was occurred by ASP.NET Core's limitation. Though I could change the settings, but I didn't want to do that, because I hadn't known the file sizes what would been actually using. So I splitted the data into chunks first, and sent them. After receiving all chunks, I merged them into one file. There might be some libraries or APIs (ex. Stream API) what did them automatically, but I couldn't find them. What I did [ASP.NET Core] Make CORS enabled [Angular] Split a large file into chunks [Angular][ASP.NET Core] Send and receive data as form data [ASP.NET Core] Merge chunks into one file [ASP.NET Core] Make CORS enabled Because the client side application(Angular) and the server side application(ASP.NET Core) had been separated, I had to make CORS(Cross-Origin Requests)

[Nest.js] Use WebSocket with ws

Intro Until last time , I had used node-web-rtc to try WebRTC. But because the example was a little complicated for I understood the core functions of using WebRTC. So I look for other frameworks or libraries. PeerJS is a famous library for WebRTC. peers/peerjs: Peer-to-peer data in the browser. - GitHub peers/peerjs-server: Server for PeerJS - GitHub PeerJS - Simple peer-to-peer with WebRTC A problem is I don't know how to integrate to the Nest.js project. I couldn't find examples. So I don't choose at least this time. What shall I choose? According MDN, WebRTC doesn't specify strictly what technology is used on server application for connecting two devices. Signaling and video calling - Web APIs | MDN But in many examples include MDN's one use WebSocket. samples-server/s/webrtc-from-chat at master · mdn/samples-server · GitHub So I try WebSocket in the Nest.js project. Use WebSocket in a Nest.js project Nest.js has a function for using We

[Nest.js] Show static files

Intro I wanted to use Nest.js and WebRTC(node-webrtc). NestJS - A progressive Node.js framework Documentation | NestJS - A progressive Node.js framework And because I wanted to try with simple page(not use JavaScript frameworks), I added static HTML, CSS, JavaScript into a Nest.js project. Prepare Install First, I installed @nestjs/cli. First steps | NestJS - A progressive Node.js framework As same as last time , I couldn't do global install because I had used Volta. But I could installed by volta. volta install @nestjs/cli Create project nest new nest-web-rtc-sample volta pin node@12 Run npm start After doing "npm start", I could getting "Hello World!" from http://localhost:3000. Add static files I could add static files by two ways. @nestjs/serve-static First one of them was using "serve-static". Serve Static | NestJS - A progressive Node.js framework npm install --save @nestjs/serve-static And I needed adding a module into app.modu