SQL Replace för att skapa Slugs

Har på många tidigare projekt använt Id-nummer i url:erna för att IIS och .NET haft så dåligt stöd för att skapa användarvänliga url:er. Gör nu om en del gamla sidor till ASP.NET MVC och lägger över dem till IIS 7-servrar som har bättre stöd för url-omskrivning.

Brukar lägga till ett speciellt databas-fält för att spara den sista delen av url:en som ska vara till för att identifiera blogginlägget, produkten, kategorien eller vad det nu handlar om och basera denna på den äldre titeln. Använder det uttryck som även Wordpress använder för att beskriva ett sånt fält, "Slug".

Här är ett skript som jag precis körde på en sådan databas. Detta byter ut de tecken jag inte vill ha i url:erna mot ett vanligt bindestreck, gör om allt till gemener och byter ut å,ä,ö mot a,a,o.

UPDATE BlogPost SET Slug=Lower(Title);
UPDATE BlogPost SET Slug=REPLACE(Slug,'å','a');
UPDATE BlogPost SET Slug=REPLACE(Slug,'ä','a');
UPDATE BlogPost SET Slug=REPLACE(Slug,'ö','o');
UPDATE BlogPost SET Slug=REPLACE(Slug,' ','-');
UPDATE BlogPost SET Slug=REPLACE(Slug,'&','-');
UPDATE BlogPost SET Slug=REPLACE(Slug,'/','-');
UPDATE BlogPost SET Slug=REPLACE(Slug,'-','-');
UPDATE BlogPost SET Slug=REPLACE(Slug,'.','-');
UPDATE BlogPost SET Slug=REPLACE(Slug,',','-');
UPDATE BlogPost SET Slug=REPLACE(Slug,'_','-');
By Jesper Lind

Kom igång med ASP.NET MVC Release Candidate

ASP.NET MVC är ett ramverk som erbjuder ett sätt att utveckla webbplatser som främjar testbarhet, struktur och klar separation av huvudbry. Man får intuitiva url:er och total kontroll över html-kod och css som rendereras. Själva designmönstret Model-View-Controller är ju inget nytt utan har tidigare funnits i webbramverk som t ex Zend, Django, eller Ruby On Rails. Det här handlar alltså om Microsofts implementering för webb av mönstret.

Ramverket utannnonserades av Microsoft i slutet av 2007 och har sedan dess släppts i ett antal förhandstitt-versioner (fem tror jag), en betaversion och nu nyligen en kandidat till den slutgiltiga versionen. Utveckligen har skett i stor samverkan med utvecklarcommunityn och det har varit riktigt roligt att se det växa fram. Det riktiga släppet ska enligt tidigare meddelanden släppas nu under februari månad. Återstår att se ifall de håller den tidsramen, men nu är det hur som helst inte långt kvar.

Det är alltså ett perfekt läge att börja testa med ramverket ifall du inte gjort det tidigare, något jag rekommenderar varmt. Web forms i all ära, när jag har kört MVC ett tag så lockar inte den klassiska modellen längre.

Bra introduktionsartiklar till ASP.NET MVC av Stephen Walter

Stephen Walter skriver för tillfället på boken ASP.NET MVC Framework Unleashed och bjuder på sin blogg på några exempelkapitel från denna. Riktigt bra ifall man vill lära sig runderna i ASP.NET MVC.

I Chapter 1 - An Introduction to ASP.NET MVC ger han en introduktion till vad han anser hur bra mjukvara ska byggas, designmönster, arkitektur och vikten av testdriven utveckling. Han förklarar även hur standardinstallationen av ASP.NET MVC-installationen fungerar.

Vidare med Chapter 2 - Building a Simple ASP.NET MVC Application ber han oss lustigt nog att glömma vad han just sagt om testbarhet och de stora målen med mönstret och visar oss istället hur man bygger en enkel applikation, utan ett enda test. Här får vi dock lära sig hur man skapar projektetet i Visual Studio och bekantar oss med filstruktur coh de allmänna begreppen.

Sen visas i Chapter 3 - Understanding Controllers hur Controllers fungerar, vad för olika typer av resultat de returnerar, hur man kan begränsa dem till att bara acceptera specifika HTTP-attribut och hur man testar dem.

Det i skrivandes stund sista kapitlet som förhandsvisas är Chapter 9 - Understanding Routing och här visas hur man sätter upp sina routes i Global.asax för hur url-stukturen på för sin applikation ska se ut. Han går igenom hur man kan sätta begränsningar på dem och hur man debuggar och testar dem.

En riktigt lärolik samling artiklar alltså och hoppas fler kapitel dyker upp snart. Tänkt bara att detta är temporära kapitel ur boken som kan komma att ändras för att reflektera eventuella sista-minuten-ändringar vi kan komma att få se i den slutgiltiga versionen av ASP.NET MVC.

Köra olika versioner av ramverket samtidigt

Till sist ett litet tips ifall du redan har utvecklat sajter på tidigare versioner och vill testköra den nya RC-versionen utan att oroa dig för att dina tidigare projekt slutar att fungera. Här handlar det om att ta bort MVC-referenserna från GAC efter du installerat den senaste releasen. Man måste in i registret och röja så var försiktig vad du än gör. Jag har följt instruktionerna på min maskin och det gick fint. Mina äldre projekt körs med betaversionens MVC-ddl:er som ligger i respektive projekts Bin-mapp.

Att jag inte ens har provat att skapa ett RC-projekt är en annan femma. Försöker hålla mig eftersom den riktiga versionen kanske släpps typ imorgon...

By Jesper Lind

Spåra formulärspostningar med Google Analytics

Har tänkt igenom hur denna blogg kan bli bättre och roligare att läsa och har en del ideér. För att kunna mäta om förändingar är bra eller dåliga så ville jag först sätta upp några mål i Google Analytics, och det har jag sysslat med de senaste dagarna. Tänkte dela med mig av vad jag lärt mig.

Först tänkte jag igenom vad målen med bloggen är och kom fram till att det viktigaste och roligaste är när man får input från sina läsare. Det är på så sätt som bloggen kan utvecklas och växa och därför bestämde jag mig för att sätta upp följande två mål.

  1. Kontaktformulär skickat
  2. Kommentar postad

När man sätter upp mål-urlerna i Google Analytics så har man tre olika alternativ, Exakt matchning, Rubrikmatchning och Matchning av vanliga uttryck. Utan att gå in för mycket på dem så kan jag kontatera att Exakt matchning fungerade bäst för det ja ville göra. Hos Google finns det en bra hjälpsida som förklarar hur de olika alternativen fungerar.

De två målen har jag implementerat lite olika så tänkte förklara här hur jag gjort.

Så satte jag upp mål för Kontaktformuläret

Kontaktformuläret postar tillbaks till sig själv och jag har alltså ännu inte gjort om det till PRG-designmönstret som jag skrev om här om dagen. Eftersom adressen inte ändras var jag tvungen att skicka med den påhittade sida "/contact-form-submitted" som jag angett i mitt första mål.

I ContactControllern (ASP.NET MVC) så skickar jag med parameter i ViewData när användaren har postat meddelandet:

this.ViewData["TrackPageView"] = "\"/contact-form-submitted\"";

Denna parameter sätts sen in längst ner på sidan i skriptet för Google Analytics:

<script type="text/javascript">
//<![CDATA[
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write("\<script src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'>\<\/script>" );
//]]>
</script>
<script type="text/javascript">
//<![CDATA[
var pageTracker = _gat._getTracker("<%=Request.Url.ToString().ToLower().IndexOf("codeodyssey.se") != -1 ? "UA-406884-2" : "UA-406884-1" %>");
pageTracker._initData();
pageTracker._trackPageview(<%=ViewData["TrackPageView"] %>);
//]]>
</script>

Mål-koden för kommentarerna

Kommentarsfunktionen har jag nyligen gjort om så den följer PGR-mönstret och här hade jag lite svårare att lägga in spårningskoden på rätt ställe. Provade en del olika grejer där jag bland annat försökte lägga in det på den adress som man postar kommentaren till (bloggurl plus "/add-comment" på slutet). Vet inte exakt varför det inte gick med regulärt uttryck men antar att det beror på att den sidan returnerar en 302-respons (see other adress). Kan vara så att man inte kan tracka såna sidor med Google Analytics.

Sen kom jag på en enklare lösning. La på ett onclick-event på submit-knappen istället där jag anropar pagetrackern och det fungerar nu fint.

<input onclick="pageTracker._trackPageview('/comment-submitted');" type="submit" value="<%= GetLocalResourceObject(" />" class="submit-btn"/>

Först trodde jag att huvudskriptet där tracken inkluderas var tvungen att ligga ovanför eventet, med det visade det sig att den inte behövde, den har ju redan registrerats när sidan laddas. Google Analytics Tracking API var användbart för felsökning och genom att anropa _getAccount() kunde jag bekräfta att eventet hade kontakt med trackern.

Dags att mäta, förändra och förfina

Så nu är det bara att luta sig tillbaks och börja analyserar hur kommentarer och kontaktmeddelande postas på Code Odyssey. Kom gärna med förslag och ideér hur sidan kan göras bättre för att uppmuntra fler kommentarer och rikare samtal.

Vill du själv göra samma sak och använder WordPress kan jag rekommendera How To Track Wordpress Signups and Comments With Google Analytics hos TD Creative.

By Jesper Lind

Mozilla Labs Bespin - kodredigering i molnet

Bespin

Detta är något nytt och väldigt spännande. Mozilla Labs har precis släppt en prototyp av en kodeditor som de kallar Bespin.

Har precis sett introduktionsfilmen som du hittar i releaselänken ovan och testkört själva editorn.

Man använder sig av HTML5-taggen Canvas för att rita upp scrollbars, de grafiska elementen samt även själva texten om jag förstått det hela rätt. Det gör att man kan finna funktioner som inte funnits på nät-applikationer innan. T ex kan de mäta längden på textsträngar och få texten att anpassa sig efter de omliggande panelerna och hur mycket utrymme som finns tillgängligt.

Prestandan på textediteringen blir med hjälp av Canvas-rendereringen väldigt god. I videon visas exempel på hur man redigerar en fil på över 30000 rader och det fortfarande går väldigt snabbt att skriva. Något vi inte sett på webben innan.

Även fast det är en tidig protoyp ser det mycket lovande ut och jag tror detta kan utvecklas till något riktigt häftigt. Senast för nån timme sen satt jag och försökte editera kod i en TinyMCE-editor som jag har konfigurerat själv och det är verkligen en stor möda. Det behövs något bättre på webben och Bespin kan vara svaret.

Målet med projektet är att skapa en produkt som kan mäta sig med med traditionella kodredigerare som körs i skrivbordsmiljö. Än är det nog läng väg kvar innan jag ska byta ut Visual Studio mot ett webbaserat alternativ, men kanske blir det tillräckligt bra i framtiden för att man ska göra viss del av sitt kodande ute i molnet. Möjligheten till att kollaborera många andra användare samtidigt i samma filer är minst sagt intressant.

I det första utförandet stöjder Bespin syntax highlighting för Javascript, HTML och CSS, men fler språk kommer att läggas till i senare versioner.

Man kan programmerar egna kommandon och på så sätt utöka editorn med egen funktionallitet. Det kommer även finnas en modell för att kunna dela dessa påbyggnader med andra användare.

By Jesper Lind

ASP.NET MVC - Kommentarsfunktion med PRG Pattern

Har programmerat om kommentars-funktionen på bloggen och den följer nu designmönstret Post/Redirect/Get (PRG Pattern). Det innebär att när en kommentar postas så görs det till en specifik url som bara accepterar Http-verbet "Post". Sen skickas besökaren tillbaks till inläggets vanliga url med en ankarlänk till den nyligen postade kommentaren tillagd på slutet.

Innan denna förändring så postades kommentaren direkt till samma vy/url som även används till att visa inlägget.

Fördelar med PRG-mönstret

Fördelen med att följa PRG-mönstret är att kommentaren inte dubbelpostas ifall användaren klickar på tillbaka-knappen i sin webbläsare. Nuförtiden så varnar ju dock de flesta moderna webbläsare att en ompostning kommer ske, men det är ofta man inte tänker på att det inte går att backa och det är ett rätt störande meddelande som man slipper med PRG-mönstret.

Läs mer hos Stephen Walter som också beskriver samma mönster med ASP.NET MVC i artikeln "Call RedirectToAction after Submitting a Form".

Hur man gör för att redirecta till en länk med ankare på slutet hittade jag på en japansk blogg.

Hur det är implementerat här på bloggen

Tänkte visa lite exempelkod som är ungefär den kod som körs på bloggen just nu.

Först de routes som har med att visa inläggen och posta kommentarer:

routes.MapRoute(
    "BlogPostAddComment",
    archiveRoute + "/{year}/{month}/{day}/{slug}/add-comment", //arkiv/2008/05/29/radonförgiftning#ankar-länk
    new { controller = "Blog", action = "AddComment" }
    );

routes.MapRoute(
    "BlogPostWithAnchor",
    archiveRoute + "/{year}/{month}/{day}/{slug}#{anchor}", //arkiv/2008/05/29/radonförgiftning#ankar-länk
    new { controller = "Blog", action = "ArchiveBySlug" }
    );

routes.MapRoute(
    "BlogPost",
    archiveRoute + "/{year}/{month}/{day}/{slug}", //arkiv/2008/05/29/radonförgiftning
    new { controller = "Blog", action = "ArchiveBySlug" }
    );
	}

Sen det Action i Controllern som sätter in kommentarern i databasen och redirectar användaren till rätt vy igen. Det sker lite mer blanda annat har vi ett anti-spam-skydd och kommentarern mailas även till mig (nytt för idag så nu kommer jag vara mer alert på nya kommentarer).

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddComment(int year, int month, int day, string slug)
{

    var url = Request.Form["url"];
    int postid = Convert.ToInt32(Request.Form["postid"]);
    var name = Request.Form["name"];
    var body = Request.Form["body"];
    var email = Request.Form["mail"];

    int addedCommentId = blogService.AddComment(postid, name, body, email, url);

    return RedirectToRoute("BlogPostWithAnchor", new { action = "ArchiveBySlug", year = year, month = month, day = day, slug = slug, anchor = "comment-"+addedCommentId });

}
By Jesper Lind

Söker du oss på Google så får du mer reklam

Japp nu är det dag att stäppa upp the Adsense-game en nivå och så kanske vi kan tjäna några extra korvören. Problemet är ju bara det att du vår vanliga läsare är en tech geek som slutade att klicka på annonser nån gång runt 2001. Så det är ju inte så stor idé att visa mer reklam än det lilla vi haft i högerspalten.

Istället gör vi nu så att vi bara vi visar en stor banner längst upp på de som söker via Google. Så vi får nån nytta av förstaplasten vi har på "vinterkläder", alla som ska in och förstå hur de använder visningsprogram för bilder och fax eller hitta sina lösenord till Geni.com. Dessa tre sökningar utgör den större delen av trafiken på sajten vilket är rätt sjukt när det inte direkt är huvudämnen vi skriver om. Eftersom dessa besökare bara stannar här i genomsnitt 40 sekunder så känns det som man lika gärna kan blaffa upp en banner.

Här under är min väldigt enkla kodrad för att genomföra detta. Den är inte så speciellt genomtänkt så går säkert att förbättra. Bara kollar ifall referer innehåller "google." och att den inte kommer från Google Reader. Vill du läsa något mer avancerat så kolla in Parse Google Search Query på Dot Net Peris som visar hur man kan få fram söktermer.

<%string referrer = (HttpContext.Current.Request.UrlReferrer != null) ? HttpContext.Current.Request.UrlReferrer.ToString():string.Empty;
if (referrer.IndexOf("google.") != -1 && referrer.IndexOf("reader") == -1){%>
<!--Your Adsense Code here-->
<%}%>

Gör du nåt likande på din blogg? Skulle vara intressant att höra om andra tips på ämnet.

By Jesper Lind

Egendesignade 404-sidor på IIS7

Som standardinställning visar IIS7 rätt tråkiga felmeddelande när en sida inte kan hittas och ser ut som på bilden här under. Just nu ser denna bloggens 404-sidor ut precis så där, så vi ska försöka fixa något roligare. Detta inlägg kommer visa hur man gör för att ställa in servern så att man ska kunna visa en egen design istället.

404 - File or directory not found

Gå in på den webbplats som ska konfigureras och klicka på Error Pages. Följ sedan instruktioner på följande bild. Klicka Edit Feature settings... och välj Detailed Errors.

IIS7 404-error detailed settings

Så nu ska jag bara skicka iväg denna post till vårt webbhotell så fixar de nog de inom kort.

Sen var det där med egen design. Kommer nog inte hinna få till med något jättespännande. Om du vill se exempel på riktigt snygga och roliga 404-fel-sidor kolla in Smashing Magazine som har några riktigt fina samlingar.

By Jesper Lind

Syntaxmarkering i blogginlägg med Javascript

Har precis fixat så att kodexempel i denna blogg får syntaxen framhävd med färger så den förhoppningsvis ska bli mer lättläst. Det engelska uttrycket är ju "syntax higlighting" men jag hade lite svårt att hitta en svensk motsvarighet först. Kristoffer på Bloggy hjälpte mig och tipsade om "syntaxmarkering", som fick blir titel på detta inlägg.

När jag sökte efter en metod att få till detta hittade jag några olika alternativ, i en tråd på Stack Overflow går man igenom några av dem.

Vissa tycker att det är en bra ide att märka upp koden med html och css i förhand, och spara den färdigformatterad i databasen. Detta kan man bland annat göra med ett plugin till Visual Studio som heter CopySourceASHtml. Jag dock att jag inte ville ha in detta i databasen utan att koden skulel sparas helt utan extra HTML och CSS. För om man vill ändra på det i efterhand så är det ju omständigt att behöva ändra alla gamla exempel.

Istället beslutade jag mig för att använda Javascript och att formatteringen ska ske i besökarens webbläsare. Uppritningen blir ju något långsammare, men de andra fördelarena var tillräckligt stora för att jag skulle gå på detta spåret.

Ett sådant javascript är google-code-prettify men eftersom det inte verkar ha stöd för C# så var det inget alternativ för denna blogg som har större delen av kodexemplen på det programmeringsspråket.

Istället valde jag samma som Scott Hanselman och bloggplattformen Wordpress använder sig av. Det heter SyntaxHighlighter och är utvecklat av Alex Gorbatchev.

Ett litet problem är dock att koden ska märkas upp på följande sätt och name inte är godkänt attribut på <pre>-taggen enligt XHTML-standarderna.

<pre name="code" class="javascript">
// the code
</pre>

Lars Corneliussen har dock fixat ett jQuery-plugin beautyOfCode som ändrar beteendet i SyntaxHighlighter så man istället kan använda följande struktur:

<pre class="code">
<code class="javascript">
// the code
</code>
</pre>

Det senare alternativet är alltså godkänd XHTML och det är detta som jag använder här. Läs gärna om hur jag fixade så att TinyMCE-editorn kan skapa denna kod med hjälp av ett plugin.

Än så länge har jag bara gjort om kodexemplena på förstasidan i bloggen till att använda syntaxmarkeringen. Ska fundera lite på hur jag ska ändra alla gamla exempel som fortfarande bara visas med en grå ruta.

By Jesper Lind

Plugin till TinyMCE för att klistra in källkod

När jag postade mitt förra inlägg så märkte jag att källkoden kunde formateras bättre. HTML-editorn TinyMCE som vi använder till att redigera inläggen stoppar som default in <br /> på alla radbryt och omger stycken med paragrafer. Bra när man skriver brödtext, men onödigt när man vill posta källkod. Jag ville hellre att kodexemplena skulle vara förformatterade utan någon extra HTML-uppmärkning.

Eftersom jag har tagit bort breaks i det förra inlägget kommer här en bild på hur det såg ut innan.

Samtidigt ville jag prova med att fixa syntax-formattering där nyckelorden får färger för bättre läsbarhet. Ska skriva mer om hur jag gjorde själva syntax-uppmärkningen i ett senare blogginlägg, men kan nämna att jag gjort detta med javascript hos besökaren. Uppdatering: Nu har jag skrivit klart bloggposten om javascript-biblioteket syntaxhl som jag avänder till att visa formatteringen i själva blogginläggen.

Nu till TinyMCE-pluggen som märker upp kodstyckena i databasen. Det heter syntaxhl finns att ladda hem på GitHub och går att läsa mer om hos skaparen Richard Grundy. Vid redigering ser det ut så här:

http://codeodyssey.se/Images/Post/453/syntaxhl-plugin-for-tinymce.png

Som standard så omges koden med en textarea, något jag inte ville utan jag behövde en speciell uppmärkning för att fungera med den syntax-formatteraren jag valt. Hos Spencer Kellis hittade jag förklaring hur han hade gjort för att konfigurera TinyMCE med syntaxhl.

Först la jag syntaxhl i mappen plugin i TinyMCE. Sen modifierade jag syntax/js/dialog.js enligt följande för att få den uppmärkning jag efersträvade och inte textarea som den använder sig av som standard.

textarea_output = '<pre class="code">';
textarea_output += '<code class="' + f.syntaxhl_language.value + options + '">';
textarea_output +=  f.syntaxhl_code.value;
textarea_output += '</code></pre> ';

I databasen vill jag alltså att det ska sparas så här:

<pre class="code">
<code class="xhtml">
Testing the syntaxhl plugin for TinyMCE
</code>
</pre>

Så här ser mina inställningar nu:

<TinyMce:TextArea id="tbBody"
theme="advanced"
plugins="spellchecker,safari,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template,pagebreak,syntaxhl"
theme_advanced_buttons1="spellchecker,save,newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontsizeselect|,forecolor,backcolor"
theme_advanced_buttons2="cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,preview,pagebreak,syntaxhl"
theme_advanced_toolbar_location="bottom"
theme_advanced_toolbar_align="left"
theme_advanced_path_location="bottom"
theme_advanced_resizing="false"
extended_valid_elements="pre[class]"
pagebreak_separator="<!--more-->"
force_br_newlines="false"
convert_newlines_to_brs="false"
preformatted="true"
apply_source_formatting="false"
remove_linebreaks="false"
Value='<%# Bind("Body") %>'
Rows="20"
runat="server" />

Ändingar jag gjort sen min förra konfiguration är dessa:

  • Lagt till knappen för syntaxhl i plugin och i theme_advanced_button2.
  • Lagt till pre[class] i extended_valid_elements för att editorn ska godkänna attributet.
  • Satt force_br_newline och converty_newlines_to_brs till false.
  • Satt preformatted till true.

TinyMCE har många konfigurationmöjligheter så det finns säkert mer saker att tweaka för ännu bättre resultat. Kolla även Spenser Kellis visar upp hur han har gjort sina inställningar.

 

By Jesper Lind