Getting imports working with dotless and CssBundles

I was watching Single Page Apps with HTML5, Web API, Knockout and jQuery by John Papa on pluralsight and one of the pieces was sending compiled less files down using the bundling.

Unfortunately this did not work while using @import because the current directory was set to my IIS Express directory. After searching most suggestions were to use Directory.SetCurrentDirectory but didn’t really like that solution so this is what I decided on:

Lazy list

I have been following Rob Conery’s posts on the MVC Storefront, and trying the repository/pipes-filters for data access that he has been using.

While trying out the implementation of a LazyList he was using, I had noticed that the example table was being joined onto the category table. At the time however, I really had not thought much of it, until I read MVC Storefront: Brainbender Intermission which got me thinking.

Admittedly, I don’t really have to much of a problem with it loading all of the examples for all the categories at one time at the moment. However, I figured it would be nice to have it work the way intended, and query the database for the examples in a category only when asked for.

I liked the idea of the LazyList, and since I was already using a Service class for all data access, along with setting up the category hierarchy I moved the creation of the LazyList of examples property into the the GetCategories method of the service class.

It seems that as long as the LazyList is created after the categories .ToList() call it properly works. So I ended up with this code:

            categories.ForEach(category =>
            {
                category.Examples =
                    new LazyList
                        <DevExamples.Data.Example>(
                        from e in repository.GetExamples()
                        where e.CategoryId == category.ID
                        select e);

                var subCategories = (from sub in categories
                                     where sub.ParentId == category.ID
                                     select sub).ToList();
                category.SubCategories = subCategories;

                subCategories.ForEach(c => c.Parent = category);

            });

 

Technorati Tags:

Got my nice Urls working

Its amazing how fast things can be done when not fighting bad assumptions. In this case it was that my admin URLs needed to use the nice descriptive URLs, instead of just /[Controller]/[Action]/[id] type routing.

Once I realized I was making things overly complicated I, I ended up with a set of routing functions that are actually a bit less complicated then what I would have come up with if I had been able to extend the RouteTable the way I had planned originally.

I also decided that I didn’t like the idea of having the make every category and example name unique. Most of this was that I’m not the creative, but I also realized that it would be really ugly I wanted to have namespaces as categories. For example, it would not have been possible to have both C/System/Windows/Forms/Control and C/System/Web/UI/Control since Control would have had to be unique.

I also decided that I was going to set a limit to the depth of categories that the site was going to have, though it is easy to update this. First I made a function that would generate routes similar to those previously posted.

protected void CreateRouteSet(string baseRoute, string baseName
    , int maxDepth, object Defaults)
{
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < maxDepth; i++)
    {
        if (sb.Length > 0)
            sb.Append("/");

        sb.AppendFormat("[{0}{1}]", baseName, i);

        RouteTable.Routes.Add(new Route{
         
            Url = String.Format(baseRoute,sb.ToString()),
            Defaults = Defaults,
            RouteHandler = typeof(MvcRouteHandler)
        });
    }
}

protected void Application_Start(object sender, EventArgs e)
{

    CreateRouteSet("C/{0}", "Category", 6,
        new { Action = "Index", Controller = "Categories" }
        );

    //Other routes using the standard [Controller]/[Action]/[Id]

}

This will setup routes to handle category hierarchies up to 6 deep.  And add Category1,Category2… into the RouteData.Values collection in the controller.

Next I set up the code to allow me to handle the route, which I did in the model, adding a method that takes an IDictionary<string,object>.

public Category GetCategoryFromRouteData(IDictionary<String,object> data)
{
    //Grab just the category data
var navList = from route in data where route.Key.IndexOf("Category") == 0 orderby route.Key select new{Key = route.Key, Value = route.Value.ToString()}; string sqlSelect = @" SELECT {0}.* FROM Category {0} {1} WHERE {0}.Name = {{0}}";
//{{{2}}} will be replaced with {{<param index>}}
string join = @"INNER JOIN Category {0} ON {0}.[Key] = {1}.ParentKey AND {0}.[Name] = {{{2}}} //This is the name of the category I am actually interested in
var mainCat = navList.Last(); //Build a list of category values to for parameterized query
List<string> values = new List<string>(); values.Add(mainCat.Value); StringBuilder sb = new StringBuilder(); string lastCategory = mainCat.Key; int i = 1; foreach (var item in navList.Reverse().Skip(1)) { sb.AppendFormat(join, item.Key, lastCategory,i++); values.Add(item.Value); lastCategory = item.Key; } string sql = String.Format(sqlSelect,mainCat.Key, sb.ToString()); Category cat = this.ExecuteQuery<Category>(sql, values.ToArray()).Single();


//GetDisplayCategory skips over categories that have only 1 subcategory
//and no examples, allowing me to have the planned Url structure without
//
requiring the user to navigate through several empty categories.
return GetDisplayCategory(cat); }

I had planned on having doing it all LINQ to SQL expressions, but it was taking more time then it was worth to figure out how to do the hierarchy lookup from the category names.  I need to add some caching of the key lookups at some point, since the joins look like they might get a bit nasty for deep categories, but that can wait.

I added a few overloads to the HtmlHelper ActionLink extension methods to handle making the nice Url links.

Now I need to figure out how to deploy the usercontrols that will contain the executable part of the example. I have had some problems with compilation sometimes when I had the website directly upload the usercontrols. Plus I would like them to go into source control when I add them.

Technorati Tags: