Søg på DotNyt:
Denne blog er flyttet til www.nielsbrinch.com


søndag den 29. juli 2007

Databinding - performance, læsevenlighed og fleksibilitet

skrevet af Christian H. Nielsen

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.

0 kommentarer

torsdag den 26. juli 2007

Afspilning af video med Silverlight

skrevet af Niels Brinch

Jeg har flere gange set at Microsoft nævner at videoafspilning er en af de store fordele ved Silverlight. Jeg kan ikke se hvorfor det skulle være SÅ vigtigt, men det er da cool nok. Jeg har UploadBAG hvortil man kan uploade videoer. Det kunne være rart hvis det var muligt at se videoerne direkte fra mit site, i stedet for at skulle hente videoen først. Det burde Silverlight kunne hjælpe mig med.

Google er min ven. Det første jeg finder hedder Silverlight Streaming og ja, det handler om video. Det beskrives hvordan jeg skal hente Microsoft Expression's Media Encoder, behandle videoen deri og dernæst generere en player til videoen. Nej tak! Jeg skal ikke ind og behandle hver video enkeltvis, det skal bare virke. Jeg fortsætter min søgning ...

Det næste jeg finder er en guide til hvordan man bruger DotNetNuke's Silverlight-baserede videoafspiller. Bingo, det er nøjagtig det jeg også vil kunne. Jeg er nu overbevist om at "man kan" det jeg vil, men den konkrete guide hjælper ikke lige præcis mig.

Det næste jeg finder er en instruktionsvideo fra Microsoft som skulle vise hvordan jeg kan designe min egen videoafspiller. Meget fint. Jeg går lidt i gang med videoen og ser Expression Blend blive åbnet. Nej tak! Et dyrt designerprogram som ikke kan andet end at skrive noget xml. Det kan jeg godt selv. I stedet downloader jeg kildekoden og finder noget interessant i .xaml-filen:

<Canvas.Resources>
<Storyboard x:Name="PlayButtonAnimation">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="PlayButton" Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:02" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Canvas.Resources>
<MediaElement AutoPlay="False" Width="448" Height="368" Source="http://localhost/videos/bear.wmv" Stretch="Fill" Canvas.Left="16" Canvas.Top="16"/>

Det ser nemt ud, ikke? Jeg læser det som om der er et MediaElement som er selve videoen og så er der en "animation" til at aktivere afspilning af videoen. Nøjagtig hvad jeg ledte efter.


Jeg opsætter øjeblikkeligt en test. Jeg hentede en wmv-fil med en køn dame der ønsker sin familie en glædelig jul. Efter at have placeret den her, http://localhost/videoblog.wmv, henvist til den fra mit projekt, ændret AutoPlay-attributten til true og trykket CTRL+F5 i mit testprojekt får jeg ... blank skærm.


Aha - Cross-domain-problematik. CTRL+F5 åbner på C:\ og filen ligger på http://. Da jeg åbner Silverlight-projektet på http:// fungerer det med det samme. Det er virkelig nemt med video i Silverlight. Bravo hvis det virker med andet end wmv. Jeg henter en avi-fil og prøver - denne gang en fil der viser hvordan man svejser et rør.


Blank skærm ... Den kan ikke afspille avi-filer. Heller ikke mpg.


Et opslag på Microsoft's eget site giver mig ret. Kun wmv, wma og mp3 er understøttet.


En meget lidt fristende løsning for UploadBAG vil være, at jeg konverterer al video til wmv efter det er uploadet.


Jeg er ikke imponeret af Silverlight's videoafspilning. Men heller ikke overrasket.

0 kommentarer

torsdag den 19. juli 2007

Hvad Windows-applikationer kan

skrevet af Niels Brinch

Der har længe været snak om det fantastiske ved Ajax og jeg har selv været ret begejstret for Silverlight. Det er jeg stadig. Det er teknologier som giver webapplikationer mulighed for at nærme sig brugergrænseflader som man ellers kun kender fra fuldblods Windows-applikationer.

Hvis web-applikationer, med alle deres fordele, kan levere brugergrænseflader som er så tæt på Windows-applikationer, hvad er så Windows-applikationens berettigelse?

Svaret er, at Windows-applikationer kan samarbejde med hele Windows. Web-applikationer kan groft sagt kun samarbejde med browseren.

Jeg har netop udviklet en Windows-applikation: Instant Online Image Gallery til UploadBAG. UploadBAG er et site hvor man f.eks. kan uploade feriebillederne og så sende linket rundt til familien, i stedet for at vedhæfte billederne til en mail. Problemet for brugerne har været, at deres feriebilleder gerne fylder 1MB stykket fordi enhver familiefar efterhånden har sit eget 17 megapixel-kamera. Det tager en hulens tid at uploade.

Løsning: Formindsk billederne automatisk umiddelbart inden upload.

Fordi det er en Windows-applikation kan man vælge sine billeder blot med copy-paste eller ved at trække dem ind i programmet. Det er let at lave. Jeg hæfter først metoder på et par events:

image

Dernæst fylder jeg lidt indhold i hver metode. Det er ikke meget der skal til. Én linje kode henter et string-array med filstier ud af det objekt som bliver trukket ind i applikationen.

private void lstImages_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
e.Effect = DragDropEffects.Copy;
else
e.Effect = DragDropEffects.None;
}

private void lstImages_DragDrop(object sender, DragEventArgs e)
{
Array a = (Array)e.Data.GetData(DataFormats.FileDrop);

AddImagesToList(a);
}

Dette er blot ét eksempel på hvad en Windows-applikation kan, som en web-applikation slet ikke kommer i nærheden af. På trods af at Ajax og Silverlight fører sig frem, er fuldblods Windows-applikationer bestemt ikke ude endnu.

0 kommentarer

File is being used by another process

skrevet af Christian H. Nielsen

Jeg har igennem længere tid været plaget af en build error med teksten ”File is being used by another process”.

Jeg har af flere omgange været ude og grave i forskellige blogs for at finde en løsning, og det lykkedes nu endelig at finde noget der virker. Under projekt indstillinger som Pre-build event kan man slippe locks ved at skrive følgende:

if exist "$(TargetPath).locked" del "$(TargetPath).locked"

if exist "$(TargetPath)" if not exist "$(TargetPath).locked" move "$(TargetPath)" "$(TargetPath).locked"

 

Alternativt hvis det ikke virker kan man ud fra devisen ”større problem kræver større hammer” lave en bat-fil der dræber aspnet_wp processen, og køre den når problemet opstår. Dette gøres med følgende kommando:

taskkill /IM aspnet_wp.exe /f

 

Det er naturligvis en anelse drastisk, men ikke desto mindre ganske effektivt!

1 kommentarer

onsdag den 11. juli 2007

Rart at vide om strings

skrevet af Christian H. Nielsen

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.

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 chararray således at der ikke skabes en string før ToString() kaldes. Der er dog naturligvis også et overhead ved brug af string builder, så to gode råd er at bruge den hvis mere end 2 konkatineringer foretages, og at angive en størrelse så vidt det er muligt - da det vil betyde at arrayet redimmes 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 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 med stor sandsynlighed 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åda 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 er den hurtigste måde at checke for empty).

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.

0 kommentarer

mandag den 2. juli 2007

Webservice kald fra ASP.NET Ajax

skrevet af Christian H. Nielsen

Jeg læste fornylig et indlæg på Scott Guthries blog omkring en såkaldt ViewManager til Ajax. Ideen er at man kan lave webservice kald direkte fra javascript, hvor det html der skal returneres genereres via en UserControl.

For at kalde en webservice starter man ved at sætte en ScriptManager op med en ServiceReference til den webservice man vil tilgå. Samtidig kan man evt angive en ScriptReference hvis man ikke ønsker at have sin scriptkode liggende inline.

<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="CustomerScript.js" />
</Scripts>
<Services>
<asp:ServiceReference Path="CustomerWebService.asmx" />
</Services>
</asp:ScriptManager>
Derefter kan man så tilgå webservicen således.
function doCallbacks()
{
AJAXtest.CustomerWebService.
GetCustomersByCity("Odense", displayCustomers);
}

function displayCustomers(result)
{
$get("viewresult").innerHTML = result;
}

Uden viewmanageren vil dette kræve at man bygger det html der returneres manuelt, hvilket de fleste gør ved at lave en gang uskøn strenggymnastik. Men med ViewManageren kan man definere sit view som en helt almindelig UserControl og generere html sådan her.

[WebMethod]
public string GetCustomersByCity(string city)
{
List<Customer> customers = GetCustomersFrom(city);

return ViewManager.
RenderView("~/App_Views/Customers.ascx", customers);
}

Det gør med andre ord Ajax kald til webservices langt mere anvendelige.


For ikke at skulle gentage koden fra ViewManageren er her istedet et link til det eksempel Scott Gu har skrevet. ViewManager sample

0 kommentarer


 
Til forsiden

Niels Brinch

- Seneste indlæg