29 votes

Plan du site dynamique dans ASP.NET MVC

Je suis en train de créer automatiquement un sitemap ActionResult que les sorties valide sitemap.xml fichier. La génération réelle du fichier n'est pas un problème, mais je n'arrive pas à comprendre comment remplir la liste d'URL dans le système. Voici le code que j'ai pour l'instant:

    public ContentResult Sitemap()
    {
        XNamespace xmlns = "http://www.sitemaps.org/schemas/sitemap/0.9";
        XElement root = new XElement(xmlns + "urlset");

        //some kind of foreach here to get the loc variable for all URLs in the site
        //for each URL in the collection, add it to the root element as here

        //root.Add(
        //    new XElement("url", 
        //        new XElement("loc", "http://google.com"), 
        //        new XElement("changefreq", "daily")));

        using (MemoryStream ms = new MemoryStream())
        {
            using (StreamWriter writer = new StreamWriter(ms, Encoding.UTF8))
            {
                root.Save(writer);
            }

            return Content(Encoding.UTF8.GetString(ms.ToArray()), "text/xml", Encoding.UTF8);
        }
    }

Par exemple, imaginons que j'ai deux contrôleurs, et chaque contrôleur dispose de deux actions qui leur sont associés:

HelpController

  • Modifier
  • Créer

AboutController

  • Société
  • Gestion

Je n'arrive pas à comprendre comment obtenir une liste des URL du genre:

13voto

eduncan911 Points 5417

J'ai posté un do-it-yourself de réponses ci-dessous. Mais ici, c'est un package qui n'hors de la boîte pour MVC sites:

http://mvcsitemap.codeplex.com/ (<- ancien site, mais avec une documentation complète!)

https://github.com/maartenba/MvcSiteMapProvider/wiki (<- déplacé au nouveau site, manque un peu de documentation, et de ne pas actif)

Notez qu'il n'a une multitude de choses:

  • "Automagiquement" s'inscrit dans le Mvc itinéraires pour répondre à la SEO /sitemap.xml demandes (même si il n'existe pas de fichier /sitemap.xml). C'est complètement compatible avec tous les robots de moteur de recherche, j'ai trouvé, ainsi que de rouler dessus quand il arrive à 10000, etc.
  • Est livré avec un ensemble de vues partielles à utiliser pour le fil d'Ariane de navigation intégré! Nous utilisons cette très largement, bien que la dynamique de la partie des données est un peu lourd, il ne fonctionne pas.
  • Est livré avec un ensemble de vues partielles de Menu pour être contrôlés.
  • Les honneurs de la [Autoriser] la sécurité des morceaux de vos Contrôleurs et des méthodes d'Action.

Tous les points ci-dessus sont contrôlés à partir de la seule mvc.sitemap XML fichier vous de modifier et de configurer. Je l'ai utilisé dans un certain nombre de projets à faire 2 ou 3 des points ci-dessus. Il ont tous configurable de 1 place, et généré dynamiquement, est vraiment sympa.

Bien que je trouve la possibilité de créer des dynamiques de fournisseurs de données un peu lourd (et viole grossièrement n'importe quel type de Cio que vous voulez faire), il ne faire le travail et échelles de bien une fois que vous contourner leur mise en cache et l'utilisation de votre propre.

7voto

eduncan911 Points 5417

Comme likwid mentionne, vous souhaitez réfléchir à votre modèle(s) de l'espace de noms et d'obtenir toutes les classes qui implémentent IController. Une fois que vous avez la collecte, vous voulez réfléchir pour voir ce que les Membres (méthodes) de retour le type ActionResult.

Peut-être que vous pouvez créer votre propre attribut, [SitemapAttribute] qui vous permet de spécifier de manière sélective quelles sont les méthodes à l'index dans le sitemap (c'est à dire, Index(), mais pas de le Modifier()). Ouais, j'aime bien cette idée de contrôler les méthodes (url) qui est écrit.

C'est une excellente question parce que j'étais en train de penser à faire de même. +1!

// Controller abstract implements IController
public class HelpController : Controller
{
  public HelpController()
  {
  }

  [Sitemap]
  public ActionResult Index()
  {
    // does get written to the file, cause of [Sitemap]
  }

  public ActionResult Create()
  {
    // does not get mapped to the file
  }

  public ActionResult Edit()
  {
    // does not get mapped to the file
  }

  [Sitemap]
  public ActionResult ViewArticle()
  {
    // would get indexed.
  }
}

Pour savoir comment faire la réflexion, voici un bon article de MSDN pour vous introduit à la réflexion:

http://msdn.microsoft.com/en-us/library/ms172331.aspx

Bonne question!

7voto

dp. Points 3090

J'ai pris un coup d'oeil à Maarten Balliauw de l'approche par likwid commentaire, mais il me semble overkill pour ce que je suis en train de faire.

J'ai bidouillé une solution temporaire. Je suis simplement de passage du contrôleur et des noms d'action pour générer l'URL. Afin de générer les URL, je suis en utilisant le code suivant:

    List<string> urlList = new List<string>();
    urlList.Add(GetUrl(new { controller = "Help", action = "Edit" }));
    urlList.Add(GetUrl(new { controller = "Help", action = "Create" }));
    urlList.Add(GetUrl(new { controller = "About", action = "Company" }));
    urlList.Add(GetUrl(new { controller = "About", action = "Management" }));

où GetUrl est comme ci-dessous:

    protected string GetUrl(object routeValues)
    {
        RouteValueDictionary values = new RouteValueDictionary(routeValues);
        RequestContext context = new RequestContext(HttpContext, RouteData);

        string url = RouteTable.Routes.GetVirtualPath(context, values).VirtualPath;

        return new Uri(Request.Url, url).AbsoluteUri;
    }

Ce qui semble faire l'affaire pour l'instant, bien que je ne l'aime l'idée d'avoir actionfilter est appliqué à certaines actions que vous tiré ensemble automatiquement.

5voto

Ian Mercer Points 19271

Définissez un ActionFilterAttribute comme ceci pour mettre sur n'importe quelle méthode d'action qui est une page réelle que vous souhaitez lister dans votre plan du site: -

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class MVCUrlAttribute : ActionFilterAttribute
{
    public string Url { get; private set; }

    public MVCUrlAttribute(string url)
    {
        this.Url = url;
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        // Put this 'canonical url' into the model (which feeds the view)
        // to help search engines with issues of duplicate content
        filterContext.Controller.ViewData["CanonicalUrl"] = url;
        base.OnResultExecuting(filterContext);
    }
}
 

Ajoutez maintenant quelque chose comme ceci à votre code de démarrage d'application globale, ou utilisez-le dans votre code de génération sitemap.xml: -

    // Find all the MVC Routes
    Log.Debug("*** FINDING ALL MVC ROUTES MARKED FOR INCLUSION IN SITEMAP");
    var allControllers = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsSubclassOf(typeof(Controller)));
    Log.DebugFormat("Found {0} controllers", allControllers.Count());

    foreach (var controllerType in allControllers)
    {
        var allPublicMethodsOnController = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance);
        Log.DebugFormat("Found {0} public methods on {1}", allPublicMethodsOnController.Count(), controllerType.Name);

        foreach (var publicMethod in allPublicMethodsOnController)
        {
            var mvcurlattr = publicMethod.GetCustomAttributes(true).OfType<MVCUrlAttribute>().FirstOrDefault();
            if (mvcurlattr != null)
            {
                string url = mvcurlattr.Url;
                Log.Debug("Found " + controllerType.Name + "." + publicMethod.Name + " <-- " + url);
                Global.SiteMapUrls.Add(url);  //<-- your code here using url
            }
        }
    }
 

Vous pouvez étendre la classe d'attributs pour inclure peut-être également la fréquence des indices de mise à jour.

2voto

Paul Points 8943

Ainsi, l'obtention des contrôleurs et des actions me semble être relativement trivial partie. La partie la plus difficile est d'être en mesure d'obtenir toutes les valeurs de paramètre que vous voulez afficher dans l'url de votre sitemap. Si vous avez un modèle d'URL comme {controller}/{action}/{id}, alors vous n'allez pas être en mesure de déterminer, grâce à la réflexion de ce que le sens de l' id est, ou les valeurs possibles. Le meilleur que vous pouvez faire est de déterminer le type de système.

Ce qui s'est passé pour moi comme je regardais ce n'est qu'un sitemap est vraiment juste un autre point de vue de vos données du site. Donc on pensé au hasard que j'ai eu était que si vous héritez d'un contrôleur de base dans votre application, et vous avez une méthode sur la base de contrôleur qui doit être mise en œuvre, par exemple:

abstract ActionResult SiteMapSnippet();

Ensuite, vous pouvez créer un SiteMapController qui appelle tous les autres contrôleurs de la solution et leur demande pour leur extrait de code, puis les rendent tous ensemble dans un avis définitif. Une sorte de composite contrôleur, si ce n'est pas un concept qui a été ajoutée à ce cadre encore.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X