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

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

ただいまの
回答率

90.38%

  • C#

    9478questions

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

  • Visual Studio

    2503questions

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

  • ASP.NET

    635questions

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

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

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,487

ehyai

score 35

初めに

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);

        }

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • SurferOnWww

    2016/12/08 09:28

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

    キャンセル

  • ehyai

    2016/12/08 18:07

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

    キャンセル

回答 1

checkベストアンサー

+1

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

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

の「こちら」のリンク先が前のスレッド 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/09 17:50 編集

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

    キャンセル

  • 2016/12/09 18:02

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

    キャンセル

  • 2016/12/09 18:05

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

    キャンセル

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

  • ただいまの回答率 90.38%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C#

    9478questions

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

  • Visual Studio

    2503questions

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

  • ASP.NET

    635questions

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

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