There's no edit button for original question :(
I know I can use Exclude flag on parent page types, and even extract some interface in order to simplify the list of included / excluded content types... but I have too many page types, and I'd like to keep this DRY.
Is this possible? :)
Hi
To me this sounds like a bug. None of your speciified setting should affect the settings for ContainerPage. I will report a bug on this.
I looked at the bug but I can't really figure out what you mean, why are you using IncludeOn=B?
If I change your code above using the ExcludeOn=ContainerPage it is correctly exluded from container page. If I use IncludeOn then it is included.
[ContentType(GUID = "99853a59-1496-4b20-9a15-d993ea63a7f8")] [AvailableContentTypes( Availability.Specific, Include = new[] { typeof(B), typeof(C) }, ExcludeOn = new[] { typeof(ContainerPage) })] public class B : PageData { }
Sorry, it might not be a bug :)
If I want to include page type B on page type A, and exclude it from all other page types, do I have to use
[ContentType(GUID = "...")] [AvailableContentTypes( Availability.Specific, ExcludeOn = new[] { typeof(...), typeof(...), typeof(...), typeof(...) ... })] public class B : PageData { }
or can I just use:
[ContentType(GUID = "...")] [AvailableContentTypes( Availability.Specific, IncludeOn = new[] { typeof(A))] public class B : PageData { }
I thought if I only specify IncludeOn = 'something', that's equivalent to IncludeOn = 'something' and ExludeOn = All
Basically I don't want to update ExcludeOn list each time I create a new page type.
If I exclude PageDate like this:
[ContentType(GUID = "...")] [AvailableContentTypes(Availability.None, ExcludeOn = new[] { typeof(PageData) }, IncludeOn = new[] { typeof(A) })] public class B : PageData { }
Then I cannot create page type B under page type A.
edit: Ok, now I see what I want to achieve is not possible. Thanks Per!
I ran into this when creating a module which had two page types: X and Y
Now I want X to be created only directly under the root page, and Y only created under X, like so:
[ContentType] [AvailableContentTypes(Include = new[] { typeof(Y) }, ExcludeOn = new[] { typeof(PageData) }, Availability = Availability.Specific)] public class X : PageData { } [ContentType] [AvailableContentTypes(IncludeOn = new[] { typeof(X), typeof(Y) }, Availability = Availability.Specific)] public class Y : PageData { }
This work alright, except ofcourse Y will be able to be created on all current and future content types that does not have the [AvailableContentTypes(Include = ...)] attribute. As the defult is to have all content types available.
I did some reflecting and came up with this, but I am worried it can have unforeseen consequences, though in the interest of getting an official option to exclude a content type everywhere except where I want, here goes:
/// <summary> /// Modifies the <see cref="ContentTypeModel.AvailableContentTypes"/> setting for all content types to exclude the <see cref="Y"/> type. /// </summary> public class SetContentTypeAvailability : ContentDataAttributeScanningAssigner { public override void AssignValues(ContentTypeModel contentTypeModel) { base.AssignValues(contentTypeModel); if (contentTypeModel.ModelType == typeof (X) || contentTypeModel.ModelType == typeof (Y)) { return; } if (contentTypeModel.AvailableContentTypes == null) { contentTypeModel.AvailableContentTypes = new AvailableContentTypesAttribute(); } if (contentTypeModel.AvailableContentTypes.Exclude.All(t => t != typeof (Y))) { contentTypeModel.AvailableContentTypes.Exclude = contentTypeModel.AvailableContentTypes.Exclude.Union(new[] {typeof (Y)}).ToArray(); } } } [InitializableModule] [ModuleDependency(typeof (InitializationModule), typeof (ServiceContainerInitialization))] public class Initializer : IConfigurableModule { public void Initialize(InitializationEngine context) { } public void UnInitialize(InitializationEngine context) { } public void ConfigureContainer(ServiceConfigurationContext context) { context.Container.Configure(ctx => ctx.For<IContentTypeModelAssigner>().Use<SetContentTypeAvailability>()); } }
A neater option would be something maybe like so, where the Explicit enum would mean "ignore everything else!":
[ContentType] [AvailableContentTypes(IncludeOn = new[] { typeof(Y), typeof(X) }, Availability = Availability.Explicit)] public class Y : PageData { }
I know it's a bit late, but I have just been fixing an issue with this attribute as reported in http://world.episerver.com/blogs/Henrik-Fransas/Dates/2015/10/the-known-and-unknown-of-include-includeon-exclude-and-excludeon/ and though I would have a look into your suggestion Erik.
My suggestion in your case would be to take a step back and instead of trying too hard with the attributes and instead work directly with the IAvailableModelSettingsRepository and Register a setting there. This is the equivalent of changing the setting in the Admin UI, so the result is that new content types won't be included unless explicitly stated so. The downside of this is that you would have to take special care if you still want administrators to be able to manipulate these values.
I have the same issue, I would prefer a better solution for this scenario. A simple practical scenario is a news archive based on two page types. "NewsPageData" should only be available on "NewsListPageData", but unavailable for all other page types.
Hah! This old thread.
I actually did take a satep back and scrapped the whole idea at first. But I now revisited the IAvailableModelSettingsRepository idea from Henriks comment.
The problem with this approach is that you can not register settings specifically for ex. the root page due to it having no ModelType, atleast not from what I can see. Though that will be a minor issue for my specific scenario as editors aren't usually allowed to create pages under the root page directly anyways.
This is what I ended up with in the end:
private void InitializeContentTypeRestrictions() { // load all content types registered var contentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>(); var allContentTypes = contentTypeRepository.List().Where(c => c.ModelType != null).Select(c => c.ModelType).ToList(); var availableModelSettingsRepository = ServiceLocator.Current.GetInstance<IAvailableModelSettingsRepository>(); // create and register setting for TranslationStringPage var setting = new AvailableContentTypesAttribute(Availability.Specific) { ExcludeOn = allContentTypes.Except(new[] {typeof(TranslationStringPage), typeof(TranslationRootPage)}).ToArray(), Include = new[] {typeof(TranslationStringPage)} }; availableModelSettingsRepository.RegisterSetting(typeof(TranslationStringPage), setting); // create and register setting for TranslationRootPage setting = new AvailableContentTypesAttribute(Availability.Specific) { ExcludeOn = allContentTypes.ToArray(), Include = new[] {typeof(TranslationStringPage)} }; availableModelSettingsRepository.RegisterSetting(typeof(TranslationRootPage), setting); }
Very old post indeed haha, a more "native" solution would still be prefered in the long run of course :)
Hi,
I have the following page types:
Container page can contain any page type.
A page can contain B and C page types
B can contain B and C page types
C cannot contain any page type.
Here's the code:
The problem is, editors are allowed to create B pages types under ContainerPage.
Is this a bug with IncludeOn attribute, or is this how it's supposed to work?
Do I have to specify all AvailableContentTypes on ContainerPage or can I solve this in another way?
EPiServer 8.2.0
Thanks!