web-dev-qa-db-ja.com

ASP.NET MVCコントローラーパラメーターはオプションです(つまり、Index(int?id))

次のシナリオがあります。私のWebサイトに記事が表示されます(ブログのように管理者が入力します)。

したがって、記事を表示するには、ユーザーはHome/Articles/{記事ID}を参照します。

ただし、ユーザーはjsTreeリストを使用して、Articles.aspxビュー自体から表示する記事を選択します。

したがって、私がする必要があるのは、ユーザーが特定の記事にアクセスしている場合と、単に「メイン」の記事ページにアクセスしようとしている場合の2つのケースを区別できるようにすることです。 「Articles」コントローラーパラメーターをオプション(int?id)として設定しようとしましたが、コントローラー内でid値を「使用」する際に問題が発生します。

このシナリオを処理するための最適な方法は何ですか?おそらく、idパラメータが「url」で指定されているかどうかをチェックするためのより良いロジックが必要ですか?

単にコードの重複の理由から、2つのビュー/コントローラーの使用を避けようとしています。

9
Tom Teman

次のような個別のアクションを使用します。

public ActionResult Articles() ...
public ActionResult Article(int id) ...

または、Articlesコントローラーに移動します(デフォルトルートを使用するURLはArticlesおよびArticles/Detail/{id}):

public class ArticlesController : Controller
{
    public ActionResult Index() ...
    public ActionResult Detail(int id) ...
}

それでも投稿したとおりに使用する必要がある場合は、次のいずれかを試してください。

public ActionResult Articles(int id = 0)
{
     if(id == 0) {
         return View(GetArticlesSummaries());
     }
     return View("Article", GetArticle(id));
}
public ActionResult Articles(int? id)
{
     if(id == null) {
         return View(GetArticlesSummaries());
     }
     return View("Article", GetArticle(id.Value));
}
14
eglasius

まず第一に、私は@Steveに同意します:)。しかし、本当に使いたいのなら

int? id

単純なものを使用してIDが設定されている場合は、コントローラーメソッドをチェックインするだけです。

if(id == null)

その場合は、DB(または同様のもの)からすべての記事をロードし、それらをビューに渡します(直接、またはビューモデルを使用して)。 IDが設定されている場合は、そのIDを持つ記事をDBからロードし、それをビューに送信します(ビューモデルを使用しない場合は、リストに含めることもできます)。

ビュー内よりも、ビューに提供された記事とともにリスト内のすべての記事をロードするだけです。すべてまたは1つだけが含まれています。

完全なダミーコード

public ActionResult showArticles(int? id){
   List<Articles> aList;
   if(id == null){
       aList = repository.GetAllArticles().ToList();
   }else{
      aList = new List<Articles>(); 
      aList.add(repository.GetArticleByID(id));
   }

   return View(aList);
}

ビューには次のようなものがあります。

<% Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
Inherits="System.Web.Mvc.ViewPage<List<Articles>>"%>

foreach(Articles a in Model)
    //display article

そして、次の2つのオプションのいずれかを使用して呼び出します。

html.ActionLink("one article","showArticles","Articles",new {id = aID},null}

html.ActionLink("all articles","showArticles","Articles"}
7
bastijn

値が指定されていないことを示していることがわかっているIDのデフォルト値(通常は0)を定義します。

public ActionResult Articles([DefaultValue(0)]int Id)
{
  if (Id == 0)
    // show all
  else
    // show selected
..
5
Clicktricity

最も簡単な解決策は、2つの異なるアクションとビューを用意し、アクションに同じ名前を付けることです。

public ViewResult Articles()
{
   //get main page view model
   return View("MainPage", model);
}

public ViewResult Articles(int id)
{
   // get article view model
   return View(model);
}
2
Ryan

これを試したかどうかはわかりませんが、URLに直接値を入力している場合は、次のように渡すのではなく、次のようにします。

コントローラ/アクション/ idValue

このように渡してみてください:

コントローラー/アクション?id = value

1
Kenchi

これは私には2つの別々のページのように聞こえるので、そのように扱う必要があります。 「メイン」ビューページと「記事」ページがあります。

私はそれを2つのアクションに分割します。それらは実際にはまったく重複してはいけません。両方が同じModelViewを取得するために呼び出しを行う必要があり、記事は単にその拡張機能を取得します。

1
Steve

パラメータを必須にしてから、ルーティングにデフォルト値を設定します。これは、有効なインデックスではなく、アクションにmainページをレンダリングする必要があることを示します。

0
Lazarus

さて、これは私が使用している組み合わせソリューションです:

DefaultValueで同じコントローラーを使用する:

public ActionResult Articles([DefaultValue(0)]int id)

DefaultValueが使用された場合、「MainArticles」ビューを参照します。記事IDが提供された場合-ViewModel内に適切な記事が渡された「Articles」ビューを参照します。

どちらの場合も、ViewModelには、両方のビューに必要なデータ(完全な記事とカテゴリのリスト)が入力されます。

皆さんの助けに感謝します!

0
Tom Teman