how to create google sitemap for mvc site? - asp.net

I was wondering if anyone has done this yet or has any examples
on how to create a Google Sitemap for an MVC website.
Any help or example would be appreciated.
Im talking about this:
https://www.google.com/webmasters/tools/docs/en/protocol.html

I used Mike Brind's Sitemap code, with a small change.
You need to add the XNamespace to every XElement, otherwise Google spits the dummy.
Here's my version:
public ContentResult Index()
{
XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";
const string url = "http://www.website.com/controller/action/{0}";
var items = _db.DataAccessHere();
var sitemap = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement(ns + "urlset",
from i in items
select
//Add ns to every element.
new XElement(ns + "url",
new XElement(ns + "loc", string.Format(url, i.ItemID)),
new XElement(ns + "lastmod", String.Format("{0:yyyy-MM-dd}", i.DateAddedUTC)),
new XElement(ns + "changefreq", "monthly"),
new XElement(ns + "priority", "0.5")
)
)
);
return Content(sitemap.ToString(), "text/xml");
}
Credit to Mike for posting the original article and code.

Shameless self plug: I created a library called SimpleMvcSitemap after having weird issues with MvcSiteMapProvider on production. You can serve sitemap files from any action method without any configuration:
public class SitemapController : Controller
{
public ActionResult Index()
{
List<SitemapNode> nodes = new List<SitemapNode>
{
new SitemapNode(Url.Action("Index","Home")),
new SitemapNode(Url.Action("About","Home")),
//other nodes
};
return new SitemapProvider().CreateSitemap(nodes);
}
}
It also supports all the Google Sitemap extensions available.

The easiest way would be to use any one of a number of free sitemap builders out there - they will crawl your site, follow links, and generate a sitemap XML file for you.
Here's one for example

Here's a post that might give you some ideas. Basically it generates a sitemap from route values.

so here's the thing, using generators will just about create a link for "everything" in your site. So if you have, let's say a card site, and you have like a hundred thousand card items, each with it's own link and all, you'll likely see the same amount of links. If you want that, then xml sitemap generators are the way to go.
But if you want it a little bit personalized, you can do these:
List all major sections of your sites. This is easy to do considering that most MVCs are using the "clean URLs" sort of thing. kinda like "site.com/items/phones"
Create an XML document, depending on the language you're using.
At the minimum, you should have a document like this:
<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://dragonflysco.com/catalog/finishings/19</loc>
</url>
<!-- more here -->
</urlset>
For more advanced structure, check this:
http://www.google.com/support/webmasters/bin/answer.py?answer=183668

Related

SQL Table to SiteMapProvider 4 ASP.net mvc4

I have been trying to use SiteMapProvider from NuGet and make it link to a database in order to get all the links for a sidebar and breadcrumb, so far I don't find any tutorial, and I keep getting stuck using the information to the xml file, I am sure that I have to create a class, but I don't seem to find any tutorial on how to do this, or how to correctly make the call to this class, is there a tutorial or any website that contain this information? I have been trying to do what is included in here:
https://github.com/maartenba/MvcSiteMapProvider/wiki/Dynamic-sitemaps
But I don't know how to define the dynamicNodeProvider, any help? Sorry if it's some what vague what I am asking.. I have tried to search but I haven't find any information..
EDIT:
I was able to load information using :
[MvcSiteMapNode(Title = "HOLDCREATEREPORT", ParentKey = "Home", Key = "CreateReport")]
on each, class, but I am more interested in doing this using a unique class that loads all nodes, I have tried so far to change the sitemap xml to the following code:
navigation itself has the following code:
public class navigation : DynamicNodeProviderBase
{
public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
{
for (int i = 0; i < 20; i++)
{
DynamicNode dynamicnode = new DynamicNode();
dynamicnode.Title = "test"+ i.ToString();
dynamicnode.ParentKey = "Home";
dynamicnode.RouteValues.Add("test" + i.ToString(), "abcdb"+ i.ToString());
yield return dynamicnode;
}
}
}
yet when I run it nothing gets displayed, I am pretty sure I am missing something extremely easy >_>.
Dynamic Node Providers require a definition node. The definition node can either be in XML or as a .NET attribute. It won't be included in the SiteMap, but the nodes that the Dynamic Node Provider create will be.
[MvcSiteMapNode(Title = "Dynamic Nodes", DynamicNodeProvider = "MyNamespace.navigation, MyAssembly")]
Or
<mvcSiteMapNode title="Dynamic Nodes" dynamicNodeProvider="MyNamespace.navigation, MyAssembly">

ASP.NET Dynamic Data site within Umbraco 6

I have a Dynamic Data site in a folder called admin. This folder is in the root of the website and referenced in the reserved paths section of the web.config file.
After upgrading from Umbraco 4.7.2 to 6.0.5 I've noticed that the links in the Dynamic Data site that normally take me to my tables are now trying to hit the /umbraco/rendermvc/List controller and action. I'm assuming that somehow my routes have been changed, but being so new to MVC I have no idea how to restore these.
If it is any help, this is the section of my startup code that used to register the contexts correctly. Any help on how to restore these routes without breaking the routing of the new Umbraco version would be very appreciated!
public static void RegisterContext(RouteCollection routes, string dbName, Type contextType, string ddFolder)
{
var model = new MetaModel
{
DynamicDataFolderVirtualPath = ddFolder,
FieldTemplateFactory =
new FieldTemplateFactory()
{TemplateFolderVirtualPath = "~/admin/DynamicData/FieldTemplates",}
};
model.RegisterContext(contextType, new ContextConfiguration() {ScaffoldAllTables = true});
routes.Add(new DynamicDataRoute("admin/{dbname}/{table}/{action}.aspx")
{
Constraints = new RouteValueDictionary(new
{
action = "List|Details|Edit|Insert",
dbname = dbName
}),
Model = model
});
Models[dbName] = model;
}
I think you have to put your custom stuff in an override on the OnApplicationStarted event in a custom global.asax which inherits from Umbraco.Web.UmbracoApplication (I haven't tried it yet), see this blog (about half way down the page) and our.umbraco.

Dynamic sitemap, database driven

I've been struggling with this for a couple of days now. Can't find any good example, or an example that I understand.
Background:
I own a small blog platform for user to blog.
Each user gets their own subdomain and for now there is no sitemap available. Not good.
I want to create some kind of dynamic sitemap, where all sitemapnodes is retreived from the database. The sitemap will be used only for the search engine spiders.
System: ASP.NET, mySQL.
The sitemap is pure XML. So I need in some way to create an ASPX file that return xml-data instead of html.
And I need to somehow redirect the web.sitemap to that dynamic file.
I have never worked with XML, and I dont know how to create a file that creates XML data. So i dont even know what to search for.
I don't want any static sitemap file to be stored on the server. Everything should be created on the fly.
So. Please. If you can give me some advise about XML, any example on the internet, or just what to search for.
My main questions:
1.
How to create XML output from aspx file?
2.
How do I "inform" the system, and search engine crawlers that the file to crawl is "/sitemap.aspx"
ThankS!
I looked into MvcSiteMapProvider.MVC5 and I could not get it to work. First of all it modified my Web.config to the point that my css and js files were getting a 404 not found when running my web app.
With the time I spent getting MvcSiteMapProvider to work I could have just wrote my own.
So... here is my own dumbed down version of generating a sitemap xml.
The only thing is you have to specify your routes manually. I haven't added reflection yet to go through each controller and pull out each action.
The data-driven piece works very well though.
In your Home controller add the action Sitemap and the private helper methods.
GetRouteUrls is the manually added controller/action routes.
GetDynamicUrls builds the data-driven Urls. In my example I have a LiquidsController and a Details(string id) action.
public ActionResult Sitemap()
{
var xml = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("urlset",
new XAttribute("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9")
, GetRouteUrls()
, GetDynamicUrls()
)
);
return new XmlActionResult(xml);
}
private List<XElement> GetDynamicUrls()
{
var result = new List<XElement>();
using (var db = new ApplicationDbContext())
{
var liquids = db.Liquids.ToList();
foreach (var liquid in liquids)
{
result.Add(LocUrl("Liquids", "Details", liquid.FriendlyId));
}
}
return result;
}
private List<XElement> GetRouteUrls()
{
var result = new List<XElement>();
result.Add(LocUrl("Account", "Register"));
result.Add(LocUrl("Account", "Login"));
result.Add(LocUrl("Home", "Index"));
result.Add(LocUrl("Home", "About"));
result.Add(LocUrl("Home", "Contact"));
result.Add(LocUrl("Home", "TermsOfService"));
result.Add(LocUrl("Home", "PrivacyStatement"));
result.Add(LocUrl("Liquids", "Index"));
result.Add(LocUrl("Vendors", "Index"));
result.Add(LocUrl("Hardware", "Index"));
return result;
}
private XElement LocUrl(string controller, string action, string id = null)
{
if (!string.IsNullOrEmpty(id))
action = string.Format("{0}/{1}", action, id);
var baseUri = string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Content("~"));
return new XElement("url",
new XElement("loc", string.Format("{0}{1}/{2}", baseUri, controller, action))
);
}
I then added a route so I could access the sitemap doing /sitemap
routes.MapRoute(name: "sitemap", url: "sitemap", defaults: new {controller = "Home", action = "Sitemap"});
The XmlActionResult return type can be found here:
Return XML from a controller's action in as an ActionResult?

ASP.NET MVC Routing for files with muliple sub-directories

I need to setup a file handler to route with multiple sub directories something like tihs;
http://localhost/images/7/99/786936215595.jpg
I tried putting this in the global.asax file;
routes.Add(
"ImageRoute",
new Route("covers/{filepath}/{filename}",
new ImageRouteHandler()));
I am using the ImageHandler found in this Question, which works great if you have a single sub-directory (ie '/images/15/786936215595.jpg') but fails when you have multiple directories.
I tried setting up a wildcard and that didnt work (ie 'new Route("covers/{filepath}/*/{filename}"')
This is serving images from a large NAS (think something like 3 million images) so its not like I can just move files around.
Thanks!
Ok after much playing around and google fu I found how to make it work.
Change the route definition like this;
routes.Add(
"ImageRoute",
new Route("images/{*filepath}",
new ImageRouteHandler()));
Then put this after the default MapRoute. The important part is the "*" before the filepath, tells MVC to send anything following this as part of the filepath RouteData. So in the GetHttpHandler() method I can get the full path by using this;
string fp = requestContext.RouteData.Values["filepath"] as string;
Woot!
Can't you treat the entire path as one route parameter? Like so:
routes.Add(
"ImageRoute",
"/images/{path}",
new { controller = "Image", action = "Image" }
);
And then access the entire path in the ActionResult Image(string path) { } action method?

Creating a URL in the controller .NET MVC

I need to be able to construct a link in the Action on the controller to send an email. What is best practice to do this? I don't want to construct it myself in case my routes change.
Should I have a view for each email and render that and send it? That might be a good way of doing it.
If you just want to get the path to a certain action, use UrlHelper:
UrlHelper u = new UrlHelper(this.ControllerContext.RequestContext);
string url = u.Action("About", "Home", null);
if you want to create a hyperlink:
string link = HtmlHelper.GenerateLink(this.ControllerContext.RequestContext, System.Web.Routing.RouteTable.Routes, "My link", "Root", "About", "Home", null, null);
Intellisense will give you the meaning of each of the parameters.
Update from comments: controller already has a UrlHelper:
string url = this.Url.Action("About", "Home", null);
If you need the full url (for instance to send by email) consider using one of the following built-in methods:
With this you create the route to use to build the url:
Url.RouteUrl("OpinionByCompany", new RouteValueDictionary(new{cid=newop.CompanyID,oid=newop.ID}), HttpContext.Request.Url.Scheme, HttpContext.Request.Url.Authority)
Here the url is built after the route engine determine the correct one:
Url.Action("Detail","Opinion",new RouteValueDictionary(new{cid=newop.CompanyID,oid=newop.ID}),HttpContext.Request.Url.Scheme, HttpContext.Request.Url.Authority)
In both methods, the last 2 parameters specifies the protocol and hostname.
Regards.
I had the same issue, and it appears Gidon's answer has one tiny flaw: it generates a relative URL, which cannot be sent by mail.
My solution looks like this:
string link = HttpContext.Request.Url.Scheme + "://" + HttpContext.Request.Url.Authority + Url.Action("ResetPassword", "Account", new { key = randomString });
This way, a full URL is generated, and it works even if the application is several levels deep on the hosting server, and uses a port other than 80.
EDIT: I found this useful as well.
Another way to create an absolute URL to an action:
var relativeUrl = Url.Action("MyAction"); //..or one of the other .Action() overloads
var currentUrl = Request.Url;
var absoluteUrl = new System.Uri(currentUrl, relativeUrl);
I know this is an old question, but just in case you are trying to do the same thing in ASP.NET Core, here is how you can create the UrlHelper inside an action:
var urlHelper = new UrlHelper(this.ControllerContext);
Or, you could just use the Controller.Url property if you inherit from Controller.

Resources