Sounds like you need to hook up to MovingPage and SavingPage events and cancel out or reset UrlSegment if it's "dirty".
That or just not give Editors access to the page.
Petter, most probably editors would need to change other properties, that's just a guess. So as Johan said - I would hook on events and inspect that page's data during its lifecycle and prevent some of actions.
Yes that is why I was poiting to Johans solution too. But from the topic and the fact that it wasn't specified, I thought I would advice to try with no editor access as well..
You can use an editor descriptor to hide or make a property ready only. Use this in combination with specific a model type or an attribute to control this:
[EditorDescriptorRegistrationAttribute(TargetType = typeof(ContentData))]
public class SiteMetadataExtender : EditorDescriptor
public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes)
foreach (ExtendedMetadata property in metadata.Properties)
if (property.PropertyName == "iroutable_routesegment" && true)//Whatever logic you want to control this by, perhaps an attribute on the model class or the type of the model class)
//property.ShowForEdit = false;
// to hide the URL or
property.EditorConfiguration["readOnly"] = true;
//to make it read only.
Nice, so final solution would be to prevent editing URLSegment by UIDescriptor and preventing moving around page tree by hooking to events?
@Johan: I must admit that I had to browse the source code to see how it was done ;)
@Valdis: Yes, that sounds reasonable. Perhaps an attribute on the model class that could be used to control both of these limitations...
Clever... Combined with this code in a startup Sequence its perfekt :-)
public void CheckLoginControllerExists(object sender, EventArgs eventArgs)
var serviceLocationHelper = ServiceLocator.Current.GetInstance<ServiceLocationHelper>();
var pageTypeRepository = ServiceLocator.Current.GetInstance<PageTypeRepository>();
var repository = ServiceLocator.Current.GetInstance<IContentRepository>();
var siteDefinitionRepository = ServiceLocator.Current.GetInstance<SiteDefinitionRepository>();
var site = siteDefinitionRepository.Get("SiteName");
if (site == null) //site is not defined, bail out...
var defaultStartPage = repository.Get<PageData>(site.StartPage);
var criterias = new PropertyCriteriaCollection //set a search criteria
// Find pages of a specific page type
Name = "PageTypeID",
Condition = CompareCondition.Equal,
Required = true,
Type = PropertyDataType.PageType,
Value = pageTypeRepository.Load(typeof(LoginPage)).ID+"" //find the id of the type of page
PageDataCollection newsPageItems = serviceLocationHelper.PageCriteriaQueryService().FindPagesWithCriteria(defaultStartPage.PageLink, criterias);
foreach (var pageData in newsPageItems)
var o = pageData as LoginPage;
if (o != null) //we found our login page
//is it a child of startpage?
if (o.ParentLink == defaultStartPage.ContentLink && o.Name == "login")
return; // we found the page, everything is ok.. move along
//there is no login page, make one
var loginPage = repository.GetDefault<LoginPage>(defaultStartPage.ContentLink, pageTypeRepository.Load(typeof(LoginPage)).ID);
loginPage.Name = "login";
loginPage.URLSegment = UrlSegment.CreateUrlSegment(loginPage);
repository.Save(loginPage, EPiServer.DataAccess.SaveAction.Publish, EPiServer.Security.AccessLevel.NoAccess);
I need to instantiate a page programmatically, where the editor cannot move it or change the url. Basically I need a specific url pattern and a custom instance.
How would I go about that?