Wednesday, December 1, 2010

Speeding Up NHibernate Startup Time

Thanks to Development With A Dot for this one. Works a treat :)

jQuery "Live" and ASP.NET Ajax

Now as you may be aware, ASP.NET Ajax is a big bloaty beast and I don't like it much. I wouldn't recommend it for a public website taking a zillion hits a day.

However, for knocking together a UI for an intranet app, where you have gallons of network capacity (or is it measured in fathoms, can't remember) and can dictate the browser that will be used, it's not so bad - mainly cos it does a lot for little input. Which I do like.

I have a scenario in an intranet app where I want to show a modal popup after validating certain conditions in server-side code; and within this popup, I want to do some jQuery Ajax.

Following the quick'n'dirty approach, I used an AjaxControlToolkit ModalPopupExtender (no sniggering at the back) to show the popup. All good so far - popup appears and disappears.

Within the popup, I wanted the user to be able to search for products by name & category, and select from a list returned, closing the modal as they do so. Here's the script I was trying to attach: -

$(document).ready(function ()
{
    $("#btnSearch").click(function ()
    {
        $.getJSON("itemSearchHandler.ashx",
                    {
                        "categoryID": $("#cboSearchCategory option:selected").val(),
                        "term": $("#txtSearchProductName").val()
                    },
                    handleResult
                );
    });

    // etc


Trouble is, this handler didn't fire, and I should have guessed as to why not, but h/t to Epic Phil for the solution.

The reason the event doesn't fire is because the DOM elements I am trying to reference don't exist when $(document).ready fires. They are dynamically added by ASP.NET Ajax when the Modal is displayed. jQuery tries to attach a handler and gives up when it can't find the element I'm asking to attach my script to - btnSearch - in the DOM.

Fortunately there is a way around this, and that's to use the .live method: -

$(document).ready(function ()
{
    $("#btnSearch").live('click', function ()
    {
        $.getJSON("itemSearchHandler.ashx",
                    {
                        "categoryID": $("#cboSearchCategory option:selected").val(),
                        "term": $("#txtSearchProductName").val()
                    },
                    handleResult
                );
    });
    // etc

This will attach a handler to the event for all elements which match the current selector, now and in the future.

Handy !

Other thoughts ?
  • ASP.NET 4's ClientIDMode="static" is a life-saver for working with jQuery
  • The standard ASP.NET button control refuses to fire a Click event if it's assigned to the Ok or Cancel controls in a ModalPopupExtender. Use a standard html button (not an input type="button")
  • I feel a bit dirty using ASP.NET Ajax as I've railed against it before and rightly so - here, here and here you go - but as I said, I'm knocking out a fast-turnaround intranet application not an eBay clone
  • That's enough for now

Saturday, November 20, 2010

SiteCore 6.4

SiteCore is a great .NET-based CMS.

I've seen so many CMS's, I'm frankly sick of them. Give me something useful and new. Hello, SiteCore. It's definitely better than Kentico, Umbraco, DotNetPuke, Sharepoint (ok not just a CMS but hey), OBS and even the legendary Pile of Code.

The Online Marketing Suite is the icing in the cake. I was in an OMS training day a few weeks ago and I thoroughly enjoyed it. Instrument your code; watch the marketing people have orgasms. Great stuff.

Thing is, the latest version 6.4 is still not going to *properly* support MVC or .NET 4. MVC I'm still out on; yes I know Model-View-Controller is a great pattern, not sure ASP.NET's version is that good though.

ASP.NET 4 WebForms is superb - please read this if you're not up to speed on the many new features it offers. Most ASP.NET developers are WebForms based, and MVC is a big paradigm shift for them. I know it allows a greater testing surface, amongst other benefits, but if you're doing your job properly and maybe following an MVP pattern in your web applications, then why switch ?

I think SiteCore have a fight on their hands; open-source competitors are going to eat into their share if they can't provide up to date development models, and frankly their licensing takes the piss. They want to charge us for staging licenses. Like.. what ??? Get bent guys..

The real question. Is Orchard the new messiah, or just a very naughty boy ?

Monday, November 8, 2010

nHibernate 3.0 QueryOver - Searching, and Paging at database level

I've been through numerous data-access technologies with .NET - plain old DataReaders & SqlCommands, Code-genned layers around these of various descriptions and varying degrees of horrible, Pile of Code, Typed Datasets, Linq-to-SQL, Lightspeed, LLBLGen Pro, Entity Failwork.

Of all these, nHibernate 3.0 is definitely one of them. No doubt something better is on the horizon and when it looms into view I might take a look. Until then, this is working well for me.

In my humble opinion, NH3 is way better than Linq-to-Fail or infact any other model-based ORF (Object-Relational Failfactory).
  1. The fluent style works well; it's nice to use
  2. It's codegen-able like a crazy thing
  3. It's flexible and very extensible
  4. It performs - the generated SQL is lean and exactly what you need, it's measurably faster than L2S or Lightspeed
  5. It isn't Linq-to-SQL
  6. or a cabbage
NH3 gives us a whole set of functionality missing from 2.1 - functions that wrap typical SQL functions. It also gives us a lot of additional flexibility with lambda's prevalent over magic strings, so refactoring and catching problems at design time is now a doddle.

That said, I'd like a nicer way of doing multi-field searches; maybe by using an Expression<ICriteria> as a parameter to my search method ?

Here is my search method, abbreviated so as not to cause boredom: -

public IList CustomerSearch(CustomerSearchCriteria criteria, int pageIndex, int pageSize)
        {
            IList list = null;

            using (var session = SessionFactory.OpenSession())
            {
                var query = session.QueryOver();

                if (!string.IsNullOrEmpty(criteria.CustomerName))
                {
                    MatchMode matchMode;
                     
                    if (criteria.CustomerSearch == CustomerSearchEnum.StartingWith)
                    {
                        matchMode = MatchMode.Start;
                    }
                    else if ..
                    // etc

                    query = query.WhereRestrictionOn(x => x.CustomerName.ToLower()).IsLike(criteria.CustomerName.ToLower(), matchMode);
                }
                
                if (criteria.ActiveOnly)
                {
                    query = query.And(x => x.Active == true);
                }
                if (!string.IsNullOrEmpty(criteria.Address1))
                {
                    query = query.And(x => x.Address1.ToLower().StartsWith(criteria.Address1.ToLower()));
                }
                // etc

I'm working on a nicer way of doing this, so stay tuned. That said, the above is fairly readable; I'm just appending additional sections to the WHERE clause where needed.

Hmm.. Anyway, one thing NH3 gives us is database-level paging using the SQL Server ROW_NUMBER function, which is efficient (much more efficient than selecting the whole set into memory and doing the paging there..).

list = query.Skip(pageIndex * pageSize)
    .Take(pageSize)
    .OrderBy(x => x.CustomerName).Asc()
    .List();


This is nice, except it *only* returns the rows in the page. How do I know how many rows there are in total, so I can set up my pager accordingly ?

This is easy when done at stored procedure level, as I can just run an additional Count(*) SELECT and return an OUT parameter, all in one hit to the database. Am I going to need two hits here ?

As it turns out, the CriteriaTransformer has a "TransformToRowCount" method, which does what we need. This does issue one more SQL statement for the count, and it's submitted separately - so two round trips, not ideal.

list = query.Skip(pageIndex * pageSize)
    .Take(pageSize)
    .OrderBy(x => x.CustomerName).Asc()
    .List();

int count = CriteriaTransformer.TransformToRowCount(query.UnderlyingCriteria)
                        .UniqueResult();


And after reading this, the process has been simplified even further with the addition of an extension method. So the previous example can be re-written as just ..

list = query.Skip(pageIndex * pageSize)
    .Take(pageSize)
    .OrderBy(x => x.CustomerName).Asc()
    .List();

int count = query.RowCount();


Nice ! But still two database hits. There are two ways to fix this: -
  1. Use a transaction
  2. Use a projection
I'll write some drivel about projections at a later date.

Toodles.

StructureMap usefulness

Yet again I find myself spending literally minutes of my life trying to figure out why something is going wrong, only to find a useful feature of something that could potentially save many more minutes; time better spent writing unit tests, for example, or lolling around the coffee shop talking about stuff.

Turns out in the end I'd configured the wrong repository name. Dumbass mistake of the kind we all make from time to time, but one of those cases where the wood is clouding the view of the trees in the way woods always seem to.

I'd done this ..


instead of this..


Note "EmployeeRepository" instead of "LookupRepository". For clarification, LookupRepository wasn't yet finished.

Upon trying to resolve a reference to IEmployeeService, StructureMap was throwing Exception code 202 - "No Default Instance defined for PluginFamily IEmployeeRepository". Confusing at first, turns out I was of course staring at the obvious problem all along.

Trying to replicate this was a pain as it was a case of fire up unit test; get to point that fails; fail (repeat).

Now I'm sure you've come across the ObjectFactory's "WhatDoIHave" method - which dumps out the state of the container, and what resolves to what. It's a useful way of pinpointing anything that doesn't have a concrete type defined for resolution. However, this chap is even more useful: -


Rather than having to get to the GetInstance method of StructureMap to find out you have a configuration problem, you can instead call this after ObjectFactory.Initialize, and it'll run through the map and attempt to construct everything it can.

I wouldn't recommend this for production release, but while in build it could save you at least one cup of coffee. And that's a good thing.

StructureMap is great. So much nicer to use than Unity. Feeling the love :o)

Sunday, October 31, 2010

SQL 2008 - Stupid options and sensible practices

http://www.danrigsby.com/blog/index.php/2008/09/26/sql-server-2008-error-saving-changes-is-not-permitted/
H/T to Dan Rigsby for saving me a metric crapload of time.

Ok I can see the sense, somehow - that option prevents you from saving table changes that require the table to be copied, dropped and re-created with the changes, for example, when changing column nullability.

But to have this enabled when you're in the thick of the database design and creation process is just bloody annoying. Took me a few expletives raged at the monitor too. Grrr.

After thinking about this a bit further, it's actually a really stupid option. Anyone making changes to production databases using the table designer should be put up against a wall and shot.

Production databases. These are things that must be updated with extreme caution.

Scripting is the only way to go. At a push, use SqlCompare if you're lazy, but I've seen that go wrong too.

Script any and all database changes as you make them in development. Round-table these with the others  if you're working in a team. Work out a strategy for updating, migrating data, and so on.

In other words, do it properly ffs. Database changes are the cause of at least 176% of all production problems and if you and the guys work out a process, you are thinking correctly. If you rely on stupid table designer features to save you from your own stupidity, then you're stupid.

Thanks for listening.

Thursday, October 28, 2010

Blake's 7 is awesome :)


First technology-related post is about something to do with .NET actually no, bollocks. Watched all of the first 3 series of Blake's 7 recently. Well, series 3 is more Avon's 7 but I digress.



They don't make TV like this any more. Ok so the special effects are awful - models wobbling through the outer reaches of the BBC cleaning supplies cupboard, computers made from Lego, the inside of the Liberator looks like it was bolted together during a drunken after-party at B & Q. Some of the acting is a bit hammy.

But most of it is great, the stories are superb and it was totally better than Star (urgh) Trek, which did and shall always suck, copiously. I generally hate sci-fi TV shows, but this slice of 70's/early 80's nostalgia was great to relive. I do vaguely remember it as a kid.. had no idea what it was all about of course.

Next post will be about .NET, promise ;o)