by WebSurfer
2016年6月12日 15:27
以下は Internet Exploler (IE) に限った話ですのでご注意ください。
IE でファイルをダウンロードする際、応答ヘッダに Content-Type のみが指定されていて、Content-Disposition が指定されてない場合、ファイルの拡張子はどうなるかという話を書きます。
簡単に言うと、Microsoft の Support の記事「ファイルのダウンロードダイアログで表示されるファイル名の命名規則」の「詳細」のセクションの 2 に書いてありますように、レジストリの HKEY_CLASS_ROOT\MIME\Database\Content Type の設定によります。
具体例を書くと以下の通りです。
上の画像はレジストリの Content Type が image/tiff の拡張子の設定です。自分の開発マシン(Vista SP2 32-bit)ではデフォルトで Extension のデータは .tif になっていました。
開発マシンのローカル IIS7 に設定した images フォルダに、内容は全く同じで拡張子のみ .tiff と .tif と異なる 2 つの tiff 画像ファイルを作り、以下のように a 要素で直リンクします。それをブラウザに表示してリンクをクリックするとどうなるでしょうか?
<a href="/images/tiffdocument.tiff">tiffdocument.tiff</a>
<a href="/images/tiffdocument.tif">tiffdocument.tif</a>
実際に 2 つのファイルの拡張子は .tiff / .tif と異なるのですが、IIS7 がそれらの画像を取得してダウンロードする際、応答ヘッダに含まれる Content-Type はいずれの場合も image/tiff と設定します。(注:image/tif では IE が認識できません)
Content Type: image/tiff を受信した IE のあるクライアント PC のレジストリ設定は、上の画像が示すように image/tiff の Extension のデータが .tif となっているので、ダウンロードされた画像ファイルの名前.拡張子はどちらのリンクも tiffdocument.tif になります。
ちなみに、上の画像のレジストリの Extension のデータ .tif を .tiff に変更すると、ダウンロードされたファイルの拡張子は .tiff になります。
ダウンロードされたファイルのファイル名.拡張子を実際のファイルの通りにするには、サーバー側で Content-Disposition ヘッダでファイル名.拡張子をきちんと指定すれば、IE の場合は指定したとおりになります。
ただし、先の記事「ダウンロードの際の拡張子 と MIME Type の指定」に書きましたように、Content-Type の方を優先するブラウザもあります。
なので、ダウンロードするための HTTP ハンドラ等を作る際は、Content-Type と Content-Disposition の両方を正しく設定するように注意した方がよさそうです。
なお、プログラムで Content-Type を設定する際は image/tif ではなくて image/tiff としないと IE は認識しませんので注意してください。image/jpg も同様にダメで image/jpeg としないと IE は認識しません。
by WebSurfer
2016年6月4日 15:12
パラメータ化クエリを使用するというセキュリティ対策として普通にやるべきことをやっていれば、照合順序の違いによる文字化けに悩むことはなさそうという話を書きます。
元は MSDN Forum の「nvarcharに日本語を入力すると?????????になる」という表題のスレッドでの話です。
上の MSDN Forum のスレッドの問題は、簡単に書くと、SQL Azure の照合順序のデフォルトは SQL_Latin1_General_CP1_CI_AS となっていて、それに例えば以下のように 'あいうえお' というように N プレフィックスをつけないリテラルを INSERT すると文字化けするという話です。
INSERT INTO [Table] ([Name]) VALUES ('あいうえお')
(何故文字化けするかは MSDN Blog の記事「Unicode型列(NCHAR/NVARCHAR) に格納されるデータが “?” になる」に説明されていますので、そちらを見てください。手抜きでスミマセン)
クエリをパラメータ化して ADO.NET + SqlClient 経由で INSERT, UPDATE をかければ、照合順序が Japanese_CI_AS(デフォルト)でも SQL_Latin1_General_CP1_CI_AS(SQL Azure のデフォルトらしい)でも文字化けはしません。
パラメータ化あり / なしでどう違うかの例を以下に書きます。
まず、サンプルとして SQL Server 2008 Express に照合順序が SQL_Latin1_General_CP1_CI_AS のデータベースを作りました。以下の画像の通りです。
それに以下のコードで INSERT してみます。上のクエリがパラメータ化なし、下のクエリがパラメータ化ありです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
string connString = @"接続文字列";
using(SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
string query =
"INSERT INTO [Table] ([Name]) VALUES ('あいうえお')";
using(SqlCommand cmd = new SqlCommand(query, conn))
{
cmd.ExecuteNonQuery();
}
query ="INSERT INTO [Table] ([Name]) VALUES (@Name)";
using(SqlCommand cmd = new SqlCommand(query, conn))
{
cmd.Parameters.Add(
new SqlParameter("@Name", SqlDbType.NVarChar, 50));
cmd.Parameters["@Name"].Value = "かきくけこ";
cmd.ExecuteNonQuery();
}
}
}
}
}
結果は以下の通りです。赤枠で囲ったものがパラメータ化なし、青枠で囲ったものがパラメータ化ありです。
何故パラメータ化クエリを使うと文字化けの問題がなくなるのかと言うと、TechNet の記事「第 4 回 アドホック クエリのパラメータ化」の下の方に書いてあるように "SqlParameter クラスを利用すると、内部的には sp_executesql に変換されて実行されるようになり"、 その際以下のように N プレフィックスが付与されるからです。
exec sp_executesql
N'INSERT INTO [Table] ([Name]) VALUES (@Name)',
N'@Name nvarchar(5)',
@Name=N'かきくけこ'
というわけで、クエリをパラメータ化して ADO.NET + SqlClient を使えば(普通のやり方をしていれば)、照合順序の違いによって文字化けに悩むことはなさそうです。
by WebSurfer
2016年5月10日 17:03
Roslyn というのは Visual Studio 2015 に採用された次世代コンパイラだそうです。
ASP.NET Web アプリの場合 Web サーバーで動的にコンパイルが行われるので Roslyn の採用によってそれがうまく行かないケース(例: Trust Level が Medium のホスティングサービスを利用している)があるということを書きます。
元は MSDN Forum の「ASP.NET MVCのサイトがサーバーで実行できない問題」という表題のスレッドでの話です。
Visual Studio のデフォルト設定では、先の記事「コンパイル済みアセンブリの保存場所」で書きましたように、Web サイトプロジェクトでは全てのファイルを、Web アプリケーションプロジェクトでも一部のファイルをサーバーで動的にアセンブリにコンパイルします。
上に紹介した MSDN Forum の記事は Roslyn を使って Web サーバーで動的にコンパイルするところで問題が出たという話です。要約すると以下の通りです。
-
VS2015 で ASP.NET MVC 5 の Web アプリケーションプロジェクトを新規作成。
-
Roslyn コンパイラ関係の NuGet が 2 つ自動的にインストールされる。
Microsoft.CodeDom.Providers.DotNetCompilerPlatform
Microsoft.Net.Compilers
-
その際、Web アプリの bin フォルダに roslyn というサブフォルダが生成され、その中に csc.exe という Roslyn コンパイラが配置される。
-
さらに Web アプリの web.config に <system.codedom> 要素が生成され、サーバー側での動的コンパイルに上記 3 の Roslyn コンパイラを使うよう設定される。(注:ASP.NET MVC の場合は View を動的にコンパイルします)
-
記事を書いた人の運用サーバーでは上記 3 のコンパイラの実行権限がなく View のコンパイルに失敗する。
-
NuGet をアンインストールすれば上記 4 の設定がなくなって上記 3 のコンパイラを使わないので問題が起きない。(C:\Windows\Microsoft.NET\Framework\v4.0.30319 フォルダの csc.exe を使うと思われます・・・が未確認です)
対症療法的な解決策は上に書いた NuGet 2 つをアンインストールして Roslyn コンパイラを使わないということですが、Roslyn を使う場合は以下のいずれかの対応を取ることになります。
-
Visual Studio 側で View を含めて全てのファイルをコンパイルしてアセンブリを作成しそれをデプロイする。サーバー側での動的コンパイルは不要にする。または、
-
IIS で当該アプリをホストとしているワーカープロセスに bin/roslyn フォルダの csc.exe の実行権限を与える。
上記 1 ですが、Visual Studio のデフォルトではサーバー側でコンパイルする設定になっていますのでその変更が必要です。具体的には、MSDN ライブラリの記事 Advanced Precompile Settings Dialog Box の画像にあるように [Allow precompiled site to be updatable] にデフォルトでチェックが入っていますので、そのチェックを外します。
ただし、そうするとサーバーにデプロイした後で、View のみ(ASP.NET Web Forms アプリの場合は.aspx, .ascx のみ)差し替えるということができなくなってしまいます。(View をちょっとだけ変更しても、開発環境で全ファイルを再コンパイルして再発行することになります)
それが気に入らない場合は上記 2 の方法を取るということになりますが、そもそもが Web サーバーで .exe ファイルの実行が制限されていることからこの問題にぶつかることが多いようですので、難しいかもしれません。