2016-03-16 4 views
11

サーバー上で実行されているWeb APIプロジェクトがあります。実際のポータブルドキュメントファイル(PDF)と、データベースに格納されたbase64文字列の2種類のソースからPDFを返すことになっています。私が抱えている問題は、ドキュメントをクライアントのMVCアプリケーションに送り返すことです。これの残りの部分は、起こったことすべてについての詳細であり、すでに試したことです。Web APIアプリケーションからPDFを返す方法

私はこれらの2つのフォーマットをC#コードに変換してからPDFフォームに変換するコードを書いています。これらのドキュメントの1つを表すはずのバイト配列は正常に転送されましたが、ブラウザで表示することはできません(新しいタブで)。私はいつも「表示できません」というエラーを出す。

最近、私はサーバー側のドキュメントを見て、少なくともそれを行うことができることを確認しました。それはコードにドキュメントを取得し、(暗黙的なキャスト)ActionResultとしてそれを返したFileStreamResultを作成します。私はそれをサーバー側のMVCコントローラーに戻して、ブラウザーでPDFを表示する単純な戻り値(ビューなし)にスローしました。しかし、単にWeb API関数にまっすぐ進むと、FileStreamResultのJSON表現のように見えます。

クライアントのMVCアプリケーションに正しく返るようにしようとすると、「_バッファ」を直接設定できないことがわかります。いくつかのプロパティが返されてオブジェクトにスローされるというプライベートなエラーメッセージとアクセスできません。

上記のPDFのバイト配列表現は、base64文字列に変換されたとき、FileStreamResultによってJSONに返される "_buffer"文字列と同じ文字数を持つようには見えません。最後に約26kのAが欠けている。

このPDFを正しく返す方法についてのアイデアはありますか?必要に応じてコードを提供することはできますが、サーバーサイドのWeb APIアプリケーションからクライアントサイドのMVCアプリケーションにPDFを戻し、Webページとしてブラウザに表示する方法は知られていなければなりません。

P.S.私は "クライアント側"のアプリケーションが技術的にクライアント側ではないことを知っています。また、サーバーアプリケーションになりますが、この場合は問題にはなりません。 Web APIサーバーと比較して、私のMVCアプリケーションは "クライアント側"です。 PDFサーバー・サイドを表示するための

[AcceptVerbs("GET","POST")] 
    public System.Web.Mvc.ActionResult getPdf() 
    { 
     System.Web.Mvc.ActionResult retVal = GetPDF(); 
     return retVal; 
    } 

:GetPDFから取得

private System.Web.Mvc.ActionResult GetPDF() 
{ 
    int bufferSize = 100; 
    int startIndex = 0; 
    long retval; 
    byte[] buffer = new byte[bufferSize]; 
    MemoryStream stream = new MemoryStream(); 
    SqlCommand command; 
    SqlConnection sqlca; 
    SqlDataReader reader; 

    using (sqlca = new SqlConnection(CONNECTION_STRING)) 
    { 
     command = new SqlCommand((LINQ_TO_GET_FILE).ToString(), sqlca); 
     sqlca.Open(); 
     reader = command.ExecuteReader(CommandBehavior.SequentialAccess); 
     try 
     { 
      while (reader.Read()) 
      { 
       do 
       { 
        retval = reader.GetBytes(0, startIndex, buffer, 0, bufferSize); 
        stream.Write(buffer, 0, bufferSize); 
        startIndex += bufferSize; 
       } while (retval == bufferSize); 
      } 
     } 
     finally 
     { 
      reader.Close(); 
      sqlca.Close(); 
     } 
    } 
    stream.Position = 0; 
    System.Web.Mvc.FileStreamResult fsr = new System.Web.Mvc.FileStreamResult(stream, "application/pdf"); 
    return fsr; 
} 

API機能:PDFファイルを取得するための

コード

public ActionResult getChart() 
{ 
    return new PDFController().GetPDF(); 
} 

コードでMVCアプリケーションに変更があります時間の経過とともに多くのことが起こります。今のところ、ブラウザで表示しようとする段階には達しません。その前にエラーが発生します。

public async Task<ActionResult> get_pdf(args,keys) 
{ 
    JObject jObj; 
    StringBuilder argumentsSB = new StringBuilder(); 
    if (args.Length != 0) 
    { 
     argumentsSB.Append("?"); 
     argumentsSB.Append(keys[0]); 
     argumentsSB.Append("="); 
     argumentsSB.Append(args[0]); 
     for (int i = 1; i < args.Length; i += 1) 
     { 
      argumentsSB.Append("&"); 
      argumentsSB.Append(keys[i]); 
      argumentsSB.Append("="); 
      argumentsSB.Append(args[i]); 
     } 
    } 
    else 
    { 
     argumentsSB.Append(""); 
    } 
    var arguments = argumentsSB.ToString(); 
    using (var client = new HttpClient()) 
    { 
     client.DefaultRequestHeaders.Accept.Clear(); 
     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 
     var response = await client.GetAsync(URL_OF_SERVER+"api/pdf/getPdf/" + arguments).ConfigureAwait(false); 
     jObj = (JObject)JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result); 
    } 
    return jObj.ToObject<ActionResult>(); 
} 

私は、Web APIコントローラから直接メソッドを実行しているから取得するJSONは次のとおりです。

{ 
    "FileStream":{ 
     "_buffer":"JVBER...NjdENEUxAA...AA==", 
     "_origin":0, 
     "_position":0, 
     "_length":45600, 
     "_capacity":65536, 
     "_expandable":true, 
     "_writable":true, 
     "_exposable":true, 
     "_isOpen":true, 
     "__identity":null}, 
    "ContentType":"application/pdf", 
    "FileDownloadName":"" 
} 

それは途方もなく長いですので、私は「_buffer」を短縮しました。型System.Web.Mvc.ActionResultのインスタンスを作成できませんでした:Newtonsoft.Json.JsonSerializationException: は、私は現在get_pdfのリターンライン(引数、キー)

例外の詳細について、以下のエラーメッセージが表示されます。型はインタフェースまたは抽象クラスであり、インスタンス化できません。パス 'FileStream'。私は空白のPDFリーダーを(。読者が空白だった何のファイル)を取得するために使用された場合

戻る、私はこのコードを使用:コメントアウト

public async Task<ActionResult> get_pdf(args,keys) 
{ 
    byte[] retArr; 
    StringBuilder argumentsSB = new StringBuilder(); 
    if (args.Length != 0) 
    { 
     argumentsSB.Append("?"); 
     argumentsSB.Append(keys[0]); 
     argumentsSB.Append("="); 
     argumentsSB.Append(args[0]); 
     for (int i = 1; i < args.Length; i += 1) 
     { 
      argumentsSB.Append("&"); 
      argumentsSB.Append(keys[i]); 
      argumentsSB.Append("="); 
      argumentsSB.Append(args[i]); 
     } 
    } 
    else 
    { 
     argumentsSB.Append(""); 
    } 
    var arguments = argumentsSB.ToString(); 
    using (var client = new HttpClient()) 
    { 
     client.DefaultRequestHeaders.Accept.Clear(); 
     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/pdf")); 
     var response = await client.GetAsync(URL_OF_SERVER+"api/webservice/" + method + "/" + arguments).ConfigureAwait(false); 
     retArr = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); 
    } 
    var x = retArr.Skip(1).Take(y.Length-2).ToArray(); 
    /*Response.Clear(); 
    Response.ClearContent(); 
    Response.ClearHeaders(); 
    Response.ContentType = "application/pdf"; 
    Response.AppendHeader("Content-Disposition", "inline;filename=document.pdf"); 
    Response.BufferOutput = true; 
    Response.BinaryWrite(x); 
    Response.Flush(); 
    Response.End();*/ 
    return new FileStreamResult(new MemoryStream(x),MediaTypeNames.Application.Pdf); 
    } 

は、他のいくつかの試みからのコードです。私がそのコードを使用していたとき、私はサーバーからバイト配列を返していました。それはのように見えた:

JVBER...NjdENEUx 
+0

を助け、私はしましたMr.T @などいくつかのサンプルコード、特定のエラーメッセージ、 –

+0

を表示ちょうど私の編集で今追加したいと思うことがすべて追加されました。 – Doctor93

+0

なぜ 'get_pdf'で' JObject'を使用していますか? – Jacob

答えて

12

PDF(Web API)を返すいくつかのサーバーサイドコード。あなたがウェブAPIを呼び出し、ブラウザで新しいタブでPDF文書を開きます。この

<a href="api/documents/1234" target = "_blank" class = "btn btn-success" >View document</a> 

ような何かを行うことができ、私のビュー

[HttpGet] 
[Route("documents/{docid}")] 
public HttpResponseMessage Display(string docid) { 
    HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.BadRequest); 
    var documents = reader.GetDocument(docid); 
    if (documents != null && documents.Length == 1) { 
     var document = documents[0]; 
     docid = document.docid; 
     byte[] buffer = new byte[0]; 
     //generate pdf document 
     MemoryStream memoryStream = new MemoryStream(); 
     MyPDFGenerator.New().PrintToStream(document, memoryStream); 
     //get buffer 
     buffer = memoryStream.ToArray(); 
     //content length for use in header 
     var contentLength = buffer.Length; 
     //200 
     //successful 
     var statuscode = HttpStatusCode.OK; 
     response = Request.CreateResponse(statuscode); 
     response.Content = new StreamContent(new MemoryStream(buffer)); 
     response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); 
     response.Content.Headers.ContentLength = contentLength; 
     ContentDispositionHeaderValue contentDisposition = null; 
     if (ContentDispositionHeaderValue.TryParse("inline; filename=" + document.Name + ".pdf", out contentDisposition)) { 
      response.Content.Headers.ContentDisposition = contentDisposition; 
     } 
    } else { 
     var statuscode = HttpStatusCode.NotFound; 
     var message = String.Format("Unable to find resource. Resource \"{0}\" may not exist.", docid); 
     var responseData = responseDataFactory.CreateWithOnlyMetadata(statuscode, message); 
     response = Request.CreateResponse((HttpStatusCode)responseData.meta.code, responseData); 
    } 
    return response; 
} 

。ここで

ホープ私は基本的に同じことを行う方法ですが、MVCコントローラから

// NOTE: Original return type: FileContentResult, Changed to ActionResult to allow for error results 
[Route("{docid}/Label")] 
public ActionResult Label(Guid docid) { 
    var timestamp = DateTime.Now; 
    var shipment = objectFactory.Create<Document>(); 
    if (docid!= Guid.Empty) { 
     var documents = reader.GetDocuments(docid); 
     if (documents.Length > 0) 
      document = documents[0]; 

      MemoryStream memoryStream = new MemoryStream(); 
      var printer = MyPDFGenerator.New(); 
      printer.PrintToStream(document, memoryStream); 

      Response.AppendHeader("Content-Disposition", "inline; filename=" + timestamp.ToString("yyyyMMddHHmmss") + ".pdf"); 
      return File(memoryStream.ToArray(), "application/pdf"); 
     } else { 
      return this.RedirectToAction(c => c.Details(id)); 
     } 
    } 
    return this.RedirectToAction(c => c.Index(null, null)); 
} 

これは

+0

これは機能しますが、フロントエンドからバックエンドにリンクを削除しようとしています。フロントエンドは基本的にすべてのビジネスロジックを隠している中間的な人間として行動するべきです。私の試みは、このテキストをブラウザ "StatusCode:200、ReasonPhrase: 'OK'、バージョン:1.1、コンテンツ:System.Net.Http.StreamContent、ヘッダー:{Pragma:no-cache Cache-Control:no-キャッシュDate:Wed、16 Mar Mar 2016 18:48:38 GMTサーバー:Microsoft-IIS/10.0 X-AspNet-バージョン:4.0.30319 X-Powered-By:ASP.NET Content-Length:45600コンテンツの処理:インライン。ファイル名= chart.pdfコンテンツタイプ:application/pdf Expires:-1} " – Doctor93

+1

私はそれを得ました。ありがとうございました!私はちょうどストリームとしてコンテンツを読んで、FileResultに暗黙的にキャストしてActionResultとしてキャストしなければならなかった – Doctor93

+0

こんにちは!私はあなたの例をリファクタリングして、 'response.Content = new StreamContent(new MemoryStream(buffer)) 'という行を単純化しようとしたときに壁に衝突しました。 StreamStreamに先に作成されたMemoryStream?私は試してみましたが、うまくいきませんでしたが、なぜ分かりませんか。 –

関連する問題