チェンジセット 1639 (default、framework/trunk/WebLibrary/Sources/UI/WebControls/FileUpload.cs)
- 日時:
- 2024/02/14 3:25:54 (8ヵ月前)
- ファイル:
-
- 1個の更新
凡例:
- 未変更
- 追加
- 削除
-
framework/trunk/WebLibrary/Sources/UI/WebControls/FileUpload.cs
r1637 r1639 24 24 { 25 25 using System; 26 using System.Collections.Generic; 27 using System.Collections.ObjectModel; 26 28 using System.Collections.Specialized; 27 29 using System.ComponentModel; 30 using System.Diagnostics; 31 using System.IO; 28 32 using System.Web; 29 33 using System.Web.UI; … … 31 35 32 36 /// <summary> 33 /// ユーザーがファイルを選択してサーバーにアップロードするための 34 /// テキスト ボックス コントロールと参照ボタンを表示します。 37 /// ユーザーがファイルを選択してサーバーにアップロードするための参照ボタンを表示します。 35 38 /// </summary> 36 39 [WebDescription("Description_FileUpload")] … … 61 64 private const string ValidationGroupKey = "ValidationGroup"; 62 65 66 /// <summary> 67 /// <see cref="CachePostedFile"/> プロパティ用のキー。 68 /// </summary> 69 private const string CachePostedFileKey = "CachePostedFile"; 70 63 71 64 72 /// <summary> … … 66 74 /// </summary> 67 75 private static readonly object EventFileSelectedKey = new object(); 76 77 /// <summary> 78 /// 空の <see cref="HttpPostedFile"/> の配列。 79 /// </summary> 80 private static readonly HttpPostedFile[] EmptyPostedFiles = new HttpPostedFile[0]; 81 82 83 /// <summary> 84 /// キャッシュしたファイルのコレクション。 85 /// </summary> 86 private CachedPostedFileCollection cachedPostedFiles; 87 88 /// <summary> 89 /// ファイルの情報をクリアするかどうか。 90 /// </summary> 91 private bool clearFiles; 68 92 69 93 … … 204 228 } 205 229 230 /// <summary> 231 /// <see cref="FileUpload"/> コントロールを使用してアップロードされたファイルを 232 /// 保持し続けるかどうかを設定または取得します。 233 /// </summary> 234 /// <value> 235 /// ポストされたファイルを保持する場合は <see langword="true"/>。 236 /// それ以外の場合は <see langword="false"/>。 237 /// 既定値は <see langword="false"/>。 238 /// </value> 239 /// <remarks> 240 /// <para> 241 /// このプロパティを <see langword="true"/> に設定すると、 242 /// アップロードが行われたポストバック時にアップロードされたファイルをビューステートに保持し、 243 /// 次回のポストバック時にアップロードされたファイルの内容にアクセスできるようになります。 244 /// </para> 245 /// <para> 246 /// 保持しているファイルをクリアしたい場合は <see cref="ClearFiles"/> 247 /// メソッドを呼び出します。 248 /// </para> 249 /// </remarks> 250 [Themeable(false)] 251 [DefaultValue(false)] 252 [WebCategory("Behavior")] 253 [WebDescription("Description_CachePostedFile")] 254 public virtual bool CachePostedFile 255 { 256 get 257 { 258 return (bool)(ViewState[CachePostedFileKey] ?? false); 259 } 260 261 set 262 { 263 ViewState[CachePostedFileKey] = value; 264 } 265 } 266 267 268 /// <summary> 269 /// <see cref="FileUpload"/> コントロールを使用してアップロードされたファイルに格納されているバイトの配列を取得します。 270 /// </summary> 271 /// <value> 272 /// アップロードされたファイルに格納されていた <see cref="byte"/> 配列。 273 /// </value> 274 /// <remarks> 275 /// <see cref="CachePostedFile"/> が <see langword="true"/> の場合、 276 /// 一度格納されたファイルはポストバックを繰り返しても保持されます。 277 /// この場合、このプロパティは最後にアップロードされた時のファイルに格納されていたバイト配列を返します。 278 /// </remarks> 279 [Browsable(false)] 280 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 281 public new byte[] FileBytes 282 { 283 get 284 { 285 HttpPostedFile postedFile = PostedFile; 286 return postedFile != null 287 ? Reflections.HttpInputStream.GetAsByteArray(postedFile.InputStream) 288 : new byte[0]; 289 } 290 } 291 292 /// <summary> 293 /// <see cref="FileUpload"/> コントロールを使用してアップロードされたファイルを指す 294 /// <see cref="Stream"/> オブジェクトを取得します。 295 /// </summary> 296 /// <value> 297 /// <see cref="FileUpload"/> を使用してアップロードされたファイルを指す <see cref="Stream"/>。 298 /// </value> 299 /// <remarks> 300 /// <see cref="CachePostedFile"/> が <see langword="true"/> の場合、 301 /// 一度格納されたファイルはポストバックを繰り返しても保持されます。 302 /// この場合、このプロパティは最後にアップロードされた時のファイルを指すストリームを返します。 303 /// </remarks> 304 [Browsable(false)] 305 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 306 [DebuggerBrowsable(DebuggerBrowsableState.Never)] 307 public new Stream FileContent 308 { 309 get 310 { 311 HttpPostedFile postedFile = PostedFile; 312 return postedFile != null 313 ? postedFile.InputStream 314 : Stream.Null; 315 } 316 } 317 318 /// <summary> 319 /// ファイルが <see cref="FileUpload"/> コントロールに格納されているかどうかを示す値を取得します。 320 /// </summary> 321 /// <value> 322 /// ファイルが <see cref="FileUpload"/> コントロールに格納されている場合は <see langword="true"/>。 323 /// それ以外の場合は <see langword="false"/>。 324 /// ASP.NET の標準の実装とは異なり、空のファイルをアップロードした場合でも <see langword="true"/> を返します。 325 /// また、ファイルのストリームをクローズした後でも <see langword="true"/> を返しますが、 326 /// ファイルの長さ (<see cref="HttpPostedFile.ContentLength"/>) は <c>0</c> となります。 327 /// </value> 328 /// <remarks> 329 /// <see cref="CachePostedFile"/> が <see langword="true"/> の場合、 330 /// 一度格納されたファイルはポストバックを繰り返しても保持されます。 331 /// この場合、このプロパティは <see langword="true"/> を返します。 332 /// </remarks> 333 [Browsable(false)] 334 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 335 public new bool HasFile 336 { 337 get 338 { 339 return PostedFile != null; 340 } 341 } 342 343 /// <summary> 344 /// ファイルが <see cref="FileUpload"/> コントロールに格納されているかどうかを示す値を取得します。 345 /// </summary> 346 /// <value> 347 /// ファイルが <see cref="FileUpload"/> コントロールに格納されている場合は <see langword="true"/>。 348 /// それ以外の場合は <see langword="false"/>。 349 /// ASP.NET の標準の実装とは異なり、空のファイルをアップロードした場合でも <see langword="true"/> を返します。 350 /// また、ファイルのストリームをクローズした後でも <see langword="true"/> を返しますが、 351 /// ファイルの長さ (<see cref="HttpPostedFile.ContentLength"/>) は <c>0</c> となります。 352 /// </value> 353 /// <remarks> 354 /// <see cref="CachePostedFile"/> が <see langword="true"/> の場合、 355 /// 一度格納されたファイルはポストバックを繰り返しても保持されます。 356 /// この場合、このプロパティは <see langword="true"/> を返します。 357 /// </remarks> 358 [Browsable(false)] 359 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 360 public new bool HasFiles 361 { 362 get 363 { 364 return PostedFiles.Count > 0; 365 } 366 } 367 368 /// <summary> 369 /// <see cref="FileUpload"/> コントロールを使用してアップロードされたファイルの基になる 370 /// <see cref="HttpPostedFile"/> オブジェクトを取得します。 371 /// </summary> 372 /// <value> 373 /// <see cref="FileUpload"/> コントロールを使用してアップロードされた <see cref="HttpPostedFile"/> オブジェクト。 374 /// <see cref="HasFile"/> プロパティが <see langword="false"/> 375 /// を返す場合は <see langword="null"/>です。 376 /// </value> 377 /// <remarks> 378 /// <see cref="CachePostedFile"/> が <see langword="true"/> の場合、 379 /// 一度格納されたファイルはポストバックを繰り返しても保持されます。 380 /// この場合、このプロパティは最後にアップロードされた時のファイルを返します。 381 /// </remarks> 382 [Browsable(false)] 383 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 384 public new HttpPostedFile PostedFile 385 { 386 get 387 { 388 // クリアされている場合 389 if (clearFiles) 390 { 391 return null; 392 } 393 394 Page page = Page; 395 if (page == null || !page.IsPostBack) 396 { 397 return null; 398 } 399 400 // キャッシュされていればキャッシュから返す 401 if (cachedPostedFiles != null) 402 { 403 return cachedPostedFiles.PostedFile; 404 } 405 406 HttpPostedFile postedFile = base.PostedFile; 407 return IsValidPostedFile(postedFile) 408 ? postedFile 409 : null; 410 } 411 } 412 413 /// <summary> 414 /// <see cref="FileUpload"/> コントロールを使用してアップロードされたファイルのコレクションを取得します。 415 /// </summary> 416 /// <value> 417 /// <see cref="FileUpload"/> コントロールを使用してアップロードされたファイルのコレクション。 418 /// <see cref="HasFiles"/> プロパティが <see langword="false"/> 419 /// を返す場合は空のコレクションです。 420 /// </value> 421 /// <remarks> 422 /// <see cref="CachePostedFile"/> が <see langword="true"/> の場合、 423 /// 一度格納されたファイルはポストバックを繰り返しても保持されます。 424 /// この場合、このプロパティは最後にアップロードされた時のファイルのコレクションを返します。 425 /// </remarks> 426 [Browsable(false)] 427 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 428 public new IList<HttpPostedFile> PostedFiles 429 { 430 get 431 { 432 // クリアされている場合 433 if (clearFiles) 434 { 435 return EmptyPostedFiles; 436 } 437 438 // キャッシュされていればキャッシュから返す 439 if (cachedPostedFiles != null) 440 { 441 return cachedPostedFiles.PostedFiles; 442 } 443 444 IList<HttpPostedFile> postedFiles = base.PostedFiles; 445 return IsValidPostedFiles(postedFiles) 446 ? postedFiles 447 : EmptyPostedFiles; 448 } 449 } 450 451 452 /// <summary> 453 /// このコントロールに格納されているファイル情報を削除します。 454 /// </summary> 455 public void ClearFiles() 456 { 457 cachedPostedFiles = null; 458 clearFiles = true; 459 } 460 206 461 207 462 #region IPostBackDataHandler メンバ … … 237 492 238 493 /// <summary> 494 /// <see cref="FileUpload"/> コントロールの保存された状態を読み込みます。 495 /// </summary> 496 /// <param name="savedState"> 497 /// <see cref="FileUpload"/> の保存された状態を格納している 498 /// <see cref="object"/>。 499 /// </param> 500 protected override void LoadViewState(object savedState) 501 { 502 if (savedState == null) 503 { 504 return; 505 } 506 507 Pair state = (Pair)savedState; 508 509 // 親を呼び出す 510 base.LoadViewState(state.First); 511 512 if (state.Second != null) 513 { 514 cachedPostedFiles = CachedPostedFileCollection.CreateFromViewState(state.Second); 515 } 516 } 517 518 /// <summary> 519 /// <see cref="FileUpload"/> コントロールの状態を格納します。 520 /// </summary> 521 /// <returns> 522 /// <see cref="FileUpload"/> の保存された状態を格納しているオブジェクト。 523 /// </returns> 524 protected override object SaveViewState() 525 { 526 // 親を呼び出す 527 Pair state = new Pair 528 { 529 First = base.SaveViewState(), 530 }; 531 532 // 保持するデータが有る場合 533 if (EnsurePostedFileCache()) 534 { 535 state.Second = cachedPostedFiles.ToViewState(); 536 } 537 538 if (state.First == null && state.Second == null) 539 { 540 return null; 541 } 542 543 return state; 544 } 545 546 /// <summary> 239 547 /// コントロールのポストバック データを処理します。 240 548 /// </summary> … … 256 564 } 257 565 258 // ファイルがポストされていれば true を返す 259 HttpPostedFile postedFile = PostedFile; 260 return postedFile != null 261 && (!string.IsNullOrEmpty(postedFile.FileName) || postedFile.ContentLength > 0); 566 // ファイルがポストされていなければ false を返す 567 if (!IsValidPostedFile(base.PostedFile)) 568 { 569 return false; 570 } 571 572 // ポストされたファイルが有るのでキャッシュをクリアしてキャッシュし直す 573 cachedPostedFiles = null; 574 EnsurePostedFileCache(); 575 576 return true; 262 577 } 263 578 … … 360 675 if (page != null) 361 676 { 677 string onChange = null; 678 if (HasAttributes) 679 { 680 onChange = Attributes["onchange"]; 681 if (onChange != null) 682 { 683 onChange = ClientScriptUtility.EnsureEndWithSemiColon(onChange); 684 Attributes.Remove("onchange"); 685 } 686 } 687 688 onChange = ClientScriptUtility.MergeScript(onChange, GetOnClientChanged(), false); 689 362 690 if (AutoPostBack) 363 691 { 364 string onChange = null;365 if (HasAttributes)366 {367 onChange = Attributes["onchange"];368 if (onChange != null)369 {370 onChange = ClientScriptUtility.EnsureEndWithSemiColon(onChange);371 Attributes.Remove("onchange");372 }373 }374 375 692 PostBackOptions options = new PostBackOptions(this, string.Empty); 376 693 if (CausesValidation) … … 385 702 } 386 703 387 writer.AddAttribute( 388 HtmlTextWriterAttribute.Onchange, 389 ClientScriptUtility.MergeScript(onChange, page.ClientScript.GetPostBackEventReference(options, true), false)); 704 onChange = ClientScriptUtility.MergeScript(onChange, page.ClientScript.GetPostBackEventReference(options, true), false); 390 705 } 391 706 else 392 707 { 708 // GetPostBackEventReference を呼び出していないので登録する 393 709 page.ClientScript.RegisterForEventValidation(UniqueID, string.Empty); 710 } 711 712 if (onChange != null) 713 { 714 writer.AddAttribute(HtmlTextWriterAttribute.Onchange, onChange); 394 715 } 395 716 } … … 403 724 base.AddAttributesToRender(writer); 404 725 } 726 727 /// <summary> 728 /// クライアントサイドで実行される <c>onchange</c> イベントハンドラを取得します。 729 /// </summary> 730 /// <returns> 731 /// クライアントサイドで実行される <c>onchange</c> イベントハンドラ。 732 /// </returns> 733 protected virtual string GetOnClientChanged() 734 { 735 return null; 736 } 737 738 /// <summary> 739 /// 有効なポストされたファイルかどうかを返します。 740 /// </summary> 741 /// <param name="postedFile"><see cref="HttpPostedFile"/>。</param> 742 /// <returns> 743 /// 有効な場合は <see langword="true"/>。 744 /// それ以外の場合は <see langword="false"/>。 745 /// </returns> 746 private static bool IsValidPostedFile(HttpPostedFile postedFile) 747 { 748 return postedFile != null 749 && (!string.IsNullOrEmpty(postedFile.FileName) || postedFile.ContentLength > 0); 750 } 751 752 /// <summary> 753 /// 有効なポストされたファイルかどうかを返します。 754 /// </summary> 755 /// <param name="postedFiles"><see cref="HttpPostedFile"/> のリスト。</param> 756 /// <returns> 757 /// 有効な場合は <see langword="true"/>。 758 /// それ以外の場合は <see langword="false"/>。 759 /// </returns> 760 private static bool IsValidPostedFiles(IList<HttpPostedFile> postedFiles) 761 { 762 if (postedFiles == null) 763 { 764 return false; 765 } 766 767 // おそらく、ポストバックではない場合 768 if (postedFiles.Count == 0) 769 { 770 return true; 771 } 772 773 // 実際は未指定 (ポストされなかった場合) だった場合でも、一つデータが存在する 774 if (postedFiles.Count == 1 && !IsValidPostedFile(postedFiles[0])) 775 { 776 return false; 777 } 778 779 return true; 780 } 781 782 /// <summary> 783 /// ポストされたファイルが保持されていない場合に保持します。 784 /// </summary> 785 /// <returns> 786 /// 保持するデータがある場合は <see langword="true"/>。 787 /// それ以外の場合は <see langword="false"/>。 788 /// </returns> 789 private bool EnsurePostedFileCache() 790 { 791 // クリアされていれば保持しない 792 if (clearFiles) 793 { 794 return false; 795 } 796 797 // 保持する設定になっていない場合 798 if (!CachePostedFile) 799 { 800 return false; 801 } 802 803 // ポストバック時ではない場合は保持しない (そもそもアップロードファイルが無い) 804 Page page = Page; 805 if (page != null && !page.IsPostBack) 806 { 807 return false; 808 } 809 810 // 既に保持するデータを準備済の場合 811 if (cachedPostedFiles != null) 812 { 813 return true; 814 } 815 816 UpdatePostedFileCache(); 817 return cachedPostedFiles != null; 818 } 819 820 /// <summary> 821 /// ポストされたファイルのキャッシュ情報を更新します。 822 /// </summary> 823 private void UpdatePostedFileCache() 824 { 825 cachedPostedFiles = CachedPostedFileCollection.CreateFrom(base.PostedFiles); 826 } 827 828 829 830 /// <summary> 831 /// アップロードされたファイルの保存情報を保持するクラスです。 832 /// </summary> 833 [Serializable] 834 [DebuggerDisplay(@"\{FileName = {fileName}\}")] 835 private sealed class CachedPostedFile 836 { 837 /// <summary> 838 /// ファイル名。 839 /// </summary> 840 [DebuggerBrowsable(DebuggerBrowsableState.Never)] 841 private readonly string fileName; 842 843 /// <summary> 844 /// MIME コンテンツタイプ。 845 /// </summary> 846 [DebuggerBrowsable(DebuggerBrowsableState.Never)] 847 private readonly string contentType; 848 849 /// <summary> 850 /// ファイルの内容を表すバイト配列。 851 /// </summary> 852 /// <remarks> 853 /// ファイルが空の場合は <see langword="null"/>。 854 /// </remarks> 855 [DebuggerBrowsable(DebuggerBrowsableState.Never)] 856 private readonly byte[] contents; 857 858 859 /// <summary> 860 /// インスタンスを作成します。 861 /// </summary> 862 /// <param name="postedFile">ポストされたファイル。</param> 863 internal CachedPostedFile(HttpPostedFile postedFile) 864 { 865 fileName = Path.GetFileName(postedFile.FileName); 866 contentType = postedFile.ContentType; 867 contents = Reflections.HttpInputStream.GetAsByteArray(postedFile.InputStream); 868 } 869 870 871 /// <summary> 872 /// ファイル名を取得します。 873 /// </summary> 874 /// <value> 875 /// ファイル名。 876 /// </value> 877 internal string FileName 878 { 879 get 880 { 881 return fileName; 882 } 883 } 884 885 /// <summary> 886 /// MIME コンテンツタイプを取得します。 887 /// </summary> 888 /// <value> 889 /// MIME コンテンツタイプ。 890 /// </value> 891 internal string ContentType 892 { 893 get 894 { 895 return contentType; 896 } 897 } 898 899 /// <summary> 900 /// ファイルの内容を表すバイト配列を取得します。 901 /// </summary> 902 /// <value> 903 /// ファイルの内容を表すバイト配列。 904 /// ファイルが空の場合は <see langword="null"/>。 905 /// </value> 906 internal byte[] Contents 907 { 908 get 909 { 910 return contents; 911 } 912 } 913 } 914 915 916 917 /// <summary> 918 /// アップロードされたファイルの保存情報を保持するクラスです。 919 /// </summary> 920 [DebuggerDisplay(@"Count = {Count}")] 921 private sealed class CachedPostedFileCollection : 922 Collection<CachedPostedFile> 923 { 924 /// <summary> 925 /// このコレクションの要素を元に作成された <see cref="HttpPostedFile"/> の読み取り専用のリスト。 926 /// </summary> 927 private IList<HttpPostedFile> postedFiles; 928 929 930 /// <summary> 931 /// インスタンスを作成します。 932 /// </summary> 933 /// <param name="list"><see cref="FileUpload.CachePostedFile"/> の配列。</param> 934 private CachedPostedFileCollection(CachedPostedFile[] list) 935 : base(list) 936 { 937 Debug.Assert(list.Length > 0, "Invalid count"); 938 } 939 940 941 /// <summary> 942 /// 格納されたファイルを取得します。 943 /// </summary> 944 /// <value> 945 /// 格納されたファイル。 946 /// </value> 947 internal HttpPostedFile PostedFile 948 { 949 get 950 { 951 return PostedFiles[0]; 952 } 953 } 954 955 /// <summary> 956 /// 格納されたファイルのコレクションを取得します。 957 /// </summary> 958 /// <value> 959 /// 格納されたファイルのコレクション。 960 /// </value> 961 internal IList<HttpPostedFile> PostedFiles 962 { 963 get 964 { 965 if (postedFiles == null) 966 { 967 HttpPostedFile[] newPostedFiles = new HttpPostedFile[Count]; 968 for (int i = 0; i < Count; i++) 969 { 970 CachedPostedFile cachedPostedFile = this[i]; 971 972 // 長さが 0 のファイルの場合は Contents が null 973 byte[] contents = cachedPostedFile.Contents; 974 975 newPostedFiles[i] 976 = Reflections.HttpPostedFile.CreateInstance( 977 cachedPostedFile.FileName, 978 cachedPostedFile.ContentType, 979 Reflections.HttpInputStream.CreateInstance( 980 contents != null 981 ? Reflections.HttpRawUploadedContent.CreateInstance(contents) 982 : null, 983 0, 984 contents != null 985 ? contents.Length 986 : 0)); 987 } 988 989 postedFiles = Array.AsReadOnly(newPostedFiles); 990 } 991 992 return postedFiles; 993 } 994 } 995 996 /// <summary> 997 /// ポストされたファイルのリストからインスタンスを作成して返します。 998 /// </summary> 999 /// <param name="postedFiles">ポストされたファイルのリスト。</param> 1000 /// <returns> 1001 /// キャッシュするデータのコレクション。 1002 /// 有効なポストされたファイルが無い場合は <see langword="null"/>。 1003 /// </returns> 1004 internal static CachedPostedFileCollection CreateFrom(IList<HttpPostedFile> postedFiles) 1005 { 1006 if (postedFiles == null || postedFiles.Count == 0 || !IsValidPostedFiles(postedFiles)) 1007 { 1008 return null; 1009 } 1010 1011 CachedPostedFile[] cachedPostedFiles = new CachedPostedFile[postedFiles.Count]; 1012 for (int i = 0; i < postedFiles.Count; i++) 1013 { 1014 cachedPostedFiles[i] = new CachedPostedFile(postedFiles[i]); 1015 } 1016 1017 return new CachedPostedFileCollection(cachedPostedFiles); 1018 } 1019 1020 /// <summary> 1021 /// ビューステートに保存したデータからインスタンスを作成します。 1022 /// </summary> 1023 /// <param name="viewState">ビューステート。</param> 1024 /// <returns> 1025 /// <paramref name="viewState"/> を元に作成したインスタンス。 1026 /// </returns> 1027 internal static CachedPostedFileCollection CreateFromViewState(object viewState) 1028 { 1029 return new CachedPostedFileCollection((CachedPostedFile[])viewState); 1030 } 1031 1032 /// <summary> 1033 /// ビューステートに保存するデータを取得します。 1034 /// </summary> 1035 /// <returns> 1036 /// ビューステートに保存するデータ。 1037 /// </returns> 1038 internal object ToViewState() 1039 { 1040 // 実体は配列 (コンストラクタで渡した配列) 1041 return Items; 1042 } 1043 } 405 1044 } 406 1045 }
※ 詳しい使い方は
TracChangeset を参照してください。