Uppgradera från ASP.NET Mvc 2 till Mvc 3

1. Fixa web.configs

Sök på följande sträng i ditt projekt (finns i några web.configs):

System.Web.Mvc, Version=2.0.0.0

Och replaca den med denna:

System.Web.Mvc, Version=3.0.0.0

Se till att du har följande längst ner i web.config:

<runtime>    
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>     
</assemblyBinding> 
</runtime>
Referera rätt namespace:
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

2. Sätt project GUID

Högerklicka på ditt projekt och välj unload. Sen edit project.

Byt ut (Gamla Mvc 2):

F85E285D-A4E0-4152-9332-AB1D724D3325

Mot (Mvc 3):

E53F8FEA-EAE0-44A6-8774-FFD645390401

3. Lägg till värden i app.config

 <add key="webpages:Version" value="1.0.0.0"/>
 <add key="ClientValidationEnabled" value="true" />
 <add key="UnobtrusiveJavaScriptEnabled" value="true" />
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

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

ISAPI Rewrite 3 på Bineros servrar

Vi har börjat testa lite smått på några webbsajter att använda ISAPI-modulen som finns installerad hos Binero och det fungerar ganska bra. Vi har till och med fått igång ett första MVC-projekt på .NET 3.5. Riktigt kul med ett webbhotell som är framåt och förstår vilken teknik vi utvecklare vill ha.

Det tog lite tid att lista ut hur man fick igång det eftersom Bineros förklaring av Rewrite 3 inte är så utförlig. De har manualen på deras sajt så där kan man lära sig lite (funkar dock inte med Firefox 3). Helicon Tech som ligger bakom modulen rekommenderas också.

Mest hjälp för att få igång det hade jag av av några trådar på Aspsidan och webForum.

Något att tänka på är att de ändringar man gör i Script Mappings i Bineros kontrollpanel tar ett tag innan de slår igenom. Kommer ihåg den första kvällen då jag kämpade med det in på småtimmarna men hade ingen lycka. Provade mängder av olika konfigurationer och gav sist upp och bara lämnade det. Nästa morgon när jag laddade upp sidan så bara det fungerade!

Så nu ska jag förklara det jag kommit på hittills.

Det första man måste göra är att lägga till en *-mappning enligt följande.

Filetype: *
Executable: Aspnet2
is wildcard: false
is script engine: false
verify that file exists: false

När du ändå är där kan du även lägga till .asax eftersom Binero verkar ha glömt det i standardinställningen. Se bilden för exempel på de två inställningarna längst ner.

 

Sen är det dags att knåpa ihop en httpd.ini (uppdatering: filen ska ha namnet .htaccess och inget annat) som styr hur ISAPI Rewrite 3 ska uppföra sig. Här under ser ni våran som fungerar fint om man vill ta bort .aspx ändelserna. Jag har dock inte lyckats att exkludera vissa mappar, så om någon kan se vad det är för fel på sista raden som ska blocka mappen "MappSomInteSkaOmskrivas" så uppskattar jag tips. Uppdatering: Denna rad måste ju givetvis ligga överst för att de andra reglerna ska ignoreras. Har nu uppdaterat skriptet som det ska se ut och då funkar det mycket bättre.

# Helicon ISAPI_Rewrite configuration file
# Version 3.1.0.34

RewriteEngine on

#Exclude folder
RewriteRule /(?!(?:Images|Css|MappSomInteSkaOmskrivas)/.*).* - [L]

#Redirect extension requests to avoid duplicate content
RewriteRule ^([^?]+)\.aspx$ $1 [NC,R=301]

#Internally add extensions to request
RewriteCond %{REQUEST_FILENAME}.aspx -f
RewriteRule (.*) $1.aspx
By Jesper Lind
1