As I mentioned in Developer Notes #1, BV Commerce 6 is a hybrid application. It uses both Web Forms and MVC pages along with WCF services and AJAX to create a compelling user experience. From a developer’s perspective this might seem confusing so here is a short explanation of the request/response process in BV6.
Web Server
Internet Information Server (IIS) is the web server software running on the computer that hosts your BV Commerce web site. A customer requests a web page and that request is handled by IIS which then decides what program or module should be responsible for returning a response.
In the default configuration, IIS passes all requests to the ASP.NET runtime unless there is an error. This lets BV Commerce process requests for pages and resources that don’t physically exist but are referenced in a URL. If there is an error, the default BV Configuration is to have IIS pass error information to the Error.aspx page where it can be logged.
Routing
When BV Commerce 6 first starts the Application_Start function in the Global.ASAX file is called. This in turn calls the RegisterAllRoutes() function which creates the routing table.
Routing is a new feature in Web Forms 4 that comes from the MVC framework. It allows an ASP.NET application to examine the requested URL and direct a specific page or controller to handle the request instead of just blinding looking for an exact physical file match on disk.
Because BV Commerce 6 is a hybrid application there are a series of rules that direct request to either ASPX pages or MVC controller classes. At the beginning of the routing table is a list of items to ignore like favicon.ico or the entire /images folder. This speeds up requests by skipping URLs that won’t have any processing.
The first section of routes map URLs to ASPX pages. For example, the URL /checkout is mapped to the Checkout.aspx page using this rule:
routes.MapPageRoute("checkout-route", "checkout", "~/checkout.aspx");
The next section of routes maps to MVC controllers like the CSS controller or FileUpload Controller using similar rules such as:
routes.MapRoute(“css”, “css/{themename}/styles.css”, new { controller = "StyleSheets", action = "Index" });
The last line in the routing table maps to the FlexPage controller. This MVC controller checks for URLs matching anything else in the system including 301 redirects and other custom URLs. If the FlexPage controller can’t find a match a 404 error is thrown.
BaseStorePage
Once the routing table matches a page or controller the request is passed on. Almost every page inherits from the BaseStorePage class. This class is used to ensure that every request has the information it needs about the current environment so that requests can be processed. MVC controllers don’t inherit from BaseStorePage but have very similar code in the OnActionExecuting function.
The BaseStorePage class implements the IMultiStorePage interface. This interface exposes a ServiceFactory class from the BVSoftware.Commerce module. During pre-init, the base class instantiates a new ServiceFactory and sets the current request context and locates the current store based on the URL.
If you did any programming work in BVC 2004 the ServiceFactory class will seem familiar as it exposes a service based API for interacting with objects like Categories and Products. The difference is that the ServiceFactory in BV Commerce 6 is not a static, global class but rather one that has been injected with information about the current environment. It also uses lazy loading for individual services so that if a page doesn’t request the CatalogService it never gets loaded/created for that request.
Next the BaseStorePage does some initial setup like settings the URLs for styles sheets, loading headers and footers for the current theme, setting cart counts, loading additional meta tags, logging affiliate requests and checking to see if the store is closed or not before turning control over to the page or controller itself.
Pages and Controllers
At this point the ASPX page or MVC controller for the request takes over. ASPX pages go through the normal page cycle of Init, Load, etc. MVC controllers will have a specific function called based on the routing table and will return a result of some kind.
Because of the IMultiStore interface each page or controller has access to a wealth of information such as the CurrentStore including settings, CurrentRequest which includes the URL requested and pre-configured services like CatalogService or OrderService.
For example, a category page could call:
Services.CatalogService.Categories.Find(categoryId);
To get a category by it’s Id. The function call appears as though it’s a global function but it really is a class that’s created just in time with the correct configuration information. The ServiceFactory takes the burden out of instantiating classes.
What’s with IMultiStorePage and finding the Current Store?
BV Commerce 6 shares a common code base with the BV Commerce hosted service. It may seem strange that each request needs to find out what the current store is until you realize that on the hosted platform thousands of stores are all running on one “application.”
In the Toolkit version of BV Commerce 6 there is a quick shortcut that defaults the store name to www. So, the first ever request for a page on the Toolkit version will create a “www” store if it doesn’t exist. The URL parser defaults to the single store quickly without actually checking the URL.
The IMultiStorePage interface name really represents the fact that calls into the BVSoftware.Commerce library are designed to be store independent. Passing in environment settings also makes the core modules much easier to test.
In the future there may be a multi-store version of the ToolKit and you should not hardcode store name or Id in any custom code. Always use the CurrentStore propery on the ServiceFactory class to determine which store you’re working on.