sitecore

Sitecore MVC in a multisite environment: area’s

by Chris van de Steeg. 0 Comments

If you are creating a multisite environment using Sitecore & MVC (or any MVC site for that matter), chance is you have to do some weird naming in your controllers to avoid naming conflicts.

This is why Microsoft introduced area’s in their implementation of MVC (as did others before them)

Using them in Sitecore is actually pretty easy, thanks to (again) sitecore’s flexible pipilines.

First, we extend the Initialize pipeline with our own step:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <!-- Loader -->
      <initialize>
        <processor type="BoC.Sitecore.Pipelines.InitializeRoutes, Thieme.Framework" />
      </initialize>
    </pipelines>
  </sitecore>
</configuration>

Then add our class to the project:

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Sitecore.Configuration;
using Sitecore.Mvc.Configuration;
using Sitecore.Pipelines;

namespace BoC.Sitecore.Pipelines
{
    public class InitializeRoutes
    {
        public virtual void Process(PipelineArgs args)
        {
            var scRoute = RouteTable.Routes[MvcSettings.SitecoreRouteName] as Route;
            var indx = RouteTable.Routes.IndexOf(scRoute);
            AreaRegistration.RegisterAllAreas();
            foreach (var info in Factory.GetSiteInfoList())
            {
                if (info.Properties["mvcArea"] != null)
                {
                    var newRoute = new Route(scRoute.Url, 
                        new RouteValueDictionary(scRoute.Defaults), 
                        new RouteValueDictionary(scRoute.Constraints), 
                        new RouteValueDictionary(scRoute.Constraints), 
                        scRoute.RouteHandler);
                    newRoute.DataTokens.Add("area", info.Properties["mvcArea"]);
                    newRoute.Constraints.Add("sc-issite", new IsCorrectSiteContraint(info.Name));

                    if (info.Properties["mvcNamespaces"] != null)
                    {
                        newRoute.DataTokens["Namespaces"] = info.Properties["mvcNamespaces"].Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                        newRoute.DataTokens["UseNamespaceFallback"] = false;
                    }

                    RouteTable.Routes.Insert(indx, newRoute);
                }

            }
        }

        public class IsCorrectSiteContraint : IRouteConstraint
        {
            private readonly string _siteId;

            public IsCorrectSiteContraint(string siteId)
            {
                _siteId = siteId;
            }

            public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values,
                RouteDirection routeDirection)
            {
                return global::Sitecore.Sites.SiteContext.Current.Name == _siteId;
            }
        }
    }
}

Now what this code does, is to add a route to the routecollection for every Sitecore-site configured. It uses a routeconstraint to validate if the route is applyable for the current request. If it is applyable the property ‘mvcArea’ of the configured website is set as the MVC area for that request. So, we will have to extend the <site> tag of the sitecore configuration with an mvcArea attribute, like so:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <sites>
      <site  mvcarea="Corporate" mvcnamespaces="Corporate.Framework.*,Website.Corporate.*" language="nl-NL" content="web" database="web" scheme="http" patch:before="site[@name='website']" name="Corporate" hostname="coporate.com" targethostname="coporate.com" virtualfolder="/" physicalfolder="/" rootpath="/sitecore/content/Corporate" startitem="Home" allowdebug="true" cachehtml="true" htmlcachesize="10MB" enablepreview="true" enablewebedit="true" enabledebugger="true" disableclientdata="false" />
    </sites>
  </sitecore>
</configuration>

As you can see, we also specify “mvcnamespaces”, although these are optional, it allows you to tell MVC where to look for your controllers.

It’s this easy. So now you’re ready to go and create your controllers & views in the correct manner. Don’t forget to place your views in the correct folder (in this case: areas\corporate\views\)

eFocus crawler based Lucene Websearch for Sitecore (open source!)

by Chris van de Steeg. 2 Comments

If you work with Sitecore 7, you probably know that Sitecore 7 has greatly improved the search capabilities. But still, there is no native way to search through your generated html. There are several paid solutions like the dtSearch module for sitecore, but still, they all feel not to deepily integrated with Sitecore.

At eFocus we created our custom Websearch module, which crawls your website (or any website) and then adds the html content to your Sitecore Lucene index. It’s a total integrated Sitecore solution, so configuring and using it is a piece of cake.

The project uses (a slightly modified version of) the awesome NCrawler for the crawling part.

Go checkout the module at the Sitecore Marketplace or take a look at the source on GitHub

MVC MusicStore for Sitecore 6.6

by Chris van de Steeg. 6 Comments

THIS IS AN UPDATED VERSION OF Sitecore MVC Music Store TO MAKE IT WORK WITH THE OFFICIAL SUPPORTED MVC INSIDE SITECORE 6.6

In my last blog post about using the MVC Framework inside Sitecore, I announced that I’d write another blog post on how to actually create a real world application with MVC inside Sitecore. The first blog post was just a proof of concept, creating a real world application with it, helps completing the code.

Sitecore has announced that it will support MVC in Sitecore version 6.6. Great news! This tutorial will use the technical preview of Sitecore 6.6 to rebuild the mvc musicstore inside a Sitecore environment.

Since Microsoft has already created a nice tutorial for getting started with ASP.NET MVC : MVC Music Store tutorial. I figured it’d also be a nice tutorial to get started with MVC inside Sitecore. It’s an easy to follow, small tutorial, which makes it easy to go through for both experts and beginners in the world of MVC. Experts can just skip the parts explaining how MVC itself works and go straight to the action. For beginners, the entire tutorial takes less then 2 hours. It will be the best invested 2 hours of your programmer’s life so far :)!

Once you have completed the Microsoft tutorial, the steps in this blog-post will help you transform it to a Sitecore project.

Step 1 – complete the tutorial

First, follow the entire tutorial (or if you’re an expert on MVC already, just download the package:http://mvcmusicstore.codeplex.com/)

Step 2 – Get Sitecore running with MVC support

Follow the instructions given by John West to get Sitecore 6.6 with MVC support up and running.

Step 3 – copy contents

Copy the wwwroot contents of the mvcmusicstore project into the wwwroot of an existing Sitecore project (or create a new one first), but SKIP the web.config files! Note that you should copy the web-files to the web folder of your sitecore project! (if you downloaded the package, the web-content is inside the ‘MvcMusicStore’ folder inside the zip file)

Now open the Sitecore project in visual studio, and add the project you just copied to your solution (File –> Add –> Existing project).

Step 4 – connectionstrings

Copy the connectionstring in the web.config of the original created MVCMusicStore project, to the App_Config\Connectionstrings.config inside your sitecore solution.

Step 5 – Global.asax

Modify the default route in global.asax.cs. You can do that by adding any static string value in front of the default route. I chose ‘musicstore_api’. Doing this will make all your controller actions accessible through /musicstore_api/home/index, this could come in handy for stuff you need to access without going through sitecore (eg. ajax calls, delete actions, etc)

image

If you now run your application, and everything went fine, your application should show the default sample Sitecore homepage. If you now go to /musicstore_api/ , the musicstore should work exactly the same as when you finished the original tutorial. (Note: if you downloaded the sample code instead of making your own, and you run in to the error code “Unable to find the requested .Net Framework Data Provider. It may not be installed.”, you need to install MS Sql Compact CE 4.0)

These first 5 steps were the steps required to get an existing MVC application working inside the sitecore wwwroot. Now we’ll start modifying the existing app to become an application fully powered by sitecore!

Step 6 – Create layout

In Visual Studio, copy /Views/Shared/_Layout.cshtml to /Views/Shared/_SitecoreLayout.cshtml
image

Open _SitecoreLayout.cshtml and replace
image
with
image

In the Sitecore Content Editor user interface, navigate to the /sitecore/layout/Layouts/ folder that contains the default layouts. Underneath, create a new ‘Layout folder’ named ‘MVC MusicStore’. Now copy the ‘Sample layout’ item and paste it inside your newly created folder (using your right mouse button), name it ‘Shared layout’
image[2]

Having your newly pasted layout selected, go to the ‘content’ tab, and change the Path field to /views/shared/_SitecoreLayout.cshtml
image

Step 7 – Create Sitecore templates

Run your application, and go the the Sitecore desktop (/sitecore/shell/default.aspx) and open the template manager.

Screenshot - 3-6-2012 , 14_14_50

Add a new template folder underneath ‘Templates\User defined’ called ‘MVC MusicStore. Underneath that new folder, add a new template.

image

Call the new template ‘Default page’ and just let the base template field as it is. Click next, next, finish.

image

Select your new ‘Default page’ item in the tree, and on the ribbon ‘Builder options’ click the ‘Standard values’ button in the template section.

image

And next on the ‘Presentation’ ribbon, click the ‘Details’ button in the layout section

image

This will open the layout details wizard:

image

Here, click the Edit-button under the ‘Default’ section (marked with a red border in the screenshot above), which will open the “Device Editor” popup:

image

In the dropdown, choose the ‘Shared Layout’ the MVC MusicStore folder and click OK twice

image

Step 9 – Register controller actions

Unfortunately, Sitecore does not automatically detect all controller actions and registers them as a rendering, like BoC.Sitecore.Mvc does. I will update BoC.Sitecore.Mvc ofcourse, to auto register all your controller actions, but for now, you will have to add them by hand.

In the Sitecore contenteditor, navigate to /sitecore/Layout/Renderings. Click the item with your right mouse button and choose Insert->Rendering Folder, name it ‘MVC MusicStore’. Inside that folder, add another folder ‘Home’. Click with the right mouse button on that Home item, and choose Insert->Controller rendering. Name it ‘Index’
image
Select your new rendering, and in the content tab, enter ‘Home’ as the controller, and ‘Index’ as the action.
image

Now you’ll have to do this for all actions wer’re going to use in this tutorial, your tree should end up like this:
image

Step 9 – Create sitecore items

Based on our previously created ‘Default page’ template, we’re now going to add the Sitecore items based on this template.

Open up the content editor in sitecore, and delete the exiting homepage item (/sitecore/content/home). Add a new Home item by click the ‘Content’ item with the right mouse button and choosing ‘Insert –> Insert from Template’.
image

Call the item Home and pick our just created ‘Default page’ template as it’s template
image

Using this same template, create the following tree inside Sitecore:
image
IMPORTANT Notice the * in front of Genre and Id…. these are wildcard mappings! The nameof the items should be * and the displayname *Genre and *Id.

Step 10 – Attach controller actions

On these pages, we’ll attach the appropiate MVC Action. Start with the Home item. Click on it in the tree, and open the ‘Presentation’ ribbon. Now click on the details button:
image
This will open the layout popup
image

Now click the Edit-button under the ‘Default’ section (marked with a red border in the screenshot above), which will open the “Device Editor” popup
image

Click the controls tab, and choose ‘Add’. That will bring up the ‘Select a rendering’ window.
image

Choose Renderings/MVC MusicStore/Home/Index and enter ‘main’ as the placeholder name (remember we added that $Html.SitecorePlaceholder(“main”) to _SitecoreLayout.cshtml?). Click on Select, and then on OK twice to save all your changes.

Now do the same for all other pages you’ve created except the ‘checkout’ page (that is just a placeholder). The other pages should get the following controls:

  • Checkout –> Renderings/MVC MusicStore/Checkout/Complete
  • Checkout/AddressAndPayment –> Renderings/MVC MusicStore/Checkout/AddressAndPayment
  • ShoppingCart –> Renderings/MVC MusicStore/ShoppingCart/Index
  • Store –> Renderings/MVC MusicStore/Store/Index
  • Store/Browse –> Renderings/MVC MusicStore/Store/Browse
  • Store/Browse/*Genre –> Renderings/MVC MusicStore/Store/Browse
  • Store/Details –> Renderings/MVC MusicStore/Store/Details
  • Store/Details/*Id –> Renderings/MVC MusicStore/Store/Details

Step 11 – Publish & test

Now, publish your entire site (! beware that if you’re using the sample database with the sample item template, that there is a worfklow attached to the new items by default… you need to approve them before publishing). After publishing, you can go checkout the homepage of your website. HEY! It’s just showing ‘default page’ ??

This is because by default, Sitecore holds a default.aspx in the root, and MVC by default does not trigger any route if the file exists on disk. You can enable routing for existing files by adding ‘routes.RouteExistingFiles = true;’ to the RegisterRoutes method in global.asax.cs, or you can just delete the default.aspx. I chose the latter one: just rename your default.aspx page in the root of your website’s folder to default.aspx.bak. Refresh your homepage.

Much better, but now what! the navigation menu and logo are shown twice!

image

Step 12 – Modify viewstart

The reason for the page being displayed twice, is because the default MVC Musicstore project does not take into account that the views can be accessed as a child-action. Adding the actions as a sublayout inside our sitecore pages, makes the actions being rendered as childactions. To skip the layout being rendered in child mode, open Views/_ViewStart.cshtml and modify the one line that’s in there to:
image

(I do hope Sitecore will support ViewContext.IsChildAction, as that is the official way to check if your view should be partially rendered)

Save the file, and check the homepage again: Looking just fine now!

Step 13 – Modify Links

Though the website looks good now, all links are pointing to the /musicstore_api folder. Even though that will work just fine, that’s the native MVC you’re calling then. To point all links to the sitecore versions, we’ll have to change all link renderings. This is the most dramatic change in an existing MVC application. In fact, we’ll break compatibility here, since the links will become Sitecore specific. I haven’t figured out a way to keep this compatible. Then again, I don’t think you’d ever even want that. Thing is, with a standard MVC application, a controller action always has it’s own url. With SitecoreMvc any page in Sitecore can use the same MVC Action over and over again, on different url’s. This is so different, it’ll be impossible to keep things cross-compatible.

First, we need to add 2 files to our MVC solution. One of the files will extend the default HtmlHelper with some extra methods to easily create links to Sitecore items. The other file will add support for wildcard items (remember that *Id and *Genre items you’ve created?). Download Extensions.cs and WildcardValueProvider.cs and add them to your solution (eg. in a Helpers folder) (these files will ofcourse also be part of the next BoC.Sitecore.MVC release, but we’re still working without external libs in this tutorial)
image

In your global.asax, register the wildcardvalueprovider in the application_start:
image

Now, go change all the links in the project….

Open Views/Store/GenreMenu.cshtml. Modify the @Html.ActionLink in there, to the following:

image

See how we’ve mapped Genre as a parameter? The wildcard resolver will pick that up.

In Views/Home/Index.cshtml and Views/Store/Browse.cshtml change the action Url.Action to
image
This is the alternate method to set the wildcard item (*Id): by providing an anonymous object with the correct values

The Html.ActionLink in Views/Store/Index.cshtml to
image

The Html.ActionLink in Views/ShoppingCart/CartSummary.cshtml to
image

In Views/ShoppingCart/Index.cshtml, change the $.post(“/ShoppingCart/RemoveFromCart” to
image
(See how this will go directly to MVC! This won’t hit any Sitecore item, hence the url would become /musicstore_api/shoppingcart/removefromcart).

In the same file, replace the checkout Html.ActionLink with
image
and the details Html.ActionLink to
image

In Views/ShoppingCart/Complete.cshtml change the Html.ActionLink to
image

In Controllers/ShoppingCartController.cs, in the AddToCart method, change the RedirectToAction to
image

and, the last one, in Controllers/CheckoutController.cs, in the AddressAndPayment method, change the RedirectToAction to
image

Step 13 – Remove authorization

As a last step remove the Authorize attribute on the CheckoutController. In this tutorial, we’ll not be setting up Account related stuff, it’ll be taken care with in the follow-up of this post.

image7

Step 14 – Run

Now run your project again! Everything but Account-related stuff should work fine now! Add albums to your cart, check out, etc.

Conclusion

That concludes this tutorial for now. It should give you a good idea on how to get MVC up and running for your Sitecore projects.In the next blog post about Sitecore & MVC, I will explain how to use the Sitecore security in this MVC Musicstore and we’ll get rid of the external database by creating Sitecore items for the albums. I will try to add the new Model’s feature in Sitecore 6.6 for that. The albums will the be editable using both the Sitecore content-editor AND page-editor.