web-dev-qa-db-ja.com

AngularJSとASP.NET Web APIを使用したバイト配列のアップロード/ダウンロード

バイト[]をアップロード/ダウンロードするためのソリューションの調査と作業に数日費やしました。私は近いですが、AngularJSコードブロックにあるように見える残りの問題が1つあります。

SOについても同様の質問がありますが、回答はありません。 https://stackoverflow.com/questions/23849665/web-api-accept-and-post-byte-array を参照してください

ここに、問題を述べる前にコンテキストを設定するための背景情報をいくつか示します。

  1. 専用サーバーデータベースの一部として使用されるbyte []をアップロードおよびダウンロードするための汎用クライアント/サーバーインターフェイスを作成しようとしています。
  2. TypeScript、AngularJS、JavaScript、およびBootstrap CSSをクライアントで使用して、単一ページアプリ(SPA)を作成しています。
  3. サーバーでASP.NET Web API/C#を使用しています。

SPAは、Silverlightで開発された既存の製品を置き換えるために開発されているため、既存のシステム要件に制約されます。 SPAはまた、幅広いデバイス(モバイルからデスクトップ)と主要なOSをターゲットにする必要があります。

いくつかのオンラインリソース(以下に記載)を利用して、コードの大部分を機能させることができました。以下のByte Rotリンクのbyte []に​​非同期マルチメディアフォーマッタを使用しています。

http://byterot.blogspot.com/2012/04/aspnet-web-api-series-part-5.html

ASP.NET Web APIのコントローラーからバイナリファイルを返す

  1. クライアントのテストケースとして、Uint8Arrayに変換されたjpegを使用しています。
  2. 実際のシステムバイト配列には、事前定義されたデータパケットに圧縮された混合コンテンツが含まれます。ただし、有効なバイト配列を処理できるようにする必要があるため、イメージは有効なテストケースになります。
  3. データは、以下に示すクライアントとサーバーのコードおよびByte Rot Formatter(表示されていませんが、Webサイトで入手可能)を使用してサーバーに正しく送信されます。
  4. 文字列パラメータのメタデータとともに、jpegがbyte []としてサーバーで適切に受信されることを確認しました。
  5. 私はFiddlerを使用して、正しい応答がクライアントに送り返されることを確認しました。
    • サイズは正しいです
    • 画像はFiddlerで表示できます。
  6. 私の問題は、Angular以下に示すクライアントコードのサーバー応答が正しくないことです。

    • 不正解とは、間違ったサイズ(〜10K対〜27.5K)であり、それはは、UintArrayコンストラクターの有効な値として認識されません。以下のクライアントコードに示されている返された「応答」の上にカーソルを置くと、Visual StudioはJFIFを表示しますが、コンテンツの他の目に見えるインジケーターはありません。

/ **********************サーバーコード************************/[FromBody] byte []の後に、不足しているアイテムをコードに追加しました

public class ItemUploadController : ApiController{ 
[AcceptVerbs("Post")]
    public HttpResponseMessage Upload(string var1, string var2, [FromBody]byte[] item){
        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
        var stream = new MemoryStream(item);
        result.Content = new StreamContent(stream);
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        return result;
    }
}

/ *****************クライアントコードの例******************** /

コードから省略しているのは、実際の変数パラメーターだけです。

$http({
url: 'api/ItemUpload/Upload',
    method: 'POST',
    headers: { 'Content-Type': 'application/octet-stream' },// Added per Byte Rot blog...
    params: {
        // Other params here, including string metadata about uploads
        var1: var1,
        var2: var2
    },
data: new Uint8Array(item),
// arrybuffer must be lowecase. Once changed, it fixed my problem.
responseType: 'arraybuffer',// Added per http://www.html5rocks.com/en/tutorials/file/xhr2/
transformRequest: [],
})
.success((response, status) => {
    if (status === 200) {
        // The response variable length is about 10K, whereas the correct Fiddler size is ~27.5K.
        // The error that I receive here is that the constructor argument in invalid.
        // My guess is that I am doing something incorrectly with the AngularJS code, but I
        // have implemented everything that I have read about. Any thoughts???
        var unsigned8Int = new Uint8Array(response);
        // For the test case, I want to convert the byte array back to a base64 encoded string
        // before verifying with the original source that was used to generate the byte[] upload.
        var b64Encoded = btoa(String.fromCharCode.apply(null, unsigned8Int));
        callback(b64Encoded);
    }
})
.error((data, status) => {
    console.log('[ERROR] Status Code:' + status);
});

/ ************************************************* *************** /

ヘルプや提案をいただければ幸いです。

ありがとう...

より多くの診断データを含むように編集されました

まず、angular.isArray関数を使用して、応答値が配列ではないことを確認しました。

次に、次のコードを使用して、応答を調べました。これは、非表示の文字列のようです。先頭の文字は、画像バイト配列コードの有効なシーケンスに対応していないようです。

var buffer = new ArrayBuffer(response.length);
var data = new Uint8Array(buffer);
var len = data.length, i;
for (i = 0; i < len; i++) {
    data[i] = response[i].charCodeAt(0);
}

実験結果

ダウンロードしたサーバーで、0〜255のバイト配列値を作成して実験を行いました。 AngularJSクライアントは最初の128バイトを正しく受信しましたが(つまり、0、1、...、126、127)、残りの値はInternet Explorer 11では65535、ChromeおよびFirefoxでは65533でした。 Fiddlerは、ネットワークを介して256個の値が送信されたことを示していますが、AngularJSクライアントコードで受信されたのは217文字のみです。サーバー値として0〜127のみを使用すると、すべてが機能しているようです。しかし、クライアントの応答は、署名されたバイトとより一致しているようです。これは可能ではないと思います。

サーバーからのFiddlerの16進データは256バイトを示し、値は00,01、...、EF、FFの範囲であり、これは正しい値です。前に述べたように、画像を返してFiddlerで適切に表示できるため、Web APIサーバーインターフェイスはPOSTとGETの両方で機能します。

私はVanilla XMLHttpRequestを試してみて、AngularJS環境の外部で動作することを確認します。

XMLHttpRequest Testing Update

Vanilla XMLHttpRequestがGETのサーバーで動作し、正しいバイトコードとテストイメージを返すことができることを確認できました。

良いニュースは、AngularJSをハックしてシステムを機能させることができることですが、悪いニュースは、これを行うのが好きではないことです。私はすべてのクライアント側サーバー通信でAngularを使用したままにします。

私はAngularJSで発生しているGET byte []の問題のみを処理する別の問題をStack Overflowで開きます。解決策が得られたら、他の人を助けるための歴史的な目的のための解決策でこの問題を更新します。

更新

GoogleグループのEric Eslingerから、responseTypeはすべて「小文字」の「arraybuffer」であることを示す小さなコードセグメントが送られてきました。上記のコードブロックを更新して小文字の値を表示し、メモを追加しました。

ありがとう...

12
Highdown

ようやくGoogleグループのEric Eslingerから返事が来ました。彼は彼が使用していることを指摘しました

$http.get('http://example.com/bindata.jpg', {responseType: 'arraybuffer'}).

彼はキャメルケースがおそらくそれが重要であったと述べました。 1つのキャラクターを変更し、フロー全体が現在機能しています。

すべてのクレジットは、Eric Eslingerに帰属します。

11
Highdown