ASP.NET MVC-コントローラーからApp_Dataフォルダーへの絶対パスを見つける


282

ASP.NET MVCプロジェクトのコントローラーからApp_Dataフォルダーへの絶対パスを見つける正しい方法は何ですか?一時的に.xmlファイルを操作できるようにしたいのですが、パスをハードコーディングしたくありません。

これは動作しません:

[HandleError]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        string path = VirtualPathUtility.ToAbsolute("~/App_Data/somedata.xml");

        //.... do whatever 

        return View();
    }

}

Webコンテキスト外ではVirtualPathUtility.ToAbsolute()が機能しないと思います。文字列パスは「C:\ App_Data \ somedata.xml」として返されます

MVCアプリで.xmlファイルのパスをどこに決定すればよいですか?global.asaxをアプリケーションレベルの変数に貼り付けますか?


私は懸念とテスト容易性の分離の意味で推測します-VirtualPathUtility.ToAbsolute()は動作しないはずです。しかし、これを行う正しい方法は何ですか?
BuddyJoe 2009

回答:


398

ASP.NET MVC1-> MVC3

string path = HttpContext.Current.Server.MapPath("~/App_Data/somedata.xml");

ASP.NET MVC4

string path = Server.MapPath("~/App_Data/somedata.xml");


MSDNリファレンス:

HttpServerUtility.MapPathメソッド


6
@Cleiton Url.ContentがサーバーパスではなくURLを提供することを除いて。
アンドリューダンクマン、2012

8
mvc4の場合はServer.MapPath()のみです
SeriousM

6
MVC4の方法は機能しませんでした。使用するCurrentServer.MapPath(...)、SeriousMで述べたように。
グリゴラン2013年

26
使用System.Web.Hosting.HostingEnvironment.MapPath()
Vince Panuccio 2013

1
HttpContext.Currentの呼び出しが、HttpContextがない状況(application_startなど)で機能しない
mcintyre321

274
string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();

これはおそらく、より正確な方法です。


25
「App_Data」文字列をハードコーディングしていないためです。これは、将来のバージョンで変更される場合や、Monoなどで異なる場合があります
Alex

19
この答えのいいところは、system.web 参照せずに Modelプロジェクトで使用できるため、明確な分離を維持できることです。良いですね!
フランス、

10
ブログの記事ピートは、これを使用することがなぜ良い考えではないのかについても言及しています。
アンディ

13
MSDNに記載されていないため、使用しないでください。
Alexander Abramov 2012

10
「App_Data」の代わりに別の文字列をハードコーディングすることは「正しい」方法ではありません。また、.NET Coreにはアプリドメインがありません。
UserControl 2015

139

WCFサービスのコンテキスト内でも機能するので、HostingEnvironment代わりにを使用する習慣をつけようとしてServerいます。

 HostingEnvironment.MapPath(@"~/App_Data/PriceModels.xml");

6
Server.MapPathの()は、最終的HostingEnvironment.MapPath()を呼び出し、参照stackoverflow.com/questions/944219/...
トッド

3
これはコントローラーの外でも使用できるので、私のお気に入りです。System.Web.Hosting誰かが関連を知る必要がある場合に備えて、これは名前空間にありますusing。参考:docs.microsoft.com/en-us/dotnet/api/...
MDMower

7

最も正しい方法はを使用することHttpContext.Current.Server.MapPath("~/App_Data");です。これは、HttpContextが利用可能なメソッドからのみパスを取得できることを意味します。それは理にかなっています:App_DataディレクトリはWebプロジェクトのフォルダー構造です[1]。

にアクセスできないクラスから〜/ App_Dataへのパスが必要な場合はHttpContext、IoCコンテナーを使用してプロバイダーインターフェイスをいつでも注入できます。

public interface IAppDataPathProvider
{
    string GetAppDataPath();
}

あなたを使ってそれを実装するHttpApplication

public class AppDataPathProvider : IAppDataPathProvider
{
    public string GetAppDataPath()
    {
        return MyHttpApplication.GetAppDataPath();
    }
}

どこにあるかMyHttpApplication.GetAppDataPath

public class MyHttpApplication : HttpApplication
{
    // of course you can fetch&store the value at Application_Start
    public static string GetAppDataPath()
    {
        return HttpContext.Current.Server.MapPath("~/App_Data");
    }
}

[1] http://msdn.microsoft.com/en-us/library/ex526337%28v=vs.100%29.aspx


どのように静的な可能性がありHttpContext.Current、これまでありません IoCコンテナを経由して- -別の場所にあなたがそれを使用している場合は、1つの場所で利用できるように?静的プロパティはどこで利用できませんか?
M.ミンペン、2015年

Webプロジェクトでのみ使用できます。これはあなたの質問に答えますか?完全に理解しているのかわかりません。今日、私はこの(確かに単純な)問題を少し違って解決したかもしれません。私はおそらく同じプロバイダーインターフェイスを使用したでしょうが、アプリケーションルートパスを使用してApplication_Startで設定しました。
DanielLidström2015年

いいえ、HttpContext.CurrentはWebプロジェクトでのみ使用できるわけではありません... GetAppDataPath()を持つプロジェクトを参照する場合は、常にHttpContext.Currentも参照する必要があります。あなたはライブラリBを使用して、ライブラリAを使用している場合つまり、あなたのアプリケーションがライブラリAへの参照が必要になります B.
M. Mimpen

間接的なレベルを経由する代わりに、HttpContextに直接アクセスしない方が便利な場合があります。たとえば、単体テストを考えてみてください。私がこのように物事を行う理由は、通常、テスト容易性です。しかし、私はあなたの発言に関してあなたは正しくないと思います。インターフェイスのみをアセンブリ間で共有する必要があります。これが、テスト用にモックできる理由です。つまり、テストにHttpContext.Currentは必要ありません。混乱を招く場合は申し訳ありません...
DanielLidström

6

Phil Haakの例では、クレイジーな「\」スタイルのディレクトリセパレータを使用したパスを処理するときに少し安定していると思います。また、パスの連結も安全に処理します。System.IOで無料で提供されます

var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);

ただし、「Server.MapPath」の代わりに「AppDomain.CurrentDomain.BaseDirector」を試すこともできます。


4
string filePath = HttpContext.Current.Server.MapPath("~/folderName/filename.extension");

または

string filePath = HttpContext.Server.MapPath("~/folderName/filename.extension");

1
このコードは問題の解決に役立つ可能性がありますが、なぜまたはどのように質問に回答するかに関する追加のコンテキストを提供すると、長期的な価値が大幅に向上します。回答を編集して説明を追加してください。
oɔɯǝɹ

1
string Index = i;
            string FileName = "Mutton" + Index + ".xml";
            XmlDocument xmlDoc = new XmlDocument();

            var path = Path.Combine(Server.MapPath("~/Content/FilesXML"), FileName);
            xmlDoc.Load(path); // Can use xmlDoc.LoadXml(YourString);

これは、今まさに必要なパスを取得するための最良のソリューションです

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.