質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

Q&A

解決済

1回答

5250閲覧

ASP.NETにおいて、Table内のセルまたは文字がクリックされた時に指定したフォルダをダウンロードできる機能の実装の仕方を教えてほしい

ehyai

総合スコア43

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

0グッド

0クリップ

投稿2016/12/07 16:50

編集2016/12/08 14:50

###初めに
ASP.NETで、ある特定のディレクトリを取得し、そのディレクトリ内のファイルの数だけセルを作り、そのセル、またはセル内の文字がクリックされたら、イベントを起こすことができる方法を教えていただきたいと考えています。
元々は、私はユーザーが選択したファイルの中身の文章を、ブラウザに表示できるような仕組みを実装することを目的としていました。しかし、その後に構築しようと考えているシステムの内容が少し変わり、「ファイルの中身をブラウザに表示する」機能をを「ファイル自体をダウンロードする」ことに方向転換することになりました。方向転換する前のシステムを構築するためにも質問をしており、こちらに載せております。
###前提・実現したいこと
ある特定のディレクトリの中にいくつかのディレクトリがあり、さらにその中にいくつかのフォルダが入ってあります。それらを表(Table)として表し、それぞれのフォルダの名前がセル内に文字で書かれています。そして、そのセル、またはセル内の文字をクリックすることで、そのフォルダをダウンロードできる機能をつけることになりました。
そこで、行け!偏差値40プログラマー [ ASP.NET ] ファイルのアップロードとダウンロード ( FileUpload / HttpResponse.TransmitFile )というサイトを参考にして、ファイルのダウンロードを行える仕組みを考えました。以下に示すコードは一例で、FileUploadでダウンロードするフォルダを決め、ボタンを押すとそのフォルダのダウンロードを行えるというコードで、表は特定のディレクトリ中のフォルダを示すだけの状態なのですが、これを「特定のディレクトリ中のフォルダTable1内のセルに書かれたフォルダをクリックしたら、そのフォルダをダウンロードできる」ようなコードにすることは可能でしょうか。お手数ですが、よろしくお願いします。

###該当のソースコード
Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> <asp:Table ID="Table1" runat="server"> </asp:Table> <asp:FileUpload ID="FileUpload1" runat="server" /> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" /> </div> </form> </body> </html>

Default.aspx.cs

using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.IO; using System.Text; public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { cppTable(); } protected void Button1_Click(object sender, EventArgs e)//フォルダをダウンロードする部分、ここの箇所を、Tableのセル内の文字がクリックされたら行われるようにしてほしい { // ファイルがアップロードされていなければリターン if (FileUpload1.HasFile == false) { return; } // ファイルをメモリーに格納 Byte[] data = new Byte[FileUpload1.PostedFile.ContentLength]; FileUpload1.PostedFile.InputStream.Read(data, 0, FileUpload1.PostedFile.ContentLength); // レスポンスを作成して返す(アップロードされたファイルをそのままダウンロード) HttpResponse resp = HttpContext.Current.Response; resp.Clear(); resp.ContentType = FileUpload1.PostedFile.ContentType; // コンテントタイプ resp.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(FileUpload1.FileName)); resp.BinaryWrite(data); } public void cppTable() { //ディレクトリ内のフォルダの数だけ表の列を増やす IEnumerable<string> subFolders = System.IO.Directory.EnumerateDirectories(@"C:「特定のディレクトリ」", "*", System.IO.SearchOption.AllDirectories).Select(Path.GetFileName); // ファイルパスからファイル名を抽出 TableRow tableRow; TableCell tableCell; foreach (string f in subFolders) //ここで行を作っていく { tableRow = new TableRow(); tableCell = new TableCell(); tableCell.Text = f; tableRow.Cells.Add(tableCell); IEnumerable<string> Qfiles = System.IO.Directory.EnumerateFiles(@"C:「特定のディレクトリ」" + f, "*", System.IO.SearchOption.AllDirectories).Select(Path.GetFileName); foreach (string f2 in Qfiles) { tableCell = new TableCell(); tableCell.Text = f2; HyperLink hl = new HyperLink(); hl.Text = tableCell.Text; string winPath = @"C:「特定のディレクトリ」+ f + "\\" + f2; Uri u = new Uri(winPath); if (u.IsFile) { hl.NavigateUrl = winPath; tableCell.Controls.Add(hl); } tableRow.Cells.Add(tableCell); } Table1.Rows.Add(tableRow); } } }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/12/08 00:28

前のスレッド https://teratail.com/questions/57543 の続きで、前のスレッドではユーザーが選んだファイルをブラウザに表示することが目的だったが、その「ブラウザに表示する」をダウンロードすることに方向転換したということを質問の最初に書いてください。前のスレッドを最初から最後まで見ていたのは多分質問者さんと私だけです。そういう情報を追加するだけで、他の閲覧者に有益な情報を与え、質問者さんが回等を得られるチャンスが多くなると思います。それに、情報の蓄積・共有にもそうすることは意義のあることです。
ehyai

2016/12/08 09:07

アドバイスありがとうございました。SurferOnWwwさんのおっしゃる通りに情報を追加しました。
guest

回答1

0

ベストアンサー

追加情報の記載をありがとうございます。ただ、

こちらに載せております。

の「こちら」のリンク先が前のスレッド https://teratail.com/questions/57543 ではなくて、このスレッドになってしまっていますので折を見て訂正お願いします。

ダウンロードする場合でも、前のスレッドで書いたとおり、IIS のワーカープロセスにダウンロードするファイル / フォルダに対するアクセス権(読み取り権限)を与えることが必須ということは理解されているでしょうか? それは後で考えて対処するということでもいいですが、何ともならないケースもありますのであらかじめ承知しておいてください。

とりあえず、今質問にアップされているコードをできる限り利用するということで案を書いておきます。(それをお勧めするわけではないです。それをベースに改善していくということで)

(1) Default.aspx の FileUpload と Button は不要なので削除。

(2) テーブルの各行に HyperLink に代えて Button を配置し、それをクリックするとファイルをダウンロードすることにする。

(3) そのために、Default.aspx.cs のコードの foreach (string f2 in Qfiles) のループの中で、HyperLink を Button に変更し、hl.NavigateUrl = winPath; とする代わりに Button.CommandArgument プロパティに winPath を設定し、Click イベントに Button1_Click メソッドをアタッチする。

(4) Button1_Click メソッドの中身を、CommandArgument プロパティからファイルパスを取得し、HttpResponse.TransmitFile メソッドを使ってファイルをダウンロードするように全面的に書き換える。その際注意すべきは以下の通りです:

(4-1) ブラウザによってファイルの種類を判断する方法が異なるので、Content-Disposition: ヘッダと Content-Type: ヘッダの両方を正しく指定しておくようにしてください。

(4-2) TransmitFile メソッドの直後に Response.End(); を書いて強制終了させてください。推奨されていませんが、それがないと不必要な <!DOCTYPE ... で始まる html コードも送信されてしまいますので。

(4-3) ファイル名に日本語(ASCII 文字以外)を使うと文字化けするので、とりあえず使わないようにしてテストしてください。

【2016/12/9 13:45 追記】

下の私の 2016/12/09 13:18 のコメントで「回答欄に Button1_Click メソッドの実装例を追記しておきます」と書きましたが、それを以下に書きます。ファイル名はとりあえず ASCII 文字限定としてください。

protected void Button1_Click(object sender, EventArgs e) { string fpath = ((Button)sender).CommandArgument; Response.Clear(); Response.AppendHeader("Content-Disposition", "attachment; filename=" + Path.GetFileName(fpath)); Response.ContentType = "text/plain"; // C ソースのテキストファイルを想定 Response.TransmitFile(fpath); Response.End(); }

うまく行かなかったら、以下の点を確認してください。

(1) fpath に cppTable メソッドで設定した winPath が取得できているか。

(2) ワーカープロセスは fpath で指定されるファイルの読み取り権限を持っているか。(開発マシンで、Visual Studio から IIS Express を使用して動かしている場合は、質問者さんが開発マシンにログインしたアカウントの権限になるはず。まずはその条件で試してみてください)

日本語のファイル名の対応は、話が非常に長くなるので、上記でダウンロードがうまくいったらこのスレッドはクローズし、新たに別のスレッドを立てて質問するようにしてください。

推奨されていない Response.End() を避ける方法についても、新たに別のスレッドを立てて質問するようにしてください。

投稿2016/12/08 11:08

編集2016/12/09 04:48
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ehyai

2016/12/08 19:25

回答してくださってありがとうございます。SurferOnWwwさんのおっしゃる通りにコードを書こうとしましたが、躓いてしまった点が出てきたので書いておきたいと思います。具体的には、Button1_Click(object sender, EventArgs e)内のFileUpload1と書いていた部分をどのように書き直せばよいかがわからないという点と、CommandArgument プロパティからファイルパスを取得という点(foreach (string f in subFolders)の中の方だけではダメなのか)、Content-Disposition: ヘッダと Content-Type: ヘッダの指定の方法です。また、、ファイル名を日本語を使っていけないということでしたが、こちらのサイト「http://linux.ohwada.jp/modules/smartsection/item.php?itemid=516」をうまく使って、何とか日本語のファイルも扱えるようになったりしないでしょうか。またもや質問しなおすことになってしまい本当に申し訳ありませんが、SurferOnWwwさんさえよろしければ、よろしくお願いします。 以下コード----- protected void Button1_Click(object sender, EventArgs e) { // ファイルがアップロードされていなければリターン if (FileUpload1.HasFile == false) { return; }//FileUpload1を何に変えたらよいか教えてほしい // 一時ファイルに保存 string fpath = Path.GetTempFileName(); FileUpload1.SaveAs(fpath); // レスポンスを作成して返す(アップロードされたファイルをそのままダウンロード) HttpResponse resp = HttpContext.Current.Response; resp.Clear(); resp.ContentType = FileUpload1.PostedFile.ContentType; // コンテントタイプ resp.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(FileUpload1.FileName)); resp.TransmitFile(fpath); Response.End(); //強制終了 resp.Flush(); // 一時ファイルを削除 File.Delete(fpath); } public void cppTable() { //ディレクトリ内の問題フォルダの数だけ表の列を増やす IEnumerable<string> subFolders = System.IO.Directory.EnumerateDirectories(@"C:「特定のディレクトリ」, "*", System.IO.SearchOption.AllDirectories).Select(Path.GetFileName); // ファイルパスからファイル名を抽出 TableRow tableRow; TableCell tableCell; foreach (string f in subFolders) //ここで行を作っていく { tableRow = new TableRow(); tableCell = new TableCell(); tableCell.Text = f; tableRow.Cells.Add(tableCell); IEnumerable<string> Qfiles = System.IO.Directory.EnumerateFiles(@"C:「特定のディレクトリ」" + f, "*", System.IO.SearchOption.AllDirectories).Select(Path.GetFileName); foreach (string f2 in Qfiles) { tableCell = new TableCell(); tableCell.Text = f2; Button hl = new Button(); hl.Text = tableCell.Text; string winPath = @"C:「特定のディレクトリ」" + f + "\\" + f2; Uri u = new Uri(winPath); if (u.IsFile) { hl.CommandArgument = winPath; hl.Click += new EventHandler(Button1_Click); tableCell.Controls.Add(hl); } tableRow.Cells.Add(tableCell); } Table1.Rows.Add(tableRow); } } ----- Default.aspxの方は、asp:FileUploadとasp:Buttonを削除しました。
退会済みユーザー

退会済みユーザー

2016/12/09 04:18

掲示板でやり取りして解決しようとしているのですから、解答のヒントで解決できる基本的な知識が必要なのですが・・・ と言っていても始らないので、回答欄に Button1_Click メソッドの実装例を追記しておきます。
ehyai

2016/12/09 08:52 編集

実装例を教えてくださってありがとうございます!SurferOnWwwさんの書いてくれたコードを実装したら、クリックしたファイルを無事にダウンロードすることができました。あなたのおかげで自分の目的としているシステムも作れそうです。ちなみに、ダウンロードするファイルのファイル名やファイルのパスの途中のフォルダ名が日本語の状態でも試してみたら、問題なくダウンロードできました。また今回のコードに関して何か問題が発生したら、その時は別のスレッドを立てて質問したいと思います。本当にありがとうございました。なお、自分はASP.NETでのプログラミングはほんの一か月前に始めたばかりで、そのため知識もあまりなく、結果何度も質問し直すこととなり、申し訳ありませんでした。もう少し、その基本的な知識を付けられるように努力したいと思います。
退会済みユーザー

退会済みユーザー

2016/12/09 09:02

日本語のファイル名が文字化けする・しないはブラウザによります。IE は日本語のままだと文字化けするはずです。結構奥が深い問題なので軽く考えない方がいいと思います。
退会済みユーザー

退会済みユーザー

2016/12/09 09:05

あと、ワーカープロセスのアクセス権の問題も。場合によってはどうしてもアクセス権が与えられず何ともならないケースもあります。こちらも軽く考えない方がいいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問