スレッドまたはタイマーで HttpServerUtility.MapPath メソッドにアクセスするにはどうすればよいですか?
-
02-07-2019 - |
質問
私は System.Timers.Timer
私のAsp.Netアプリケーションでは、 HttpServerUtility.MapPath
経由でのみ利用できると思われる方法 HttpContext.Current.Server.MapPath
。問題はそれです HttpContext.Current
は null
いつ Timer.Elapsed
イベント火災。
HttpServerUtility オブジェクトへの参照を取得する別の方法はありますか?それをクラスのコンストラクターに注入できます。安全ですか?現在のリクエストの終了時にガベージ コレクトされないことを確認するにはどうすればよいですか?
ありがとう!
解決
使用可能です HostingEnvironment.MapPath()
の代わりに HttpContext.Current.Server.MapPath()
ただし、スレッドまたはタイマーイベントではまだ試していません。
私が検討したいくつかの(実行不可能な)解決策。
私が気にしている唯一の方法
HttpServerUtility
はMapPath
. 。したがって、代わりに使用できますAppDomain.CurrentDomain.BaseDirectory
そしてそこから自分の道を構築していきます。 ただし、アプリが仮想ディレクトリを使用している場合、これは失敗します。 (私のものはそうです)。別のアプローチ:必要なすべてのパスを
Global
クラス。これらのパスを解決するには、Application_Start
.
他のヒント
これで仮想ディレクトリの問題が解決するかどうかはわかりませんが、MapPath にはこれを使用します。
public static string MapPath(string path)
{
if (HttpContext.Current != null)
return HttpContext.Current.Server.MapPath(path);
return HttpRuntime.AppDomainAppPath + path.Replace("~", string.Empty).Replace('/', '\\');
}
HostingEnvironment は、モックするのが非常に難しいクラスであるため、完璧なソリューションではありません (「 HostingEnvironment.MapPath を使用するコードを単体テストする方法).
テスト容易性が必要な人にとって、より良い方法は、によって提案されているように独自のパスマッパー インターフェイスを作成することかもしれません。 https://stackoverflow.com/a/1231962/85196, として実装する場合を除いて、
public class ServerPathMapper : IPathMapper {
public string MapPath(string relativePath) {
return HostingEnvironment.MapPath(relativePath);
}
}
結果は簡単にモック化でき、内部で HostingEnvironment を使用し、潜在的に問題に対処することもできます。 ase69s の懸念 同時に。
タイマーを開始する前に MapPath 関数を呼び出して、結果を単純にキャッシュすることはできませんか?ティックイベント内で MapPath 呼び出しを行うことは絶対に必要ですか?
タイマーが経過すると、現在の HTTP コンテキストは存在しません。これは、タイマー イベントが特定の HTTP リクエストに関連していないためです。
HTTP コンテキストが利用可能な HttpServerUtility.MapPath を使用する必要があります。これは、要求パイプライン イベント (Page_Load など) の 1 つ、または Application_Start などの Global.asax イベントで行うことができます。
MapPath の結果を Timer.Elapsed イベントからアクセスできる変数に割り当てます。ここで、Path.Combine を使用して、必要な特定のファイルの場所を取得できます。
この時点で null になる理由は (よく考えてみると)、タイマー経過イベントが HTTP リクエストの一部として発生しない (したがってコンテキストがない) ためだと思います。サーバー上の何かが原因で発生します。