2009-04-07 56 views
28

Estoy intentando crear un mapa de sitio automático ActionResult que genera un archivo sitemap.xml válido. La generación real del archivo no es un problema, pero parece que no puedo averiguar cómo completar la lista de URL en el sistema. Aquí está el código que tengo hasta ahora:Mapa del sitio dinámico en ASP.NET MVC

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); 
     } 
    } 

Por ejemplo, supongamos que tengo dos controladores, y cada controlador tiene dos acciones asociadas a ellos:

HelpController

  • Editar
  • Crear

AboutController

  • Compañía
  • Gestión

Me parece que no puede encontrar la manera de obtener una lista de URL como:

+1

Recientemente, como respuesta de @ eduncan911, la mejor solución es usar http://mvcsitemap.codeplex.com/ proyecto activo y actualizado, soporte para el recorte de seguridad y generará sitemap.xml. También puede comprimir automáticamente el mapa del sitio si el agente lo admite y dividir el mapa del sitio en sub-sitemaps si el sitio es demasiado grande porque el sitemap.xml estándar tiene el límite para 50k nodos solamente. – CallMeLaNN

+0

Gracias CallMeLaNN. Recientemente actualicé la respuesta para enumerar esos puntos y más, así como también el sitio al que se movió. – eduncan911

Respuesta

6

Eché un vistazo al enfoque de Maarten Balliauw por el comentario de likwid, pero parece ser excesivo para lo que estoy tratando de hacer.

He pirateado una solución temporal. Simplemente estoy pasando los nombres de controlador y acción para generar las URL. Con el fin de generar la URL de, estoy usando el siguiente código:

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" })); 

donde getUrl es la siguiente:

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; 
    } 

Esto parece hacer el truco por ahora, aunque me gusta la idea de tener actionfilter aplicado a ciertas acciones que se agrupan automáticamente.

0

Ha intentado algo como esto:

http://blog.maartenballiauw.be/post/2008/08/29/Building-an-ASPNET-MVC-sitemap-provider-with-security-trimming.aspx

Después de volver a leer su pregunta, veo que quieres algo un poco diferente que el ejemplo que he proporcionado. Creo que tendrías que reflejar todos los controladores conocidos y sus acciones para construir un mapa del sitio de forma dinámica.

Sería mucho más simple utilizar una base de datos o un archivo de mapa del sitio como su fuente, creo.

7

Como dice likwid, desea reflejar el espacio de nombres de su modelo y obtener todas las clases que implementan IController. Una vez que tenga la colección, quiere reflexionar para ver qué Miembros (métodos) devuelven el tipo ActionResult.

Quizás pueda crear su propio atributo, [SitemapAttribute] que le permita especificar selectivamente qué métodos indexar en el mapa del sitio (es decir, Index(), pero no Edit()). Sí, me gusta esa idea de controlar qué métodos (urls) se escriben.

Esta es una excelente pregunta porque estaba pensando en hacer lo mismo. +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. 
    } 
} 

Para saber cómo hacer la reflexión, aquí hay un buen artículo de MSDN para conseguir una presentación a la reflexión:

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

Buena pregunta!

+0

¿Puedes publicar un ejemplo de uso de la reflexión para crear el contenido? Específicamente cómo obtener la URL de la acción? –

+0

Gracias Mike, pero no tengo ningún código. Era solo una sugerencia. A continuación parece haber otros ejemplos. – eduncan911

2

Por lo tanto, el conseguir de los controladores y acciones me parece que es la parte relativamente trivial. La parte difícil es poder obtener todos los posibles valores de parámetros que pueda querer mostrar en las direcciones URL de su mapa del sitio. Si tiene un patrón de URL como {controller}/{action}/{id}, no podrá determinar por reflexión cuál es el significado de id, ni los posibles valores. Lo mejor que puede hacer es determinar el tipo de sistema.

Lo que ocurrió cuando estaba viendo esto es que un mapa del sitio es realmente solo otra vista de los datos de su sitio. Así que un pensamiento al azar que tenía era que si heredar de un controlador de base en su aplicación, y usted tiene un método en el que el controlador de base que tiene que ser implementado, por ejemplo:

abstract ActionResult SiteMapSnippet(); 

entonces se podría crear un SiteMapController cuales llama a cada uno de los otros controladores en la solución y les pide su fragmento, y luego los representa a todos en una vista final. Una especie de controlador compuesto, aunque ese no es un concepto que se haya agregado a este marco todavía.

13

He publicado una respuesta do-it-yourself abajo más abajo. Pero aquí es un paquete que lo hace fuera de la caja para los sitios MVC:

http://mvcsitemap.codeplex.com/ (< - sitio antiguo, pero con una amplia documentación!)

https://github.com/maartenba/MvcSiteMapProvider/wiki (< - se trasladó a nuevo sitio, que carece de alguna documentación, y no como activo)

Tenga en cuenta que lo hace una multitud de cosas:

  • Automáticamente registra a sí mismo en las rutas MVC para responder a SEO /sitemap.xm l solicitudes (aunque no hay ningún archivo físico para /sitemap.xml). Esto es completamente compatible con todos los robots de motor de búsqueda que he encontrado, así como también cuando llega a 10.000, etc.
  • Viene con un conjunto de vistas parciales para usar para BreadCrumb navegación incorporada! Usamos esto bastante extensamente, aunque la porción de datos dinámicos es un poco engorrosa, funciona.
  • Viene con un conjunto de vistas parciales para controlar el menú también.
  • Honora los bits de seguridad [Autorizar] de sus Controladores y métodos de Acción.

Todos los puntos anteriores se controlan desde el único archivo XML de mvc.sitemap que edita y configura. Lo he usado en varios proyectos ahora para hacer 2 o 3 de los puntos anteriores. Tenerlo todo configurable en 1 lugar, y generado dinámicamente, es realmente agradable.

Aunque considero que la capacidad de crear proveedores de datos dinámicos es un poco engorrosa (y viola groseramente cualquier tipo de IoC que desee), hace el trabajo y escala muy bien una vez que omite su almacenamiento en caché y usa el suyo.

+8

Eso es un mapa del sitio ASP.NET no un archivo sitemap.xml para un motor de búsqueda –

+1

@Hightechrider crea un sitemap.xml para sus mapas registrados. Habilitar es trivial. https://github.com/maartenba/MvcSiteMapProvider/wiki/Exporting-the-sitemap-for-search-engine-indexing – tugberk

+1

Eso es nuevo, gracias por señalarlo y por la nueva ubicación. –

5

Definir una ActionFilterAttribute como este para poner en cualquier método de acción que es una página real que se desea listar en el mapa del sitio: -

[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); 
    } 
} 

Ahora añadir algo como esto a su código global inicio de la aplicación, o utilizarlo en su código de generación 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 
      } 
     } 
    } 

puede ampliar la clase de atributo para incluir quizás también la frecuencia de actualización de pista.

+0

Hola. ¿Es este sitemap válido según las pautas de google? –

Cuestiones relacionadas