كيف يمكن أن ديناميكية فتات الخبز يتحقق مع ASP.net MVC?

StackOverflow https://stackoverflow.com/questions/1066777

  •  21-08-2019
  •  | 
  •  

سؤال

كيف يمكن أن ديناميكية فتات الخبز أن يتحقق مع ASP.net MVC?

إذا كنت غريبة عن ما فتات الخبز هي:

ما هي فتات الخبز?حسنا, إذا كان لديك أي وقت مضى تصفحها متجر على الانترنت أو قراءة المشاركات في المنتدى, كنت قد واجهت المحتمل فتات الخبز.أنها توفر طريقة سهلة لمعرفة أين أنت على الموقع.مواقع مثل كريغزلست استخدام فتات الخبز لوصف موقع المستخدم.فوق قوائم في كل صفحة هو الشيء الذي يبدو مثل هذا:

s.f.bayarea كريغزلست > مدينة سان فرانسيسكو > الدراجات

تحرير

أنا أدرك ما هو ممكن مع SiteMapProvider.أنا على علم أيضا من مقدمي هناك على شبكة الإنترنت التي تمكنك من خريطة sitenodes إلى وحدات تحكم الإجراءات.

ولكن ماذا عن عندما تريد التفصيلي النص إلى تطابق بعض ديناميكية قيمة مثل هذا:

منزل > المنتجات > سيارات > تويوتا

منزل > المنتجات > سيارات > تشيفي

منزل > المنتجات > معدات التنفيذ > الكرسي الكهربائي

منزل > المنتجات > معدات التنفيذ > المشنقة

...حيث فئات المنتجات والمنتجات السجلات من قاعدة البيانات.بعض الروابط يجب أن تكون محددة بشكل ثابت (المنزل بالتأكيد).

أنا في محاولة لمعرفة كيفية القيام بذلك, ولكن أنا متأكد من شخص قد فعلت هذا بالفعل مع ASP.net MVC.

هل كانت مفيدة؟

المحلول

وهناك أداة للقيام بذلك على كود بلاكس: http://mvcsitemap.codeplex.com/ [مشروع انتقل إلى جيثب]

وتحرير:

وهناك طريقة لاستخلاص SiteMapProvider من قاعدة البيانات: <لأ href = "http://www.asp.net/Learn/data-access/tutorial-62-cs.aspx" يختلط = "نوفولو noreferrer" > http://www.asp.net/Learn/data-access/tutorial-62-cs.aspx

هل يمكن أن يكون قادرا على تعديل أداة mvcsitemap لاستخدام ذلك للحصول على ما تريد.

نصائح أخرى

خريطة الموقع هم بالتأكيد شوط واحد ... بدلا من ذلك، يمكنك كتابة واحدة نفسك! (كما بالطبع طالما يتم اتباع قواعد MVC القياسية) ... أنا فقط كتبت واحدة، وأنا أحسب أنني سوف تتقاسم هنا.

@Html.ActionLink("Home", "Index", "Home")
@if(ViewContext.RouteData.Values["controller"].ToString() != "Home") {
    @:> @Html.ActionLink(ViewContext.RouteData.Values["controller"].ToString(), "Index", ViewContext.RouteData.Values["controller"].ToString()) 
}
@if(ViewContext.RouteData.Values["action"].ToString() != "Index"){
    @:> @Html.ActionLink(ViewContext.RouteData.Values["action"].ToString(), ViewContext.RouteData.Values["action"].ToString(), ViewContext.RouteData.Values["controller"].ToString()) 
}

ونأمل شخص ما سوف تجد هذه مفيدة، وهذا هو بالضبط ما كنت أبحث عنه عندما بحثت SO لفتات الخبز MVC.

ASP.NET 5 (الملقب ASP.NET الأساسية)، MVC الأساسية الحل

في ASP.NET الأساسية، هي الأمثل أشياء أخرى ونحن لسنا في حاجة إلى stringify العلامات في طريقة التمديد.

في ~/Extesions/HtmlExtensions.cs:

using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace YourProjectNamespace.Extensions
{
    public static class HtmlExtensions
    {
        private static readonly HtmlContentBuilder _emptyBuilder = new HtmlContentBuilder();

        public static IHtmlContent BuildBreadcrumbNavigation(this IHtmlHelper helper)
        {
            if (helper.ViewContext.RouteData.Values["controller"].ToString() == "Home" ||
                helper.ViewContext.RouteData.Values["controller"].ToString() == "Account")
            {
                return _emptyBuilder;
            }

            string controllerName = helper.ViewContext.RouteData.Values["controller"].ToString();
            string actionName = helper.ViewContext.RouteData.Values["action"].ToString();

            var breadcrumb = new HtmlContentBuilder()
                                .AppendHtml("<ol class='breadcrumb'><li>")
                                .AppendHtml(helper.ActionLink("Home", "Index", "Home"))
                                .AppendHtml("</li><li>")
                                .AppendHtml(helper.ActionLink(controllerName.Titleize(),
                                                          "Index", controllerName))
                                .AppendHtml("</li>");


            if (helper.ViewContext.RouteData.Values["action"].ToString() != "Index")
            {
                breadcrumb.AppendHtml("<li>")
                          .AppendHtml(helper.ActionLink(actionName.Titleize(), actionName, controllerName))
                          .AppendHtml("</li>");
            }

            return breadcrumb.AppendHtml("</ol>");
        }
    }
}

و~/Extensions/StringExtensions.cs لا يزال هو نفسه على النحو التالي (انتقل لأسفل لرؤية إصدار MVC5).

في عرض الحلاقة، نحن لسنا بحاجة Html.Raw، كما يأخذ الشفرة الرعاية للهروب عند التعامل مع IHtmlContent:

....
....
<div class="container body-content">

    <!-- #region Breadcrumb -->
    @Html.BuildBreadcrumbNavigation()
    <!-- #endregion -->

    @RenderBody()
    <hr />
...
...

ASP.NET 4، 5 MVC الحل

و=== ORIGINAL / ANSWER OLD أدناه ===

و(التوسع في الإجابة شون حدى في أعلاه)

إذا كنت تريد أن تجعل من يحركها تمديد (حفظ المشاهدات نظيفة)، يمكنك أن تفعل شيئا مثل:

في ~/Extesions/HtmlExtensions.cs:

و(متوافقة مع MVC5 / ألبس الحذاء)

using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace YourProjectNamespace.Extensions
{
    public static class HtmlExtensions
    {
        public static string BuildBreadcrumbNavigation(this HtmlHelper helper)
        {
            // optional condition: I didn't wanted it to show on home and account controller
            if (helper.ViewContext.RouteData.Values["controller"].ToString() == "Home" ||
                helper.ViewContext.RouteData.Values["controller"].ToString() == "Account")
            {
                return string.Empty;
            }

            StringBuilder breadcrumb = new StringBuilder("<ol class='breadcrumb'><li>").Append(helper.ActionLink("Home", "Index", "Home").ToHtmlString()).Append("</li>");


            breadcrumb.Append("<li>");
            breadcrumb.Append(helper.ActionLink(helper.ViewContext.RouteData.Values["controller"].ToString().Titleize(),
                                               "Index",
                                               helper.ViewContext.RouteData.Values["controller"].ToString()));
            breadcrumb.Append("</li>");

            if (helper.ViewContext.RouteData.Values["action"].ToString() != "Index")
            {
                breadcrumb.Append("<li>");
                breadcrumb.Append(helper.ActionLink(helper.ViewContext.RouteData.Values["action"].ToString().Titleize(),
                                                    helper.ViewContext.RouteData.Values["action"].ToString(),
                                                    helper.ViewContext.RouteData.Values["controller"].ToString()));
                breadcrumb.Append("</li>");
            }

            return breadcrumb.Append("</ol>").ToString();
        }
    }
}

في ~/Extensions/StringExtensions.cs:

using System.Globalization;
using System.Text.RegularExpressions;

namespace YourProjectNamespace.Extensions
{
    public static class StringExtensions
    {
        public static string Titleize(this string text)
        {
            return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(text).ToSentenceCase();
        }

        public static string ToSentenceCase(this string str)
        {
            return Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1]));
        }
    }
}

وثم استخدامها مثل (في _Layout.cshtml على سبيل المثال):

....
....
<div class="container body-content">

    <!-- #region Breadcrumb -->
    @Html.Raw(Html.BuildBreadcrumbNavigation())
    <!-- #endregion -->

    @RenderBody()
    <hr />
...
...

مارتن Balliauw هو MvcSiteMapProvider عملت بشكل جيد بالنسبة لي.

أنا خلقت صغيرة mvc التطبيق لاختبار مزود: MvcSiteMapProvider الاختبار (404)

ولقد بنيت هذه الحزمة nuget لحل هذه المشكلة لنفسي:

https://www.nuget.org/packages/MvcBreadCrumbs/

ويمكنك المساهمة هنا إذا كان لديك أفكار له:

https://github.com/thelarz/MvcBreadCrumbs

لكل من يهمه الأمر، فعلت نسخة محسنة من HtmlExtension التي هي أيضا مناطق النظر وبالإضافة إلى ذلك يستخدم انعكاس لمعرفة ما اذا كان هناك وحدة تحكم افتراضي داخل منطقة أو عمل فهرس داخل وحدة التحكم:

public static class HtmlExtensions
    {
        public static MvcHtmlString BuildBreadcrumbNavigation(this HtmlHelper helper)
        {
            string area = (helper.ViewContext.RouteData.DataTokens["area"] ?? "").ToString();
            string controller = helper.ViewContext.RouteData.Values["controller"].ToString();
            string action = helper.ViewContext.RouteData.Values["action"].ToString();

            // add link to homepage by default
            StringBuilder breadcrumb = new StringBuilder(@"
                <ol class='breadcrumb'>
                    <li>" + helper.ActionLink("Homepage", "Index", "Home", new { Area = "" }, new { @class="first" }) + @"</li>");

            // add link to area if existing
            if (area != "")
            {
                breadcrumb.Append("<li>");
                if (ControllerExistsInArea("Default", area)) // by convention, default Area controller should be named Default
                {
                    breadcrumb.Append(helper.ActionLink(area.AddSpaceOnCaseChange(), "Index", "Default", new { Area = area }, new { @class = "" }));
                }
                else
                {
                    breadcrumb.Append(area.AddSpaceOnCaseChange());
                }
                breadcrumb.Append("</li>");
            }

            // add link to controller Index if different action
            if ((controller != "Home" && controller != "Default") && action != "Index")
            {
                if (ActionExistsInController("Index", controller, area))
                {
                    breadcrumb.Append("<li>");
                    breadcrumb.Append(helper.ActionLink(controller.AddSpaceOnCaseChange(), "Index", controller, new { Area = area }, new { @class = "" }));
                    breadcrumb.Append("</li>");
                }
            }

            // add link to action
            if ((controller != "Home" && controller != "Default") || action != "Index")
            {
                breadcrumb.Append("<li>");
                //breadcrumb.Append(helper.ActionLink((action.ToLower() == "index") ? controller.AddSpaceOnCaseChange() : action.AddSpaceOnCaseChange(), action, controller, new { Area = area }, new { @class = "" }));
                breadcrumb.Append((action.ToLower() == "index") ? controller.AddSpaceOnCaseChange() : action.AddSpaceOnCaseChange());
                breadcrumb.Append("</li>");
            }

            return MvcHtmlString.Create(breadcrumb.Append("</ol>").ToString());
        }

        public static Type GetControllerType(string controller, string area)
        {
            string currentAssembly = Assembly.GetExecutingAssembly().GetName().Name;
            IEnumerable<Type> controllerTypes = Assembly.GetExecutingAssembly().GetTypes().Where(o => typeof(IController).IsAssignableFrom(o));

            string typeFullName = String.Format("{0}.Controllers.{1}Controller", currentAssembly, controller);
            if (area != "")
            {
                typeFullName = String.Format("{0}.Areas.{1}.Controllers.{2}Controller", currentAssembly, area, controller);
            }

            return controllerTypes.Where(o => o.FullName == typeFullName).FirstOrDefault();
        }

        public static bool ActionExistsInController(string action, string controller, string area)
        {
            Type controllerType = GetControllerType(controller, area);
            return (controllerType != null && new ReflectedControllerDescriptor(controllerType).GetCanonicalActions().Any(x => x.ActionName == action));
        }

        public static bool ControllerExistsInArea(string controller, string area)
        {
            Type controllerType = GetControllerType(controller, area);
            return (controllerType != null);
        }


    public static string AddSpaceOnCaseChange(this string text)
    {
        if (string.IsNullOrWhiteSpace(text))
            return "";
        StringBuilder newText = new StringBuilder(text.Length * 2);
        newText.Append(text[0]);
        for (int i = 1; i < text.Length; i++)
        {
            if (char.IsUpper(text[i]) && text[i - 1] != ' ')
                newText.Append(' ');
            newText.Append(text[i]);
        }
        return newText.ToString();
    }
}

إذا يمكن بالتأكيد يمكن تحسينها (وربما لا تغطي جميع الحالات المحتملة)، لكنه لم فشلت لي حتى الآن.

لأولئك الذين يستخدمون ASP.NET النواة 2.0 و تبحث عن أكثر تنفصل من النهج فولكان هو HtmlHelper ، أوصي وجود نظرة في نظرة جزئية مع حقن التبعية.

أدناه هو تطبيق بسيط والتي يمكن بسهولة أن مصبوب لتناسب الاحتياجات الخاصة بك.

التفصيلي خدمة (./Services/BreadcrumbService.cs):

using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System;
using System.Collections.Generic;

namespace YourNamespace.YourProject
{  
  public class BreadcrumbService : IViewContextAware
  {
    IList<Breadcrumb> breadcrumbs;

    public void Contextualize(ViewContext viewContext)
    {
      breadcrumbs = new List<Breadcrumb>();

      string area = $"{viewContext.RouteData.Values["area"]}";
      string controller = $"{viewContext.RouteData.Values["controller"]}";
      string action = $"{viewContext.RouteData.Values["action"]}";
      object id = viewContext.RouteData.Values["id"];
      string title = $"{viewContext.ViewData["Title"]}";   

      breadcrumbs.Add(new Breadcrumb(area, controller, action, title, id));

      if(!string.Equals(action, "index", StringComparison.OrdinalIgnoreCase))
      {
        breadcrumbs.Insert(0, new Breadcrumb(area, controller, "index", title));
      }
    }

    public IList<Breadcrumb> GetBreadcrumbs()
    {
      return breadcrumbs;
    }
  }

  public class Breadcrumb
  {
    public Breadcrumb(string area, string controller, string action, string title, object id) : this(area, controller, action, title)
    {
      Id = id;
    }

    public Breadcrumb(string area, string controller, string action, string title)
    {
      Area = area;
      Controller = controller;
      Action = action;

      if (string.IsNullOrWhiteSpace(title))
      {
         Title = Regex.Replace(CultureInfo.CurrentCulture.TextInfo.ToTitleCase(string.Equals(action, "Index", StringComparison.OrdinalIgnoreCase) ? controller : action), "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1]));
      }
      else
      {
         Title = title;
      } 
    }

    public string Area { get; set; }
    public string Controller { get; set; }
    public string Action { get; set; }
    public object Id { get; set; }
    public string Title { get; set; }
  }
}

تسجيل في الخدمة startup.cs بعد AddMvc():

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddTransient<BreadcrumbService>(); 

إنشاء جزئي لتقديم فتات الخبز (~/Views/Shared/Breadcrumbs.cshtml):

@using YourNamespace.YourProject.Services
@inject BreadcrumbService BreadcrumbService

@foreach(var breadcrumb in BreadcrumbService.GetBreadcrumbs())
{
    <a asp-area="@breadcrumb.Area" asp-controller="@breadcrumb.Controller" asp-action="@breadcrumb.Action" asp-route-id="@breadcrumb.Id">@breadcrumb.Title</a>
}

في هذه المرحلة إلى تقديم فتات الخبز ببساطة الاتصال Html.Partial("Breadcrumbs") أو Html.PartialAsync("Breadcrumbs").

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top