September 2008 - Posts

Med jQuery så kan man på ett otroligt smidigt sätt använda Ajax. Jag kommer att gå igenom hur man gör för att skriva en enkel sida som hämtar in olika sidor med Ajax-anrop, samtidigt som den gamla texten suddas bort med en animering.

När man använder javascript - och därmed jQuery – så bör man alltid se till så att koden är semantiskt korrekt innan man applicerar javascripten. Koden bör vara så ren som möjligt och HTML-koden bör innehålla just HTML och inget annat.

HTML-koden jag kommer att använda ser ut som sådan:

   1:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   2:  <html xmlns="http://www.w3.org/1999/xhtml">
   3:  <head>
   4:      <title>jQuery Demo</title>
   5:      <link href="style.css" rel="Stylesheet" type="text/css" />
   6:      <script src="scripts/jquery-1.2.6.js" type="text/javascript"></script>
   7:      <script src="scripts/menu.js" type="text/javascript"></script>
   8:  </head>
   9:  <body>
  10:      <div id="mainContainer">
  11:          <h1>
  12:              jQuery Demo
  13:          </h1>
  14:          <ul id="menu">
  15:              <li><a href="#" class="menu-startpage">Startsidan</a></li>
  16:              <li><a href="#" class="menu-aboutme">Om mig</a></li>
  17:              <li><a href="#" class="menu-other">Annat</a></li>
  18:          </ul>
  19:          <div id="main">
  20:          </div>
  21:      </div>
  22:  </body>
  23:  </html>

Det är alltså helt vanlig XHTML. Jag har inga javascript eller annat i koden, utan allt kommer att läggas i menu.js.

Det vi kommer att göra i javascriptet är att vi kommer att sätta ett onclick-event på alla länkar under #menu li där vi använder klassnamnet för att visa vilken sida som skall hämtas. När vi sedan klickar på en länk så kommer div-elementet med id:t “main” att försvinna med en animering, fyllas på med HTML genom ett Ajax-anrop och sedan visas igen med en liknande animering.

Javascriptet i sin helhet ser ut på detta sätt:

   1:  $(document).ready(function() { Initialize(); });
   2:   
   3:  function Initialize() {
   4:      SetupMenu();
   5:      $('#main').hide();
   6:      $('.menu-startpage').click();
   7:  }
   8:   
   9:  function SetupMenu() {
  10:      $('#menu li a').click(function() { LoadPage(this); });
  11:  }
  12:   
  13:  function LoadPage(e) {
  14:      var page = e.className.split(' ')[0];
  15:      $('#menu li a').removeClass('active');
  16:      $(e).addClass('active');
  17:      $.ajax({
  18:          method: "get",
  19:          url: "LoadPage.aspx",
  20:          data: "page=" + page,
  21:          beforeSend: function() { $('#main').hide('slow').fadeOut(); },
  22:          complete: function() { $('#main').show('slow').fadeIn(); },
  23:          success: function(result) { $("#main").html(result); }
  24:      });
  25:  }

Vi börjar med att anropa metoden Initialize() när DOM:en är redo för förändringar. Som jag har skrivit i ett tidigare blogginlägg så är det inte detsamma som window.load då den sistnämnde även väntar på att alla bilder och annat skall laddas.

I Initialize() så börjar vi med att köra metoden SetupMenu() där vi sätter ett onclick-event på alla länkar under #menu li. När användaren klickar på en länk så skall LoadPage(e) köras där e är en referens till elementet. Efter det så gömmer vi div-elementet då vi inte har någon information att visa än, och efter det trigga click-eventet för startsidan så att den skall laddas in när besökaren går till sidan.

Än så länge är det inga konstigheter, utan det är just när användaren klickar på en länk som det magiska sker. Det som händer då är att LoadPage(e) körs, och där så börjar vi med att plocka fram första klassen för elementet då den aktuella länken blir tilldelad klassnamnet “active”. Sedan tar vi bort klassen “active” från alla länkar för att kunna sätta den igen på länken som det har klickats på.

Nästa steg är att köra ajax-metoden. jQuery har en metod som heter just ajax och som tar emot en anonym funktion. I den funktionen som i själva verket är en Json-sträng anger vi olika properties för Ajax-anropet. Att tilldela properties på detta sätt är standard i jQuery och används av de flesta funktioner där. Det går även att använda när man skriver egna funktioner för jQuery.

De metoder vi använder här är:

  • method – Anger vilken metod som skall användas vid anropet. Vi använder här get, men skulle lika gärna kunna använda post.
  • url – URL till sidan som skall anropas. Här anropar vi LoadPage.aspx som returnerar olika texter beroende på vad som skickas in till sidan. Det här kan vara vilken typ av sida som helst, och returnera antingen HTML, XML eller Json. Sedan tar jQuery hand om outputen och parse:ar den om så behövs.
  • data – Här anger vi datan som skall skickas. Då vi kör med get som metod så skickas den som en querystring till sidan som vi har angett.
  • beforeSend – Funktion som skall köras innan datan skickas. Här gömmer vi undan den gamla informationen med dels hide(‘slow’) som “viker ihop” elementet, och sedan fadeOut() som gör att opaciteten sänks för elementet.
  • complete – Det här körs när datan är hämtad. Här väljer vi att visa div-elementet igen på samma sätt som vi nyss gömde det på.
  • success – När vi har hämtat datan så kör vi en funktion som tar emot datan som parameter. Det vi gör här är att sätta HTML-koden för elementet genom metoden html().

När vi nu kör sidan så kommer den att ladda in startsidan och sedan visa informationen där. När vi sedan klickar på en länk så försvinner den gamla informationen samtidigt som den nya laddas in och sedan visas. Vi kan alltså med så lite som 25 rader kod göra ett Ajax-anrop och dessutom animera div-elementet och sätta klasser på länkarna! Det här är en av anledningarna till varför jQuery har blivit så populärt bland utvecklare som det är, och det är dessutom anledningen till varför Microsoft valde att ha med detta i de kommande versionerna av ASP.NET.

Jag har även lagt upp ett demo där du kan se hur det fungerar.

Då Microsoft har sagt att jQuery följer med i framtida versioner av ASP.NET så kan det vara bra att veta vad som egentligen går att göra med det. Det finns väldigt många som inte vågar peta på javascript, utan istället använder antingen helt färdiga javascript, eller använder t.ex. ASP.NET Ajax Control Toolkit (inget illa om det, det gör det möjligt att på ett snabbt sätt få in smutt funktionalitet på sidan) för att få sidan lite mer dynamisk. Problemet här är dock att man inte alltid får det exakt som man har tänkt sig, och för att få det så måste man faktiskt våga skapa den där lite småläskiga js-filen och börja skriva.

Visual Studio 2008 kom med utbyggd intellisense för javascript, inklusive möjligheten att ha XML-kommentarer på funktionerna. I och med implementerandet av jQuery i ASP.NET så kommer vi även att få full intellisense med kommentarer även för det, vilket underlättar en hel del.

Jag kommer här att gå igenom en snabb introduktion av selectors i jQuery. Selectors var något som fanns med på ASP.NET Ajax Roadmap, men varför uppfinna hjulet på nytt? Selectors i jQuery är väldigt användbara och välutvecklade och vi kan med dem hämta vissa kontroller på ett mycket smidigare sätt än med vanlig javascript.

HTML-filen jag kommer att använda mig utav ser ut på detta sätt:

   1:  <html xmlns="http://www.w3.org/1999/xhtml">
   2:  <head>
   3:      <title>jQuery Demo</title>
   4:      <script src="scripts/jquery-1.2.6.js" type="text/javascript"></script>
   5:      <style type="text/css">
   6:          .redBackground { background-color: #f00; }
   7:      </style>
   8:  </head>
   9:  <body>
  10:      <div id="mainContainer">
  11:          <h1>jQuery Demo</h1>
  12:          <ul id="ul1">
  13:              <li><a href="#1">Link #1</a></li>
  14:              <li><a href="#2">Link #2</a></li>
  15:              <li><a href="#3" class="link3">Link #3</a></li>
  16:              <li><a href="#4">Link #4</a></li>
  17:              <li><a href="#5">Link #5</a></li>
  18:          </ul>
  19:          
  20:          <ul id="ul2">
  21:              <li><a href="#1">Link #1</a></li>
  22:              <li><a href="#2">Link #2</a></li>
  23:              <li><a href="#3" class="link3">Link #3</a></li>
  24:              <li><a href="#4">Link #4</a></li>
  25:              <li><a href="#5">Link #5</a></li>
  26:              <li><a href="#6">Link #6</a></li>
  27:              <li><a href="#7">Link #7</a></li>
  28:              <li><a href="#8">Link #8</a></li>
  29:              <li><a href="#9">Link #9</a></li>
  30:              <li><a href="#10">Link #10</a></li>
  31:          </ul>
  32:      </div>
  33:  </body>
  34:  </html>

Det är inga konstigheter här, det enda jag har lagt till här förutom den vanliga HTML-koden är en css-klass kallad redBackground samt att jag hämtar in jQuery 1.2.6 som är den senaste versionen i nuläget.

Selectors i jQuery gör att man kan hämta ett eller flera element med minimal kod. Nedan finns en lista på enkla selectors samt en beskrivning på vad de gör:

$("*")

Hämtar alla element på sidan.

$("ul")

Hämtar alla ul-element på sidan.

$("ul li")

Hämtar alla li-element som ligger någonstans under en ul.

$("#ul1 li")

Hämtar alla li som ligger under ett element med id satt till “ul1”.

$("#ul1 li a:first")

Hämtar den första länken av alla länkar som ligger under någon li i den ul som har id “ul1”.

$(".link3")

Hämtar alla element som har klassen “link3”.

Detta är bara ett handplock av alla varianter som finns med jQuery. När vi har hämtat någon av dessa så kan vi sedan antingen använda dem som vanligt med javascript, eller använda någon utav de funktioner som följer med jQuery. Vill vi sätta klassen “redBackground” på de element som har klassen “link3” så kan vi köra följande kod:

$(".link3").addClass("redBackground");

Då alla metoder returnerar objektet i sig så kan man helt enkelt lägga till nästa metod direkt efter på samma rad. Ett annat exempel där vi vill “fade:a” ut och sedan in varannan li i den ul som har id:t “ul2” så kan vi göra det på detta sätt:

$("#ul2 li:odd").fadeOut().fadeIn();

Sådant som kräver mängder med rader kod om vi hade behövt skriva det själva kan vi nu skriva med en enkel rad!

Vill ni testa de här exemplen snabbt så kan ni lägga till den här koden på sidan efter att referensen till jQuery-javascriptet:

   1:  <script type="text/javascript">
   2:      $(document).ready(function() { RunScripts(); });
   3:   
   4:      function RunScripts() {
   5:          $("#mainContainer").fadeOut().fadeIn().fadeOut().fadeIn();
   6:          alert('All: ' + $("*").length);
   7:          alert('ul: ' + $("ul").length);
   8:          alert('ul li: ' + $("ul li").length);
   9:          alert('#ul1 li: ' + $("#ul1 li").length);
  10:          alert('#ul1 li a:first: ' + $("#ul1 li a:first")[0].length);
  11:          alert('.link3: ' + $(".link3").length);
  12:          $("#ul2 li:odd").fadeOut().fadeIn();
  13:          $(".link3").addClass("redBackground");
  14:      }
  15:  </script>

I javascriptet ovan så kör jag $(document).ready(function); för att köra RunScripts. Anledningen till att jag kör det istället för window.onload = function; är att den sistnämnda kör scriptet när allt på sidan är laddat, inklusive stora bilder och annat som körs på sidan. Med ready-metoden som ingår i jQuery så kan man köra metoden när all HTML-kod har laddats in, vilket gör att det går mycket snabbare.

Ni kan även se att $ används flitigt, och det är i själva verket bara ett alias för jQuery. Det går att skriva till exempel jQuery(“*”), men det kräver extra tecken vilket är anledningen. Används andra bibliotek som t.ex. prototype eller mootools så kan det vara bra att använda originalet då det kan krocka annars.

För mer info om de metoder och selectors som finns, besök jQuery.

Om du har önskemål på något annat om jQuery, så lämna gärna en kommentar så kan jag se vad jag kan göra.

Microsoft gick nyss ut med att Visual Studio 2010 (codename “Rosario”) och .NET Framework 4.0 kommer att finnas tillgängligt på MSDN 1 oktober. Det finns många nyheter, speciellt för testare.

Jag har inte så mycket information om det än, annat än det som finns i länkarna nedan, men så fort jag får tag på en kopia så blir det att testa för fulla muggar. :-)

Microsoft gick tidigare under kvällen ut officiellt med att de har påbörjat ett samarbete med jQuery-teamet. För de som inte visste det så är jQuery ett alldeles utmärkt javascript-bibliotek med mängder av finnesser. Det finns otroligt bra funktioner som kan användas för att med några enstaka rader kod modifiera stora delar av sidan samt animera dem. Det finns även en hel del plugins som gör det möjligt att på ett busenkelt sätt få in avancerade javascript på sin sida.

Samarbetet leder bland annat till att Microsoft officiellt kommer att ha support för jQuery! För utvecklare betyder detta även att vi kommer att få med jQuery framtida versioner av ASP.NET Ajax, samt att det kommer inbyggt med ASP.NET MVC. Förutom det så kommer Microsoft även att se till att intellisense fungerar perfekt med Visual Studio 2008.

Vi kommer att kunna ta del av detta inom en snar framtid, men vill du experimentera med jQuery redan nu så finns det att ladda ned här.

Det här är totally awesome!

Mer information:

ASP.NET 4.0 Ajax har en ny funktion som kallas templates. Med templates kan du på ett enkelt sätt hämta data och visa på sidan, utan att behöva skapa upp alla element i javascriptet. Först skapar man själva mallen och sedan har man ett element som skall populeras med data och rendera den efter mallens utseende.

Jag kommer att hämta data från en PageMethod och sedan rendera den på sidan i en lista. Datan kommer att vara en List<Customer> där Customer är en klass med tre egenskaper, Name (string), Company (string) samt Age (int?).

Det första som måste göras är att skapa en referens till dels MicrosoftAjaxTemplates.js (jag kommer att använda mig utav den som kom med Preview 2, den som finns för Preview 1 har en annorlunda struktur) samt även till Customer.js där jag har funktionaliteten för att hämta data samt fylla den.

   1:  <asp:ScriptManager runat="server" ID="sManager" EnablePageMethods="true">
   2:      <Scripts>
   3:          <asp:ScriptReference Path="~/MicrosoftAjaxTemplates.js" />
   4:          <asp:ScriptReference Path="~/Customer.js" />
   5:      </Scripts>
   6:  </asp:ScriptManager>

 

Vår page method:

   1:  [WebMethod]
   2:  public static List<Customer> GetCustomers()
   3:  {        
   4:      List<Customer> coll = new List<Customer>();
   5:      coll.Add(new Customer() { Name = "Mikael Söderström", Company = "Strand Interconnect", Age = 23 });
   6:      coll.Add(new Customer() { Name = "Bill Gates", Company = "Microsoft", Age = null });
   7:      return coll;
   8:  }

Koden för Customer-klassen:

   1:  public class Customer
   2:  {
   3:      public string Name { get; set; }
   4:      public string Company { get; set; }
   5:      public int? Age { get; set; }
   6:  }

Koden ovan är ganska självförklarande, så den kommer jag inte att gå igenom utförligt, men det vi gör är iaf att vi i GetCustomers returnerar en List<Customer> med två personer, jag själv och Bill Gates. Jag är 23 år, och Bill Gates har ingen ålder (läs: odödlig).

Det vi ska göra med den här datan är att visa upp den i en enkel ul-lista. För att göra det så skapar vi först upp koden för vår template, vilken kommer att fyllas med data.

   1:  <div id="CustomerTemplate" class="sys-template">
   2:      <ul>
   3:          <li>Namn: {{ Name }}</li>
   4:          <li>Företag: {{ Company }}</li>
   5:          <li>
   6:              Ålder: 
   7:              <!--* if (Age) { *-->
   8:              {{ Age }}
   9:              <!--* } *-->
  10:              <!--* if (!Age) { *-->
  11:              Odödlig
  12:              <!--* } *-->
  13:          </li>
  14:      </ul>
  15:  </div>

 

Det vi har här är ett div-element som är en container för vår template. Den behöver ett id för att vi skall kunna hämta den från javascriptet, och den bör ha ett klassnamn för att vi skall kunna dölja den. När vi hämtar datan så är det inte det här div-elementet som fylls med datan, utan den är enbart en mall för hur det skall se ut.

När vi hämtar datan så har vi tre fält, Name, Company samt Age och genom att lägga in dessa inom {{ och }} så kan vi specifiera vart vi vill ha dem. Det går även att använda till exempel fältet.format(formatering) för att formatera texten, vilket kan vara bra om det är ett datum som skall visas. I koden ovan har vi även med if-satser för att kunna rendera olika texter baserat på vilket värde som kommer. Då vi har en nullable int för åldern, så skriver vi ut åldern om den har ett värde, annars skriver vi ut “Odödlig”.

När vi har hämtat datan så kommer den som jag har nämnt tidigare, att fyllas på i ett annat element, men med vår template för utséendet. Vi kommer att ha ett tomt div-element för det:

   1:  <div id="CustomerData"></div>

Även detta element behöver ett id för att vi enkelt skall kunna veta vilket element som skall fyllas.

Nästa steg är att skapa javascriptet som skall användas för att hämta datan och skriva ut den på sidan. Här använder vi Sys.UI.Template(element) samt dess metod createInstance(element, data) för att hämta vår template samt skriva ut en Json-sträng till elementet som skall innehålla datan.

   1:  function pageLoad() {
   2:      PageMethods.GetCustomers(LoadCustomers);
   3:  }
   4:   
   5:  function LoadCustomers(args)
   6:  {
   7:      var template = new Sys.UI.Template($get("CustomerTemplate"));
   8:      for (var i = 0; i < args.length; i++)
   9:      {
  10:          template.createInstance($get("CustomerData"),
  11:                  {
  12:                      Name: args[i].Name,
  13:                      Company: args[i].Company,
  14:                      Age: args[i].Age
  15:                  });
  16:      }
  17:  }

I metoden pageLoad() som körs när sidan har laddats så anropar vi vår page method kallad GetCustomers, och när datan är hämtad så körs LoadCustomers som i args-attributet har datan om personerna.

I LoadCustomers så skapar vi först en ny template med parametern satt till CustomerTemplate då det är vår template. Sedan loopar vi igenom alla värden i args då det är en array med alla värden då vi returnerade en List<Customer>. I varje iterering så körs template.createInstance för att fylla på med ny data i data-elementet. För enkelhetens skull så använder jag samma namn i Json-strängen som våra properties heter i datan som hämtas.

När vi nu kör koden så kommer den att vid sidladdningen asynkront hämta datan från vår page method och fylla på i data-elementet. Först skapas en ul-lista med mig, och sedan en med Bill Gates. Då Bill Gates ålder var satt som null så kommer det att stå “Ålder: Odödlig” på honom.

Är det några oklarheter så lämna en kommentar. :-)

Nu börjar vi närma oss släppet av Silverlight 2 RTW (Released To Web)! Idag släpptes Silverlight 2 Dev Runtime RC 0, Expression Blend 2 SP 1 RC 0 samt Silverlight Tools for Visual Studio 2008 SP 1 (RC 0).

Innan ni uppgraderar till RC 0 så bör ni absolut gå igenom listan med breaking changes:
http://silverlight.net/blogs/msnow/archive/2008/09/25/silverlight-version-2-rc0-release.aspx

Behöver jag ens nämna att Scott Guthrie har bidragit med bilder och kod tillsammans med den infon man kan tänkas behöva?

Nu ser jag bara fram emot en preview, eller iaf lite information om vad som kommer i Silverlight 3. Men vem vet, det kanske dyker upp någon presentation under PDC:n?

Microsoft släppte nyligen Preview 2 av ASP.NET 4.0 Ajax på CodePlex. Denna innehåller en ny funktionalitet kallad “Observer Pattern” och gör det möjligt att på ett enkelt sätt bli notifierad när ett objekt förändras. Jag ska visa ett enkelt exempel där vi genom att skriva i en Textbox vill fånga upp alla ändringar och slänga upp i en alert-ruta.

Det första som behövs är MicrosoftAjaxTemplates.js som följer med i senaste versionen av ASP.NET 4.0 Ajax. Sedan skall vi använda de befintliga javascript-biblioteken som redan finns för den senaste fulla versionen av ASP.NET Ajax, för att få tillgång till de metoder som finns där.

För att skapa en ny observer så skall vi använda Sys.Observer.observe(object), som låter oss lägga till olika typer av observers. V skall sedan lägga till add_propertyChanged(function) på en JSON-sträng som vi skall ha för att lagra värdet som skickas in.

Vi börjar med att lägga in en ScriptManager-kontroll på sidan som först lägger in js-filen med de nya funktionerna, och sedan en js-fil med vår egna javascript-kod, för att vara säker på att allt körs som det ska.

   1:  <asp:ScriptManager runat="server" EnablePageMethods="true">
   2:      <Scripts>
   3:          <asp:ScriptReference Path="~/scripts/MicrosoftAjaxTemplates.js" />
   4:          <asp:ScriptReference Path="~/scripts/AjaxDemo.js" />
   5:      </Scripts>
   6:  </asp:ScriptManager>
   7:   
   8:  <input type="text" id="Textbox" />

I vår egna js-fil så bör det se ut i stil med detta:

   1:  var enteredValue = { value: '' };
   2:   
   3:  function pageLoad() {
   4:      Sys.Observer.observe(enteredValue);
   5:      enteredValue.add_propertyChanged(enteredValueChanged);
   6:      $addHandlers($get('Textbox'), { keyup: textBoxValueChanged });
   7:  }
   8:   
   9:  function enteredValueChanged(sender, args)
  10:  {
  11:      alert(enteredValue.value);
  12:  }
  13:   
  14:  function textBoxValueChanged(e) {
  15:      enteredValue.setValue('value', this.value);
  16:  }

Det vi gör här är att vi först skapar en enkel Json-sträng med ett fält som vi kallar “value”. Sedan har vi en metod kallad pageLoad() (den körs automatiskt genom ASP.NET Ajax när sidan laddas). Nästa funktion, kallad changeHandler(e), är den som körs när vi skriver in något i textrutan som vi har på sidan.

I pageLoad skapas en ny observer där vi pekar den mot enteredValue. Vi lägger sedan till en händelse för enteredValue och som triggas när den ändras. När den gör det så slänger vi upp en alert-ruta med det nya värdet.

För att det öht skall ändras så måste vi fånga alla ändringar av vår textruta. Det kollar vi genom att lägga till en handler för den och som skall köras vid “keyup”. Även denna använder Json för att vi på ett snyggt och smidigt sätt skall kunna lägga till olika typer av händelser på denna.

När vi nu ändrar värde i vår textbox så körs först changeHandler(e) och byter värde på enteredValue till det nya. Sedan körs funktionen i enteredValue.add_propertyChanged(…) och som visar rutan.

Genom att använda observer patterns så kan man på ett väldigt enkelt sätt spåra ändringar i objekt och sedan använda dessa för olika ändamål. Exempel kan vara validering, asynkrona slagningar mot en extern datakälla eller liknande.

Om ungefär en månad under PDC 2008 så kommer Microsoft att visa upp deras nya satsning med kodnamnet "Oslo", samt dessutom släppa en CTP av SDK:n. För att förklara Oslo med en mening så är det en modelleringsplattform som underlättar arbetet med tjänsteorienterade applikationer.

Det finns tre delar som kommer att kunna användas för att jobba med Oslo, ett visuellt verktyg för att arbeta med modeller, ett språk (har för tillfället kodnamnet "D") som komer att hjälpa till vid skapandet av DSL (Domain-Specific Languages) samt ett repository för att göra modellerna tillgängliga för det medföljande verktyget och även egenutvecklade komponenter.

Repositoryt i Oslo är uppbyggt av System Center 5, Visual Studio 10 samt Biztalk Server 6. Annat som tas upp i samband med Oslo är Visual Studio 10 samt .NET Framework 4.0 med uppdaterade versioner av både Workflow Foundation samt Windows Communication Foundation för utveckling samt Biztalk Services för de olika tjänster. Har vi tur så kommer ett gäng härliga testversioner på PDC:n. :-)

Det finns inte alltför mycket information tillgänglig i dagsläget, så det är mycket spekulationer runt om. Det sägs att språket "D" kommer att generera SQL, precis som Linq to SQL. Om de fungerar på samma sätt finns det dock inga bevis på. En fråga som dyker upp då är om det kanske är så att D i själva verket är en påbyggnad av Linq to SQL eller Linq to Entities? Kommer man att kunna använda detta för vanlig databashantering, eller enbart för att kunna arbeta med just "Oslo"? Det har även ryktats om att D skall bygga på XAML, vilket är intressant då det redan används i WPF, Silverlight och Workflow Foundation.

Verktyget för Oslo kommer att ge en stor bild över hur allt runtomkring fungerar. Då Oslo har som huvuduppgift att underlätta arbetet med SOA så kommer det att ställas stora krav på att allt fungerar stabilt. Man kommer att genom verktyget kunna monitorera, följa olika processer med mera. För att underlätta arbetet mer så kommer man även att få med ett nytt designerverktyg för Workflow Foundation.

Vad gäller systemkrav har jag fortfarande inte sett något, ej heller om det på något sätt kommer att finnas något utbyggt stöd för det i Windows Server 2008 R2/Windows Server 7 eller Windows Server 7.

Det är väldigt svårt att föreställa sig exakt hur det kommer att se ut i arbetet med Oslo om man själv inte har tillgång till det, men något som är säkert är att årets PDC kommer att bli fruktansvärt intressant!

IDG har publicerat en artikel idag som tar upp hur vanligt det är med svaga lösenord. Alldeles för ofta brukar lösenord som “Password”, flickvännens namn, sonens personnummer och liknande användas, vilket gör att det blir alldles för lätt att knäcka det, även om det är krypterat.

Det man bör göra för att lagra lösenorden är att tvinga fram ett lösenord med många olika tecken, samt “konstiga” tecken som ½”#¤%& och liknande, samt hasha med ett salt. Det bör göras genom att man slumpar fram ett lösenord istället för att låta användaren själv välja vad denne skall ha.

Problemet då är dock att det blir svårt att komma ihåg lösenordet, så då kan det hända att det står skrivet på en post it-lapp på skärmen istället, vilket inte hellre gör det alltför säkert.

Så hur ska man kunna ha säkra lösenord, men samtidigt göra det enkelt för användaren att logga in? Det finns många sätt att lösa det på, till exempel med koddosor. De kräver dock en extra hårdvara som måste införskaffas och de kräver dessutom mycket jobb för att konfigurera.

Ett annat sätt är att använda Windows CardSpace. Det enda det kräver är att användaren har en Identity Selector samt ett InfoCard, antingen self issued, eller ett managed som är utfärdat från den Identity Provider (IP) som används.

Att implementera stöd för Windows CardSpace är som jag har visat i de föregående posterna ingen stor utmaning. De är dessutom plattforsoberoende då det bara postar en XML-fil som behöver tolkas hos RP. Det finns exempel på internet där Windows CardSpace postar XML:en mot en PHP-sida, helt utan problem och med samma säkerhet som om det hade varit ASP.NET.

Säkerhet är något som tas på alltför litet allvar idag och som absolut borde prioriteras högre, inte minst på grund av de stora hackerattacker som har uppstått på grund av att användare är tillåtna att ha lätta lösenord.

I samband med förra artikeln om Windows CardSpace så startade jag en tråd på Aspsidan för att kunna diskutera ämnet. En av kommenterarna som dök upp var av en person som hade börjat kika på hur han skulle implementera Windows CardSpace till sin befintliga ASP.NET-sida men sedan gett upp då det hade varit för krångligt. Det är nog ett väldigt vanligt problem, så därför tänkte jag visa hur det går till steg för steg.

Det första vi behöver är förstås en ASP.NET-sida. Jag kommer att använda mig utav SqlMembershipProvider, men självklart är det möjligt att använda sig utav andra providers som bygger på ASP.NET Membership. Jag kommer sedan att använda Comment-fältet för användaren för att hantera kopplingen mellan InfoCards och ASP.NET-användare. I exemplet så kommer en användare bara kunna ha ett InfoCard per konto, men det bör finnas möjlighet att använda flera kort, för att göra det möjligt att logga in på flera platser. Precis som i förra artikeln så kommer jag att köra över ren HTTP för enkelhetens skull. Skall det användas på en publik hemsida så bör ni absolut använda HTTPS för att höja säkerheten mellan klient och server.

De funktioner som kommer att finnas med är:

  • Möjlighet att koppla ett InfoCard till sitt ASP.NET Membership-kontot.
  • Möjlighet att logga in med användarnamn och lösenord.

Det första vi gör är att skapa ett nytt Web Application Project och skapa upp en databas med standardtabellerna som används för ASP.NET Membership (de som skapas med aspnet_regsql.exe).

Vi kommer att spara ett värde som kallas PPID i användarens comment-fält Anledningen till att vi sparar det där nu är för att slippa skriva kod som inte är relevant för tillfället. Det skulle dock kunna sparas i till exempel en separat tabell i databasen för att göra det möjligt för användaren att koppla flera kort. PPID är ett ID som är unikt för kortet och “Relying Party” (kommer att förkortas RP framöver). Om samma kort används hos en annan RP så kommer ett annat PPID att användas. Helst bör man använda UniqueID, men hur det fungerar kommer jag att ta upp senare. PPID är det enda “Token” (bra svensk översättning på det, någon?) som användaren inte har möjlighet att påverka, till skillnad från till exempel namn, e-postadress, personnummer med mera.

När vi använder ASP.NET Membership så skall användaren ha angivit en e-postadress, vilken vi kommer att anta är densamma som används i det InfoCard som kommer att skickas in. På så sätt kan vi enkelt plocka fram det eller de konton som innehåller e-postadressen och sedan se om något av dem har associerat kontot med ett PPID.

Det första vi skall göra nu är att skapa upp en sida med standardkontrollerna för att skapa en användare. Det gör vi genom att använda CreateUserWizard-kontrollen. Där skapar vi en användare som har samma e-postadress som vi har i något av våra InfoCards. När det är gjort och vi vet att vi kan logga in på sidan så är det dags att skapa upp sidan som tar hand om kopplingen mellan konto och InfoCard. Det första vi gör är att ta en modifierad version av formuläret som användes i introduktionsposten. Skillnaden mot det formuläret är att vi nu vill få tag i kortets PPID.

Koden som vi använder i aspx-filen för att hämta in PPID och sedan koppla mot den inloggade användaren är som följande:

<object type="application/x-informationcard" name="xmlToken">
    <param name="tokenType" value="urn:oasis:names:tc:SAML:1.0:assertion" />
    <param name="requiredClaims" value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" />
</object>
<asp:Button ID="btnAssociate" runat="server" Text="Associate account" onclick="btnAssociate_Click" />

Och när vi sedan skall koppla det mot användaren i btnAssociate_Click:

protected void btnAssociate_Click(object sender, EventArgs e)
{
    MembershipUser user = Membership.GetUser();
    user.Comment = GetPPID();
    Membership.UpdateUser(user);
}
 
private string GetPPID()
{
    XmlDocument doc = new XmlDocument();
    doc.LoadXml(Request.Form["xmlToken"]);
    XmlNode node =
        doc.SelectSingleNode(
            "/saml:Assertion/saml:AttributeStatement/saml:Attribute[@AttributeName='privatepersonalidentifier']", GetNamespaces(doc));
    return node.InnerText;
}
 
private XmlNamespaceManager GetNamespaces(XmlDocument doc)
{
    XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
    nsManager.AddNamespace("saml", "urn:oasis:names:tc:SAML:1.0:assertion");
    return nsManager;
}

Nu har vår användare sparat undan sitt PPID. Det skall sedan användas för att identifiera användaren. Nästa steg är att hämta PPID samt e-postadressen från kortet för att användaren skall kunna identifieras. Vi skall använda ett likadant formulär som innan, med skillnaden att vi nu även skall hämta e-postadressen.

<object type="application/x-informationcard" name="xmlToken">
    <param name="tokenType" value="urn:oasis:names:tc:SAML:1.0:assertion" />
    <param name="requiredClaims" value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" />
</object>
<asp:Button ID="btnLogin" runat="server" Text="Login" OnClick="btnLogin_Click" />

Det som sker när vi skickar in ett InfoCard nu är att vi skall hämta alla konton med e-postadressen och se om vi kan hitta något som är associerat med kortets PPID. Om vi hittar ett sådant så loggar vi in användaren.

protected void btnLogin_Click(object sender, EventArgs e)
{
    XmlDocument doc = new XmlDocument();
    doc.LoadXml(Request.Form["xmlToken"]);
    string email = doc.SelectSingleNode("/saml:Assertion/saml:AttributeStatement/saml:Attribute[@AttributeName='emailaddress']", GetNamespaces(doc)).InnerText;
    string ppid = doc.SelectSingleNode("/saml:Assertion/saml:AttributeStatement/saml:Attribute[@AttributeName='privatepersonalidentifier']", GetNamespaces(doc)).InnerText;
 
    MembershipUserCollection users = Membership.FindUsersByEmail(email);
 
    foreach (MembershipUser mu in users)
    {
        if (mu.Comment != null && mu.Comment.Equals(ppid))
            FormsAuthentication.RedirectFromLoginPage(mu.UserName, false);
    }
}

Tack vare detta kan nu användaren logga in med det kopplade kontot utan att behöva ange varken användarnamn eller lösenord. Det gör att man kan ge användaren möjlighet att logga in på ett mycket säkrare sätt.

Detta är endast en enkel inloggning där användaren kan koppla ett kort till sitt konto, men det skulle kunna byggas ut med till exempel:

  • Möjlighet att koppla flera kort till samma konto.
  • Möjlighet att skapa konton genom att skicka in ett InfoCard och sedan generera ett starkt lösenord.
  • Möjlighet att generera ett nytt lösenord genom att skicka in ett InfoCard.

Det finns många möjligheter, och det är du själv som bestämmer vart du vill komma med din lösning.

Precis som i förra artikeln så rekommenderar jag inte att man tar koden rakt av och använder i en skarp miljö, utan snarare har den i referenssyfte.

More Posts Next page »