mha.dk

Random thoughts of wisdom - the personal blog of Michael Holm Andersen

Looking at ASP.NET MVC 3

I’m in the process of re-writing www.aspnethotel.dk to use ASP.NET MVC 3 and are planning to use the new view engine (“Razor”). For more info about this, take a look at http://www.asp.net/mvc/mvc3

Webshop launched

The new B2C edition of our games and movies shop, located at http://www.mbc.dk/ is finally online.

The site is built using Visual Studio 2010, ASP.NET 4.0, Webform Routing, LINQtoSQL, jQuery and various other technologies.

The system uses LINQtoSQL as ORM and a custom build Repository on-top to handle all data access/business logic. A quick look at the DBML reveals a rather complex database schema as we exchange a lot of data with our ERP system (Axapta).

dbmlGW

The Solutions currently consists of 9 projects in total: 7 class library and 2 websites.

vsgw

The frontend website (webshop) uses Webform Routing to achieve SEO friendly URLs

frontgw

The backend website controls the all the frontend webshop’s (it’s possible to run multiple webshops on the same backend), data exchange with Axapta, CMS, CRM etc.

backendgw

.. it’s been lot’s of fun to build the system from the ground up (I started with a completely ‘clean plate’), and are now working on the B2B website.

301 Redirects on IIS7 – come again Microsoft!!

Creating a 301 Redirect in IIS7 is EVEN MORE CRAPPY than on IIS6 – I was going “nuts” trying to find out why my 301 Redirect didn’t work.

What I wanted to do (a pretty common scenario) was to redirect traffic from my URL without www to the www.somethinggoeshere.dk version of my domain name – however this (one should think!) simple task is not easily done!! Here’s how to do it:

You have to create a new website (one could wonder why it’s not possible simply to add e.g. 301 Permanent headers to a host name and in this way quickly be able to add a list of URLs which would be 301 redirected) – when creating the website you HAVE to enter a Physical Path when creating the site. The wizard forces you to pick a path even if you plan to redirect the site to a URL.

The most obvious would be to pick the root folder of the site you plan on redirecting to, however this (why, Microsoft?) caused an error for both sites due to a continuous redirection. You have to create an empty directory for the site you want to redirect, which makes no sense at all (why does the directory matter when all I want to do is make a 301 permanent redirect).

This ought to be MUCH SIMPLER if you ask me!

Transfer files from HTC Desire to PC using WiFi

wifitransfer

You gotta love the HTC Desire :-) .. Transferring files to / from the device to Vista or Windows 7 is as easy as:

  1. Connect your Desire to your WiFi network
  2. Download EStrongs File Explorer from Marked
  3. Create a share on your PC, for easy access give “everyone” modify access
  4. Launch EStrongs File Explorer on phone and choose “LAN” and enter your username and password – your Desire is now connected to the share on the PC
  5. On the phone (in EStrongs File Explorer), choose “Local”, select some files and choose copy. Change the view to “LAN” and choose paste.


The files from your HTC Desire is now copied to your share on the PC using WiFi – of course you can also transfer from PC to Phone :-)

Off topic: Making of the Korean Actress "Song Hye Kyo"

As some of you may know I have a past making/teaching 3D computer graphics – so I just had to mention this, and show how far 3D has come in its pursuit of creating realistic 3D imagery:

3d_final_large

100% 3D computer generated using Zbrush and 3DSMAX– WOW!! – See the image in hi-res here: http://www.cgarena.com/freestuff/tutorials/max/songhyekyo/final_large.jpg

You can read the “making of” story here: http://www.cgarena.com/freestuff/tutorials/max/songhyekyo/

Firefox Addon – Cool add-on for SEO work

Came across a nice little plug-in for Firefox today while working with SEO optimization: Meta Description & Title on Top

The add-on adds Description, Keywords and Title of the current page to the top for easy viewing, like this:

metadata

Really useful when browsing your site and making sure you’re “google proff” :-)

LINQ to SQL – Group 2 rows into 1

Jacob and I have been struggling with some “nasty” LINQ today where we need to get the aggregated value of a Quantity column from a transaction table, however a little “twist” was that we need to sum all the positive values into one group and all the negative values into another, and in the result set end up with only ONE row containing a PositiveQuantitySum and a NegativeQuantitySum … at first it sound pretty easy, but turned out not to be the case.

After a few attempts we ended up with this LINQ which actually gives the correct result, but we have 2 rows (one “positive”, one “negative”) – here is the LINQ:

from test in
(from t in AxInventTransactions
where t.Quantity >= 0 &&
              t.DateFinancial >= DateTime.Parse("01-04-2010") &&
              t.DateFinancial <= DateTime.Parse("31-08-2010") &&
              t.Customer.StatisticsGroupName.Contains("S")
              orderby t.ItemNumber, t.CustomerAccountNumber
              group t by new { t.ItemNumber, t.CustomerAccountNumber, t.VendorAccountNumber, t.Customer.StatisticsGroupName, CustomerName = t.Customer.Name, ProductName = t.Product.Name }
              into myGroup select new { myGroup.Key.ItemNumber,
              myGroup.Key.CustomerAccountNumber, 
              myGroup.Key.VendorAccountNumber, 
              myGroup.Key.StatisticsGroupName, 
              myGroup.Key.ProductName, 
              myGroup.Key.CustomerName, 
             Quantity = myGroup.Sum(i => i.Quantity)
})
.Union(from t in AxInventTransactions
where t.Quantity < 0 &&
              t.DateFinancial >= DateTime.Parse("01-04-2010") &&
              t.DateFinancial <= DateTime.Parse("31-08-2010") &&
              t.Customer.StatisticsGroupName.Contains("S")
              orderby t.ItemNumber, t.CustomerAccountNumber
              group t by new { t.ItemNumber,
                               t.CustomerAccountNumber,
                               t.VendorAccountNumber,
                               t.Customer.StatisticsGroupName,
                               CustomerName = t.Customer.Name,
                               ProductName = t.Product.Name} 
              into myGroup select new { myGroup.Key.ItemNumber,  
                             myGroup.Key.CustomerAccountNumber, 
                             myGroup.Key.VendorAccountNumber, 
                             myGroup.Key.StatisticsGroupName, 
                             myGroup.Key.ProductName, 
                             myGroup.Key.CustomerName, 
Quantity = myGroup.Sum(i => i.Quantity) } ).OrderBy(x => x.ItemNumber).ThenBy(x => x.CustomerAccountNumber)
orderby test.ItemNumber, test.CustomerAccountNumber
select new
{
            ItemNumber = test.ItemNumber,
            CustomerAccountNumber = test.CustomerAccountNumber,
            VendorAccountNumber = test.VendorAccountNumber,
            QuantityPlus = test.Quantity >= 0 ? test.Quantity : 0,
            QuantityNeg = test.Quantity < 0 ? test.Quantity : 0,
            StatisticsGroupName = test.StatisticsGroupName,
            ProductName = test.ProductName,
            CustomerName = test.CustomerName,
}

The above LINQ which uses UNION to merge the two result set (positive / negative)produces a result set something like this:

result1

We would like to have this result as ONE row, containing a column for the positive sum (6) and a column for the negative sum (-3).

While eating dinner tonight (I now, geeky!), I realized that we had to skip UNION and do it all “in one go”. The problem however is that (as you probably already know): Anonymous types can't be null

… and grouping all the positive and negative values of Quantity “in one go” would result in a NULL value for each “alternate” value (or whatever we should call it), causing an InvalidOperationException in this case: “The null value cannot be assigned to a member with type System.Int32 which is a non-nullable value type.”

So .. we need to make sure that IF the value returned by Sum() is actually NULL (which does not play together with System.Int32 :-) we instead return 0 (as it’s harmless to either add/subtract zero, this will of course not affect the result).

I ended up with this LINQ:

from t in AxInventTransactions
where     t.DateFinancial >= DateTime.Parse("01-04-2010") && 
          t.DateFinancial <= DateTime.Parse("31-08-2010") && 
          t.Customer.StatisticsGroupName.Contains("S") 
          orderby t.ItemNumber, t.CustomerAccountNumber 
          group t by new {
t.ItemNumber,
                           t.CustomerAccountNumber, 
                           t.VendorAccountNumber,
                           t.Customer.StatisticsGroupName,
                           CustomerName = t.Customer.Name, 
                           ProductName = t.Product.Name } 
          into myGroup select new { myGroup.Key.ItemNumber,
                         myGroup.Key.CustomerAccountNumber, 
                         myGroup.Key.VendorAccountNumber, 
                         myGroup.Key.StatisticsGroupName, 
                         myGroup.Key.ProductName, 
                         myGroup.Key.CustomerName, 
QuantityPlus = myGroup.Where(x => x.Quantity >= 0).Sum(i => i.Quantity) != null ? myGroup.Where(x => x.Quantity >= 0).Sum(i => i.Quantity) : 0, 
QuantityNeg = myGroup.Where(x => x.Quantity < 0).Sum(i => i.Quantity) != null ? myGroup.Where(x => x.Quantity < 0).Sum(i => i.Quantity) : 0 }

Which produces a result set like this:

result2

As you can see we now have ONE row with a column for “all positive values aggregated” and column for “all negative values aggregated”, which is exactly what I want.

The ‘trick’ is to make sure you don’t get any NULL values into the quotation, which is done using the ternary operator (very useful in LINQ also!), like so:

QuantityPlus = myGroup.Where(x => x.Quantity >= 0).Sum(i => i.Quantity) != null ? myGroup.Where(x => x.Quantity >= 0).Sum(i => i.Quantity) : 0

Which “translates” to something like this:

If Quantity is equal or larger than 0, add the value of Quantity to the aggregated “QuantityPlus” (System.Int32), however if the Quantity value does NOT meet the criteria (aka is a negative value) then NULL would be added (which of course will cause an exception!), SO INSTEAD we need to add the value 0 to the aggregated “QuantityPlus” (using the ternary operator takes care of this).

Hope the above makes sense and helps anyone which is facing similar problem finding the solution a bit easier :-) .. if anyone knows an alternate way of solving this issue, please feel free to write me an email.

Learn jQuery

If you’re interested in jQuery take a look at jQuery Fundamentals by Rebecca Murphey, awesome work!

WebMatrix – alive again!

After about 7 years, Microsoft have decided to re-activate WebMatrix aka “The Matrix” :-)

WebMatrix is everything you need to build Web sites using Windows. It includes IIS Developer Express (a development Web server), ASP.NET and SQL Server Compact (an embedded database). It streamlines Web site development and makes it easy to start Web sites from popular open-source apps. The skills and code you develop with WebMatrix transition seamlessly to Visual Studio and SQL Server.

You can download the beta here: http://www.microsoft.com/web/webmatrix/

The WebMatrix is a smaller / lighter product that the Express product series, which of course still are available for download. If you’re ‘lazy’ you can use the Microsoft Web Platform Installer 2.0 for easy setup / install.

Android + Evernote == perfect combination

If you own an Android (or iPhone for that matter) you owe it to yourself check out Evernote (http://www.evernote.com/)

Evernote makes it extremely easy to save your ideas, things you see, things you like etc., and find them all on any computer, phone or device you use.

I use Evernote to:

  • Take pictures of business cards and make these searchable via the awesome OCR functionality of Evernote
  • Mark text (e.g. information about conferences, address information etc.) in Firefox and with a single click create a note which I can see on my Android phone
  • Using the Windows application easily tag, sort and organize notes into Notebooks
  • Using the “folder watch” feature (Windows application), drop a file into a folder and auto generate a note (in my “Imported” notebook) containing all the information, and having it available on my Android (e.g. PDF files, .txt files etc.)
  • Take images of ‘everything’ for later use, e.g. wine labels, recipes, signs and more – all searchable through the OCR feature of Evernote
  • Store important information in Emails on my phone, simply marks the text in Outlook and with a single click create a note.