I wanted to make a simple page navigation macro that, instead of only taking into account "Visible" would also look at whether or not a member has access to a page (and leave out unaccessible pages from the nag bar).
There is a lot of confusion online, even on these forums where people seem to think that something like
foreach (var page in CurrentPage.Children.Where("Visible &&
HasAccess") would work.
However, that last bit of code will not work because, during runtime, page will resolve (is that the correct terminology?) to DynamicPublishedContent and Children will be a DynamicPublishedContentList and the string argument of Where() will be converted into a lambda expression by Umbraco.Web.Dynamics.ExpressionParser<T>.Parse(...) and this is the problem:
DynamicPublishedContent has no definition for something like IsProtected() of HasAccess() so obviously they cannot be resolved by the above Where()...
One has to resort to Umbraco.MemberHasAccess() and Umbraco.Isprotected() but as far as I know, you cannot use them in the Where() call because it cannot be parsed (or am I wrong?), as far as I can tell because arguments are needed for MemberHasAccess:
Nonetheless, being able to not only filter visible pages but also accessible ones from a Where() would be very, very convenient in my opinion.
Could anyone comment on this? I would really like to understand why MemberHasAccess was implemented in the way it was and put in UmbracoHelper instead of being an integral part of DynamicPublishedContent.
I actually prefer the current implementation wherein web security is seperated from content. For partial actions you would also be using User.IsInRole() rather than IPublishedContent.HasAccess().
The option to hide or show content in navigation ("Visible") is unrelated to security imo (and correctly so a property on content).
And if that means writing an extra IF statement within a FOREACH.. I really don't mind :)
PS: you could also use an extension method for filtering secured content
Here's an example for strongly typed content:
public static IEnumerable<IPublishedContent> AndHasAccess(this IEnumerable<IPublishedContent> content)
{
var helper = new UmbracoHelper(UmbracoContext.Current);
foreach (var c in content)
{
if (helper.IsProtected(c.Id, c.Path) && helper.MemberHasAccess(c.Id, c.Path))
yield return c;
}
}
I hadn' t looked at it in that way and I have to say it seems to make sense.
Your proposed extension method also seems like an elegant solution...
One more thing I currently do not fully grasp: would you have any idea why the Where on DynamicPublishedContent does not accept lambdas as arguments instead of strings needing parsing by ExpressionParser? Currently, my understanding of dynamics, lambdas and such does not reach much further than being able to use existing stuff so this might be a stupid question...
That's a tough question. I don't really have much experience with dynamic types as in most of our projects we have full control over model and content and I really prefer strongly typed models because I'm a monkey without intellisense :)
I do believe much of the confusion is caused by the quick pace at which dynamic types have changed over time (from Razor scripts in Umbraco 4.x to Umbraco 6 and 7) and the documentation still mentions the dynamic query parser has its merits when it comes to complex querying (i.e. lambdas)
The best advice I can give is to code by example and poke around and to keep reporting issues when you're stuck.
@Lennart, what a great extension method, I will be adding that one to my collection!
@Kris, you cannot use Lambda expressions with dynamics, that's why we have the Expression Parser instead. However if you want to do a Lambda you could either use a fully typed .Where or if you really want to you can used typed for your query and get it to return dynamic, here is how:
@PartialViewMacropage and page protection status
Hello all,
I wanted to make a simple page navigation macro that, instead of only taking into account "Visible" would also look at whether or not a member has access to a page (and leave out unaccessible pages from the nag bar).
There are lots of examples in this respect:
There is a lot of confusion online, even on these forums where people seem to think that something like
foreach (var page in CurrentPage.Children.Where("Visible && HasAccess")
would work.However, that last bit of code will not work because, during runtime, page will resolve (is that the correct terminology?) to
DynamicPublishedContent
and Children will be aDynamicPublishedContentList
and the string argument of Where() will be converted into a lambda expression byUmbraco.Web.Dynamics.ExpressionParser<T>.Parse(...)
and this is the problem:DynamicPublishedContent has no definition for something like
IsProtected()
ofHasAccess()
so obviously they cannot be resolved by the above Where()...One has to resort to
Umbraco.MemberHasAccess()
andUmbraco.Isprotected()
but as far as I know, you cannot use them in theWhere()
call because it cannot be parsed (or am I wrong?), as far as I can tell because arguments are needed forMemberHasAccess
:Nonetheless, being able to not only filter visible pages but also accessible ones from a Where() would be very, very convenient in my opinion.
Could anyone comment on this? I would really like to understand why MemberHasAccess was implemented in the way it was and put in UmbracoHelper instead of being an integral part of DynamicPublishedContent.
Cheers,
Kris
Hi Kris,
I actually prefer the current implementation wherein web security is seperated from content. For partial actions you would also be using User.IsInRole() rather than IPublishedContent.HasAccess().
The option to hide or show content in navigation ("Visible") is unrelated to security imo (and correctly so a property on content).
And if that means writing an extra IF statement within a FOREACH.. I really don't mind :)
Grtz
L
PS: you could also use an extension method for filtering secured content
Here's an example for strongly typed content:
Usage:
I'm sure you can do the same for dynamic types.
Grtz
L
Hi Lennart,
I hadn' t looked at it in that way and I have to say it seems to make sense.
Your proposed extension method also seems like an elegant solution...
One more thing I currently do not fully grasp: would you have any idea why the Where on DynamicPublishedContent does not accept lambdas as arguments instead of strings needing parsing by ExpressionParser? Currently, my understanding of dynamics, lambdas and such does not reach much further than being able to use existing stuff so this might be a stupid question...
Hi Kris,
That's a tough question. I don't really have much experience with dynamic types as in most of our projects we have full control over model and content and I really prefer strongly typed models because I'm a monkey without intellisense :)
I do believe much of the confusion is caused by the quick pace at which dynamic types have changed over time (from Razor scripts in Umbraco 4.x to Umbraco 6 and 7) and the documentation still mentions the dynamic query parser has its merits when it comes to complex querying (i.e. lambdas)
The best advice I can give is to code by example and poke around and to keep reporting issues when you're stuck.
@Lennart, what a great extension method, I will be adding that one to my collection!
@Kris, you cannot use Lambda expressions with dynamics, that's why we have the Expression Parser instead. However if you want to do a Lambda you could either use a fully typed .Where or if you really want to you can used typed for your query and get it to return dynamic, here is how:
Jeavon
is working on a reply...