6

設定:

メニューを管理するためにmvcSiteMapProviderでASP.NETMVC4を使用しています。

ノードが現在のブランチにあるかどうかを評価するカスタムメニュービルダーがあります(つまり、SiteMap.CurrentNodeがCurrentNodeであるか、CurrentNodeがその下にネストされているかどうか)。コードは以下に含まれていますが、基本的に各ノードのURLをチェックし、現在のノードの「家系図」まで、現在のノードのURLと比較します。

CurrentBranchは、カスタムメニュービルダーによって、CurrentBranchのメニュー項目を強調表示するクラスを追加するために使用されます。

問題:

私のカスタムメニューは正常に機能しますが、が一貫した方法でのmvcSiteMapProviderを評価していないようです。urlCurrentNode

2つのノードが同じアクションを指し、アクションのパラメーターによってのみ区別される場合、SiteMap.CurrentNodeは正しいルートを使用していないようです(区別パラメーターを無視し、デフォルトでで定義されたアクションにマップする最初のルートになります)ノード)。

問題の例:

アプリで私は持っていMembersます。

メンバーには、MemberStatus「未処理」、「アクティブ」、または「非アクティブ」のフィールドがあります。MemberStatusを変更するために、私はProcessMemberControllerAdminというエリアにいます。処理は、のProcessアクションを使用して実行されProcessMemberControllerます。

私のmvcSiteMapには、両方がProcessアクションにマップする2つのノードがあります。それらの唯一の違いはalternateパラメーター(私のクライアントのドメインセマンティクスなど)であり、ある場合には「処理済み」の値を持ち、他の場合には「未処理」の値を持ちます。

ノード:

    <mvcSiteMapNode title="Process" area="Admin" controller="ProcessMembers" action="Process" alternate="Unprocessed" />
    <mvcSiteMapNode title="Change Status" area="Admin" controller="ProcessMembers" action="Process" alternate="Processed" />

ルート:

これらの2つのノードへの対応するルートは次のとおりです(ここでも、それらを区別する唯一のものは代替パラメーターの値です)。

context.MapRoute(
                    "Process_New_Members",
                    "Admin/Unprocessed/Process/{MemberId}",
                    new { controller = "ProcessMembers", 
                        action = "Process", 
                        alternate="Unprocessed", 
                        MemberId = UrlParameter.Optional }
                );


context.MapRoute(
                    "Change_Status_Old_Members",
                    "Admin/Members/Status/Change/{MemberId}",
                    new { controller = "ProcessMembers", 
                        action = "Process", 
                        alternate="Processed", 
                        MemberId = UrlParameter.Optional }
                );

何が機能するか:

Html.ActionLinkヘルパーはルートを使用し、期待するURLを生成します。

@Html.ActionLink("Process", MVC.Admin.ProcessMembers.Process(item.MemberId, "Unprocessed")

// Output (alternate="Unprocessed" and item.MemberId = 12):   Admin/Unprocessed/Process/12


@Html.ActionLink("Status", MVC.Admin.ProcessMembers.Process(item.MemberId, "Processed")

// Output (alternate="Processed" and item.MemberId = 23):   Admin/Members/Status/Change/23

どちらの場合も、出力は正しく、私が期待しているとおりです。

動作しないもの:

私のリクエストに2番目のオプション、つまり、/Admin/Members/Status/Change/47alternate="Processed"と47のMemberIdに対応するオプションが含まれているとします。

静的なCurrentBranchプロパティ(以下を参照)をデバッグすると、SiteMap.CurrentNodeは次のように表示されます。

PreviousSibling: null
Provider: {MvcSiteMapProvider.DefaultSiteMapProvider}
ReadOnly: false
ResourceKey: ""
Roles: Count = 0
RootNode: {Home}
Title: "Process"
Url: "/Admin/Unprocessed/Process/47"

つまり、リクエストURLが/ Admin / Members / Status / Change / 47の場合、はにSiteMap.CurrentNode.Url評価され/Admin/Unprocessed/Process/47ます。つまり、alternateパラメータを無視し、間違ったルートを使用しています。

CurrentBranch静的プロパティ:

/// <summary>
        /// ReadOnly. Gets the Branch of the Site Map that holds the SiteMap.CurrentNode
        /// </summary>
        public static List<SiteMapNode> CurrentBranch
        {
            get
            {
                List<SiteMapNode> currentBranch = null;
                if (currentBranch == null)
                {
                    SiteMapNode cn = SiteMap.CurrentNode;
                    SiteMapNode n = cn;
                    List<SiteMapNode> ln = new List<SiteMapNode>();
                    if (cn != null)
                    {
                        while (n != null && n.Url != SiteMap.RootNode.Url)
                        {
                            // I don't need to check for n.ParentNode == null
                            // because cn != null && n != SiteMap.RootNode
                            ln.Add(n);
                            n = n.ParentNode;
                        }
                        // the while loop excludes the root node, so add it here
                        // I could add n, that should now be equal to SiteMap.RootNode, but this is clearer
                        ln.Add(SiteMap.RootNode);

                        // The nodes were added in reverse order, from the CurrentNode up, so reverse them.
                        ln.Reverse();
                    }
                    currentBranch = ln;
                }
                return currentBranch;
            }
        }

質問:

私は何が間違っているのですか?

ルートは、期待どおりにHtml.ActionLlinkによって解釈されますが、期待どおりにSiteMap.CurrentNodeによって評価されません。つまり、ルートを評価する際に、SiteMap.CurrentNodeは識別可能な代替パラメーターを無視します。

4

4 に答える 4

3

パラメータからルートを取得しようとしているためだと思います。基本的に、MVCはあなたが参照している可能性のあるルートを推測しようとしているだけです。

正しい方法は、名前でルートを処理することです。したがって、サイトマップは、コントローラ、アクションなどではなく、ルート名を参照する必要があります。

于 2012-10-08T09:30:54.520 に答える
2

補遺-私はそれを機能させることができました!!:

大きなつまずき:

異なるルートを使用して同じコントローラーアクションを指す場合、1つが異なるノードを持つようにすると、私が抱えていた大きな問題は次のとおりでした。

異なるノードにキーを与える必要があります!!! それ以外の場合、SITEMAPはレンダリングされません!!

たとえば、ルート属性だけでは不十分であり、同じアクションを指す各ノードに一意のキーを与えて、それらを互いに区別する必要があります。

<mvcSiteMapNode title="Edit Staff" area="Admin" controller="EditStaff" route="Admin_AdministratorDetails" action="Start" key="administrators_details" />
<mvcSiteMapNode title="Edit Staff" area="Admin" controller="EditStaff" route="Admin_StaffDetails" action="Start" key="staff_details" />

気づいたら、今は普通の航海です。そうでなければ、すべてがあいまいで鈍いです。

ノート:

質問では、さまざまなルートから呼び出されていたアクションはプロセスアクションでした。これを別のアクションの呼び出しに変更しました。しかし、オブジェクト(Solicitors)を編集するときは、それを行うことができませんでした。編集は、カスタムメニュービルダーと同様に、非常にうまく機能するMVCウィザードによって行われるためです。ウィザードを3回再作成することは単に不可能でした(というより、DRY)。そのため、同じアクションを指すさまざまなルートでメニューハイライトを正しく機能させる必要がありました。

Un-DRYファッジは行いません。私のクライアントはそれに値しません。

解決策(アクションとルートが質問と異なる理由については、注を参照してください):

Carlos Martinezによる提案は機能しますが、ルートの詳細を示す編集済みのサイトマップと組み合わせて、Html.ActionLinkではなくHtml.RouteLinkを使用する必要があります。

基本的に、ノードでは、route属性を使用する必要があります。

<mvcSiteMapNode title="Details Active Solicitor" area="Solicitors" controller="EditSolicitor" action="Start" route="Active_Details" key="company_activeSolicitors_details"/>

次に、ビューで、アクションリンクの代わりに、RouteLinkヘルパーを使用します。

@Html.RouteLink("Details", "Active_Details", new { action="Start", controller="EditSolicitor", idSolicitor = item.SolicitorId, returnUrl = Request.RawUrl })

ルート登録ファイルに、同じアクションを呼び出すルートを記述できるようになりました。

context.MapRoute(
                "Unprocessed_Details",
                "Unprocessed/Edit/{idSolicitor}/{action}",
                new { action = "Start", controller = "EditSolicitor", idSolicitor = UrlParameter.Optional }
            );

            context.MapRoute(
                "Inactive_Details",
                "Inactive/Edit/{idSolicitor}/{action}",
                new { controller = "EditSolicitor", action = "Start", idSolicitor = UrlParameter.Optional }
            );

            context.MapRoute(
                "Active_Details",
                "Solicitors/Edit/{idSolicitor}/{action}",
                new { controller = "EditSolicitor", action = "Start", idSolicitor = UrlParameter.Optional }
            );

ご覧のとおり、3つのルートで呼び出されるのとまったく同じアクションです。mvcSiteMapNodeでルート名を指定している限り、メニューの作成時にルートが正しく区別され、必要に応じて強調表示が機能します。

XMLに混乱することに注意してください:

私はXMLが大嫌いです。特に風邪を引いているときは、それは私を困惑させ、混乱させます。

問題は、route属性をmvcSiteMapNodesに追加すると、混乱する可能性が高くなることです。

そして私が得た混乱

私は最初にCarlosの提案を試しましたが、うまくいきませんでした。エラーが何であったかはわかりませんが、歯の櫛でそれを通過し、現在は機能しています。厄介なのは、自分が何を間違っていたのかわからないことです。

希望に生きる:

mvcSiteMapNodeのフリンジの側面ではありますが、これが文書化されることを願っています。

于 2012-10-09T12:22:09.993 に答える
0

念のため、次のことを試してみてください。

context.MapRoute(
                    "Process_New_Members",
                    "Admin/{alternate}/Process/{MemberId}",
                    new { controller = "ProcessMembers", 
                        action = "Process", 
                        alternate="Unprocessed", 
                        MemberId = UrlParameter.Optional }
                );

このように、この追加のパラメーターを要求することにより、各ルートを区別します。

于 2012-10-08T09:35:08.783 に答える
0

で使用できurlますmvcSiteMapNode。以下のように:

<mvcSiteMapNode title="Process" area="Admin" controller="ProcessMembers" action="Process" aurl="/Admin/ProcessMembers/Process/Unprocessed"/>
<mvcSiteMapNode title="Change Status" area="Admin" controller="ProcessMembers" action="Process" url="/Admin/ProcessMembers/Process/Processed" />

もちろん、RoutConfigURLが機能するのに適切なものを使用する必要があります。ここにサンプルがあります。

于 2019-05-15T08:22:29.380 に答える