Sitecore Url works with any Extension - sitecore

In my website , the url's are working even entering something after .aspx and giving staus code 200.
Eg: below is normal page with .aspx and status code 200.
But even i have any random extension i got 200 status code which suppossed to be a 404 Status code,
Any Help.

Sitecore is quite generous when it resolves URL's. If you want to enforce correct extensions, you could create a custom Item Resolver which ensures the context item remains null in the process method if the URL has the incorrect extension.
Here's a helpful article on creating an Item Resolver:
Thoughts on httpRequestBegin - Custom Item Lookups
In my example below, the base process method is called. After that we check if the Context Item meets the requirements, and set it to null if not. (You'll need to implement TemplateIsAPageType and ExtensionIsValid as you see fit.)
public class CustomItemResolver : HttpRequestProcessor
{
public override void Process( HttpRequestArgs args )
{
base.Process(args);
if( Context.Item != null && TemplateIsAPageType() && !ExtensionIsValid())
{
Context.Item = null;
}
}
}
Another approach might be something like this, where we compare the requested URL with the resolved item's 'ideal' URL:
public class CustomItemResolver : HttpRequestProcessor
{
public override void Process( HttpRequestArgs args )
{
base.Process(args);
if( Context.Item == null)
return;
var requestUrl = HttpContext.Current.Request.RawUrl;
var idealUrl = LinkManager.GetItemUrl(Context.Item);
if(requestUrl != idealUrl)
Context.Item = null;
}
}

Sitecore skips everything after the last dot ”.” in an url when attempting to resolve an item.
This is done by the class Sitecore.Web.RequestUrl which has a property called ItemPath. This property attempts to create a valid path to an item from the requested url. It is not possible to override this property.
If you for some reason would like Sitecore to return a 404 status code if an item is requested with a file extension, such as .aspx, you could do something like this in a 404 not found item resolver. See this post http://laubplusco.net/handling-404-sitecore-avoid-302-redirects/ the following method extends the one shown in the post.
protected virtual bool IsValidContextItemResolved(string filePath)
{
if (Context.Item == null || !Context.Item.HasContextLanguage())
return false;
if (filePath.Contains(".") && !RequestIsForPhysicalFile(filePath))
return false;
return !(Context.Item.Visualization.Layout == null
&& string.IsNullOrEmpty(WebUtil.GetQueryString("sc_layout")));
}
It is important to ensure that the requested url is not for a physical file first. This is done by checking that the args.Url.filepath does not map to a physical file.
The rule which I show here says that if an item has been resolved and the filepath contains a dot then the requested url should return a 404 and the context item should be the not found item. The code could be extended to check what comes after the dot to see if it is a valid extension.

Related

Error resolving URL's that do not have a space

Currently in an effort to upgrade our site from 7.2 to 8.2 161115 and getting a Document Not Found error if a URL does not have a space in it.
Almost all of the URL's in our site have a space in the content item name and work fine. Only a few don't.
For example these work:
/Page Name/
/Page-Name/
/Page/Sub Page/
/Page/Sub-Page/
These do not work:
/Page
/Page/SecondaryPage
This error occurs on a special template we have called "Context Resolver" which forwards a visitor to a different page based on rules. The template has three fields:
Forwarding Enabled (checkbox)
Rules (ruleset)
Default Item (droptree)
The idea is that these items make decisions on where to send a visitor. We have a pipeline that runs the following code:
public override void Process(HttpRequestArgs args)
{
if (args == null) return;
var item = Sitecore.Context.Item;
if (item == null) return;
if (item.TemplateID != SitecoreDefinitions.ContextForwarderTemplate) return;
if (!item.IsContextForwarderEnabled()) return;
var rulesItem = item.Fields["Rules"];
if (rulesItem != null)
{
RuleFactory.InvalidateCache();
var rules = RuleFactory.GetRules<RuleContext>(rulesItem);
if (sitecoreRepository.ExecuteRules(rules.Rules))
return;
}
ReferenceField refItem = item.Fields["Context"];
Context.Item = refItem.TargetItem;
}
This work's great, as expected from our previous 7.2 site on any URL with a space. If there is no space, it fails. Without the rules, there is no difference, so the error is happening from this line:
Sitecore.Context.Item = someNewItem
Thoughts? We can easily reproduce this issue with this template type on the working URL's by removing the space, and add a space on failing URL's to make them work.

Implementing Sitecore Multisite Robots.txt files

How to implement to have different robots.txt files for each website hosting on the same Sitecore solution. I want to read dinamically robots.txt from sitecore items.
you need to follow next steps:
1) Create and implement your custom generic (.ashx) handler.
2) In the web.config file add the following line to the section
3) Navigate to the section and add here
4) On home item you will have "Robots" field (memo, or multi line field, not richText field)
Your custom generic handler will look like :
public class Robots : IHttpHandler
{
public virtual void ProcessRequest(HttpContext context)
{
private string defaultRobots = "your default robots.txt content ";
string robotsTxt = defaultRobots;
if ((Sitecore.Context.Site == null) || (Sitecore.Context.Database == null))
{
robotsTxt = defaultRobots;
}
Item itmHomeNode = Sitecore.Context.Database.GetItem(Sitecore.Context.Site.StartPath);
if (itmHomeNode != null)
{
if ((itmHomeNode.Fields["Robots"] != null) && (itmHomeNode.Fields["Robots"].Value != ""))
{
robotsTxt = itmHomeNode.Fields["Robots"].Value;
}
}
context.Response.ContentType = "text/plain";
context.Response.Write(robotsTxt);
}
We had similar problems especially in the multi site environment, so we used the handlers for implementing robots.txt
Create a new class inheriting from IHTTPHandler and implement the logic within the process method. Write the XML ouput to the context object.
context.Response.ContentType = "text/plain";
context.Response.Output.Write({XML DATA});
Add the custom handler and trigger.
<handler trigger="~/Handlers/" handler="robots.txt"/>
<add name="{Name}" path="robots.txt" verb="*" type="{Assembly Name and Type}" />
It seems that if you want to access Sitecore Context, and any items, you need to wait untill this stuff is resolved. The aboce method will always give you a null in the Site definition, as this isnt resolved when the filehandler kicks in.
It seems that to get the Sitecore.Context, you should implement a HttpRequestProcessor in Sitecore, that renderes the robots.txt, example on this website:
http://darjimaulik.wordpress.com/2013/03/06/how-to-create-handler-in-sitecore/
You can refer to this blog post for step-by-step explanation on how to do it with a custom HttpRequestProcessor and a custom robots settings template : http://nsgocev.wordpress.com/2014/07/30/handling-sitecore-multi-site-instance-robots-txt/

Set queryable source on Rendering Parameter Template field

I have a Rendering Parameter template applied to a sublayout. It has a single Droptree field on it, and I want to set the Source of that field to a Sitecore query so I can limit the options available for that field.
Source can be:
query:./*
or
query:./ancestor-or-self::*[##templatename='MyTemplate']/
The query just needs to grab items relative to the content item that we're on. This normally works with Droptree fields in the content editor.
However I'm finding that the query isn't working here because we're in the rendering parameters, so it's not using the content item as it's context.
The query fails and I just get the full Sitecore tree.
I found this can be fixed up for the Datasource field with 'Queryable Datasource Locations' at this link:-
http://www.cognifide.com/blogs/sitecore/reduce-multisite-chaos-with-sitecore-queries/
However I don't know where to start to get this working for other rendering parameter fields.
Any ideas? (I'm using Sitecore 6.6 Update 5)
Unfortunately, the pipeline mentioned in Adam Najmanowicz's answer works for some other types, like Droplink and Multilist, but the pipeline isn't run for Droptree fields.
After looking into this deeper I found that the Source of a Droptree field IS using the wrong context item, as Adam mentioned, but the code comes from the Droptree field itself:-
Sitecore.Shell.Applications.ContentEditor.Tree, Sitecore.Kernel
Utilising the query string code from Adam's answer, we can create a 'fixed' Droptree custom field, that is almost the same as the regular Droptree but will use the correct context item instead.
The code will inherit from the normal Tree control, and only change the way that the Source property is set.
public class QueryableTree : Sitecore.Shell.Applications.ContentEditor.Tree
{
// override the Source property from the base class
public new string Source
{
get
{
return StringUtil.GetString(new string[]
{
base.Source // slightly altered from the original
});
}
set
{
Assert.ArgumentNotNull(value, "value");
if (!value.StartsWith("query:", StringComparison.InvariantCulture))
{
base.Source = value; // slightly altered from the original
return;
}
Item item = Client.ContentDatabase.GetItem(this.ItemID);
// Added code that figures out if we're looking at rendering parameters,
// and if so, figures out what the context item actually is.
string url = WebUtil.GetQueryString();
if (!string.IsNullOrWhiteSpace(url) && url.Contains("hdl"))
{
FieldEditorParameters parameters = FieldEditorOptions.Parse(new UrlString(url)).Parameters;
var currentItemId = parameters["contentitem"];
if (!string.IsNullOrEmpty(currentItemId))
{
Sitecore.Data.ItemUri contentItemUri = new Sitecore.Data.ItemUri(currentItemId);
item = Sitecore.Data.Database.GetItem(contentItemUri);
}
}
if (item == null)
{
return;
}
Item item2 = item.Axes.SelectSingleItem(value.Substring("query:".Length));
if (item2 == null)
{
return;
}
base.Source = item2.ID.ToString(); // slightly altered from the original
}
}
The above code is pretty much the same as the Source property on the base Tree field, except that we figure out the proper context item from the URL if we've detected that we're in the rendering parameters dialog.
To create the custom field, you just need to edit the Web.Config file as described here. Then add the custom field to the core database as described here.
This means that parameters can now have queries for their source, allowing us to limit the available items to the content editor. (Useful for multi-site solutions).
The key here would be to set the Field Editor's context to be relative to the item you are editing instead of the Rendering parameters (that I think it has by default).
So you could have processor:
public class ResolveRelativeQuerySource
{
public void Process(GetLookupSourceItemsArgs args)
{
Assert.IsNotNull(args, "args");
if (!args.Source.StartsWith("query:"))
return;
Item contextItem = null;
string url = WebUtil.GetQueryString();
if (!string.IsNullOrWhiteSpace(url) && url.Contains("hdl"))
{
FieldEditorParameters parameters = FieldEditorOptions.Parse(new UrlString(url)).Parameters;
var currentItemId = parameters["contentitem"];
if (!string.IsNullOrEmpty(currentItemId))
{
Sitecore.Data.ItemUri contentItemUri = new Sitecore.Data.ItemUri(currentItemId);
contextItem = Sitecore.Data.Database.GetItem(contentItemUri);
}
}
else
{
contextItem = args.Item;
}
}
}
hooked as:
<sitecore>
<pipelines>
<getLookupSourceItems>
<processor patch:before="*[#type='Sitecore.Pipelines.GetLookupSourceItems.ProcessQuerySource, Sitecore.Kernel']"
type="Cognifide.SiteCore.Logic.Processors.ResolveRelativeQuerySource, Cognifide.SiteCore" />
</getLookupSourceItems>
</pipelines>
</sitecore>
Together with ResolveQueryableDatasources from Przemek's blog this should solve your problem.

How to generate media item link with id instead of path in Sitecore

Anyone knows how to generate links in sitecore with ID instead of item path?
If you use GetMediaUrl method from the API, I can get this URL:
/~/media/Images/Archive/content/News and Events/News_and_Events_Level2/20070419162739/iwhiz3.jpg
The problem with this approach is that if someone changes the media item name, removes it somewhere or deletes it, the above link will break.
I notice if I insert a media link from rich text editor, I get the link as below:
/~/media/14BDED00E4D64DFD8F74019AED4D74EB.ashx
The second link is better because it's using the item id, so if the actual media item is renamed, removed, or deleted, all related links will be updated too. On top of that, when Sitecore renders the page, it will actually convert the above link and display the item path so it's readable.
I'm using Sitecore 6.5 and currently doing content migration so I need to make sure all internal links are updated properly.
May I know if there is a method to generate the second link by using sitecore API?
Thanks!
The GetMediaItemUrl extension method seems to give you what you want.
public static class ItemExtensions
{
public static string GetMediaItemUrl(this Item item)
{
var mediaUrlOptions = new MediaUrlOptions() { UseItemPath = false, AbsolutePath = true };
return Sitecore.Resources.Media.MediaManager.GetMediaUrl(item, mediaUrlOptions);
}
}
[TestFixture]
public class when_using_items_extensions
{
[Test]
public void a_url_based_on_media_item_id_can_be_generated()
{
// Arrange
Database db = global::Sitecore.Configuration.Factory.GetDatabase("master");
Item item = db.GetItem("/sitecore/media library/Images/MyImage");
// Act
var mediaUrl = item.GetMediaItemUrl();
// Assert
Assert.That(mediaUrl, Is.EqualTo("/~/media/17A1341ABEEC46788F2159843DCEAB03.ashx"));
}
}
These are called dynamic links and you can normally generate them using the LinkManager e.g:
Sitecore.Links.LinkManager.GetDynamicUrl(item)
.. but I'm not sure of the method to do this with Media links (there probably is one but I cant seem to find it and its not on MediaManager) but the basic syntax is:
"/~/media/" + item.ID.ToShortID() + ".ashx"
If you always want to use ID's instead of paths, you can change this setting in webconfig to false (like this):
<setting name="Media.UseItemPaths" value="false"/>`
Here is what the webconfig describes about it:
MEDIA - USE ITEM PATHS FOR URLS
This setting controls if item paths are used for constructing media URLs.
If false, short ids will be used.
Default value: true
Then you can use the default implementation (without additional parameters):
Sitecore.Resources.Media.MediaManager.GetMediaUrl(item);
This is what I use:
var imgField = ((Sitecore.Data.Fields.ImageField)currentItem.Fields["Icon"]);
MediaUrlOptions opt = new MediaUrlOptions();
opt.AlwaysIncludeServerUrl = true;
// Absolute Path works as well. So either use AbsolutePath or AlwaysIncludeServerUrl
opt.AbsolutePath = true;
string mediaUrl = MediaManager.GetMediaUrl(imgField.MediaItem, opt);

Sitecore: How to get Item's Alias Url

Is it possible to get the Alias url of an Item from .NET? I am able to use Sitecore.Links.LinkProvider class to get the item's default url, but I haven't found a way to get the Alias url.
I don't think there's a method built into the Sitecore API anywhere that does that, but you could try something like this ...
string query = String.Format("/*/system/Aliases//*[##templateid='{0}' and contains(#Linked item, '{1}')]", Sitecore.TemplateIDs.Alias, Sitecore.Context.Item.ID);
Sitecore.Data.Items.Item alias = Sitecore.Context.Database.SelectSingleItem(query);
string aliasUrl = string.Empty;
if (alias != null) {
aliasUrl = String.Format("/{0}.aspx", alias.Name);
}
(I have not tested this, it's based on some code I'm already using + some other stuff off the top of my head.)