2021年9月29日 星期三

[Q&A] Send image from ionic to asp.net core (IFormFile) web api

 [Q]

We are looking to upload image from ionic to .net core web api. To achieve this we are using file transfer plugin.

So, far we understood that image will be converted into base64. However, what we are looking is how can we sent form data along with multiple image to web api?

Below is the code from ionic side.

HTML code to trigger select image function:

<ion-button fill="clear" expand="full" color="light" (click)="selectImage()">
      <ion-icon slot="start" name="camera"></ion-icon>
      Select Image</ion-button>

Component file code to upload image using ionic camera Plugin:

async selectImage() {
      const actionSheet = await this.actionSheetController.create({
          header: "Select Image source",
          buttons: [{
                  text: 'Load from Library',
                  handler: () => {
                      this.takePicture(this.camera.PictureSourceType.PHOTOLIBRARY);
                  }
              },
              {
                  text: 'Use Camera',
                  handler: () => {
                      this.takePicture(this.camera.PictureSourceType.CAMERA);
                  }
              },
              {
                  text: 'Cancel',
                  role: 'cancel'
              }
          ]
      });
      await actionSheet.present();
  }

  takePicture(sourceType: PictureSourceType) {
      var options: CameraOptions = {
          quality: 100,
          sourceType: sourceType,
          saveToPhotoAlbum: false,
          correctOrientation: true
      };

      this.camera.getPicture(options).then(imagePath => {
        this.base64img="data:image/jpeg;base64,"+imagePath;
        this.uploadPic();
      });

  }

Component file code to pass image to web api:

uploadPic() {
        const fileTransfer: FileTransferObject = this.transfer.create();
        let filename = this.base64img.split('/').pop();
        let options: FileUploadOptions = {
            fileKey: "file",
            fileName: filename,
            chunkedMode: false,
            mimeType: "image/jpg",
            params: { 'title': this.imageTitle }
        }

        fileTransfer.upload(this.base64img, '<api endpoint>', options).then(data => {
          alert(JSON.stringify(data));
        }, error => {

          alert("error");
          alert("error" + JSON.stringify(error));
        });
      }

By doing this we are able to get the file in HttpContext.Request.Form.Files, but how can we get this in [FromBody] request parameter in web api? So, that I can get form data as well images to upload.

Also, we have tried by adding only one request parameter in web api, by assuming that the base64 which passed from client side will be received at in request parameter. But this also didn't work, which has given error 'Value cannot be null'.




[A]


You can send base64 data to any server API using HttpClientModule

Just do following changes in your code

Step 1: In app.module.ts

import { HttpClientModule } from '@angular/common/http';

include HttpClientModule in imports

Step 2: In page.ts

import { HttpClient } from '@angular/common/http';

constructor(private httpClient: HttpClient) { }

Initialise HttpClient in the constructor of page.ts

 sendData(base64img,other_data) {
    let _url = "";
    let formData = new FormData();
    formData.append("base64img", base64img);
    formData.append("other_data", other_data);
    this.httpClient.post(_url, formData).subscribe((res) => {
    //res contains server response
    });
  }





from:
https://stackoverflow.com/questions/58429122/send-image-from-ionic-to-asp-net-core-web-api

2021年5月2日 星期日

編譯 iOS 出現 ‘xcodebuild’ requires Xcode 的錯誤訊息

 自己寫的「圖書館多重帳戶」app 一直都只有 Chrome  Android 版本,

今天想來編譯一下 Cordova 的 iOS 版本時,

又遇到了一些和先前遇過不同的問題…

這些是之前編譯與除錯 iOS 時曾遇到的問題:

 

來記錄一下這次遇到的問題吧~

 

1. Cordova 專案中缺少 iOS 平台支援

在執行 cordova build ios 之後,出現了錯誤訊息

The platform “ios” does not appear to have been added to this project:

testuser@localhost ~ $ cordova build --debug ios

(node:16131) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: The platform "ios" does not appear to have been added to this project.

 

這是因為我之前移掉了 ios 的 platform~

執行 cordova platform 可以看到目前專案中只安裝了 android 平台支援:

testuser@localhost ~ $ cordova platform

Installed platforms:
  android 6.2.3
Available platforms:
  browser ~5.0.1
  ios ~4.5.4
  osx ~4.0.1
  windows ~5.0.0
  www ^3.12.0

 

只要把 ios 平台支援加上就好了:

cordova platform add ios

 

2. 找不到完整的 Xcode

繼續執行 cordova build ios,又出現了另一個錯誤訊息

tool ‘xcodebuild’ requires Xcode, but active developer directory

‘/Library/Developer/CommandLineTools’ is a command line tools instance

這個還真的有點搞不懂是在做什麼:

testuser@localhost ~ $ cordova build --debug ios

(node:16169) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance

 

不過我這台 Mac 的確是還沒安裝 Xcode…

先到 Mac 的 App Store 搜尋 Xcode 來安裝~

裝好之後,記得要執行一次 Xcode,

它還會繼續安裝其他的元件:

 

註:如果裝好 Xcode 後沒有先執行一次,

執行 cordova build ios 可能會出現找不到模擬器的錯誤訊息,

執行過 Xcode 後就會消失了:

testuser@localhost ~ $ cordova build --debug ios

(node:99278) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Command failed: xcrun simctl list --json
dyld: Library not loaded: /Library/Developer/PrivateFrameworks/CoreSimulator.framework/Versions/A/CoreSimulator
  Referenced from: /Applications/Xcode.app/Contents/Developer/usr/bin/simctl
  Reason: image not found

 

但 Xcode 裝好之後,還是會出現 ‘xcodebuild’ requires Xcode 的錯誤訊息…

查了一下,是說預設的 /Library/Developer/CommandLineTools 目錄下,

並沒有完整的 Xcode,但 cordova build ios 需要的是完整的 Xcode。

因此要執行下面的指令,切換到剛裝好的 Xcode 路徑上:

sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

 

這時再執行 cordova build ios,就沒有問題了:

testuser@localhost ~ $ cordova build --debug ios

Building for iPhone X Simulator
......
** BUILD SUCCEEDED **

 



from: https://ephrain.net/cordova-%E7%B7%A8%E8%AD%AF-ios-%E5%87%BA%E7%8F%BE-xcodebuild-requires-xcode-%E7%9A%84%E9%8C%AF%E8%AA%A4%E8%A8%8A%E6%81%AF/

2021年4月9日 星期五

Ionic error message: Unsupported engine package: '@angular/cli@11.1.4'

Error message:
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular/cli@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/architect@0.1101.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/core@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/schematics@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@schematics/angular@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/core@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/schematics@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@schematics/update@0.1101.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/core@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/schematics@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@stencil/core@2.5.2',
npm WARN EBADENGINE   required: { node: '>=12.10.0', npm: '>=6.0.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }  



Solution:
$ npm -v
7.5.0

$ npm install --global npm@6

removed 60 packages, changed 194 packages, and audited 436 packages in 30s

3 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

$ npm -v
6.14.11

$ npm install -g @angular/cli
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
/usr/local/bin/ng -> /usr/local/lib/node_modules/@angular/cli/bin/ng

> @angular/cli@11.1.4 postinstall /usr/local/lib/node_modules/@angular/cli
> node ./bin/postinstall/script.js

? Would you like to share anonymous usage data with the Angular Team at Google u
nder
Google’s Privacy Policy at https://policies.google.com/privacy? For more details
 and
how to change this setting, see http://angular.io/analytics. Yes

Thank you for sharing anonymous usage data. If you change your mind, the following
command will disable this feature entirely:

    ng analytics off

+ @angular/cli@11.1.4
added 5 packages from 2 contributors, removed 7 packages and updated 234 packages in 103.594s
————————————————
  

 

2021年3月31日 星期三

如何在應用程式利用Google發通知郵件

1.申請1個Google的信箱。

2.使用應用程式密碼登入帳戶

使用應用程式密碼。

    1. 前往您的 Google 帳戶
    2. 選取 [安全性]。
    3. 選取「登入 Google」底下的 [應用程式密碼]。您可能需要登入。如果您沒有看到這個選項,可能原因如下:
      1. 您的帳戶並未設定兩步驟驗證。
      2. 您目前只設定使用安全金鑰進行兩步驟驗證。
      3. 您使用的是公司、學校或其他機構專用的帳戶。
      4. 您已啟用進階保護功能。
    4. 選擇底部的 [選取應用程式] 並選擇您所使用的應用程式 下一步 選擇 [選取裝置] 並選擇您所使用的裝置 下一步 選取 [產生]。
    5. 按照操作說明輸入應用程式密碼。應用程式密碼是指裝置上黃色列中的 16 位數代碼。
    6. 輕觸 [完成]。
3.參數設定參考
<configuration>
  <system.net>
    <mailSettings>
      <smtp deliveryMethod="Network" from="xxxxx@gmail.com">
        <network defaultCredentials="false" host="smtp.gmail.com" port="587" userName="xxxxx@gmail.com" password="xxxxxxxxxxxxxxxx" enableSsl="true" />
      </smtp>
    </mailSettings>
  </system.net>


2021年3月24日 星期三

關於 RxJS 裡的 BehaviorSubject 可以怎麼用!

 RxJS 裡的 Subject 有 4 種類型,Subject、BehaviorSubject、ReplaySubject 和 AsyncSubject,每一種類型的 Subject 都有各自的特性及使用時機,這次會使用 BehaviorSubject來管理使用者的登入狀態


BehaviorSubject

BehaviorSubject 與一般的 Subject 有什麼不一樣,差別有兩個

  1. BehaviorSubject 可以給予初始值
  2. 每一個 Observer 都可以在註冊的當下,立刻取得目前 BehavoirSubject 的值 (以下皆簡稱為 Subject)

這兩種特性,就非常適合用在使用者登入狀態管理的這種情境

使用情境

使用者登入基本上,狀態就兩種,登入與尚未登入,而每一個頁面都可以在取得該使用者目前的登入狀態。也可以即時知道已登入的使用者登出的時間點。

根據上列的描述,我們會實作一個 UserService,用來執行跟管理使用者的登入,登出行為及狀態。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from "rxjs";

@Injectable()
export class UserService {
isLoginSubject = new BehaviorSubject<boolean>(this.hasToken());

/**
* 如果有取得token,表示使用者有登入系統
* @returns {boolean}
*/
private hasToken() : boolean {
return !!localStorage.getItem('token');
}

/**
* 登入使用者,並通知所有訂閱者
*/
login() : void {
localStorage.setItem('token', 'JWT');
this.isLoginSubject.next(true);
}

/**
* 登出使用者,並通知所有訂閱者
*/
logout() : void {
localStorage.removeItem('token');
this.isLoginSubject.next(false);
}

/**
*
* @returns {Observable<T>}
*/
isLoggedIn() : Observable<boolean> {
return this.isLoginSubject.asObservable();
}
}

Component 的使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { Component, OnInit } from '@angular/core';
import { AuthService } from "../auth.service";
import { Observable } from "rxjs";

@Component({
selector: 'app-main-nav',
template: `
<ul>
<li *ngIf="!(isLoggedIn | async)" (click)="authService.login()>
<a>Login</a>
</li>
<li *ngIf="(isLoggedIn | async)" (click)="authService.logout()">
<a>Logout</a>
</li>
</ul>
`
})
export class MainNavComponent implements OnInit {
isLoggedIn : Observable<boolean>;

constructor( public userService : UserService ) {
this.isLoggedIn = userService.isLoggedIn();
}
}

這樣子就完成了一個陽春型的使用者登入狀態管理 service。



參考資料

2021年3月21日 星期日

No pipe found with name 'translate'

 Error message:

error NG8004: No pipe found with name 'translate'.



page module 要作如下配置:

import { TranslateModule } from '@ngx-translate/core';


@NgModule({

  imports: [

TranslateModule

  ],

  exports: [

TranslateModule

  ]

})


If 'ion-title' is an Angular component, then verify that it is part of this module.

 Error message:

1. If 'ion-title' is an Angular component, then verify that it is part of this module.

2. If 'ion-title' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.


page ts 要加 entryComponents:

const tmpModule = NgModule({

         declarations: [tmpCmp],

         imports:[IonicModule],

         entryComponents: [tmpCmp]

    })(class {});


[Q&A] Send image from ionic to asp.net core (IFormFile) web api

 [Q] We are looking to upload image from ionic to .net core web api. To achieve this we are using file transfer plugin. So, far we understoo...