List of Themes in View

Topics: Writing modules
Dec 30, 2013 at 8:17 PM
I'm writing a simple module that will allow the website user to change the current theme from a menu...it's a theme demo site that allows the user to view different themes while maintaining the same content.

I've got most of it working, but I can't seem to figure out the best way to get a list of themes to display in the shape that I'm forcing into every page.

I'm using a FilterProvider to inject a shape at the end of the body tag. In that shape, I need to create a list of enabled themes to choose from. I already have the controller action to post the choice to which will get stored in a session variable and retrieved to change the theme using ThemeSelectorResult.

I tried looking at the Controller action for Vandelay.Industries theme selector, but I can't seem to figure out how to use the same type of logic in the shape.

Any ideas on how I can achieve this? Or is there a way to pass that list into the shape from the FilterProvider? Here is how I'm generating the shape in the FilterProvider
_workContextAccessor.GetContext(filterContext).Layout.Zones["Body"].Add(_shapeFactory.Create("ThemeSwitcher"), ":after");
Thanks for any help
Dec 30, 2013 at 10:53 PM
Not sure if this is the best way, but I added an IEnumerable<string> of the enabled themes to a session variable in the FilterProvider:
HttpContext.Current.Session["EnabledThemes"] = _extensionManager.AvailableExtensions().Where(d => DefaultExtensionTypes.IsTheme(d.ExtensionType) && _shellDescriptor.Features.Any(sf => sf.Name == d.Id)).Select(d => d.Id).OrderBy(n => n);
then I'm retrieving it in the shape
IEnumerable<string> themes = HttpContext.Current.Session["EnabledThemes"] != null ? (IEnumerable<string>)HttpContext.Current.Session["EnabledThemes"] : null;
any issues with this that you can see or suggestions for a better solution?
Dec 30, 2013 at 11:14 PM
What about having a dedicated part storing nothing but with a display driver filling the shape 's model with anything needed in display ?
Dec 30, 2013 at 11:19 PM
Layout is a dynamic, I guess you can put whatever you want in there as well.

Better yet, why don't you put the list to your shape? It's dynamic as well, and the list should be in it logically. Something like:

dynamic shape = _shapeFactory.Create(....);
shape.EnabledThemes = _extensionManager....
....Layout.Zones("Body").Add(shape);

and in your template:
IEnumerable<string> themes = Model.EnabledThemes;


Marked as answer by psenechal on 2/6/2014 at 4:37 PM
Dec 30, 2013 at 11:37 PM
Brilliant...thanks Kass! Never even occurred to me to actually USE the shape I was generating as an actual shape =)

Much simpler and a way better option than throwing it into a session variable.
Developer
Jan 2, 2014 at 4:13 AM
@psenechal That's the whole beauty of shapes:) Shape is, simply put, a dynamic viewmodel which can be easily extended with whatever data you need without having to use any intermediate carrier like Session/TempData/ViewBag etc.

Session is evil, btw;)
Jan 3, 2014 at 6:43 PM
Question for you since session is evil =)

I need to set a value in a Controller, then be able to pick it up in a class file that is implementing IThemeSelector.

In the Controller, I'm currently doing the following
        [HttpPost]
        public ActionResult SwitchTheme(string themeName, string returnUrl) {
            if (!string.IsNullOrWhiteSpace(themeName)) {
                HttpContext.Session["ActiveTheme"] = themeName;
            }

            return Redirect(returnUrl);
        }
and in the class file, I'm doing the following
    public class ThemeSelector : IThemeSelector {
        public ThemeSelectorResult GetTheme(RequestContext context) {
            if (HttpContext.Current.Session["ActiveTheme"] != null) {
                return new ThemeSelectorResult { Priority = 1, ThemeName = HttpContext.Current.Session["ActiveTheme"].ToString() };
            }

            return null;
        }
    }
Do you know if there's a possible way to do this without using session? Thanks =)
Jan 4, 2014 at 5:25 AM
Use a cookie.
I use this tech for a currency selector with good results.
Coordinator
Jan 4, 2014 at 8:28 AM
Edited Jan 4, 2014 at 8:29 AM
Argh. Come on. Let's be serious for a second. Why is Piotr saying that session is evil? Well, if you are not careful, you are storing data (in memory or wherever your session is kept), per user, which can quickly add up to some major scalability issues. Mostly, that's it. If your session information is short-lived and small, you're mostly fine using it. It so happens that ASP.NET MVC has a mechanism for short-lived, small amounts of data to persist until the next request: TempData. What do you think it uses under the hoods by default? That's right, session. What's nice about it is that it cleans up after itself. And what do you know? Orchard already uses it: that's how notifications work.

Just use TempData: it was designed for what you're doing, exactly...

Now you want to know something that's truly evil? Imagine a data payload that travels back and forth with every single f@$%^ request, and that adds its weight to everything you do, from the moment you set it to the moment you remove it, if you ever do. In case you didn't guess, I just described cookies. Oh, and they have major privacy issues, too. I can see very, very few reasons to ever store anything in cookies nowadays, except as a fallback for antique browsers, and except for session ids. If the data needs to be stored on the server, the database, Session, the cache, Application, and TempData are there. If it can be stored on the client, client storage works wonderfully, and doesn't have the problems of cookies.
Jan 4, 2014 at 9:33 AM
Edited Jan 4, 2014 at 9:34 AM
@Bertrand that's a long debate and opinions are cycling.
I woudl just say that Orchard also uses cookies (and many modules) and the 'payload' of a cookie is minimal (its size being very small) compared to other 'data transiting on http',
Cookies are universal, managed by 'message header' layers of code with very easy API.
Why trigger all these memory intensive systems as session for storing a 15 bytes theme name (TempData).
Cookies will be on every server of a farm ... and session also: the energy to do it happen correctly is not the same.
Cookies are sent by browsers in every transaction
In my opinion perfect for very basic non secured concepts.
Coordinator
Jan 5, 2014 at 1:07 AM
Hum. Sure, let's let people evaluate opinions. Just a note: querystrings can transfer small payloads through a redirect without being stuck in all the subsequent requests. Did you consider that possibility?

Sure, Orchard is using cookies in several places. That doesn't make it right. Storing the expansion state of admin submenus for example, is a very bad use-case. That info would be much more efficiently stored in client user storage.

Do you have evidence that using TempData triggers "memory intensive systems"?
Jan 5, 2014 at 7:14 AM
Yes query string but not very nice looking, nice for REST.

Back to orchard, what is the usage of this cookie created by base.js script:: orchrd_ ?
I noticed some orchard sites have got rid of it?
Even if they all present the Google, Facebook, Twitter, etc. cookies...it will be a long fight, @Bertrand to remove cookies :)
Coordinator
Jan 5, 2014 at 7:21 AM
That's the one I was talking about: it memorizes the deployment states of admin submenus, which shouldn't be in cookies, but rather in local storage. The good news is that only admins see it, as far as I can tell.
You can be sure that Google, Facebook and Twitter are going to use cookies for a very, very long time, because they have one of the actual scenarios: tracking you.
Jan 5, 2014 at 8:30 AM
Edited Jan 5, 2014 at 8:31 AM
I Will investigate because I have it on my home pages ?

As soon as you intend to do some kind of analysis or commerce on a site you get implied in this cookie madness...
Coordinator
Jan 5, 2014 at 9:40 AM
Not necessarily: you can get a lot of info from referrers and from what they do on your site. You don't have to spy on your customers wherever they go, and you don't have to hand over your data to Google.
Jan 5, 2014 at 4:04 PM
That's not what I'm saying.
You move the subject far from cookies. (as usual :) )
The term spying and the related actions are media stars today and as are used as weapons everywhere.
But look, this is more a matter of law, insn't it ?
Coordinator
Jan 6, 2014 at 1:38 AM
The problem is that as usual, I have no idea what you're saying :)
Jan 6, 2014 at 5:37 AM
:)
I was saying that from a suggestion of using a cookie to store a data value related to each user, the conversation moved to the international plot of bad guys spying us everywhere...
Jan 6, 2014 at 9:23 AM
Anyway this doesn't matter
Coordinator
Jan 7, 2014 at 8:02 AM
Not really, no, and I like to tease you ;) Neither cookies nor session are that bad in the case of @psenechal's theme selection, because it's a user choice that needs to persist across requests, and that the server needs to know about. Choosing one over the other depends if you value scalability over a lot of concurrent users or over a lot of concurrent requests. In both cases, caching is going to be tricky. In the case of storing currency preferences, I don't know your exact situation but I'd guess that you could use local storage and make the conversions client-side. There would probably be benefits in doing so, actually, such as instant switching, or being able to cache your pages.
Jan 7, 2014 at 8:46 AM
Edited Jan 7, 2014 at 8:48 AM
Ok, it was my feeling of actual process anyway. Concerning currencies, it works fine actually, also solving the pb of 'anonymous currency'. I use a currency solver requesting: site, current user and some other solution providers: no problems today, no time to start changing what is working, is not complicated and does not look absolutely obsolete -orchard know this paradigm :) -.
I must also say that I am not sure that local storage would work on any device where is running a browser, with better chance that cookies management works?
I know that you use it for nwazet shopping cart, here on my side I use session ( :) ) but it would have a higher priority to change ... may be for DB when I have time finding a way to have fast db access out of NHibernate 'sordid one transaction effect' as I have been doing for years.
Concerning caching my product pages, as I have currencies and sometime the shopping cart displayed on them, caching is not desired. I cache static images in browser and sever cache, try to use MS CDN for js and css. I would appreciate to find a free solution for images in CDN....
  • I would also appreciate to have all orchard actual css and js in the MS CDN ??? -
Coordinator
Jan 8, 2014 at 8:17 AM
This is why you render the cache from a secondary ajax request: so that you can cache the page. All product pages on Nwazet are cached. The cart doesn't get in the way.
As for css and js in CDN, don't count on it ;)
Jan 8, 2014 at 8:05 PM
Good point, and I am doing also this for the Money selector, so I could cache :)