LavaBlast Software Blog

Help your franchise business get to the next level.
AddThis Feed Button

Hybrid Accordion/TreeView Sitemap

clock December 20, 2007 09:14 by author EtienneT

Live Demo | Source Code (VS 2008) (856.65 kb)

The TreeView site map that we use in FranchiseBlast has become too long to fit reasonably the left panel of our application. We wanted something more compact that would be as simple to use and maintain as our current solution.

Matt Berseth gave us the idea of using an AjaxControlToolkit Accordion to achieve a nice look and feel for our sidebar. Our site map is automatically generated from our Web.sitemap file. (We use different *.sitemap files for each client; we needed something dynamic to cut down on maintenance time. We simply change which *.sitemap file the Web.config points to in our configuration generation scripts.) Furthermore, we also trim what is available in the sidebar according to user roles. I've added a reference to the appropriate web.config settings to achieve this behaviour below.

<siteMap defaultProvider="secureProvider">
<providers>
<add name="secureProvider" type="System.Web.XmlSiteMapProvider" siteMapFile="Web.sitemap" securityTrimmingEnabled="true"/>
</providers>
</siteMap>

Yesterday, I began coding a quick solution to our problem. I was inspired by the code in this post but ultimately I changed it a lot. We wanted all first level nodes in the Web.sitemap to be Accordion panes and all the other levels to be contained in TreeViews inside the parent pane.

We also highlight the current page in bold in the TreeView and display a different pane color to represent the current selection. Altogether, this is pretty simple stuff but hopefully it will help you avoid re-inventing the wheel.

Happy holidays to all!

 

Live Demo | Source Code (VS 2008) (856.65 kb)

kick it on DotNetKicks.com

 

 

 

 

 



Debug Visualizer for SubSonic Collections

clock December 7, 2007 20:00 by author EtienneT


Wouldn't it be nice to be able to see a SubSonic collections while you are debugging, just like the DataSet debug visualizer? Because we often need such a tool to debug our SubSonic collections here at LavaBlast, I've created a small Visual Studio Debug Visualizer that you can use to see what your SubSonic collections contain.  How does it work?  While you are debugging, put a breakpoint somewhere and simply hover your mouse over a SubSonic collection variable.  You should see something similar to the screenshot shown above.

Once the tooltip has appeared, you can click on the small magnifier to open the debug visualizer.  You'll see a DataGridView similar to the picture on the right. This will show all your SubSonic objects in a easy to navigate list.  Basically my code takes the SubSonic list and transform it in a DataTable.  I can't use the method ToDataTable() from the SubSonic AbstractList because this requires access to the provider's configuration, and the JIT executing the debug visualizer doesn't have access to it.

To use this simple tool, download this file SubSonicVisualizer.dll (8.00 kb) and put it in your [My Documents]\Visual Studio 2008\Visualizers\ folder, creating the directory if it doesn't already exist. (You might want to double check your file system permissions on this folder, as well.) I compiled this for Visual Studio 2008.  I have also included the source code here (Visual Studio 2008) in case anyone wants to enhance it.

SubSonicVisualizer.zip (386.36 kb)

If you are using Visual Studio 2005, I think this file will work for you, but I have not tested it: SubSonicVisualizer2005.dll (8.00 kb). I simply changed the reference from Microsoft.VisualStudio.DebuggerVisualizers.dll version 9.0 to 8.0 and, from what I have read, it should work in VS.NET 2005.

kick it on DotNetKicks.com


Multitasking while Visual Studio builds

clock December 5, 2007 13:25 by author EtienneT

Are you using Visual Studio and your solutions are taking longer than 10s to build? Why not put those 10s to good use and do something other than stare emptily at your poorly decorated office? Maybe you are worried that your build will finish before you expect it to and you don't want to lose precious time? You don't have to worry about this anymore thanks to what I found today! You can now feel free to peruse a few blog posts while Visual Studio is building!  [insert witty comment about how men have difficulty multi-tasking here]. 

Robert Robins posted this on his blog recently and I didn't even know it existed! You can configure VS.NET build sounds that information you where the build is done!

Go to the Control Panel, Sound and Audio Devices, Sounds Tab, Microsoft Visual Studio, and configure the sounds you'd like to play when the build succeeds/fails. LavaBlast is not responsible for what your coworkers do to you after configuring Pee-wee Herman or a bomb siren as your default sounds.

Happy coding!

 

 

 

 

kick it on DotNetKicks.com


SubSonic object change tracking

clock November 28, 2007 08:44 by author EtienneT

Sometimes you want to know what your users are doing in your system. You probably don't want to spend too much time on this feature, but it is nice to be able to prove that a certain user introduced data inconsistencies and it isn't your fault. Obviously, the "client is always right" but tracking down the source of a problem (and pointing fingers) is something that is very useful to developers like us!

We decided to add events in our controllers to catch when an object is updated or inserted. When that occurs, we can produce simple HTML about the object through reflection. If the user changed an object, we can generate a nice view of what was changed, as well. Here is an example of a save to the database. We generate a string and insert it into our ElectronicJournal (audit log) to keep track of all the actions in the system:

Type: InventoryItem
Schema: SubSonic.TableSchema+Table
ItemGUID: d7fc5f85-129a-4909-b4ac-490fc26d9007
StoreID: TestStore1
StorePrice: [12.99] -> [7.99]
Tax1: True
Tax2: True
Tax3: True
Tax4: True
CreditPoints: [129] -> [79]
SalePoints: [1299] -> [799]
BonusPoints: 0
StockQuantity: 0
IsReportable: True
PromptForPrice: False
HideItemInStore: False
Item: 3.2
Store: Test Store 1
TableName: InventoryItems
ProviderName:
NullExceptionMessage: {0} requires a value
InvalidTypeExceptionMessage: {0} is not a valid {1}
LengthExceptionMessage: {0} exceeds the maximum length of {1}

By tracking various actions in your database, you can make a quick listing to track a user's actions. If you add a few more columns in your audit log table, you can track who did the change, when they did it, their IP, etc. We keep track of a set of action types which allows us to filter by "Saved Objects" on a particular date, for a certain person (for example). This allows us to visualize what a user did in an efficient manner. Obviously this is a pretty simple example that is based on the existence of SubSonic objects and we don't handle complicated scenarios for the time being. If you run update queries on the database that change multiple objects in one save, we obviously never generated any SubSonic objects and cannot track those changes. However, most of the time, it is sufficient to have a good idea of what is going on. Again, we reap the benefits of our standard use of custom SubSonic controllers.

I have included a pretty simple utility class that you can use to do this. It's pretty generic, so you can easily use this with your own classes. The methods of interest in the class are:

public static string DumpObjectToHtml<T>(T before, T after)

and

public static string DumpObjectToHtml(object obj)

 

The class includes some other useful functions like:

 

public static C Paging<T, C>(C result, int startRowIndex, int maximumRows)
where T : ActiveRecord<T>, new()
where C : ActiveList<T, C>, new()

and

public static void Sort<T, C>(string sort, C result)
where T : ActiveRecord<T>, new()
where C : ActiveList<T, C>, new()

 

Those two methods enable you to page or sort a SubSonic collection if you can't use SQL Paging/Sorting. I had to use this to Page/Sort a SubSonic collection containing both database objects and my objects that I created after the database call. I hope this can be useful to someone.

SubSonicHelper.cs (3.57 kb)

kick it on DotNetKicks.com


SubSonic magic

clock November 27, 2007 16:13 by author EtienneT

ASP.NET developers who don't know what SubSonic is should definitely go read about it. We have been using SubSonic since the initial 2.0 release and have built most of our recent data-driven applications using this wonderful tool. We really like SubSonic and think it has helped us tremendously in our daily productivity. For all simple SQL operations, we try to never write custom SQL and use the SubSonic Query object instead. What I want to talk about today is how we use SubSonic in our main project FranchiseBlast and how we think this could be useful for other programmers like us.

A bit of introduction is required; FranchiseBlast has a set of different web pages to manage our data (products, sale reports, pricing, web orders, etc.). Most of these pages use the typical master list / detailed view usage scenario, with the master list being filtered due to search criteria. Additionally, because FranchiseBlast includes fine-grained access control, all lists need to be filtered according to these permissions, which vary per user. Although there are many built-in constructs in ASP.NET (GridView, DetailsView, FormView, etc.) that support this scenario via an SqlDataSource, but let us explain why we prefer using SubSonic.

SubSonic Controllers

Most of the time, you don't want to rewrite the same code again and again. When doing a classic scenario of displaying a GridView in ASP.NET, you are faced with multiple things you have to handle. First, how do you do sorting? Do you do it in memory with a DataView, for example, or do you let SQL server do it? Writing the SQL to benefit from SQL Server sorting is more work, but if your table has a lot of data, then it becomes absolutely necessary.

What do you do for paging? Do you want to fetch ALL the rows from your database and then let the grid view handle the paging in memory? This works well until you have a table containing thousands of rows because your GridView only displays the first 15 rows and you're transferring the all that data from SQL Server to ASP.NET for nothing (that's if you didn't use caching, but that's of another subject).

Sorting and paging are only two problems. What about filtering with a search string? Filtering by user permissions? These are problems we wanted to solve once and for all at LavaBlast when creating our core data management engine. We did not want to copy paste complex SQL code everywhere to manage filtering, sorting, and paging, as this would cause a maintainability nightmare. We don't have millions of rows in our tables, but we have enough to cause perform issues if we don't think about scalability.

So what is the miracle solution? Here at LavaBlast, we think the solution is custom SubSonic controllers used with ASP.NET ObjectDataSource. We assume our readers already know how to use an ObjectDataSource and have a reasonable knowledge of SubSonic. So if you are not really familiar with ObjectDataSource, you should probably read this tutorial first: Displaying Data With the ObjectDataSource. And if you are not familiar with SubSonic, go to the web site and watch some SonicCasts or go read Rob Conery's blog (very interesting blog). Rob is one of the authors of SubSonic who just got hired by Microsoft to continue to work on the goodness of SubSonic! Nice work Rob!

Some code

Here is some sample source code that makes use of our custom Controller class. This class was manually authored and it adds a few methods to the Controller SubSonic generated for us by using the partial class mechanism available in C#. It returns a sorted list of item groups (a set of items) filtered by the user's permissions. Furthermore, it returns only the item groups to be displayed in the UI. We've extracted out the generic concepts of filtering, sorting, and paging. In the end, SubSonic generates a single SQL query that generates temporary tables in which the rows that are populated in the UI are displayed.

This controller is bound to an ObjectDataSource which feeds records into the GridView. FetchByProductAuthority has parameters to handle sorting, paging, and data filtering. "startRowIndex" and "maximumRows" are parameters used for paging. The "sort" parameter specifies the sort column name and the other three parameters are for filtering our data.

SubSonic connects to our SQL Server Database and uses code templates to generate ActiveRecord objects for all our tables, views, and stored procedures. Using strongly typed objects throughout our applications instead of ADO.NET DataRows greatly improves its maintainability for a negligible performance hit, since we only need a couple dozen objects to render one page of a GridView.

One of our ideas was to change the code generation templates to make all controllers derive from our base controller class. We made this class generic so that it could be used for all kinds of SubSonic objects and makes it easier to deal with object collections, also generated by SubSonic.

[DataObject]
public abstract class SubSonicController<T, C>
where T : AbstractRecord<T>, new()
where C : AbstractList<T, C>, new()

We modified the code generation templates so that SubSonic controllers would extend our base controller:

[System.ComponentModel.DataObject]
public partial class ItemGroupController : SubSonicController<ItemGroup, ItemGroupCollection>

Since the class is partial, you can make a new file and continue to write methods for this controller in a completely separate file which won't be overwritten by SubSonic when you regenerate objects from the relational database. We could also have inherited from the generated controller to perform our extensions.

In any case, all our controllers have the same base class. This enables us to add functions to all our controllers. The most basic tasks you want to do with a controller is to do SQL sorting of your data and SQL paging. SubSonic can easily do the sorting and paging for you with a SubSonic Query object. So we decided to write custom function to adapt ObjectDataSource parameters to work with the SubSonic Query object. I include some code here to show how we do this:

protected static Query GetQueryByParams(string sort, int startRowIndex, int maximumRows)
{
Query q = CreateQuery();

q = AddPaging(q, startRowIndex, maximumRows);

q = AddSort(q, sort);
return q;
}

protected static Query AddSort(Query q, string sort)
{
if (!string.IsNullOrEmpty(sort))
{
if (sort.Contains("DESC"))
q.OrderBy = OrderBy.Desc(sort.Split(' ')[0]);
else
q.OrderBy = OrderBy.Asc(sort.Split(' ')[0]);
}

return q;
}

protected static Query AddPaging(Query q, int startRowIndex, int maximumRows)
{
if (maximumRows > 0)
{
q.PageIndex = (int)(startRowIndex / maximumRows) + 1;
q.PageSize = maximumRows;
}

return q;
}

Therefore, when we want to construct a basic query which handles sorting and paging for us, all we have to do is to write this code: Query q = GetQueryByParams(sort, startRowIndex, maximumRows);. In addition, for those who are not yet familiar with the ObjectDataSource, it automagically provides the sort, startRowIndex, maximumRows according to what is clicked in the GridView. In summary, we don't have much code to write to obtain data efficiently from our database that respects our business processes (access control, auditing, etc.).

Furthermore, we added a custom method to handle searching through a list of columns: see the SearchFields property above. We simply define a List<string> of column names in which we wish to search and our base controller handles adding the required filters to the SubSonic Query object. Finally, we also added default sorting, which allows us to simply set the DefaultSort property in our controller to be used when no sort column is specified in the Fetch methods.

I'll stop here; I think this article is already WAY too long. I hope this can be useful to someone! We're currently considering upgrading the controller templates to automatically include methods like FetchByProductAuthority which are commonly used in FranchiseBlast, depending on the SQL Schema of the table. We could even generate the sort/search fields by using metadata stored in the database. Furthermore, we're very interested in generating some ASCX/ASPX files, following the architecture imposed by our solution, which would make use of our controllers. These generated files would be good starting points to cut down on development time for some of our pages.

I include the SubSonicController class if anyone would be interested.

SubSonicController.cs (4.22 kb)

As for the code template for SubSonic, just modify it to use this base class and pass the right types in the generic parameters.

 [System.ComponentModel.DataObject]
    public partial class <%=tbl.ClassName %>Controller : SubSonicController<<%=tbl.ClassName%>, <%=tbl.ClassName%>Collection>

If you have any questions or comments, don't hesitate to send them in.

Edit: It has come to my attention that I forgot to provide a disclaimer concerning the SearchFields in this post. SubSonic 2.0 does not fully support the OR query construct. Keep in mind that your query will not work properly if you specify more than one field name in the SearchField list PLUS you also use the AND query construct.  (SubSonic uses boolean operator precedence, and not parenthesis.

 

kick it on DotNetKicks.com


Free charting for ASP.NET

clock November 18, 2007 23:15 by author EtienneT

 

Last week I stumbled upon this article by accident: Charts And Graphs: Modern Solutions. This article offers a really good overview of the web-based charting solutions on the market. There are a lot more products available on the market, but what interested me the most in this article were the FREE solutions (as in beer)! My cheap entrepreneur spirit compelled me to check the free solutions. I was really surprised to find that one of them had a Free Charting ASP.NET library.

 

Open Flash Chart

Open Flash Chart was the first one that got my attention because it had a Google Analytics look. Open Flash Chart uses a Flash-based engine and downloads a separate file to know what to display. This file contains both the data and the appearance of the graph.

On the main page of the project, there is no mention of the existence of a .NET library to use this project. However, in the latest release (1.9.5) two guys made a library that can be used in an ASP.NET project! I downloaded the latest version and began to play with the project. I must say that the library is promising, but there are lots of problems. I fixed some of them and I intend to submit my changes to the team.

A simple example

I decided to try the solution a little bit with some data from our data warehouse. I used SubSonic to query the data since I can't live without it! As there is no data binding in the library, you have to do this work by yourself but it should be pretty easy to add this functionality to the library.

The first step is to have an *.aspx page displaying a custom control:

<graph:Chart ID="chart" Width="100%" Height="400" runat="Server" Url="daysOfWeekData.ashx" />

This control basically inserts a Flash control in the page. The Url property specifies the URL of a file containing both the data and graph's format settings. In this example, I use daysOfWeekData.ashx which contains a bar chart of the average sales a franchise store made for each day of the week during some pre-defined time period.

How does this works?

This is a pretty simple chart. You can hover over each column and the value of the bar will show in a tooltip. So basically daysOfWeekData.ashx uses the Open Flash Chart .NET library allowing us to customize our graph and insert our data. After manipulating the data, we can render the objects to the Response stream in query string format:

&title=,& &x_label_style=12,0x000000,2,1,0x000000& &x_axis_steps=1& &y_ticks=5,10,5& &bar_glass=65,#871E00,#FF7B00,Sales,12 &values=10852.69,6702.74,5327.95,5167.67,4982.08,10143.17,19958.16& &y_min=0& &y_max=19968& &tool_tip=Total Sales for #x_label#:
#val#& &x_labels=Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday&

This code is then read and interpreted by the Flash control and displayed the chart.

I have included the code for daysOfWeekData.ashx.cs (1.96 kb), in case you are interested.

kick it on DotNetKicks.com


ASP.NET GridView column resizing

clock November 8, 2007 00:54 by author EtienneT

We use lots of ASP.NET GridViews in our main product, FranchiseBlast.  We think it's important to make our users' browsing experience as pleasant as possible.

Today, we included a new feature to enable our users to be able to dynamically resize the columns of a GridView.  All the credit for the original source code goes to Matt Berseth who published his code on his blog: GridView column resizing.  Unfortunately, the column resize behavior was not implemented as AjaxControlToolkit Control Extender. Therefore, this morning I took his code and adapted it to be reusable as a control extender.  I have included the code here so that others can benefit from it (see at bottom of this article).  We also included small feature to improve the sort order visualization, in the GridView. Many thanks again to Matt Berseth.

 Here is a screenshot of one of the dynamic reports in FranchiseBlast.

FranchiseBlast is architectured with re-usable base classes and we do lots of things in the codebehind instead of the typical ASPX/ASCX.  Here is some sample code to programmatically add the extender to the page:

 

Thanks to our architecture, these five lines enable column resizing on all of the GridViews in FranchiseBlast.

Here is the source code, should anyone be interested:

GridViewResizeExtender.zip (262.87 kb)



Have a unique selling proposition

clock October 1, 2007 16:37 by author EtienneT

If you are in the retail industry, chances are that you probably already know that you have to have a unique selling proposition to offer your clients.  But hey, what’s a unique selling proposition?  In the book Reality in Advertising, author Rosser Reeves defines a unique selling proposition (USP) as:

1. Each advertisement must make a proposition to the customer: "buy this product, and you will get this specific benefit."
2. The proposition itself must be unique - something that competitors do not, or will not, offer.
3. The proposition must be strong enough to pull new customers to the product. 

A franchisor needs to have something that will make its stores shine apart from the competition. As an example, let us discuss Teddy Mountain, one of our first clients here at LavaBlast. Teddy Mountain is a stuff-your-own teddy bear type of store. Stuffed animals have been around for years and are available it countless locations.  Some stores offer dirt cheap stuffed animals while others brand the bear with a particular tourist attraction such as the Eiffel Tower. Retailers in the stuff-your-own teddy bear industry sell more than just a physical teddy bear, they sell an experience and their selling proposition revolves around this custom-creation experience.

Teddy Mountain wanted to offer something more personal to the client to complement the experience.  They decided to offer birth certificates for each teddy bear they sell.  Simple idea, but this creates a strong bond between a child and their new teddy bear.  A picture of the child with their new friend would be taken and would be printed at the counter when the teddy bear was paid for.  One could think that this simple concept is insufficient to pull new customers to the product, yet in-store behavior has proven otherwise. Children are drawn towards the camera feed presented on the kiosk and often want to purchase a bear simply to get their picture taken.

The picture here shows the in-store kiosk being used by some children.  This kiosk has two screens with two webcams and prints in the color laser printer at the cash register.  The kiosk must be simple to operate because it is used mainly by children.   This is fairly simple software and other stores also produce certificates, but the kiosk appearance (touch screen interface, webcam, three-dimensional fixtures done by Studio Y Creations) adds to the child’s in-store experience and puts Teddy Mountain in a unique position.  Because we’ve integrated the certificate with the point of sale, the employees don’t have much overhead to deal with.  Coming up in the near future are many new features on the website that link the in-store experience with the online one, refining the brand’s uniqueness.

Teddy Mountain operates in an industry which is dominated by a giant and software alone cannot be the only unique selling proposition. Teddy Mountain experience is enriched by large-scale three-dimensional fixtures that attract children from the mall inside the store. These fixtures put a little bit of magic in the shopping experience and illuminate child birthday parties. There are other refinements that define Teddy Mountain; having a clear unique selling proposition is key to increasing sales but also to attract new franchise prospects. However, since our goal is to illustrate how LavaBlast is a piece of the puzzle, as opposed to selling you a franchise, we won’t go into more detail.



Month List

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2017

Sign in