none
[ASP.NET MVC3 + IIS7]IISにアプリケーションを配置した際、パスが異なってしまう RRS feed

  • 質問

  • 環境:[Windows Vista SP1, VisualStudio 2010 Pro]

    先の問題が解決しないまま、新たに質問を投げかけていることをお詫びします。

    ローカルで動いていたものをサーバーに上げるとパスが異なるため、動かなくなる問題に遭遇しています。

    例えば、MusicStoreというWebアプリケーションを開発していて、

    HomeControllerにCategoryアクションメソッドを追加、さらにそのViewを作成し、Categoryページを構築したとします。

    ここで、Categoryページへのアドレスはルーティングがデフォルトのままだとすると、

    http://localhost:54371/Home/Category みたいな感じになると思います。他のページからこのページにアクセスする場合は/Home/Categoryにリンクを張ります。

    ですが、このアプリケーションをIIS7に登録すると、http://サーバーIP/MusicStore/Home/Categoryというようにアプリケーション名が間に入ることで、

    /Home/Categoryというリンクは無効なアドレスになってしまいます(/MusicStore/Home/Categoryでアクセスできる)。

     

    この問題は、IIS7の仮想ディレクトリ機能を使ってhttp://サーバーIP/MusicStore/にhttp://サーバーIP/へのエイリアスを張れば解決できそうです。

    ですが、これではIIS7一つでアプリケーション一つしか動かせない状態になってしまいよろしくありません。

    また、Html.ActionLinkなどのヘルパーメソッドを使えば、アプリケーション名がついたアドレスが生成されるのでアクセスができるようになります。

    けど、Html.ActionLinkを使いたくない場合、また使えたとしても、Ajaxを使用していると少々都合が悪いことがあります

    (http://サーバーIP/MusicStore/Home/#Categoryとしたいところがhttp://サーバーIP/MusicStore/Home/#/MusicStore/Home/Categoryみたいなアドレスになってしまう)。

     

    この問題はどのように解決すれば良いのでしょうか?

    ローカルの設定を、サーバーに配置されることを想定して設定すればよさそうですが、設定の仕方がわかりません。できないのかもしれません。


    2011年4月7日 10:33

回答

  • jQuery の問題と、ASP.NET の問題を一緒にしないほうがよいです。jQuery を利用しないで問題になるのか、jQuery を利用したときだけ問題になっているのか、というぐらいは頑張って切り分けてほしいところです。(jQuery は ASP.NET MVC で採用されているので、jQuery の話題はそれなりに通じると思っています)

    以下はすべて jQuery の話で、ASP.NET とは無縁です。

    > ローカルで例えばhttp://localhost:54371/Homeにいるときに/Home/Categoryへのリンクをクリックした場合、
    > ×http://localhost:54371/Home/#Category
    > ○http://localhost:54371/Home/#Home/Category
    > が正しいですね。

    「正しい」というのは、NZ-00 さんが期待したとおりということでいいですか? jQuery mobile で、Ajax 経由でのリクエストを行う場合の URL は「

    最初にリクエストした URL#たどったリンクのHREF

    という URL になります。jQuery mobile を利用して http://localhost:XXX/Home でリクエストされたレスポンスから、Html.ActionLink で作成した /Home/Category へのリンクをクリックした場合の URL は http://localhost:XXX/Home#/Home/Category となるというのが jQuery mobile の標準的な挙動です。同様に、

    > http://サーバーIP/MusicStore/Home/#/MusicStore/Home/Category
    > というようなURLになってしまうのです。

    というのは、jQuery mobile としては正しい挙動です。

    > 得られるURL http://localhost:54371/Home/#Category

    という結果を得たい場合、jQuery mobile では、/Home/ において <a href="Category"> というリンクをたどればよいことになります。ただし、jQuery mobile では URL の先頭と末尾の / に意味を持たせているので、元の投稿にある

    > ローカルで例えばhttp://localhost:54371/Homeにいるときに

    という条件の場合、末尾に / がないためこのリンクを使用するとページのロードに失敗したというダイアログが表示されるはずです。これは、jQuery mobile の仕様です。また、同様の理由で標準のルーティングである {controller}/{action}/{id} において /Home/Category という URL を使用していると、同様の理由でエラーダイアログに飛ばされることが発生するため、/Home/Category/ と、/ を省略しない形でリクエストを行うようにする必要があります。

    ついでに、jQuery mobile は PC 用のフルブラウザ等でもかなりイイカンジに動いて便利ですが、URL の表示が普段隠れているようなモバイル向けなので URL が汚いのは見ないことにしたほうがよいかと思います。どうしても URL が気になるなら、/Home/ も表記しないで / だけでアクセスさせて、デフォルトコントローラのデフォルトアクションからすべてを始めるようにするとよいでしょう。

    • 回答としてマーク NZ-000 2011年4月13日 1:12
    2011年4月11日 12:15

すべての返信

  • Url.Action ヘルパー メソッドを使えばいいと思います。
    Ajax の場合ですと次の記事が参考になると思います。(Razor を使っている場合には、それ風に書き換えてみてください。)

     Using jQuery Ajax methods in ASP.NET MVC: $.get() and $.getJSON() vs. $.post() - Scott's Blog
     http://weblogs.asp.net/srkirkland/archive/2009/09/08/using-jquery-ajax-methods-in-asp-net-mvc-get-and-getjson-vs-post.aspx
    2011年4月7日 16:20
  • > ですが、これではIIS7一つでアプリケーション一つしか動かせない状態になってしまいよろしくありません。

    サブドメインを利用できるのであれば、IISの設定で複数のサイトを立ち上げ、それぞれをサブドメインに割り当てることが可能です。
    基本的にはMVCは1つのサイト内では1つのアプリケーションを動作させることを前提にしているのではないかと思っています。


    あおい情報システム株式会社 小野修司(どっとねっとふぁん)
    2011年4月8日 0:11
  • totojoさんありがとうございます。


    ヘルパーメソッドを使うと確かにアクセスできるURLは取得できるんですが、アドレスバーのURLがhttp://サーバーIP/MusicStore/Home/#/MusicStore/Home/Categoryみたいになっちゃうんですよ。これも何とかしたいと考えています。

     

    2011年4月8日 0:18
  • ヘルパー メソッドを使ったからといって、ローカルで

     http://localhost:54371/Home/#Category

    となっていたものが、IIS に上げた途端、

     http://サーバーIP/MusicStore/Home/#/MusicStore/Home/Category

    とはならないはずです。

    別のスレッドで、"%23" を "#" に置き換えるヘルパー メソッドをご紹介しましたが、これを使ったのが原因ということはありませんか?
    もしご紹介したヘルパー メソッドを使用しているようであれば、これを Url.Action に置き換えるとどうなるでしょうか?
    (ちなみに、ご紹介したヘルパー メソッドは内部で Url.Action を呼んでいますので、Url.Action を二重に呼び出さないようにご注意ください。)
    2011年4月8日 1:01
  • 小野@どっとねっとふぁんさんありがとうございます。

    >サブドメインを利用できるのであれば、IISの設定で複数のサイトを立ち上げ、それぞれをサブドメインに割り当てることが可能です。

    Webサイトを追加し、別途用意したIPアドレスを割り当てる感じでしょうか。
    なかなか厳しい手段(IPアドレスを用意することが)ですが、1サイト1アプリの構成を複数作れることで、私の期待通りの動きを実現しつつ、複数アプリが動かせるわけですね。

    >基本的にはMVCは1つのサイト内では1つのアプリケーションを動作させることを前提にしているのではないかと思っています。

    確かに何も設定せずに開発するとそのようなアプリケーションができてしまうのでそんな気もします。
    ところで、開発環境のプロジェクトの設定をいじくっていたら、

    プロジェクトのプロパティ→Web→サーバー→Visual Studio 開発サーバーを使用する→仮想パス

    にアプリケーション名を指定することで、ローカル環境でIISに登録したときと同じパスが実現できることがわかりました。

    少し期待とは違いますが、この設定を利用することでローカルとサーバー間のパス不一致は起きなくなりそうです。

    2011年4月8日 1:17
  • 申し訳ありません。少し補足と訂正をさせてください。

    ローカルで例えばhttp://localhost:54371/Homeにいるときに/Home/Categoryへのリンクをクリックした場合、
    ×http://localhost:54371/Home/#Category
    ○http://localhost:54371/Home/#Home/Category
    が正しいですね。

    あと、環境に書いていなかったのですが、jquery mobileを導入しています。

    jquery mobileを利用するとデフォルトでリンクがAjax通信で動作するようになってまして・・・。
    Ajaxを使ってと言いましたが、jquery mobileが勝手にやってるいる状態です。

    -------

    上記リンクはUrl.Actionを使って得られたパスです。

    IISに配置するとUrl.Actionで得られるパスが/MusicStore/Home/Categoryに変わります。

    ですので、
    http://サーバーIP/MusicStore/Home/#/MusicStore/Home/Category
    というようなURLになってしまうのです。

    >別のスレッドで、"%23" を "#" に置き換えるヘルパー メソッドをご紹介しましたが、これを使ったのが原因ということはありませんか?
    今回の問題はこれを導入(実は調べたいことがどんどんでてきてまだ試せてません)する前の話なので原因ではありません。


    2011年4月8日 1:46
  • やりたいことが実現できました!

    <a href="#" onclick="getCategory();">リンク</a>

    みたいにしといて以下のようなスクリプトでリンク先に飛ぶようにすれば、期待するアクションを実行しつつ、期待したURLを得ることができました。

     

    function getCategory() {
     $.ajax({
      url: '@Url.Action("Category", "Home")',
      dataType : 'html',
      success : function (data) {
       window.location.href = '#Category';
      }
     });
    }
    
    得られるURL
    http://localhost:54371/Home/#Category

    これを使えば、Url.Actionを利用しているのでサーバーとローカルでURLの不一致を気にしなくてもよくなりますが、
    一応念のため、ローカルとサーバー上でのアドレスが同じになるよう先に述べた設定を行っています。

    みなさん、ありがとうございます。


    • 回答としてマーク NZ-000 2011年4月8日 3:02
    • 編集済み NZ-000 2011年4月8日 3:03 お礼の言葉を忘れてました。
    • 回答としてマークされていない NZ-000 2011年4月8日 5:25
    2011年4月8日 3:01
  • だめだ。無理やりURLかえたらダイレクトにURLを打ち込んだ時に飛べないことがわかりました。
    それに他にもいろいろ不都合が・・・
    2011年4月8日 5:27
  • 状況がよく分かっていないのでハズレかもしれませんが・・・

    > けど、Html.ActionLinkを使いたくない場合、また使えたとしても、Ajaxを使用
    > していると少々都合が悪いことがあります

    UrlHelper.Content メソッドも使いたくない/都合が悪いのでしょうか?

    例えば、以下のようにすると、

    <a href="@Url.Content("~/Home/#Category")">リンク</a>

    開発サーバーのときは、

    <a href="/Home/#Category">リンク</a>

    IIS のときは(アプリケーションのエイリアスが MusicStore の場合)、

    <a href="/MusicStore/Home/#Category">リンク</a>

    となると思います。


    #Visual Studio 開発サーバーは使わないで、開発時点から IIS を使ったほうが、
     今回の問題のみならず、開発サーバーと IIS の違いによるいろいろなトラブル
     が避けられるので、開発環境の Vista が Professional 版以上ならそうするこ
     とをお勧めします。

    2011年4月10日 6:54
  • > ローカルの設定を、サーバーに配置されることを想定して設定すればよさそうですが、設定の仕方がわかりません。できないのかもしれません。

    仮想ディレクトリまでのパスは、プロジェクトのプロパティにあるはずです。デフォルトで "/" とだけ入っているはず。手元で確認できないのですが、Web とかのタブに、そのまんま仮想パスの設定欄があるはずです。

    (他の人が書かれていないようなので、これだけ)

    2011年4月11日 4:02
  • #Visual Studio 開発サーバーは使わないで、開発時点から IIS を使ったほうが、
     今回の問題のみならず、開発サーバーと IIS の違いによるいろいろなトラブル
     が避けられるので、開発環境の Vista が Professional 版以上ならそうするこ
     とをお勧めします。


    SP1 を当てて、IIS Express にしてしまうのもアリなんではないでしょうか。

     IIS Expressの紹介 - @IT
     http://www.atmarkit.co.jp/fdotnet/scottgublog/20100702iisexpress/iisexpress.html
    2011年4月11日 5:18
  • > Webサイトを追加し、別途用意したIPアドレスを割り当てる感じでしょうか。

    まあ、イメージはそれに近いですが。
    IISはIPアドレス毎にサイトを立てることもサポートしてくれますが、IP1つでホストヘッダー名でサイトを区別して動作する、といったこともできます。
    「サブドメインを利用できるのであれば」と記述したのはこれを念頭においています。

     


    あおい情報システム株式会社 小野修司(どっとねっとふぁん)
    2011年4月11日 5:55
  • jQuery の問題と、ASP.NET の問題を一緒にしないほうがよいです。jQuery を利用しないで問題になるのか、jQuery を利用したときだけ問題になっているのか、というぐらいは頑張って切り分けてほしいところです。(jQuery は ASP.NET MVC で採用されているので、jQuery の話題はそれなりに通じると思っています)

    以下はすべて jQuery の話で、ASP.NET とは無縁です。

    > ローカルで例えばhttp://localhost:54371/Homeにいるときに/Home/Categoryへのリンクをクリックした場合、
    > ×http://localhost:54371/Home/#Category
    > ○http://localhost:54371/Home/#Home/Category
    > が正しいですね。

    「正しい」というのは、NZ-00 さんが期待したとおりということでいいですか? jQuery mobile で、Ajax 経由でのリクエストを行う場合の URL は「

    最初にリクエストした URL#たどったリンクのHREF

    という URL になります。jQuery mobile を利用して http://localhost:XXX/Home でリクエストされたレスポンスから、Html.ActionLink で作成した /Home/Category へのリンクをクリックした場合の URL は http://localhost:XXX/Home#/Home/Category となるというのが jQuery mobile の標準的な挙動です。同様に、

    > http://サーバーIP/MusicStore/Home/#/MusicStore/Home/Category
    > というようなURLになってしまうのです。

    というのは、jQuery mobile としては正しい挙動です。

    > 得られるURL http://localhost:54371/Home/#Category

    という結果を得たい場合、jQuery mobile では、/Home/ において <a href="Category"> というリンクをたどればよいことになります。ただし、jQuery mobile では URL の先頭と末尾の / に意味を持たせているので、元の投稿にある

    > ローカルで例えばhttp://localhost:54371/Homeにいるときに

    という条件の場合、末尾に / がないためこのリンクを使用するとページのロードに失敗したというダイアログが表示されるはずです。これは、jQuery mobile の仕様です。また、同様の理由で標準のルーティングである {controller}/{action}/{id} において /Home/Category という URL を使用していると、同様の理由でエラーダイアログに飛ばされることが発生するため、/Home/Category/ と、/ を省略しない形でリクエストを行うようにする必要があります。

    ついでに、jQuery mobile は PC 用のフルブラウザ等でもかなりイイカンジに動いて便利ですが、URL の表示が普段隠れているようなモバイル向けなので URL が汚いのは見ないことにしたほうがよいかと思います。どうしても URL が気になるなら、/Home/ も表記しないで / だけでアクセスさせて、デフォルトコントローラのデフォルトアクションからすべてを始めるようにするとよいでしょう。

    • 回答としてマーク NZ-000 2011年4月13日 1:12
    2011年4月11日 12:15
  • >SuferOnWwwさん

    >開発サーバーのときは、
    ><a href="/Home/#Category">リンク</a>
    >IIS のときは(アプリケーションのエイリアスが MusicStore の場合)、
    ><a href="/MusicStore/Home/#Category">リンク</a>
    >となると思います。

    なるほどリンク先にアンカー指定を。ふむふむ。
    確かにリンク先に飛んだ際、狙い通りのURLになります。
    ただ、後出しで出した情報のjquery mobileの挙動が関係しまして
    http://localhost:54371/MusicStore/#/MusicStore/Home/#Category
    となっているようです。
    jquery mobileを使わなければうまくいくことがわかりました。
    参考なりました。



    >totojoさん
    おぉ、これは良いものですね。
    SP1はすでに当てているので(う、情報出し忘れた)すぐに試せそうです。
    まだIISを使いこなせていないので、これを機にIISをの勉強も始めたくなってきました。



    >小野@どっとねっとふぁんさん
    了解しました。



    >K.Takaokaさん
    >「正しい」というのは、NZ-00 さんが期待したとおりということでいいですか?
    誤記という意味です。

    >> http://サーバーIP/MusicStore/Home/#/MusicStore/Home/Category
    >> というようなURLになってしまうのです。

    >というのは、jQuery mobile としては正しい挙動です。

    ですね。当初は全く挙動がわからず、ローカルではうまくいくのにちくしょーくらいしか考えつかなかったので。
    その後調べた結果とK.Takaokaさんの情報を参考にだいぶすっきりしてきました。

    いろいろ情報ありがとうございます。
    2011年4月13日 1:12