QA@IT

ASP.NET で、Input(File) を用いて画像をアップロードしようとしたところ、posted.FileNameの箇所で「オブジェクト参照がオブジェクト インスタンスに設定されていません。」というエラーが出ます。

13466 PV

Web Developer 2010 Express で開発しています。OSはWindows8.1です。

「ファイルを選択」でJPG画像を選択すると、ブラウザ上では確かにファイル名が表示されています。
しかし、”BtnUP”ボタンを押すと、コードのposted.FileName がNothingになっており、タイトルのようなエラーが出てしまいます。
どこを見直したら良いのかの見当がつかず、難渋している次第です。
よろしくお願いいたします。

コード部分は以下のようになっております。

Public Class Upload
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    End Sub

    Protected Sub BtnUp_Click(sender As Object, e As EventArgs) Handles BtnUp.Click
        Dim posted As HttpPostedFile
        Dim SendPath As String

        posted = Request.Files("user1")
        If Not posted.FileName = "" Then
            posted.SaveAs(SendPath & "_1.JPG")
        End If
    End Sub
End Class

ソース部分は以下のようになっております。

<%@ Page Title="" Language="vb" AutoEventWireup="false" MasterPageFile="~/Site.Master" CodeBehind="Upload.aspx.vb" Inherits="WebAppJK.Upload" %>

<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server" enctype="multipart/form-data">

</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <asp:Button ID="BtnUp" runat="server" Text="Button" />


    <input id="File1" name="user1" type="file" /><br />
</asp:Content>

回答

普通の html の input type="file" ... を使った場合と、サーバーコントロール(input type="file" runat="server" ... または FileUpload)を使った場合とでは ASP.NET がレンダリングする html ソースが違ってきます。そこがうまくいかなかった原因のようです。

具体的には以下の通りです。

(1) <input id="File1" type="file" name="user1" />

上記の場合、ASP.NET がレンダリングする html ソース以下のようになります。("005-FileUpload2.aspx" は自分が検証に使ったページのファイル名です)

<form method="post" action="005-FileUpload2.aspx" id="form1">

<input id="File1" type="file" name="user1" />

ファイル選択後、Button クリックでサーバーに送信されるデータは:

user1=0_1133062.jpg

結果、サーバー側で Request.Files["user1"] を取得すると null になります。

(2) <input id="File1" type="file" name="user1" runat="server" />

上のコードの場合(runat="server" 属性を追加)、ASP.NET がレンダリングする html ソースでは、以下のように、form 要素に enctype="multipart/form-data" が追加されます。また、input type="file" ... の name 属性に設定した "user1" は "File1" に変わり、Master Page を使うと ContentPlaceHolder 名などが追加され、さらに変わって以下のようになります。

<form method="post" action="005-FileUpload2.aspx" id="form1" enctype="multipart/form-data">

<input name="ctl00$ContentPlaceHolder1$File1" type="file" id="ContentPlaceHolder1_File1" />

ファイル選択後、Button クリックでサーバーに送信されるデータは:

Content-Disposition: form-data; name="ctl00$ContentPlaceHolder1$File1"; filename="0_1133062.jpg"
Content-Type: image/jpeg

と期待した形式になりましたが、neme 属性の設定値が "user1" から "ctl00$ContentPlaceHolder1$File1" に変わってしまったので、Request.Files["user1"] では取得できません(null になる)。

Request.Files["ctl00$ContentPlaceHolder1$File1"] または Request.Files[File1.UniqueID] なら取得できますが、将来も命名規則が変わらないという保障はないでしょうから、そうすることはお勧めできません。

結局、ASP.NET Web Forms アプリを作っているなら、input type="file" ではなくて、FileUpload サーバーコントロールを使うことをお勧めします。先にも書きましたが、以下の MSDN ライブラリを見てください。サンプルコードも記載されています。

FileUpload クラス
http://msdn.microsoft.com/ja-jp/library/system.web.ui.webcontrols.fileupload(v=vs.110).aspx

編集 履歴 (0)
  • この質問でなぜrunat serverを指定したのかはわかりませんが、runat=serverを指定した場合にどうするか私の回答に追記しました。 -
  • runat="server" 属性を追加すれば ASP.NET が自動的に form 要素に enctype を設定する。ただし、それ以外にも注意するところがある。だから FileUpload がお勧めと言ったつもりですが・・・ -
  • 回答欄のように、FileUpload サーバーコントロールで書きなおしてみました。ありがとうございました。 -

書き直してみたものです。FileUpload サーバーコントロールを6個並べ、ボタンでアップロードします。
1) 起動直後のページイメージ
_.jpg
2) コード部分

Imports System.IO

Public Class Start
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Me.Form.Enctype = "multipart/form-data"

    End Sub

    Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        Dim fileName As String

        Dim SendPath As String = "C:\picture\"

        ' 0番目
        If (upfile.HasFile) Then
            fileName = upfile.FileName
            upfile.SaveAs(SendPath & "0_" & upfile.FileName)
        End If

        ' 1番目
        If (upfile1.HasFile) Then
            fileName = upfile1.FileName
            upfile1.SaveAs(SendPath & "1_" & upfile.FileName)
        End If

        ' 2番目
        If (upfile2.HasFile) Then
            fileName = upfile2.FileName
            upfile2.SaveAs(SendPath & "2_" & upfile.FileName)
        End If

        ' 3番目
        If (upfile3.HasFile) Then
            fileName = upfile3.FileName
            upfile3.SaveAs(SendPath & "3_" & upfile.FileName)
        End If

        ' 4番目
        If (upfile4.HasFile) Then
            fileName = upfile4.FileName
            upfile4.SaveAs(SendPath & "4_" & upfile.FileName)
        End If

        ' 5番目
        If (upfile5.HasFile) Then
            fileName = upfile5.FileName
            upfile5.SaveAs(SendPath & "5_" & upfile.FileName)
        End If

    End Sub

End Class

3)ソース部分

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Start.aspx.vb" Inherits="TEST.Start" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">

<head>
    <style type="text/css">
        .auto-style1 {
            width: 324px;
        }
        .auto-style2 {
            width: 323px;
        }
    </style>
</head>

<body>

    <form id="form1" runat="server" enctype="multipart/form-data">

         <asp:Button ID="Button1" runat="server" Text="Button" /> <br/> <br/> 
         <table style="width: 83%;">
             <tr>
                 <td class="auto-style1" style="vertical-align: top">


        <asp:FileUpload ID="upfile" runat="server" />
                     <br />
       <img id="thumb" width="320" style="vertical-align: top"/></td>
                 <td class="auto-style2" style="vertical-align: top">  


      <asp:FileUpload ID="upfile1" runat="server" />  
                     <br />
    <img id="thumb1" width="320"/></td>
                 <td style="vertical-align: top">  

       <asp:FileUpload ID="upfile2" runat="server" /> 
                     <br />
    <img id="thumb2" width="320"/></td>
             </tr>
             <tr>
                 <td class="auto-style1" style="vertical-align: top">  

       <asp:FileUpload ID="upfile3" runat="server" /> 
                     <br />
    <img id="thumb3" width="320"/></td>
                 <td class="auto-style2" style="vertical-align: top">  

       <asp:FileUpload ID="upfile4" runat="server" /> 
                     <br />
    <img id="thumb4" width="320"/></td>
                 <td style="vertical-align: top">  

       <asp:FileUpload ID="upfile5" runat="server" /> 
                     <br />
    <img id="thumb5" width="320"/></td>
             </tr>
             <tr>
                 <td class="auto-style1" style="vertical-align: top">&nbsp;</td>
                 <td class="auto-style2" style="vertical-align: top">&nbsp;</td>
                 <td style="vertical-align: top">&nbsp;</td>
             </tr>
         </table>



    </form> 


    <script>

        showImage(false);


 // 0番目
$("#upfile").onchange = function(evt){
    showImage(false);
    var files = evt.target.files;
    if(files.length == 0) return;
    var file = files[0];
    if(!file.type.match(/image/)) {
        alert('画像ファイルを選んでください');
        return;
    }        
    var reader = new FileReader();        
    reader.onload = function(evt) {
        $("#thumb").src = reader.result;
        showImage(true);
    }
    reader.readAsDataURL(file);
}

// 1番目
$("#upfile1").onchange = function (evt) {
    showImage(false);
    var files = evt.target.files;
    if (files.length == 0) return;
    var file = files[0];
    if (!file.type.match(/image/)) {
        alert('画像ファイルを選んでください');
        return;
    }        
    var reader = new FileReader();        
    reader.onload = function (evt) {
        $("#thumb1").src = reader.result;
        showImage(true);
    }
    reader.readAsDataURL(file);
}

// 2番目
$("#upfile2").onchange = function (evt) {
    showImage(false);
    var files = evt.target.files;
    if (files.length == 0) return;
    var file = files[0];
    if (!file.type.match(/image/)) {
        alert('画像ファイルを選んでください');
        return;
    }
    var reader = new FileReader();
    reader.onload = function (evt) {
        $("#thumb2").src = reader.result;
        showImage(true);
    }
    reader.readAsDataURL(file);
}

// 3番目
$("#upfile3").onchange = function (evt) {
    showImage(false);
    var files = evt.target.files;
    if (files.length == 0) return;
    var file = files[0];
    if (!file.type.match(/image/)) {
        alert('画像ファイルを選んでください');
        return;
    }
    var reader = new FileReader();
    reader.onload = function (evt) {
        $("#thumb3").src = reader.result;
        showImage(true);
    }
    reader.readAsDataURL(file);
}

// 4番目
$("#upfile4").onchange = function (evt) {
    showImage(false);
    var files = evt.target.files;
    if (files.length == 0) return;
    var file = files[0];
    if (!file.type.match(/image/)) {
        alert('画像ファイルを選んでください');
        return;
    }
    var reader = new FileReader();
    reader.onload = function (evt) {
        $("#thumb4").src = reader.result;
        showImage(true);
    }
    reader.readAsDataURL(file);
}

// 5番目
$("#upfile5").onchange = function (evt) {
    showImage(false);
    var files = evt.target.files;
    if (files.length == 0) return;
    var file = files[0];
    if (!file.type.match(/image/)) {
        alert('画像ファイルを選んでください');
        return;
    }
    var reader = new FileReader();
    reader.onload = function (evt) {
        $("#thumb5").src = reader.result;
        showImage(true);
    }
    reader.readAsDataURL(file);
}

// 6番目
$("#upfile6").onchange = function (evt) {
    showImage(false);
    var files = evt.target.files;
    if (files.length == 0) return;
    var file = files[0];
    if (!file.type.match(/image/)) {
        alert('画像ファイルを選んでください');
        return;
    }
    var reader = new FileReader();
    reader.onload = function (evt) {
        $("#thumb6").src = reader.result;
        showImage(true);
    }
    reader.readAsDataURL(file);
}

function showImage(b) {
    var val = b ? "block" : "none";

    $("#thumb").style.display = val;
    $("#thumb1").style.display = val;
}    
編集 履歴 (0)

マスターページを利用していますので、マスターページのFormのenctypeを設定する必要があります。

Site.MasterのFormタグに追加する手はありますが、アップロードを行わないページに対しては無意味なため、
必要なページのPage_Loadイベントで設定する方がいいでしょう。

upload.aspx.vbのPage_Loadの先頭で以下の様にしてください

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    Me.Form.EncType = "multipart/form-data"

End Sub

現在、Content1のタグ につけているenctypeは不要です。

スマホからなのでタイプミスなどあったらごめんなさい。


inputタグでrunat="server"をつけた場合

runatサーバーをつけるとname属性が変わるので…というのが他の回答についてますが、
runat="server"をつけた時は以下の様にコントロールから取れます。

File1.PostedFile.SaveAs(SendPath & "_1.JPG")

指定されたかは、PostedFileのFilenameプロパティからわかると思います。

なお、質問だとSendPathに何もセットしていませんが、SendPathも適切な値に設定して下さいね。

編集 履歴 (3)
  • 「Formのenctype」というのがキーワードになって原因がわかりました。FileUpload サーバーコントロールを使うか、input type="file" に runat="server" 属性を追加すると、マスターページであってもなくても、ASP.NET が自動的に form 要素に enctype を設定するようです。 -
  • 詳しくは別途解答欄に書きます。 -
  • 先の私の回答は、input type="file" に runat="server" 属性を追加して使うことをお勧めしているわけではなく、FileUpload を使うことをお勧めしているので、誤解のないようお願いします。 -
  • @SurferOnWww さん、了解しました。 -

ご自分の環境をもう少し詳しく書いていただけませんか?

VS と OS のバージョン以外に、ASP.NET, IIS のバージョン、ASP.NET 開発サーバー / IIS Express / IIS のどれを使っているか、使っているブラウザ・・・などです。

質問と関係ないと思われるかもしれませんが、意外なところで関係があったりしますので。

どこを見直したら良いのかの見当がつかず、難渋している次第です。

Dim posted As HttpPostedFile から posted.FileName の間まで posted には何も代入されてないから(Nothing のままだから)、タイトルのエラーが出るのです。←【訂正】失礼しました。代入されてましたね。エラーの原因は下の【追伸】を見てください。

なので、そこを見直してみましょう。HttpRequest.Files プロパティで HttpFileCollection オブジェクトを取得し、それから HttpPostedFile オブジェクトを取得してそれを posted に代入・・・というように。

それより、ASP.NET Web Forms アプリなら FileUpload サーバーコントロールを使ってはいかがですか。その方が簡単ですし。詳しくは以下の MSDN ライブラリを見てください。サンプルコードも記載されています。

FileUpload クラス
http://msdn.microsoft.com/ja-jp/library/system.web.ui.webcontrols.fileupload(v=vs.110).aspx

もし、FileUpload クラスを使えない理由があるなら、その理由を書いてください。他の案が出せるかもしれませんので。

【追伸】

HttpFileCollection オブジェクトの中に input id="File1" ... の HttpPostedFile オブジェクトが含まれるようにするには、input id="File1" ... に runat="server" 属性を追加してサーバーコントロール(HtmlInputFile)にする必要がありますのでご注意ください。←【訂正】たびたびすみません、間違ってました。【追伸2】を見てください。

【追伸2】

上の【追伸】は間違ってました。すみません。

実際にコードを書いて検証して見ましたが、input type="file" ... をサーバーコントロールにしなくても、name 属性を与えてやれば、HttpFileCollection オブジェクトの中から name 属性に設定した値を key として持つ HttpPostedFile オブジェクトとして取得できました。

質問者さんのコードは <input id="File1" name="user1" type="file" /> なので C# なら Request.Files["user1"] で当該 HttpPostedFile オブジェクトが取得できるのは確認できました。

VB.NET で Request.Files("user1") と書くと同じになるんでしたっけ? だとすると、質問者さんのケースで HttpPostedFile オブジェクトが取得できない理由は分かりません。デバッガで Files などに何が含まれるか調べてください。

編集 履歴 (3)
  • ご丁寧にありがとうございます。
    1)環境は、ASP.NET4,IISは8.0,ブラウザは(Windows8.1上の)Google Chromeと(iPad上の)Safariです。
    2) FileUpload サーバーコントロールを使わない理由は特にありません。 FileUpload サーバーコントロールも試してみます。
    -
  • デバッガで Files プロパティを見れば、user1 が含まれているかどうかすぐ分かると思いますので、それをまずやってみてはいかがでしょう? もし、デバッガの使い方が分からないなら、ググって調べると参考になる記事が多々見つかると思います。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。