views:

275

answers:

5

I am running out of ideas here. Maybe you can advice me what pattern or method(s) to use.

User should be able to log in and change the appearance only for his/her profile. The difference (AFAIK) with personalization is that personalized layout are seen only for the editor (him-/herself). The difference between skinning, I guess, is that Skins are predefined but users should be able to change the settings themselves.

I need to be able to display the customized layout to everyone who visit author`s page.

The good solution would be to keep the layout info in a DB table. Also it should be cached I guess to take load off the DB and used in CSS.

Thanks

Edit:

OK I have done some research now. Came up with this kind of idea.

In a View get a userId (Guid type) from a DB and set it to the ViewData: ViewData["userId"] = profile.userId;

That View uses the following MasterPage called 'Profile.Master' and links to the dynamic CSS file:

    <link href="<%= Url.Action("Style", "Profile", 
        ViewData["userId"]) %>" rel="stylesheet" type="text/css" />
</head>

In the ProfileController get the CSS data from DB and return it to the dynamic CSS View:

public ActionResult Style(Guid userId)
{
    var styles = (from s in Db.UserStyleSet.OfType<UserStyle>()
                  where s.aspnet_Users.UserId == userId
                  select s);

    return View("Style", styles);
}

The problem is that the UserId is never passed to the dynamic CSS link:

The parameters dictionary contains a null entry for parameter 'userId' of non-nullable type 'System.Guid' for method 'System.Web.Mvc.ActionResult Style(System.Guid)' in 'Project.Controllers.ProfileController'.

Any advice is welcome, thank you.

A: 

This issue is more complex than choice of any particular pattern or handful of techniques. But... this is an issue that has been longed-solved by the Dot Net Nuke which is an ASP.Net project. It is open source and supports all of the user-specific skinning features that you're looking to support.

i suggest studying DNN's implementation of these features to give you a clue to support skinning in your MVC app.

Paul Sasik
A: 

You could use a CMS framework. See this question for suggestions

erikkallen
Thanks but no thanks :)
J Pollack
A: 

You could dynamically build a CSS file and save the css name in the user's db entry.

Austin
This would not be a very good solution for my project. When there would be many CSS files it would get slower. Databases are mean to keep/handle large amount of data.
J Pollack
+2  A: 

Very neat layout customization features you can find in Kona project developed by Rob Conery. When you run source code which you can find here, you will see layout management UI which allows you to change the position of each component on the screen.

The approach used there is as follows:

  1. When page is rendered our customized view engine check which master page should present (this way we are able to switch themes based on current settings)

        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) {
        ViewEngineResult result = null;
        var request = controllerContext.RequestContext;
        if (controllerContext.Controller.GetType().BaseType == typeof(KonaController)) {
            var orchardController = controllerContext.Controller as KonaController;
            string template = orchardController.ThemeName;
    
  2. View engine uses master page and renders view which was defined by specific controller action resolved using route tables. For instance, we typed main url of the site which pointed to Home Controller, Index method. This method returned Index.aspx view which was rendered by View engine.

  3. While view engine is rendering the Index.aspx page it launches helper methods like

    <%this.RenderWidgets("sidebar1"); %>.

This method is truely responsible for rendering specific widdgets per each div in the aspx page. This way, if your user changes the layout of the widgets they will be correctly presented on the screen.

        public static void RenderWidgets(this ViewPage pg,  Kona.Infrastructure.Page page, bool useEditor, string zone) {
        if (page != null) {
            foreach (IWidget widget in page.Widgets.Where(x => x.Zone.Equals(zone, StringComparison.InvariantCultureIgnoreCase))) {

                string viewName = useEditor ? widget.EditorName : widget.ViewName;


                if (widget.ViewName != null) {
                    if (widget.IsTyped) {
                        var typedWidget = widget as Widget<IList<Product>>;
                        pg.Html.RenderPartial(viewName, typedWidget);
                    } else {
                        pg.Html.RenderPartial(viewName, widget);
                    }
                } else if (!string.IsNullOrEmpty(widget.Title)) {
                    pg.Html.RenderPartial("TitleAndText", widget);

                } else {
                    pg.Html.RenderPartial("TextOnly", widget);
                }
            }
        }
    }

How user is able to change the layout? Kona has very neat javascript which is used together with Ajax and user simply drag&drop widgets from one panel to another to reorder the layout.

maciejgren
A: 

How much customisation do you need? Storing an entire css in the database 1 style at a time seems a little overkill, are you sure your users really need / want that level of customisation?

Wouldn't it be simpler to present a list of themes, allow the user to select the one they want and then store that information with the user profile so that when you retrieve the profile details you also retrieve the theme. This information can then be used to select the appropriate master as well as passed to the view to render the correct stylesheet(s).

If you really want to allow extreme customisation down to the individual style level, I would use a default css and then when the user customises their layout, copy the default and alter as necessary, creating a custom css for the user. Each time the user updates their profile layout, simply update the css file with the changes. To get around css caching, record an incrementing version number for each change and append that to the end of the url for the css e.g. <link rel="stylesheet" href="user001.css?v=2>.

Neal
I would like to allow users only to change colors. No layout changes. User will fill a form with custom colors and it will be stored in the DB by style groups (ie. style for body tag).The customized CSS will be placed into the Master page`s <head> and will override the styled defined in external CSS file.
J Pollack
Please edit your original question to clarify this as you refer to both layout and appearance.
Neal