ASP.NET MVC3 app (part 2) – ajax cascading dropdown

 

To make cascading dropdowns in application from part 1, I created ProductFilter:

image

I will use this class as model for my home controller Index method:

image

Here you can also see Manufacturers JsonResult method, which is used for asynchronous refresh of second dropdown:

imageimage

Manufacturer dropdown is loaded with manufacturers which produce models of chosen product type. This is made possible with simple jquery function:

image

This function accepts url of method which provides json list of items for dropdown, passes formData parameter with id, and places results into target for which selector “target” is provided.

This is how my view from which this method is called looks:

image

Two dropdowns are created using standard MVC helpers, and onchange event function is attached using jquery. More dropdowns can be chained in the same way, there is only necessary to add change function in the same manner. However, this is no good, as event attachment is manual, and script must be written, and included into view as selectors are generated here. My goal is to make these event attachments unobtrusive, and I will write about that in part 3.

For now, you can download project source code here.

Back to part 1

ASP.NET MVC3 app (part 1) – Entity Framework and code first

How often you need to have cascading choices on UI in order to make your application user friendly? In my experience, almost every modern application has some form of hierarchy, and that is where cascading dropdowns are used. But, I want to make this less repetitive and more elegant. So, let’s begin. In first part (this) I will create an simple web app using entity framework code-first and make simple model which will be used for creating this functionality. It is one speedy run-through of new features, without advanced topics, so mind some bad practices, this blog post is not about good programming, first part is for MVC3/.NET 4 beginners with experience with older versions of MVC and .NET.

It will be an mvc3 razor internet application:

image

With latest MVC tools update there are already almost all necessary NuGet packages installed in new project:

image

I will just update all of jQuery packages as they have updates at the moment, and add EntityFramework.SqlServerCompact (NuGet will add dependencies), so SQL server won’t be needed.

As this is demo app, I will put everything into single project. It will be an product catalogue.

This is data model:

image

Central object will be product model (I will use vehicles domain), which has type, version, trim level and manufacturer. Simple enough. Objects on diagram are simple POCO objects with collection properties marked as virtual, so entity framework can override them and inject DynamicProxy objects for lazy loading.

This will be my repository:

image

For this DbContext to work, I need to do one more thing – to put connection string into my web.config:

image

As I don’t want to create test data every time I change my model, I can use database initializer class to create test data (this is useful for unit testing):

image

And this is it. I now have database and data. Actually, I will have it when I start my application, if I add this to global.asax:

image

To test this, I will use controller autoscaffold feature of new MVC tools update:

image

This will autocreate controller and all views Smile. After this action, starting app and visiting http://localhost:57095/Manufacturer will give:

image

Note that only manufacturers for which I created Models are in database. This is because I only added Models, and EF added all related objects, and BMW was not among them.

Using auto scaffold I created controllers for all model objects in couple of minutes.

This is end of part 1, I now have application which will I use to create unobtrusive cascading dropdowns. In the next part I will make cascading dropdown loading using standard methods (jQuery and ajax).

For more info about EF Code First, visit

http://www.hanselman.com/blog/SimpleCodeFirstWithEntityFramework4MagicUnicornFeatureCTP4.aspx

and

http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

UPDATE: Added part 2

Take my work with me

How often did I need to copy whole virtual machine because I needed to continue work on another location? A way too often. And moments when I wait for 20-30GB to copy, sometimes seem like eternity.

Well, I spent couple minutes last night to prevent that 🙂

Here is a batch script which copies folder with my work from hdd and takes backup of database. Even more, it restores everything back when I arrive at another location 🙂

So, save this script as common.bat:

@echo off
set server=HOSTNAME\INSTANCE
set dbName=DATABASE
set projFolder="C:\Users\gorano\Documents\visual studio 2010\Projects"
set backupFolder=%CD%

if "%1"=="leaving" GOTO backup
if "%1"=="arriving" GOTO restore
echo Invalid first argument, must be "leaving" or "arriving"
GOTO end

:backup
echo backup database %dbName%
@echo on
sqlcmd -E -S %server% -Q "BACKUP DATABASE [%dbName%] TO  DISK = N'%backupFolder%\%dbName%.bak' WITH NOFORMAT, INIT, NAME = N'%dbName%-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10"
xcopy %projfolder% %backupFolder%\Projects  /E /I /Y /Q
GOTO end

:restore
if "%2"=="DeleteOld" GOTO deleteold
:restoreNoDelete
echo restore database %dbName%
sqlcmd -E -S %server% -Q "RESTORE DATABASE [%dbName%] FROM DISK = N'%backupFolder%\%dbName%.bak' WITH  FILE = 1,  NOUNLOAD,  REPLACE,  STATS = 10"
xcopy %projfolder% %projfolder%.backup  /E /I /Y /Q
xcopy %backupFolder%\Projects %projfolder%  /E /I /Y /Q
GOTO end

:deleteold
@echo Press any key to delete database %dbName% on sql server %server%
pause
sqlcmd -E -S %server% -Q "ALTER DATABASE [%dbName%] SET  SINGLE_USER WITH ROLLBACK IMMEDIATE"
sqlcmd -E -S %server% -Q "DROP REMOVETHISWORD DATABASE [%dbName%]"
GOTO restoreNoDelete

:end
pause

To run this easily, make “i’mleaving.bat” with

common leaving

and “i arrived.bat” with

common arriving DeleteOld

All you need to change is to set your server\instance, database name, folder with projects, and to delete “REMOVETHISWORD” under :deleteold, as words DROP and DATABASE does not stand well together (I don’t want to hack wordpress script injection protection to post this) 🙂
In combination with DropBox, this is great thing. You can also add 7z line to compress/decompress these files so dropbox sharing is more meaningfull (if you have large database).

Pravda iz m:tel-a – imate prijatelje :)

Čini se da ovaj sistem “dok ćutiš – j…. ćemo te” funkcioniše i kod nas, jer čak i giganti popuštaju kad se malo pobunimo. Iako sam ja svoju pobunu počeo davno prije Tunisa, Egipta i RS, tek sad je nastupio rezultat:

Odgovor m:tel-a na moj prigovor
Odgovor iz m:tel-a na moj prigovor

Šta da kažem nego – zadovoljan sam. Još da su im telefoni malo jeftiniji nego što su u prodavnicama… možda čak ne raskinem pretplatu jednog dana kada/ako mi firma vrati broj 🙂

Sad, mnogi će reći da 13 maraka (+PDV) i nije nešto značajno, ali to je 13 maraka (+PDV) koje ja NISAM potrošio a (greškom?) su mi naplaćene. Nije bitna količina, bitan je princip. I bitno je da bar nešto funkcioniše kako treba. Danas m:tel, a sutra će neko dobiti povrat novca za artikal koji je lažno reklamiran ili povrat obaveza koje je platio državi a zatvorio je preduzeće prije isteka uplaćenog perioda ili ima pravo na umanjenje… bitno je suprotstaviti se. Tek kada bude dovoljan broj onih koji se suprotstavljaju, a vjerujem da će ih biti, onda će onome ko odgovara na sve te prigovore dop….. pa će sistem da se popravi tako da se više ne čine te greške.

Update – 2011/02/14 16:10

Pošto sam dobio par pitanja u vezi svoje žalbe, pronašao sam i nju:

Prigovor koji sam poslao u m:tel povodom računa na kom nije obračunan bonus
Prigovor na račun iz m:tel-a

Jebem ti državu!

Dobijem ti ja uputnicu za ultrazvuk. Čuj dobijem, zaradim – nakon svetog januara dobijem glavobolju (a nikad me glava ne boli), izmjerim tlak kad ono oba preko 100. Odem kod svoje doktorke, dam malo krvi, vagnu me, kaže ti si debeo. Dobro, to sam znao. Kaže izgleda da ti je i jetra masna (ne bi me čudilo), al da mi budemo sigurni da nije šta drugo, aj ti na ultrazvuk. I tako ja dobijem tu uputnicu.
Naivan, kao i mnoga čeljad koja hoće da isprave krivu Drinu i da doprinesu da ovaj sistem bude bar malo bolji, naručiću se ja gore na Paprikovac. Kontam, bolje nek oni nešto rade, slabe su im plate, a i uslovi za rad. Nazovem klinički centar, tu mi dadnu jedan broj telefona. Nazovem taj broj, javi se teta kaže, eee mi smo u istoj zgradi al nije ovaj broj, zovi ovaj sad… (a nemate centralu???), al dobro, nazovem ja taj treći, opet se javi treća teta, kaže e to je to. Super, reko’ ja bih da se naručim na ultrazvuk. E, to ne može, evo već je 16h, nema sad ovde više nikog, sutra ti nazovi, al prije podne. Nazovem ja sutra, kažem tako, kaže meni četvrta teta ima termin za desetak dana (o, pa izgleda da oni imaju sasvim dovoljno pacijenata???), reko dobro, može tad, kaže ujutro u 8:00, nemoj doručkovati.
Dođe i taj dan, ja ustanem, spremim se, ne doručkujem i zapalim gore. Malo gužva usput, a malo (mnooooogo) i na parkingu, al stignem ja tamo, zakasnim samo 2 minuta. Predam knjižicu i uputnicu, i kaže meni teta 15 maraka košta pregled. Reko dobro, vadim pare, i kontam, a koliko bi tek koštao da mi ne odbija fond svaki mjesec 200-300 maraka od plate? Kaže meni teta, u stvari aj se ti prvo pregledaj pa ćeš onda da platiš (k’o da je znala…), idi gore do kraja hodnika pa lijevo.
Odem ja tamo, ono tu u tom hodniku rentgen, konsultacije za dojku, mamografija i ultrazvuk. Čeka tu masa naroda, al malo bolje pogledam većinom neko doveo ženu, neko majku, pitam jel čeka neko ultrazvuk, ono niko, svi gore na konsultacije i mamografiju. Dobro, pokucam uđem u ultrazvuk, ono nema nikog. Kaže čovjek ispred, maloprije izađe sestra. Sačekam ja još malo, nema nikog, a ja nervozan kad ne doručkujem. Vratim se tamo na recepciju, kažem nema nikoga tamo, odgovara mi teta, eto sad je sestra otišla. Ja opet tamo, stanem malo, još malo, izlazi sestra i kaže sjedi dečko i ode negdje. Ja kontam šta ja čekam ovdje, više me košta ovo vrijeme nego da platim sve što treba u privatnoj klinici, i odlučim, ode ja. Vratim se na recepciju, reko tako, sad je gotovo pola devet, ja da sam znao da je situacija ovakva, ja se gospođo ne bi ni naručivao. Kasnim na posao, treba li da vam šta platim? Kaže ona ne trebaš ništa, samo, jel vam dala sestra vašu knjižicu i uputnicu? Reko’ nije, jel mogu doći po to oko 17h? Kaže ajoj ne može, ček sad ću ja nju zvati. Nazove, čeka, niko se ne javlja, nazove drugi broj, treći, kaže momak mora na posao može li dobiti knjižicu, ova joj odgovara “šta bi mu ja”. Kaže meni ta teta tako je, doktor će doći sigurno do 11, pa ako može da tad dođeš ponovo, biće i knjižica? Hvala vam gospođo doviđenja! Donikad!
Napustio ja i bolnicu, i brdo, i kontam, učini mi žena uslugu. Ovdje, ko ima knjižicu ne može se osjećati bolje. A, ako nije crno, onda je bijelo. Evo ja se već osjećam bolje bez svoje. Sad bar znam na čemu sam, i mogu bar u to da se uzdam.

Omlet sa sirom i slaninom

Ponovo pišem recept, ništa ukusniji od prošlog (iako neki sumnjaju u moje prošlo remek djelo :)), ali ovoga puta malo sofisticiraniji. Vrlo jednostavno jelo, idealno za one koji ne znaju ama baš ništa u kuhinji 🙂

Za početak, potrebni resursi:

  • 2 jaja (kokošijih)
  • 200g svježeg sira
  • komad pancete (slanine)
  • list gauda sira
  • masline
  • ~ 15 minuta vremena

Algoritam:

  1. Staviti tavu da se grije sa par kapi ulja
  2. Razmutiti jaja (u tanjiru ili sl.)
  3. Ako se tava ugrijala, dodati jaja u tavu,
    u suprotnom ih dodati čim se ugrije 🙂
    (drugi thread radi dalje, ovaj ovde čeka
    i provjerava)
  4. Isjeći slaninu na sitne komadiće
  5. Isjeći masline na sitne komadiće
  6. Čim jaja počnu da koagulišu od
    temperature, dodati isjeckanu slaninu
    i masline
  7. Namazati svježi sir na gauda sir
  8. Presjeći gauda po pola, pa ga staviti
    na jaja
  9. Kada se gauda počne topiti, presaviti
    omlet, peći još minut i skinuti
  10. Jesti!
Jaja sa slaninom i maslinama
6. Jaja sa slaninom i maslinama
Svježi na gauda siru
7. Svježi na gauda siru

Sir dodan na omlet
8. Sir dodan na omlet

Omlet sa sirom i slaninom
Omlet sa sirom i slaninom

Fix selected tab in SharePoint top links menu

Fastest way to accomplish this is to use jquery! 🙂

function fixTabs(){
    $.each($(".customNavTabActive"), function() {
        $(this).removeClass("customNavTabActive");
        $(this).parentsUntil("table").each(function() {
            $(this).removeClass("customNavTabActive");
        });
    });
    $.each($("a.customNavTab"), function() {
        if (this.href == document.location.href || this.href + "/default.aspx" == document.location.href) {
            $(this).parent("td").addClass("customNavTabActive");
        }
    });
}

Update: I have improved this code a little bit 🙂

function fixTabs(){
    var normalNavTavCss = "customNavTab";
    var firstCellActiveCss = "customNavTabActive";
    var firstCellCss = "customNavTab";
    var lastCellActiveCss = "customNavTabActive";
    var lastCellCss = "customNavTab";
    var cellActiveCss = "customNavTabActive";
    $.each($("." + cellActiveCss), function() {
        $(this).removeClass(cellActiveCss);
        $(this).parentsUntil("table").each(function() {
        $(this).removeClass(cellActiveCss);
        });
    });
    var lastCell;
    var lastCellSelected;
    $.each($("." + normalNavTavCss + " a"), function(i) {
        lastCell = $(this).parent("td");
        var location = document.location.href.replace("/default.aspx", "");
        var link = this.href.replace("/default.aspx", "");
        lastCellSelected = (link == location || location.indexOf(link) > -1);
        if (lastCellSelected) {
            if (i == 0) {
                lastCell.addClass(firstCellActiveCss);
            }
            else {
                lastCell.addClass(cellActiveCss);
            }
        }
        else if (i == 0) {
            lastCell.addClass(firstCellCss);
        }
    });
    if (lastCellSelected) {
        lastCell.removeClass(cellActiveCss);
        lastCell.removeClass(firstCellActiveCss);
        lastCell.addClass(lastCellActiveCss);
    }
    else {
        lastCell.addClass(lastCellCss);
    }
}

IIS and ASP.NET 4.0 applications

If you cannot start debugging on web server, cannot open application on IIS at all, have any problems with managed integrated handler or similar when accessing application, then you need to install .NET 4.0 on server. Easiest way is using Web Platform Installer, under Frameworks.

If .NET 4.0 is already installed, then you need to open cmd as Administrator, and run “%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -i”

That solved problems for me.

Sir sa jajima i sirom

Ovo je jedno jelo koje moram da opišem. Sve je počelo tako što sam bio sam u stanu, i gladan. Došao sam do frižidera da vidim šta ima unutra, i nađem svježi sir zbregov – zadnji dan roka, a neotvoren. Uključim šporet, uzmem 2 jaja, razbijem ih i izmutim sa malo mlijeka i dodam malo brašna. To saspem u veliku tavu za palačinke, i kad se malo počelo stvrdnjavati, bacim na to onih pola kile sira jer ne mogu ostaviti ništa – propade 🙂
Odmah se vidjelo da je tava za palačinke greška za ovaj poduhvat pa sam uzeo veliku tavu i pretresao sve u nju, i izmiješao onaj omlet sa dna u sir. Potom se ta smjesa od temperature razrijedila, i sir se pretvorio u tekućinu. U to sam usuo još jedno jaje, malo posolio i izmiješao pa je dobilo žućkastu boju. Miješajući “to” sam shvatio da se tako ne može jesti jer to nije nikakvo jelo, ni supa, nije ništa. Onda sam uzeo dvije kriške hljeba i udrobio u to, i izmiješao, i onda je počelo da liči na neku žućkastu poparu, ili bijelu cicvaru, hljeb se baš lijepo povezao s tim i zgusnuo smjesu, ali je još bila pomalo tečna, a nisam htio da stavljam više hljeba jer bi bilo previše, ostali bi komadići neistopljenog hljeba, pa sam našao 3 lista gauda sira, koja sam smotao u rolu i isjeckao u tu smješu, a onda izmiješao dok se nije istopio i povezao sa ostatkom.
Tada sam tavu sklonio sa šporeta i stavio da se hladi, a dok sam čekao, iskidao sam u to nekoliko listova kulena, i isjeckao unutra 5 maslina, i sve smiješao.
Rezultat je bio mimo svih mojih očekivanja. Ovo je jedno izvanredno jelo, ali obavezno u njega treba ići neki kulen koji dobro miriše. Smjesa sireva i hljeba je upila sav taj miris i aromu, i ukus je toliko fantastičan koliko je izgled očajan:

Localizing Sharepoint resources – transliteration to Cyrillic

Recently I tried to localize MS WSS 3.0 site collection to unsupported language – Serbian, cyrillic (Serbia). LCID of this culture is 3098. This language is almost the same as existing latin localization to Serbian (Serbia) with LCID 2074. To get cyrillic version of resource files (resx), I installed Serbian latin language pack and searched wwwroot and 12 folders for “sr-latn-cs”, and took following files: core.sr-latn-cs.resx, resources.sr-latn-cs.resx, spadmin.sr-latn-cs.resx, spcore.sr-latn-cs.resx, spsearchadmin.sr-latn-cs.resx and wss.sr-latn-cs.resx

I got Search Center and language pack for it installed, so in an environment without search center, there should be some of these files missing.

To get sr-cyrl-cs.resx versions of theese files, I made small console application which parsed through xml files and replaced latin letters with cyrillic. Character swap is simple, and to parse xml I used following code:

static void Main(string[] args)
        {
            if (args.Length == 0) args = new string[]{"source", "destination"};
            DirectoryInfo source = new DirectoryInfo(args[0]);
            foreach (FileInfo file in source.EnumerateFiles())
            {
                XmlTextReader reader = new XmlTextReader(file.OpenText());
                XmlDocument doc = new XmlDocument();
                doc.Load(reader);
                reader.Close();
                FileInfo dest = file.CopyTo(Path.Combine(args[1], file.Name.Replace(SourceLang, DestLang)), true);
                XmlDocument destination = new XmlDocument();
                foreach (XmlNode node in doc.ChildNodes)
                {
                    ParseChildren(node);
                }

                XmlTextWriter writer = new XmlTextWriter(dest.OpenWrite(), Encoding.Unicode);
                doc.Save(writer);
                writer.Close();
            }
        }

        private static void ParseChildren(XmlNode sourceNode)
        {
            foreach (XmlNode node in sourceNode.ChildNodes)
            {
                switch (node.NodeType)
                {
                    case XmlNodeType.Text:
                        if (node.Name == "#text" && node.HasChildNodes == false 
                            && node.Value.Length > 0 && node.ParentNode.ParentNode.Name == "data")
                        {
                            if (!node.ParentNode.ParentNode.Attributes["name"].Value.ToUpper().Contains("accesskey".ToUpper())
                                && !node.ParentNode.ParentNode.Attributes["name"].Value.ToUpper().Contains("_AK".ToUpper()))
                            {
                                node.Value = SmartConvertToCyrillic(node.Value);
                            }
                            else
                            {
                                break;
                            }
                        }
                        break;
                    default:
                        break;
                }
                if (node.HasChildNodes)
                    ParseChildren(node);
            }
        }

Important lines here are in case XmlNodeType.Text:

Those lines discriminate nodes which are values and need to be transliterated to Cyrillic.

When new resx files have been placed back to same respective folders where their sources for transliteration were found, then new language had to be enabled in Sharepoint.

Registry key HKEY_LOCAL_MACHINESOFTWAREMicrosoftShared ToolsWeb Server Extensions12.0InstalledLanguages contains string values whose names are LCID-s of installed languages, and value is version of satellite assembly of microsoft.sharepoint.intl.resources.dll in GAC. I added new string value named “3098” with value “12.0.0.0”. I even disassembled latin version of this dll and made cyrillic but I have what it seems unsolvable problem of impossibility to build that dll in Language version other than “Language neutral”, and I believe that is the key to enable localization of administration pages and parts of UI that is not localized.

Adding 3098 registry value enabled “Serbian Cyrillic” language in “New Web Site” SharePoint page, but to get templates for Team site, Blank, etc, it is necessary to make “3098” folder in C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12TEMPLATE

I used 2074 folder as a template, and edited files in 2074/XML subfolder to get site templates in site creation wizard.

Newly created site was mostly localized – parts which are visible to users, but administrative pages are localized from satellite dll, and I did not succeed in building language specific version of dll to use it for this purpose. Also, this dll must be signed for SharePoint to use it, and to circumvent this I used delay sign, and then added exception for signature verification using gacutil.

This was very useful resource http://social.msdn.microsoft.com/Forums/en/sharepointdevelopmentprerelease/thread/023d1fb9-c415-405a-8944-c709c0cc8f01

Useful links

Page with bunch of useful software (Stranica sa hrpom korisnog softvera)

http://www.weethet.nl/english/download.php

Find alternatives to well known programs:

http://alternativeto.net/

Windows 7 hotkeys:

http://hubka.net/archive/2009/03/29/windows-7-hotkeys.aspx

Fix MSN pop-up on minimizing Firefox:

http://jonathanhu.com/2009/05/15/how-to-fix-windows-live-msn-pop-up-when-minimize-firefox-in-windows-7/

Change default location for Windows 7 Windows Explorer:

http://www.windows7hacker.com/index.php/2009/05/how-to-change-the-default-location-in-windows-explorer-to-my-computer-in-windows-7/

PID/VID database – info on any unknown hardware

http://www.pcidatabase.com/

Fix Vista TCP/IP after clicking on “Remove outdated LSP”:

Reinstall and Reset TCP/IP (Internet Protocol) in Windows Vista, 2003 and XP » My Digital Life

Many pdf books on computer sciences:

FlazX – Welcome to your Computer & IT learning center

Ljudi…

Čini mi se da su ljudi faktor koji sa najvećim koeficijentom utiče na to koliko nam je naš život lijep (ili nije).  Razmišljajući zašto je meni život toliko lijep ovakav kakav je i zašto ne patim od želje da odem negdje daleko i tamo radim bolji posao i više zarađujem zaključio sam da je to zato što ne znam kakvim ću tamo ljudima biti okružen. Teško da mogu biti bolji nego što su sad.

Počev od porodice (doduše, tu sam imao sreće jer je to jedino što ne možeš izabrati), preko prijatelja, ljudi sa kojima se družim, živim, školujem i radim, svuda imam osobe kojima mogu da se divim, sa kojima mogu da razgovaram u nedogled i sa kojima mogu da se smijem. Neki su u mojoj okolini zato što sam ja to htio, a neki su zato što sam ja htio biti u njihovoj okolini, ali svi su tu, i mislim da je to toliko pozitivna stvar u životu da može da lako zasjeni mnoštvo negativnih i da mnoge probleme učini lako rješivima.

Povremeno slušam nekoga od tih ljudi u svojoj okolini kako se čude nekome tamo ko je napravio nešto, sad je nebitno šta. I onda razmislim čega se taj čovjek odrekao da bi stigao tamo. I vidim da je stvarno nešto postigao, ali nije postignuće to što (skoro) svi misle da je, već to što se on odrekao mnoštva stvari koje mi uzimamo zdravo za gotovo. Većina nas može da postigne to isto, i to nije problem. Problem je pomisao da ćemo prestati da radimo sve ono što smo navikli da radimo sa svojim prijateljima (neko razgovara, neko pije, neko roštilja… uglavnom druži se). Da li je ikad neko pomislio da je neko od tih poznatih primjeraka čovjeka možda morao da ostavi iza sebe porodicu, prijatelje i sve koje poznaje da bi mogao da dođe tamo gdje ima uslove da napravi ono što je napravio? I da je bez obzira na taj uspjeh vjerovatno ostao otuđen od prvih, a pronašao malo drugih prijatelja?

Koliko cijenite prijatelje?