The Progressive .NET Tutorials 2011

by DotNetNerd 26. July 2011 18:50

I have been offerede the opportunity to give away two tickets to The Progressive .NET Tutorials in London, which take place from the 5th to the 7th of september 2011.

The event consists of twelve 4-hour hands-on Workshops which provide a deep dive into advanced topics for agile .NET developers. The topics include Gherkin, WebSharper, RESTful web services and Async methods in C# 5. The tutorials are in-depth, hands-on tutorials run by experts who are there to be quizzed, questioned and interrogated for all three days. The program and list of speakers including the infamous Jon Skeet can be viewed here.

To participate in the draw for the two tickets all you have to do is write me a short email at christian@dotnetnerd.dk with a reason why you should be the one to win!

Even if you don’t win I’ve got your back, if you wish to participate. You will get a £50 discount if you use the promocode: “PROGNET50” – but hurry up because there are only 125 tickets available.

 progressivenew

NuPack - Microsofts own NU but with VS integration

by DotNetNerd 6. October 2010 17:44

Apparently I was not the only one who fell in love with the NU project, that I blogged a while ago. Microsoft just launched their own NuPack project which provides the same basic features, as well as integration directly with Visual Studio. As a cool sidenote it will be included in the install if you install the latest MVC 3 beta. To get started or just to see a quick runthrough of how it works take a look at Scott Hanselmans post on the subject.

 

Opsætning af IIS 7.0 og Windows Communication Foundation i Vista

by DotNetNerd 16. December 2007 14:50

Jeg opdagede idag at det er knap så "lige ud af boksen" som man kunne ønske sig at afvikle ASP.NET og Windows Communication Foundation services under Vista og IIS 7. Man kan kun undre sig over at ihvertfald ASP.NET ikke automatisk installeres ved installation af IIS, men det er åbenbart ikke tilfælder. Det lykkedes dog efter at have rodet lidt at få det til at virke og jeg vil derfor lige skrive en guide hvis andre skulle støde på samme problem. 

Installation af IIS og ASP.NET på Windows Vista

For at kunne afvikle en ASP.NET applikation skal man først installere IIS og den tilhørende ASP.NET komponent. Dette kræver administrator rettigheder og gøres ellers ved at:

  • Gå til kontrolpanel -> Programmer og funktioner.
  • Herfra vælger du "Slå windows funktioner til eller fra" i sidemenuen til venstre i vinduet.
  • Vælg internet Information Service og udvid punktet.
  • Udvid "værktøjer til webmanagement" og "kompatibilitet med IIS 6 management".
  • Vælg "Kompatibilitet med IIS-metabase og IIS 6-konfiguration".
  • Udvid også "World wide web services" og Funktioner til programudvikling.
  • Vælg ASP.NET checkboksen.

Du kan nu afvikle ASP.NET applikationer ved at oprette dem på almindeligvis via IIS management værktøjet - eller bruge default sitet ved at smide det i inetpub/wwwroot.

Installation af WCF service modellen

For at kunne afvikle en Windows Communication Foundation service skal service modellen registreres.

Dette gøres ved at:

  • Åben en kommandoprompt med admin rettigheder.
  • Gå til %Windows%\Microsoft.Net\Framework\v3.0\Windows Communication Foundation\
  • Check status ved at skrive ServiceModelReg -vi og se om service modellen allerede er installeret.
  • Er den ikke installeret skriv ServiceModelReg -i og så skulle modellen blive installeret.

Og nu kan du så også afvikle en Windows Communication Service.

Lige for en god ordens skyld skal det siges at for at hoste en WCF service under IIS 7 skal man blot smide en svc fil med følgende indhold i roden af sitet.

<%@ ServiceHost Language="C#" Debug="true" Service="Syndication.FeedService" %>

Hvor servicen skal pege på klassen der implementerer din service. Dll'en skal ellers bare ligge i en bin mappe som den plejer.

Tags: , ,

Dynamic Language Runtime

by DotNetNerd 3. November 2007 23:36

DLR - Dynamic Language Runtime.

Jeg fik for et stykke tid siden øje på en blogpost der omhandlede endnu et tiltag Microsoft arbejder på til .NET frameworket - nemlig en Dynamic Language Runtime. Umiddelbart tænkte jeg "fint nok men hvad skal jeg bruge det til". Det spørgsmål fik jeg så besvaret nu her da jeg faldt over en video fra MIX07 omkring dette emne. Jeg vender tilbage til videoen senere, da den indeholdt et temmeligt fedt eksempel som jeg vil gengive.

Kort fortalt er styrken ved dynamiske sprog at de "bare er tekst" ligesom en aspx- eller xaml-fil. Derved giver de nogle muligheder for især webudviklere ved egentlig at vende en smule tilbage til webudviklingens barndom. Idet sprogene er fortolkede, og altså "bare tekst" der ikke skal kompileres for at kunne afvikles, kan man arbejde uden konstant at skulle igennem en code-compile-review cyklus.

Dette kan især være rart hvis man skal udgive rettelser til en webapplikation, men også under selve udviklingen da man kan sidde med browseren fremme på den ene skærm imens man retter i koden på den anden og ser ændringerne slå igennem med det samme.

Hvilke sprog kan man så kode i?

Til at at starte med arbejder Microsoft på at udvikle implementationer baseret på sprogene:

  • IronRuby
  • IronPython
  • JavaScript
  • Dynamic VB

Ligesom med den almindelige CLR er det meningen at det skal være muligt at udvide med flere sprog hen ad vejen. De 4 sprog der er med til at starte med er valgt ud fra at de for det første er meget udbredte, og så for JavaScripts vedkomne fordi det giver mulighed for at man meget let kan genanvende sine eksisterende Ajax scripts i f.eks en Silverlight applikation. VB er som altid representeret af hensyn til Microsofts eget Office team. IronRuby og IronPython er enormt populære sprog der er svære at komme uden om - og de har en force i at de begge har en lækker syntaks der er meget lidt verbos.

Mix and Match

Der før omtalte eksempel fra MIX07 synes jeg gav en virkelig god idé om hvilke muligheder der vil være for at lege "Mix and Match" i fremtiden, da det illustrerer hvor enkelt man kan blande forskellige sprog - hvad end det er CLR eller DLR sprog, og hvad enten det er ASP, Silverlight eller helt almindelig HTML.

Eksemplet er en Silverlight applikation skrevet i Ruby og benytter en knap skrevet i C#, som kører et animationsscript skrevet i DLR JavaScript der viser tekstelementer der floater rundt. Teksterne er hentet fra en service skrevet i VB, udfra et ord der er indtastet i en HTML textbox som tilgås via Silverlights HTML DOM.

require 'Silverlight.Samples.Controls.Version=0.0.0.0'

Controls = Silverlignt.Samples.Controls
Document = System.Windows.Browser.HtmlPage.Document

JS = require '3dText.js'
VB = require 'technorati.vbx'

def initialize(s, e)
    button = Controls.Button.new
    button.Text = "Click me"

    JS.initialize

    root.children.add button

    button.click do |s, e|
        JS.clearList
        term = Document.txtSearchTerm.Value
        items = VB.GetTitles(term)
        items.each { |item| JS.initializeName(item)}
        JS.playAnimation
    end
end

Som man kan se er Ruby meget letvægts, og hvis man tænker over antallet af komponenter skrevet i forskellige sprog fra forskellige miljøer der arbejder sammen her kan man ikke undgå at blive lidt imponeret over hvor smertefrit CLR og DLR sprog taler sammen.

Det er værd at bide mærke i de første 5 linier fra eksemplet hvor man ser hvor let det er at importerer komponenter fra serveren, samt at referere til dynamisk kode skrevet i andre sprog. Det er ganske enkelt bare at bruge en simpel require statement.

Derefter viser eksemplet en initialize metode, som det er defineret i den tilhørende XAML fil skal kaldes ved init. I initialize instantieres så en knap, og en tilsvarende initialize metode på JavaScript komponenten kaldes. Knappen tilføjes så til et canvas der er navngivet root. Knappen for derefter tildelt en anonym eventhandler, der clearer den liste af tekster og tilføjer nye ord hentet fra VB servicen. Til sidst er det blot at starte animationen og så er koden kørende.

Hvordan platformen blev til.

En sjov historie fra videoen er at en af dem der har været med til at lave det oprindeligt startede med at ville skrive en artikel for at lave grin med Microsoft, da han havde hørt at .NET var elendigt at bygge dynamiske sprog oven på.
Han skrev så en implementation af Python oven på CLR'en - og til hans store overraskelse sparkede den røv på den originale Python. Med andre ord viste benchmarks at hans implementation performede dobbelt så godt! Derefter endte han så med at arbejde for Microsoft og har været med til at bygge denne platform til at hoste dynamiske sprog.

Model-View-Controller - seperation of concerns

by DotNetNerd 2. November 2007 16:19

Model-View-Controller Framework

Frameworks der bygger på et Model-View-Controller pattern er blevet meget populære indenfor webudvikling, især Ruby on Rails vil mange kunne nikke genkendende til.

En af de store fordele ved MVC frameworks er at de giver "seperation of concerns" hvilket vil sige at man får adskilt datamodellen og brugergrænsefladerne. ASP.NET har været kritiseret for at netop det at opnå en klar adskillelse kan være meget svært idet en url mapper direkte til en aspx, som indeholder både markup og codebehind.

En anden force ved MVC frameworks er at de gør det muligt - og ligefrem naturligt - at basere sin udvikling på unittests. Dette er vigtigt ved udviklingen af større systemer, da man derved kan refaktorere uden at være nervøs for ikke at kunne overskue konsekvenserne.

Som alternativ til den almindelige aspx model er Microsoft derfor gået igang med at udvikle deres eget MVC framerwork, som skal passes direkte ind i .NET frameworket og understøtte både CLR og DLR sprog. MVC frameworket designes udfra at det skal være "extensible and pluggable", hvilket vil sige at der skal være muligt for udviklere at skifte ALLE enkeltdele af modellen ud hvis de ønsker at lave deres egen implementation. Derudover bliver der gjort meget ud af at frameworket skal performe godt og være "mockable" - altså det skal være muligt at lave unittesting baseret på mockups.

Routing regler 101

Routing er et kernebegreb i MVC frameworks, som går ud på at mappe en url til en given controller der skal håndtere det aktuelle request. Som standard vil MVC frameworket understøtte to former for mapning:

<Controller>/<Action>/<Param>
<SomeName>/<Action>/<Param> => <Controller>

Eksempelvis kunne man dermed lave en struktur der tillader redigering af produkter, hvor de følgende vil mappes til "rediger produkt med Id 4".

ProductsController/Edit/4
Products/Edit/4 => ProductsController

Udover at mappe til Controllers er det også muligt at mappe til ControllerFactories, som giver et abstraktionslag der kan dirigere videre til forskellige controllere alt efter hvad der skal udføres.

Routing kan f.eks sættes op i ApplicationStart eventet på Global.asax, og i de eksempler der har været vist indtil videre gør man sådan her:

Router.Routes.Add(
new Route("Products", "/Products/[action]/[id]", typeof(ProductController));


Controllers - systemets knudepunkt

Som tidligere nævnt er målet at designet skal være "extensible" og ud fra den devise er der flere mulige klasser der kan extendes, når man skal implementer sin egen controller.

Hvis man vil lave sin helt egen kan man tage udgangspunkt i interfacet IController, som har én metode kaldet Execute der modtager en IHttpContext og RouteData. RouteData er en dictionary af tokens fra url'en der udgør de parametre siden kaldes med.

public void Execute(IHttpContext context, RouteData routeData)
{
   
}

Alternativt kan man bygge videre på klasserne ControllerBase, Controller, Controller<T> eller IControllerFactory.
Det mest oplagte er at arbejde med Controller<T>, som er en typestærk standard implementation af IController.

Hver metode mapper her til en action, og parametre til de efterfølgende tokens i urlen. ControllerAction attributten fortæller at der er tale om en action, og ved at sætte DefaultAction=true indikerer man at denne metode skal kaldes hvis ingen action er givet af url'en. Udover denne attribut kan man tilføje andre til f.eks at håndtere caching.

class Products : Controller<ProductData>
[ControllerAction(DefaultAction=true)]
[OutputCache(Duration=10)]
public void List(int? number)
{
    ViewData["number"] = number;
    ProductData viewData = new ProductData();
    viewData.Number = number;
    RenderView("ProductView", ViewData); 
}

public class ProductData
{
    public int Number { get; set; }
}

ViewData bruges til at holde de data der skal passes til viewet. Der er som udgangspunkt en Dictionary til dette, med ved at bruge Controller<T> kan man angive en type man selv definerer.

Metoden RenderView bruges til at kalde et specifikt view og passe data til viewet.

Komplekse objekter kommer også til at kunne bruges som parametre ved hjælp af Type Descriptors som kan plugges ind.

Views - brugerflader rensede for logik

Views kan være aspx eller ascx filer med alt hvad de normalt kan, inclusiv brug af masterpages, bortset fra postbacks ikke er mulige og dermed undgår man at bruge viewstate.

Dette skyldes at views skal tilgås igennem en Controller, hvilket man ville bryde med ved at tillade postbacks.

Til at understøtte links ud kommer der blandt andet en hjælpeklasse der hedder html samt nogle extention methods. Skal man generere et link kan man f.eks. gøre følgende.

string link = Html.Link("Products", new {Action="Edit", param="4"});
string link = Html.Link<Products>(controller => controller.Edit(4));

På samme vis findes der en .Url metode der udelukkende returnerer url'en.

I den lidt mere fikse afdeling findes der også en metode til at lave links til paging som en pæn xhtml ul/li liste. Dette kræver at den liste man arbejder på implementerer IPagedList, som indeholder properties der beskriver det samlede antal elementer og index.

string paginationLinks = Html.PaginationLinks(viewData, "Products", "List", "10");

Af andre smarte metoder jeg lige vil nævne kort er der RedirectToAction til at håndtere redirects, og en UpdateFrom extention method, til at tage data fra Request.Form, et dataset eller andet og udfore en update.

RedirectToAction<Products>(c => c.List(0))

product.UpdateFrom(Request.Form)
Data kan fra views tilgås som tidligere antydet igennem ViewData, som kan være en type man selv definerer ellers igennem en Dictionary. Det er muligt på views det implementerer ViewPage<T> at tilgå data både via indexer og ved at tilgå properties direkte.

public class ProductView : ViewPage<ProductData>
{
    int i;
    i = ViewData["Number"];
    i = ViewData.Number
}

Ønsker man at benytte ajax vil der blive lavet sådan at man kan lave et kald og indsætte det returnerede html i en ny type panel.

Astoria - next generation dataservices

by DotNetNerd 2. November 2007 15:53

Astoria Data Services - Data in the cloud.

Microsoft arbejder for tiden på et projekt under kodenavnet "Astoria" som skal gøre det muligt at lave dataservices der lader applikationer tilgå og manipulere data via almindelige HTTP requests ved hjælp af et URI format. Idéen er at man skal kunne arbejde med ren data i sine klientapps - altså Ajax og Silverlight implementationer. Data kan efterspørges som XML eller JSON der er simple dataformater, som kan beskrive datastrukturer på en generisk måde.

Standard HTTP verber som GET, POST, PUT og DELETE definerer operationen der skal afvikles - altså om det er en select, update, insert eller delete operation.

"Under kølerhjelmen" består Astoria Dataservices af en Windows Comminication Foundation Service der stiller data til rådighed, som er defineret ved hjælp af entities frameworket over en database. Astoria er altså bygget på eksisterende teknologier, hvor der er bygget en HttpHandler over som tillader at et query defineres som en URI.

JavaScript Object Notation vs Extensible Markup Language.

Som nævnt kan data efterspørges i formaterne JSON og XML. Overordnet set kan man sige at JSON sigter imod Ajax implementationer og XML imod Silverlight, da det er "the format of choice" for tiden for de to domæner.

Da JSON er knap så kendt som XML vil jeg lige beskrive det kort. Formatet er fordelagtigt at bruge i Ajax applikationer, da det er et meget kompakt format der er velunderstøttet i Javascript, idet man kan hente en JSON.js eller bruge Microsofts implementation der følger med frameworket fra .NET 3.5.

Kort fortalt defineres et objekt således

{name:value,name:value}

og et array således

[value,value]

Ud fra disse definitioner kan man definere arrays hvor værdierne er objekter og omvendt, og det er derved muligt at beskrive komplekse datastrukturer med meget lidt overhead.

JSON serialisering.

Ved hjælp af ASP.NET Ajax er det meget enkelt at arbejde med JSON, hvilket jeg vil illustrere med et lille eksempel.

<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<script>

var value = new Person();
value.Name = "Jens";

var result = Sys.Serialization.JavaScriptSerializer.serialize(value);

alert(result);

//Objektet kan derefter gendannes enten ved at deserialisere eller ved hjælp af eval
var obj = Sys.Serialization.JavaScriptSerializer.deserialize(result);
obj = eval("(" + result + ")");

function Person()
{
    this.Name;
}
</script>

På samme måde kan man naturligvis også serialisere objekter til JSON i .NET også.
using System.Web.Script.Serialization;

...

JavaScriptSerializer serializer = new JavaScriptSerializer();

Person person = new Person();
person.Name = "Hans";

string result = serializer.Serialize(person);

Response.Write(result);

Person person2 = serializer.Deserialize<Person>(result);

Response.Write(person2.Name);
Querying via URI.

Den URL-baserede query syntax understøtter en del forskellige operatorer, men lad os lige først se på et par eksempler som jeg har fra et screencast på MSDN der bygger på Northwind databasen.

Helt enkelt kan man tilgå data ved at "slashe" ('/') sig igennem en struktur og bruge hårde klammer ('[]') til at angive nøgler som sådan:

northwind.svc/Customers[ALKFI]/Orders

Næste skridt er at man kan bruge simple operatorer, som her hvor jeg efterspørger Kunder fra London:

northwind.svc/Customers[City eq 'London']

Og slutteligt er der nogle mere advancerede operatorer - den nedenstående gør at ordrene fra kunden "ALKFI" flettes ind i de data der returneres. Det vil sige at man effektivt set kan hente kunde og ordre oplysninger som ét kald.

northwind.svc/Customers[ALKFI]?$expand=Orders

Simple query operatorer.

Operatorerne er vidst så selvbeskrivende at jeg vil nøjes med at liste dem.

eq (Equal)  /Customers[City eq 'London'] 
ne (Not equal)  /Customers[City ne 'London'] 
gt (Greater than)  /Orders[OrderDate gt '1998-5-1'] 
gteq (Greater than or equal)  /Orders[Freight gteq 800] 
lt (Less than)  /Orders[Freight lt 1] 
lteq (Less than or equal)  /Orders[OrderDate lteq '1999-5-4'] 


Advancerede query operatorer.

De advancerede operatorer giver mulighed for at hente sammensat data og lave paging. Derved er en de mest almindelige scenarier understøttet "ud af boksen".

?$expand=Orders  inkluderer ordrer inline, således at man undergår at lave to kald. 
?$orderby=ProductName  Sorterer efter ProductName. 
?$top=2  Returnerer de 2 første rækker. 
?$skip=2  Springer de 2 første rækker over. 


Custom Service Methods.

Hvis man ønsker at definere et query som er for advanceret til at kunne løses med de eksisterende operatorer er det muligt selv at skrive metoder der også kan kaldes ved hjælp af Astorias URI format.

Eksempelvis kan man lave så det er muligt at hente kunder ud fra hvad stat de bor i - hvor queriet kunne se sådan her ud:

/CustomersByState?state=WA

Implementationen af servicen er enormt simpel, da der er en Astoria template i Visual Studio man kan tage udgangspunkt i. Derefter kan metoden skrives sådan her.


[WebGet]
public static ObjectQuery<Custumers> CustomersByCity(NorthWindEntities db, string city)
{
 if (city == null || city.length < 3) {throw new Exception("Bad city");}
  
 return db.Customers.where("it.City = @city", new ObjectParameter("City", city));
}


Hvordan ser den payload jeg modtager ud?

For at give syn for sagen kan du her se det der returneres fra det simple kald til Customers[ALKFI] hvis man efterspørger XML.
<DataService xml:base="http://myserver/data.svc">
 <Customers>
  <Customer uri="Customers[ALFKI]">
   <CustomerID>ALFKI</CustomerID>
   <CompanyName>Alfreds Futterkiste</CompanyName>
   <ContactName>Maria Anders</ContactName>
   <ContactTitle>Sales Representative</ContactTitle>
   <Address>Obere Str. 57</Address>
   <City>Berlin</City>
   <Region />
   <PostalCode>12209</PostalCode>
   <Country>Germany</Country>
   <Phone>030-0074321</Phone>
   <Fax>030-0076545</Fax>
   <Orders href="Customers[ALFKI]/Orders" />
  </Customer>
 </Customers>
</DataService>

Og hvis man efterspørger JSON får man det her tilbage.

[
    {
        __metadata: {
            Type: "Customer",
            Base: "http://myserver/data.svc",
            Uri: "Customers[ALFKI]"
        },
        CustomerID: "ALFKI",
        CompanyName: "Alfreds Futterkiste",
        ContactName: "Maria Anders",
        ContactTitle: "Sales Representative",
        Address: "Obere Str. 57",
        City: "Berlin",
        Region: null,
        PostalCode: "12209",
        Country: "Germany",
        Phone: "030-0074321",
        Fax: "030-0076545",
        Orders: {
            __metadata: {
                Uri: "Customers[ALFKI]/Orders"
            }
        }
    }
]

Hvordan forbruger jeg så en service?

Næste skridt er så naturligvis at kalde servicen, hvilket jeg vil demonstrere ud fra både en Ajax og en Silverlight kontekst. Ved at bruge Microsofts Scripting Library, som er en del af ASP.NET Ajax, kan en service tilgås på den her måde:
function GetCustomer(id)
{
 var req = newe Sys.Net.WebRequest();
 req.set_url("northwind.svc/Customers[" + id + "]/Orders");
 req.get_headers()["Accept"] = "application/json";
 req.add_completed(OrdersCompleted);
 req.invoke();
}

function OrdersCompleted(response)
{
 if (response.get_statuscode() != 200){//Error}
 else
 {
  var orders = response.get_object();
  var html = Sys.StringBuilder("<ul>");

  for (var i = 0; i<orders.length; i++)
  {
   html.append("<li>" + orders[i].OrderDate + "</li>");
  }

  html.append("</ul>");

  $get(Orders).innerHTML = html.toString();
 }
}
Ligeledes kan man i Silverlight udforme et query, og der er endvidere muligt ved hjælp af et tool generere proxy klasser så man kan arbejde med strongly typed data.
WebDataContext dataContext = new WebDataContext(txtDataserviceUrl.Text);

foreach (Customer customer in dataContext.CreateQuery<Customer>("/Customers"))
{
 cmbCustomers.Items.Add(customer.Name);
}
if (cmbCustomers.Items.Count > 0)
{
 cmbCustomers.SelectedIndex = 0;
}
Hvis man vil lave inserts er det også rimeligt enkelt, hvilket jeg har fundet et eksempel på som viser hvordan en Note føjes til en Artikel i et typisk Artikel system.
Article article = (Article)lstArticles.SelectedItem;

Note note = new Note();
note.Comments = txtNewNote.Text;
note.Article.RelatedObject = article;

dataContext.Add(note, "Notes");
dataContext.SaveChanges();

lstNotes.Items.Add(note.Comments);
txtNewNote.Text = "";

Blod på tanden?

Idet trenden går imod at webapplikationer skal minde mere og mere om "rigtige" applikationer, er RIAS (Rich Interactive Applications) et af de mest hotte emner verden over inden for webudvikling. I den forbindelse er teknologier som Astoria en vigtig brik, da de gør det muligt at lave generiske applikationer der direkte fra klienten selv kan tilgå og vise data.

Jeg finder derfor emnet meget interessant og jeg håber artiklen her har giver dig blod på tanden, da jeg selv glæder mig til at teknologien bliver færdigudviklet så jeg selv kan komme til at anvende den i mine løsninger.

Tags: ,

DataBinding - performance, læsevenlighed og fleksibilitet

by DotNetNerd 2. November 2007 15:41

Jeg har ved flere lejligheder hørt forskellige udviklere snakke for og imod forskellige måder at lave databinding på - så nu besluttede jeg mig for at lave en test for at se hvad forskellen reelt er.

Udgangspunktet er en Person klasse med 1 property (Name), som der skabes en liste af der bindes til et gridview.
Jeg har lavet 3 scenarier, der henholdsvis binder ved hjælp af binding expressions med og uden brug af Eval, og ved at håndtere RowDataBound eventet på et gridview.

Lige for at gøre klart hvordan man databinder via binding expressions med og uden eval er her de to tags der er tale om:

Binding med eval:

<%# Eval("Name") %>

Binding uden eval:

<%# ((Person)Container.DataItem).Name %>

Efter at have kørt disse 3 binding scenarier en række gange fremgår det tydeligt at Eval performancemæssigt er noget tungere, og tager ca. dobbelt så lang tid som de to andre scenarier der performer rimeligt ens. Dette skyldes naturligvis at Eval benytter reflection. Det skal dog siges at vi snakker henholdsvis 1 og 2 millisekunder ved den her mængde data så vi snakker detaljer med mindre der er virkelig meget data.

Konklusion:

Håndtering af RowDataBound og brug af binding expressions uden eval er klart at foretrække ud fra et rent performancemæssigt synspunkt.

Personligt synes jeg at det er uskønt at skulle skrive en RowDataBound eventhandler i helt simple tilfælde, da det er knap så læsevenligt som at bruge et binding expression og da det kræver mere kode.

Derfra kan man så vælge ud fra om det vigtigste kriterie er performance eller fleksibilitet. Eval har en fordel i og med at aspx'en i højere grad fungerer som template det er fri for at vide hvilken type der bindes til den. I nogen tilfælde kan denne fleksibilitet veje tungere end performancemæssige hensyn - da det ved relativt små datamængder stadig vil være svært at mærke forskel. Skal man derimod lave en simpel binding af store mængder data virker expression binding ved at tilgå Container.DataItem som det rigtige valg.

 

Tags: ,

"Nice to know" om strings

by DotNetNerd 1. November 2007 15:30
For ikke ret lang tid siden gik det op for mig hvor lidt den gennemsnitlige programmør egentlig ved om den datatype der nok bruges allermest - altså strings. Jeg skal på ingen måde gøre mig bedre end andre for min viden omkring operationer på strings var heller hverken værre eller bedre end de fleste andres, før jeg læste "CLR via C#".

Derfor vil jeg lige skrive lidt "nice to know" information om strenge, dog startende med ting de fleste nok i nogen grad er klar over bare for at få alle up to speed.

1. Strings er immutable, hvilket vil sige at når en streng først er oprettet på heapen kan dens indhold på ingen måde ændres. Operationer med strings vil altid medfører at en ny string skabes. Dette er hovedårsagen til klassen StringBuilder som istedet arbejder på et char-array således at der ikke skabes en string før ToString() kaldes. Der er dog naturligvis også et overhead ved brug af StringBuilder, så to gode råd er at bruge den hvis mere end 2 konkatineringer foretages, og at angive en størrelse i constructoren så vidt det er muligt - da det vil betyde at arrayet redimentioneres så få gange som muligt.

2. .NET frameworket giver mulighed for noget der kaldes string interning, som går ud på at en string oprettes i en intern hashtable. På den måde undgår man at have flere ens strenge idet der vil returneres en reference til den eksisterende streng hvis man interner en streng der allerede findes - se metoderne string.Intern og string.IsInterned. Dette skal dog benyttes sparsomt, da en interned string sandsynligvis ikke vil blive garbage collected før app domainet lukker!

3. På grund af string interning - og fordi det giver pænere kode - er string.Empty at foretrække frem for "" sådan at man slipper for at oprette et streng objekt blot for at angive en tom streng. Ved sammenligning med en tom streng anbefales det dog istedet at man enten bruger string.IsNullOrEmpty, som er en pæn måde at checke både for null og empty, eller "myString.Length = 0" - som faktisk er den hurtigste måde at checke for empty rent performancemæssigt.

4. Som standard bruger == operatoren en Ordinal algoritme til sammenligning af strenge. Det vil sige at der ikke tages højde for Culture, men at der er forskel på små og store bogstaver. Med andre ord kan man opnå en pæn hastighedsoptimering ved specifikt at bruge en algoritme som OrdinalIgnoreCase til at sammenligne strenge der kun bruges i kode, og man kan opnå en bedre sammenligning af Culture specifik kode ved at bruge CurrentCulture / CurrentCultureIgnoreCase. Faktisk anbefaler Microsoft at man altid bruger Equals metoden med specifik angivelse af StringComparison enumeration, som beskriver hvilken algoritme der bruges, da koden derved er mere beskrivende for hvilken sammenligning man ønsker.

Hvis du vil se hvor stor forskellen rent faktisk er på algoritmernes hastighed er her en test udført af en af Microsofts egne udviklere: http://blogs.msdn.com/noahc/archive/2007/06/29/string-equals-performance-comparison.aspx

5. string.ToUpperInvariant har modtaget særbehandling i frameworket, således at den er optimeret i forhold til ToLower/ToLowerInvariant/ToUpper, derfor kan den med fordel benyttes som den foretrukne løsning hvis man ønsker at lave en streng hvor alle tegn er ens cased.

Tags:

Data Containere - lean or mean

by DotNetNerd 25. October 2007 17:45

Datacontainere - kort fortalt

I .NET findes der flere forskellige datacontainere som DataSet, Strongly typed DataSet og XmlDocument. Disse containere kan man bruge "lige ud af boksen" hvis man skulle have lyst til det, men man kan også vælge enten at lave en wrapper der arbejder på en af disse typer eller også man kan lave sine egne custom entiteter.

Hvilken container man ender med at bruge i sin applikation er oftest afgjort ud fra personlig præference og funktionelle krav til applikationen man er ved at udvikle. Da valget af containere er meget centralt i designet af en applikation mener jeg det er vigtigt at man ved hvilke konsekvenser valget har for udviklingstiden og for det overordnede design.

Det jeg vil se på i den her artikel er hvordan man vælger den "bedste" container til sin applikation og hvilke fordele og ulemper et sådan valg fører med sig.

Hvordan vælger jeg hvilken der passer bedst til min applikation?

Hvilken datacontainer der er "best" findes der ikke noget entydigt svar på, da de alle har deres fordele og ulemper. For at kunne vælge den rette datacontainer til sin applikation har jeg valgt 3 faktorer jeg vil fokusere på:

  • Design kriterier
  • Udviklingstid/levetid
  • Funktionelle krav

Design kriterier

Inden man begynder at træffe beslutninger omkring design er det altid vigtigt (ikke kun ved valg af datacontainer) at opstille nogle design kriterier, som man kan vurdere forskellige løsninger udfra. Ofte vælger man nogle begreber som er centrale for ens design, eller også tager man en fast liste af begreber og vurderer hvilke der er vigtigst for det aktuelle design. Herunder er en liste over begreber, der er relevante ved valg af datacontainere, som man typisk kan bruge til at beskrive designkriterier.

Skalerbart - skal det være muligt at skalere applikationen så den f.eks ligger på flere servere?

Genbrugbart - skal dele af applikationen kunne genbruges i andre lignende applikationer?

Integrerbart - skal applikationen integreres med andre applikationer?

Performance - er der nogen krav til hvor hurtigt en given funktion skal afvikles?

Fleksibelt - er der nogen krav til at systemet skal kunne ændres når det er taget i brug?


Funktionelle krav

Udover de generelle designkriterier kan man se på de funktionelle krav der stilles til applikationen. Skal data kunne konverteres til xml? Skal det være muligt at lave sortering? Skal data distribueres? Hvis ja, skal de så kun distribueres ud til ens egne applikationer eller også til kunder? Skal de distribueres via en webservice eller via remoting i et client/server scenarie?

Alle disse typer overvejelser er relevante for valget af datacontainer. Et Dataset kan f.eks konverteres til xml og understøtter sortering samtidig med det er en type webservices genkender og kan genskabe hos klienten. På den anden hånd kan et dataset ikke udvides med ekstra funktionalitet, og det er ikke typestærkt, hvilket kan lede til uskøn kode hvis man skal lave mange metoder til at arbejde med data som måske ligefrem bliver nød til at findes i flere lag af ens applikation.

Hvis du bruger et strongly typed dataset bliver det godt nok typestærkt, men det er stadig ikke muligt at tilføje egne funktioner, og det er mindre generisk end "lillebror".

Custom entiteter giver mulighed for at tilføje funktionalitet, men lider under den sygdom at funktionerne ikke sendes med over en webservice. Tilgengæld kan de skræddersyes så du får præcist den funktionalitet du drømmer om, og du kan distribuere denne funktionalitet ud til en klient via remoting. Overvejelserne er mange men de bør gennemtænkes for den enkelte applikation da de er meget væsentlige, og har stor betydning for hvordan de funktioner man skal udvikle kan udformes.


Udviklingstid/levetid

Sidst men bestemt ikke mindst kommer den faktor som din kunde, projektleder eller chef nok går rigtigt meget op i, og som du selv ville ønske ikke var så væsentlig. Det kan være enormt fristende at give sig i kast med at udvikle custom entiteter, da de giver maksimal frihed, men det kræver ekstra udviklingstid og er dermed til at fordyre applikationen. Derfor skal valget af custom entiteter ofte være begrundet i at det kan forlænge en applikations levetid igennem øgedet fleksibilitet eller at det giver nogle muligheder som man ikke har ved at bruge DataSet, XmlDocument eller lignende.


Forskellige datacontainere og deres datastruktur

Når man har vurderet design kriterier, funktionelle krav og udviklingstid kan man se på hvilken type datacontainer der er mest velegnet til applikationen. I nogen typer applikationer viser der sig måske ligefrem at det bedste resultat er at bruge en type container til nogle specifikke moduler, og en anden container til andre moduler.

For at kunne vælge må vi se på hvilke fordele og ulemper der er forbundet med de forskellige datacontainere. Jeg vil her gå lidt mere i dybden med den mest gængse.

  • DataSet
  • Strongly typed DataSet
  • Custom entitet
  • XmlDocument
  • XmlDataDocument

Disse datacontainere kan deles ind i 3 kategorier efter hvordan data struktureres.
Der findes de relationelle datastrukturer, som DataSet og Strongly typed DataSet, der er bygget på samme måde som en databasestruktur, med tabeller, keys og relationer.
Custom entiteter er objekt-orienterede så de indeholder typer og collections det kan bygges op i en hirakisk struktur.
Og den sidste kategori XmlDokumenter arbejder som navnet antyder med Xml som er hirakisk opbyggede tags.

Relationelle og objekt-orienterede datastrukturer er normalt dem man vælger imellem når man skal udvikle en rigtig enterprise applikation, da dette er et stort emne er set et afsnit helt for sig selv.
XmlDokumenter bruges til at løse specifikke problemstillinger, hvor man ikke ønsker at have data liggende i en database. Xml er f.eks godt til at beskrive et sitemap eller til at strukturere tekster og billeder så man slipper for at de ligger og roder i databasen.

XmlDocument klassen giver mulighed for at arbejde effektivt med data i et XMl format. Dette gøres ved hjælp af XPath queries, som der findes en hel seperat artikel om her på sitet :-)

En lidt finurlig kombination af to verdener finder man i XmlDataDocument klassen. Denne klasse kombinerer, som man måske kan gætte, brugen af DataSet og XmlDocument. Det vil sige at man kan få det bedste af funktionaliteten ved at bruge XmlDocument til rådighed så det kan bruges til at arbejde med et DataSet ved at lave et XmlDataDocument der arbejder på DataSettet. Det vil være fordyrende at sende et XmlDataDocument fra lag til lag i en applikation. Man vil derfor oftest nøjes med at sende DataSettet, og så oprette sit XmlDataDocument (der kan ses som en slags wrapper) når man har brug for denne udvidede funktionalitet.


Strulturelt vs Objekt-Orienteret

Valget imellem relationelle og objekt-orienterede datastrukturer har efterhånden udviklet sig til en hel religionskrig, som jeg vil prøve så vidt muligt at holde mig fri af. Det er imidlertid nødvendigt lige at knytte et par kommentarer til emnet.
Overordnet set er det muligt at løse de samme problemer med begge typer datastrukturer, den store forskel ligger omkring abstraktionsniveauet.

Relationelle datastrukturer afspejler databasen de anvendes oven på, hvilket nogen vil argumentere for er et problem, da man derved ikke får abstraheret databasens opbygning bort og eventuelle ændringer vil forplante sig ud i applikationen.

Objekt-orienterede strukturer derimod afspejler virkelige objekter og modeleres efter udviklerens ønsker. Dette giver ganske vidst en bedre abstraktion, således at strukturelle ændringer i databasen kun medfører ændringer i de metoder der sørger for at mappe data imellem databasen og objekterne. Ulempen ved denne fremgangsmøde er tilgengæld at strukturen tit kommer til at minde om tabeller alligevel. Dette skyldes at objekterne oftest ender med at blive sendt til en brugergrænseflade hvor de skal databindes - og denne process kræver et tabulart format. Med andre ord ser man tit at klasser ender med at beskrive kolonner via properties, og da de enkelte objekter bliver så til rækkerhvor collections så svarer til en tabel.

Prøver man bevidst på at bygge en hirakisk domæne model løber man hurtigt ind i bøvl når der skal databindes og man ender med at skrive en ordentlig bunke løkker til at finde et givent objekt i en collection. Selvom det måske kan lyde uskyldigt nok har det den sideeffekt at jo flere niveauer du har i dit hiraki, jo flere løkker har du inden i hinanden, hvilket er virkelig skidt for performance. Tænk f.eks på hvad det vil kræve for at kunne finde en medarbejder i en afdeling i en virksomhed. Egentlig et simpelt eksempel som sagtens kunne blive værre (virksomheden kunne være i en by som kunne være i en kommune i et land!), men allerede her vil man typisk skrive 3 løkker inden i hinaden således at man for hver virksomhed checker alle afdelingers medarbejdere.
Alternativet er naturligvis at skrive nogle metoder i sit data access lag som kan hente mindre dele af strukturen ud. Dette er imidlertid heller ikke altid det man ønsker, da det vil betyde at man skal skrive rigtigt mange lavniveau metoder for at kunne søge efter specifikke objekter - hvilket også kan have en effekt på helt ens design efterhånden som man har en overflod af metoder.

Designer man sin objekt struktur så flad som muligt kan der imidlertid godt være noget hentet i at man kan abstrahere databasen bort og indkapsle mapningen i sit eget data access lag. Dette kan imidlertid også godt gøres ved hjælp af f.eks et DataSet, da det strengt taget ikke behøver ligne den underliggende database - men det fungerer helt klart bedst hvis det gør.

Personligt står jeg med et ben i hver lejr, da jeg mener det er helt an på hvad man er ved at udvikle. Pointen med denne diskussion er derfor ikke at komme med en afgørelse, men derimod blot at gøre opmærksom på at der er disse 2 måder at "se verden på" og at forklare de fordele og ulemper der er forbundet med dem hver især.


Wrappere

Ved at bruge wrappere som f.eks indkapsler et DataSet eller et XmlDataDocumentkan kan tilføje alt den ekstra funktionalitet man kan tænke sig. Det giver samtidig mulighed for at trække på den eksisterende funktionalitet som der wrappede objekt har. Man betaler imidlertid den pris at man skal bryde indkapslingen hvis funktionerne skal tilgås udefra. Wrappere er desude med til at tilføre ekstra overhead, hvilket kan være et problem hvis der skal instantieres mange objekter af typen.

Den mest oplagte klasse at wrappe er nok DataSet, da det kan indeholder hvad som helst og man derved kan lave generisk funktionalitet som kan bruges på et hvilket som helst datagrundlag. XmlDataDocument er et eksempel på en wrapper der pakker et DataSet ind i XmlDocument funktionalitet.


Fordele og ulemper

Til sidst vil jeg se mere konkret på de enkelte klasser og beskrive deres fordele og ulemper. Herved håber jeg at ende med en liste som, når man har læst ovenstående, kan bruges til at træffe et fornuftigt og velovervejet valg af datacontainer.

DataSet

Har funktionalitet til at sortere, søge, filtrere i data og til at konvertere til xml.

Er meget fleksibelt, da det er generisk og data beskrives via schema information.

Kan sendes over en webservice og være fuldt funktionelt på klienten.

Skal fyldes med schema information som kan gøres på 3 måder:

  • Manuelt ved at lave et lag der sørger for at hælde data i dine DataSet.
  • Ved at læse schema information fra en XSD via ReadXmlSchema metoden.
  • Ved at hende schema information fra databsen ved hjælp af DataAdapterens FillSchema metode - dette er dog meget tungt og bør bruges med omhu.
Bruger meget hukommelse hvis man kun skal hente en enkelt række.

Strongly typed DataSet

Har samme funktionalitet som DataSet til sortering, søgning, filtrering og xml konvertering.

Er typestærkt og giver derved kønnere kode der er lettere at skrive.

Indeholder schema information som beskrives på design tidspunktet.

Klienter der henter via webservice får kopi af schema information og mister ikke funktionalitet.

Kan forbedre hastighed i forhold til et almindeligt DataSet da peopertys kalder via index.

Skal regenereres ved strukturændringer.

Større overhead than dataset.

Der er mange scenarier hvor det ikke er helt har den funktionalitet man ønsker sig.

Custom entities

Giver fuld fleksibilitet i forhold til funktionalitet.

Minimalt interface der kun stiller der til rådighed man ønsker.

Kan enten være intelligente, helt dumme (Data Transfer Objekter) eller midt imellem.

Logik kan distribueres imellem lag og imellem klienter.

Der er kun properties der sendes med over webservice, så klienten har ikke gavn af metoder og attributter.

På trods af den Objekt-Orienterede natur vil strukturen oftest ende med at ligne en tabel, af hensyn til databinding.

Indeholder ingen funktionalitet til søgning og denne kan være omfattende og problematisk ved uheldigt strukturelt design.

God performance ved få entiteter, men taber i forhold til DataSet ved store datamængder.

XmlDocument

Stærkt til at beskrive hirakiske data.

Data kan gemmes eksternt i filer og kræver ikke database eller lignende persistensmedie.

Datatilgang via query sprog.

Er ikke typestærkt.

Fladt format, da det basalt set er tekst.

Tendens til at blive rodet og tungt ved store mængder komplekse data.

XmlDataDocument

Kombinerer funktionaliteten fra DataSet og XmlDocument.

Data kan gemmes i database eller som XML.

Søgning kan laves både via Xpath queries og direkte tilgang til DataSet.

Kan anvendes efter behov og behøves ikke sendes med ved distrubution, hvor man enten sender Xml eller DataSet alene.

Kan føre til uklar kode og struktur ved blanding af XPath queries og datatilgang via DataSet.

Idet objektet består af DataSet og XmlDokument bliver objektet tungere end de to typer er hver især.

DataSet Wrapper

Man kan tilføje ønsket funktionalitet efter behov.

Kan gøres fleksibelt med hensyn til datagrundlag og tilføre generisk funktionalitet.

Kræver at man bryder indkapslingen for at kunne stille funktionalitet til rådighed.

Det er kun DataSettet der er tilgængeligt hvis der sendes objekter over en webservice - metoder og attributter frafalder.

Data behandles dybest set stadig som et DataSet, men tilfører ekstra overhead.

Silverlight - fremtiden inden for rige webklienter

by DotNetNerd 21. May 2007 18:56

Silverlight - tidligere Windows Presentation Foundation Everywhere.

Silverlight er det nye navn for det det tidligere var kendt som WPF/E - eller Windows Presentation Foundation Everywhere. Silverlight er videreudviklingen af Windows Presentation Foundation som Microsoft introducerede som del af .NET 3.0 - sammen med Windows Communication Foundation og Windows Workflow Foundation.

Silverlight er fornylig udgivet som Beta 1, og planen er at der er endelig release her til sommeren 2007. Det helt spændende er at Silverlight giver mulighed for at man kan udvikle rige brugerflader der kan køre hvor som helst, og som kan programmeres i mange forskellige sprog - herunder C# og VB som er de relevante sprog for mit vedkomne.

Derudover forbedres mulighederne for samarbejde imellem designere og udviklere markant via nye værktøjer der arbejder med XAML. Dette er noget jeg personligt har savnet igennem længere tid, da det kan føles akavet at få et design og sidde og skifte html-elementer ud med kontroller, og i sidste ende vrage nogle af de ting, da det kan være uhensigtsmæssigt at implementere.

En sidste stor pointe er at Silverlight tilbyder komponenter til lettere at vise og arbejde med video i et helt nyt omfang. For eksempel vil det være muligt at sætte bookmarks ind i video, som man så kan programmere op imod sådan at der sker noget når et bestemt punkt spilles - dette kunne være at lade brugeren deltage aktivt eller måske bare vise en reklame ved siden af. Det vil også være muligt via Expression Studio at arbejde med hvordan video vises - så videoen kan fades ind eller klippes ud som puslespil hvis man skulle have lyst til at lave den slags lir.

Med hensyn til visning af medier tilbyder Microsoft samtidig det de kalder Silverlight streaming service, hvor man kan uploade sine videoer og derefter bruge dem på sit site - der er dog en 4 GB max grænse til at starte med.

Der findes allerede en række demoer af hvad man kan lave der spænder fra online realtime videoredigering, over bestilling af flybilletter med visning af ruten, til roterende 3D-terninger som alternativ til den gode gamle dropdownboks.

.NET crossbrowser og crossplatform.

At Silverlight kan køre "hvor som helst", lægger naturligvis op til en lidt mere præcis forklaring. Det der ligger i det er at Microsoft har shippet en .NET runtime der kan køre på tværs af platform og browser, hvilket jeg indtil videre har set demonstreret på Windows og Mac med både Internet Explorer og Firefox. Det eneste det kræver er et plugin, som kan installeres på under 20 sekunder! Med andre ord er det ikke nogen egentlig hindring at skulle smide dette plugin ind som det har været tilfældet med andre plugins igennem tiden.

Det kan som en sidekommentar også nævnes at debugging også er crossplatform, så du kan sidde og debugge noget der kører i Firefox på en Mac. Om du arbejder med ASP.NET, PHP eller hvad du nu kunne finde på er heller ikke afgørende, da Silverlight kan køre sammen med hvad som helst.

Hvad er så fordelene ved at køre .NET direkte i browseren?

Der er naturligvis mange fordele ved at kunne arbejde i et fuldgyldigt programmeringssprog, men jeg vil vælge at ligge mig op af dem som Scott Guthrie fremhævede ved MIX 2007 som er.

Multi-language support: inklusiv C#, VB, Ruby, Python og andre .NET sprog (mere end 37 sprog i alt).

Høj performance runtime: eller rettere fantastisk performance, der virkelig sparker røv på alternativer som f.eks javascript hvor benchmarks har vist at det er 300-700 gange så hurtig.

Rige kontroller med grafik, medier og interaktivitet: kontroller kan se ud og reagere lige som man ønsker, idet man ikke længere er bundet til at bruge html elementer, bitmap billeder og embedded video.

Html DOM integration: der er inkluderet et html bibliotek der giver mulighed for at tilgå elementer på siden, inklusiv statusbar, window frame og lign.

Robust networking: gør det muligt at kalde hvilket som helst type endpoint og udveksle data.

Flexible data support: LINQ query API understøttelse (se evt min LINQ artikel om dette emne).

XAML og samarbejde imellem design og udvikling.

Med hensyn til samarbejde imellem designere og udviklere består det i at der kommer en række værktøjer som er målrettet begge faggrupper, således at de kan arbejde på de samme projekter.

Expression Studio er til designere og indeholder værktøjer til at designe komponenter og arbejde med grafik, medier og endcoding - som hedder Expression Design, Blend og Media Encoder.

Cider er tilsvarende tilsigtet udviklere, således at de kan arbejde lidt videre med komponenterne i forbindelse med integration.

Den underliggende teknologi eller det underliggende sprog om man vil er XAML, som du kan læse mere om her. Kort fortalt er det et XML baseret sprog til at udarbejde vector baseret grafik og animation, lidt i stil med Flash. Derved kan man faktisk læse koden og ændre i den manuelt, men derudover er der som nævnt flere forskellige værktøjer på vej, sådan at man kan arbejde med det på et noget højere abstraktionsniveau som vi er vant til.

Tags: ,

Who am I?

My name is Christian Holm Nielsen, and I work as an independent consultant, in Denmark, where I write code, give advice on architecture and help with training. On the side I get to do a bit of speaking and help with miscellaneous community events.

Some of my primary focus areas are code quality, programming languages and using new technologies to provide value.

Month List