Web Standards Update - HTML5 og CSS3 udvidelse til Visual Studio 2010

20. juli 2011

Selvom det ikke på nogen måde har været umuligt at lave hverken HTML5, XHTML5 eller CSS3 i Visual Studio 2010 har der manglet både intellisense til og validering op imod de disse ting - men det kan løses med Web Standards Update, WSU, udvidelsen til Visual Studio 2010. Opdateringen er lavet ef Microsoft-folk med danskeren Mads Kristensen i spidsen men det er dog ikke en officiel Microsoft opdatering.

I HTML5 får vi nu blandt andet glæde af de nye tags relateret til video og audio ligesom også de nye input-typer som mail, url og date er med, kigger vi på CSS3 er det blandt andet værd at se at relativt almindelige ting som filter og behavior nu kan valideres ligesom der nu er intellisense på browser-specifikke ting som -ms-*, -moz-* og -webkit-*. Endelig får vi glæde af mulighederne inden for de nye javascript browser API's som fx geolocation og local storage.

Standarderne er endnu ikke på plads så selvom opdateringen til Visual Studio bestemt er et stort skridt skal vi nok også forvente at se nyere versioner af WSU.

Her kan du downloade Web Standards Update for Microsoft Visual Studio 2010 SP1.

(X)HTML, .NET, ASP.NET, CSS, JavaScript , , ,

HTML parsing og Screenscraping med Html Agility Pack (HAP)

12. maj 2010

Det sker ret ofte at man har behov for at læse bestemte ting ud fra en hjemmeside, altså screenscraping, eller at parse egen HTML fx med henblik på at replace indhold med noget andet - regular expressions er langt fra altid et godt valg i forbindelse med denne type HTML-opgaver og andre muligheder som fx XPath eller LINQ to XML kræver, at HTML'en er valid og selvom det burde være en selvfølge er det ofte ikke tilfældet. Et rigtig godt alternativ til at screenscrape, parse HTML eller fixe fejl i HTML er Html Agility Pack (HAP), som kan downloades her; Html Agility Pack.

For at benytte HAP er alt du skal gøre at downloade løsningen fra hjemmesiden og tilføje en reference til HTMLAgilityPack.dll i dit projekt - og så er du klar til at manipulere med og hive information ud af en HTML-kilde. For at det hele kan give lidt mere mening vil jeg her komme med et par mindre eksempler;

Find billeder uden alt-attribut, indsæt den med default beskrivelse og gem som nyt dokument

HtmlDocument lHtmlDocument = new HtmlDocument();
lHtmlDocument.Load(
@"C:\dokument.html");
var lNoAltAttributeNodes = lHtmlDocument.DocumentNode.SelectNodes("//img[not(@alt)]");
if (lNoAltAttributeNodes != null)
{
   
foreach (HtmlNode lHtmlNode in lNoAltAttributeNodes)
    {
        lHtmlNode.Attributes.Append(
"alt", "manglende alt...");
    }
}
lHtmlDocument.Save(
@"C:\opdateretdokument.html");

Find alle links og aflæs title-attributten

List<string> lTitles = new List<string>();
HtmlDocument lHtmlDocument = new HtmlDocument();
lHtmlDocument.Load(
@"C:\dokument.html");
var lLinkNodes = lHtmlDocument.DocumentNode.SelectNodes("//a[@href]");
if (lLinkNodes != null)
{
   
foreach (HtmlNode lHtmlNode in lLinkNodes)
    {
       
string lLinkTitle = lHtmlNode.GetAttributeValue("title", string.Empty);
       
if (!string.IsNullOrEmpty(lLinkTitle))
        {
            lTitles.Add(lLinkTitle);
        }
    }
}


Ovenstående er selvfølgelig relativt simple eksempler men de viser alligevel godt hvor lidt der faktisk skal til for at arbejde med HAP, det eneste der kan være lidt tricky i det - hvis man ikke har arbejdet med det før - er XPath-delen, og søger du lidt starthjælp til det kan det findes her; XPath hos w3schools. Det er ikke et krav at arbejde med XPath som ovenstående to eksempler benytter da man sagtens kan gennemløbe den parsede html med almindelige løkker, men det giver alligevel rigtig mening med XPath.

.NET, ASP.NET , , , , ,

Pimp din Visual Studio med nye temaer og få bedre arbejdsmiljø

25. marts 2010

Sidder man lang tid foran sit Visual Studio synes jeg let man kan blive træt i øjnene af det som standard meget hvide udviklingsmiljø og selvom Visual Studio giver gode muligheder for at ændre opsætningen af skrifttyper og farver (i Tools -> Options -> Environment -> Fonts and Colors) er det noget der let kan tage alt for lang tid uden at man alligevel kommer frem til et særlig brugbart resultat.

Heldigvis findes der masser af færdige themes på nettet man uden videre kan importere og hvor alt arbejdet altså er gjort for en. Personligt er jeg stor tilhænger af de lidt mørkere temaer da det giver mine øjne meget mere ro til at få produceret noget - specielt temaet "Nightingale" sammen med skrifttypen Envy Code R benytter jeg rigtig meget. Temaet, både i en 2005 og 2008 version, samt findes her; Nightingale VS2005/VS2008.

Et skift af theme synes jeg, udover at kunne tilpasse ens arbejdsmiljø til ens øjne, også kan være en god måde at adskille forskellige udviklingssprog på hvis man fx både sidder med VB.NET, C# og F# samt få ny energi til programmeringen da det føles som at få et helt nyt udviklingsværktøj samtidig med at man beholder de features man kender til. Har du selv lavet ændringer til et tema så husk endelig at få taget backup af dem inden du skifter - ved import er det en også god idé at holde øje med præcis hvad de nye settings indeholder og fravælger enventuelle uhensigtsmæssige ting som fx tastatur-genveje.

Både export og import af temaer sker i Tools -> Import and Export Settings.

Som sagt findes der masser af andre themes på nettet og måske passer mit forslag ikke lige dig, så tag en tur rundt på nettet og se hvad du kan finde. Nedenfor et screenshot af Nightingale samt Envy Code R i aktion.

.NET, ASP.NET , ,

Podcast om ASP, ASP.NET og PHP

13. februar 2010

For nogle dage siden deltog jeg i en podcast primært omhandlede ASP, ASP.NET og PHP. Podcasten er et slags interview mellem Daniel Mellgaard Frost, Developer Evangelist i Microsoft Danmark, samt altså undertegnende og meget kort fortalt får du i den lidt historie om min baggrund, lidt om min nutid samt nogle tanker fx omkring religionskrig mellem, valg af og hjælpemuligheder i forskellige sprog/teknologier.

Jeg har endnu ikke turde høre podcasten igennem selv da jeg ser det som værende med stor fare for at sidde tilbage med en enormt nedtryk følelse efter at have hørt ens egne fejl såsom skæv accent, talebøffer, tekniske ups'ere etc. En enkelt ting jeg dog er rimelig overbevist om er, at jeg får det gjort til en dårlig ting, at man har så stort et udvalg af løsningsmodeller i ASP.NET i forhold til mit "gamle" sprog ASP - det er selvfølgelig ikke hensigten, for mange muligheder kan give en stor frihed! Det jeg forsøger at sige med det er, at de mange måder at kunne løse den samme udfordring på i mine øjne er med til at gøre det sværere dels at komme i gang med og dels at få hjælp til ASP.NET.

Men lyt selv her; Frosts Podcast Show #16 – Rundt om ASP, ASP.NET og PHP med Kim Larsen

ASP, Privat, ASP.NET, .NET , , ,

Gratis kontroller fra DevExpress

13. december 2009
Uanset om du udvikler winforms, ASP.NET, Silverlight eller WPF vil DevExpress bestemt være et besøg værd da de udvikler nogle i mine øjne langt hen ad vejen fantastiske kontroller - og det bedste af de hele er endda at man kan downloade 60 gratis kontroller fra dem. Gratis-pakken indeholder for det meste videreudviklede standard-kontroller som fx TextEdit, MemoEdit, CheckEdit og ListBoxControl hvor man skal op og købe en licens for at få adgang til de mest spændende kontroller til fx rapporter, kalendre, charts og grids, men som en start giver gratis-pakken i hvert fald nogle interessante muligheder.

Det jeg primært mener DevExpress er lykkedes med er at give deres kontroller er design og brugervenlighed samt at indbygge muligheder man til tider godt kan savne i standard-kontrollerne fra Microsoft - til gengæld kræver de helt store kontroller fra DevExpress også godt med tid at sætte sig ind i for at man kan danne sig bare lidt overskuelighed over dem. Skal man nævne noget negativt må det dels være, at kontrollerne til ASP.NET kan være meget klient tunge og at de, måske ikke så meget de små kontroller i gratis-pakken men nok mere de store og komplicerede, ikke er helt fejlfrie og det kan koste en del tid at finde ud af om fejlen ligger i ens egen kode eller i kontrollen - heldigvis har DevExpress et godt forum og et rigtig godt support-center, hvor man udover kodehjælp også ofte ret hurtigt får bugfixes til de fejl man måtte finde.

Teknisk giver kontrollerne selvfølgelig en del, men personligt er jeg nok mest glad for at få adgang til at kunne arbejde med nogle designede kontroller fremfor bare standard-grå Microsoft firkanter. Herunder i hvert fald en oversigt over kontrollerne fra gratis-pakken.



Udover kontroller som ovenstående udvikler DevExpress også enkelte Visual Studio Productivity Tools, bl.a. et ret godt Refactor produkt.

ASP.NET, .NET , , , , , ,

Korrekt visning af æøå - character encoding

31. juli 2009

I en tidligere artikel her på siden forsøgte jeg at komme med et opråb om korrekt brug af DOCTYPE og valid kode da det så ud til, at mange havde deres egen definition af, hvordan HTML kode kunne struktureres - og lige som om at det ser ud til at problemer med DOCTYPE og invalid HTML er lidt et "mode-problem" i øjeblikket lader det også til, at mange har problemer med deres encoding (tegnsæt) selvom dette også er en udfordring, der har eksisteret så længe man har skrevet web - så nu må vi hellere forsøge at rettet op på det.

Hvad består fejlen i og hvornår

Kort fortalt handler problemet med encoding om, at hvis man ikke har styr på encodingen i sin applikation og fx kører med flere forskellige i de forskellige lag i applikationen, så er der stor risiko for problemer med æøå og andre special karakterer på sin hjemmeside. Problemet omhandler ikke kun dynamiske applikationer - også simple statiske html-sider er ramt. Værst af alt, så er der modsat valid HTML-kodning reelt meget få ting at holde styr på her, men heldigvis er løsningerne langt hen ad vejen også rimelig simple.

Selvom det ikke bliver til meget kode, vil jeg i artiklen tage udgangspunkt i ASP.NET bare for at have et fast holdepunkt, men udfordringerne med korrekt tegnsæt kan lige så vel ramme klassisk ASP, PHP og altså selv simpel HTML.

Valg af encoding

Der findes ikke et endeligt svar på hvilken encoding man skal gå efter - men jeg kan ikke komme på en grund til ikke at vælge UTF-8 (Unicode Transformation Format 8-bit) hvorimod der er flere grunde til ikke at vælge det i Danmark nok mest kendte og brugte, ISO-8859-1, da det fx må betragtes som værende forældet da flere JavaScript-funktioner er udgået til fordel for tilsvarende Unicode-funktioner. Så selvom ISO-8859-1 flere steder anses som dét man benytter på hjemmesider i Danmark og vesteuropa så er min mening, at UTF-8 er det eneste rigtige valg i dag.

Encoding på filen

Det første sted at starte med det korrekte tegnsæt er allerede når vi laver vores filer, og det er nok her de fleste går fejl da de færreste er opmærksom på, at det har noget at sige og måske endda slet ikke er opmærksom på, at filer kan overhovedet gemmes med forskellig encoding. Visual Studio opretter som udgangspunkt filer i UTF-8, så i bund og grund behøver vi ikke bekymre os om det store her efter vores valg af netop UTF-8, men vil vi gerne være sikre kan vi åbne vores fil og klikke på Advanced Save Options i File-menuen for at se filens nuværende format og eventuelt gemme den med en ny encoding. Notepad er er også et godt lille program til at se filens encoding i, nemlig ved at klikke på Gem som og se hvilket format der står under Kodning - det "farlige" ved Notepad er, at de fleste vil opleve, at den som standard gemmer nye filer i ANSI og ikke UTF-8, og genkender Notepad ikke formatet på den fil man åbner vil det derfor også være ANSI, der gemmes i hvis man gemmer filen igen og dermed overskrive man det eksisterende format.


Encoding i HTML koden

Dette punkt er det nok de færreste der er i tvivl om så det bliver meget kort - i HTML kan vi benytte meta til at sende informationer om vores dokument til klienten, og en af de informationer vi bør sende med er Content-Type;

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

Encoding på data(basen)

Langt de fleste applikationer i dag er dynamisk opbygget ud fra data i et lager - mest oplagt selvfølgelig en database, som er det jeg vil tage udgangspunkt i selvom det bliver relativt kort da korrekt database-opsætning kan være en videnskab i sig selv - og her er encoding altså bestemt heller ikke uden betydning.

Præcis hvordan encodingen, og dataene generelt, håndteres her er lidt forskelligt fra den ene database til den anden så sæt dig godt ind i den database du arbejder med. Taler vi MySQL kan man sætte tegnsættet direkte på databasen og i MSSQL kan lidt af styringen ligge i valg af datatype, hvor nchar, nvarchar og ntext til unicode (hvilket reelt vil sige, at den valgte collation kun styrer sortering og ikke tegnsæt) og char, nvarchar og text til ikke-unicode (som altså styres af collation så æøå kun kan gemmes ved korrekt valg af collation), men her er det også værd at overveje performance ind i valget da unicode datatyperne er tungere at arbejde.

Men ellers ligger det vigtigste tiltag omkring encoding-opsætningen i valget af ens collation - collations handler ikke kun om encoding men også om sortering og sammenligning af data - et simpelt eksempel på dette kunne være en numeriske collation, der sorterer 1 før 2 eller en karakter collation, der bestemmer om hvorvidt a er det samme som á eller ej, men det er ikke desto mindre vigtigt at tage stilling til.

Encoding fra serveren

Det sidste sted det kan gå galt er i forhold til hvilken encoding serveren sender dokumentet afsted i - og her ved jeg at flere webhoteller vælger at sender ISO-8859-1 som standard da det stadig er det format langt de fleste vælger og dette betyder altså, at vi har noget at skal tage forhold for med vores valg af UTF-8. Heldigvis er det ret simpel at styre da vi i vores web-config kan tilføje følgende til at overskrive webhotellets valg;

<system.web>
  <
globalization responseEncoding="utf-8" requestEncoding="utf-8" fileEncoding="utf-8" />
</system.web>


Tilsvarende muligheder har vi selvfølgelig til rådighed i fx PHP gennem .htaccess.

Vil du se hvad serveren sender af sted sammenlignet med din meta kan du gå ind på http://validator.w3.org/, vælge More Options og sætte hak i Verbose Output før du validerer dit dokument - er der uoverenstemmelser mellem dokumentets og serverens format vil du her få besked om det.

Ikke flere problemer med æøå

Nu har vi endelig fået styr på hvilke 4 flaskehalse der er for at få æøå vist korrekt på vores hjemmeside - så dem ser vi selvfølgelig ikke flere af fremover :)

(X)HTML, ASP, ASP.NET

MailDefinition - skabeloner til email-udsendelse

28. juli 2009

Er der noget udviklere kan lide så er det (blandt andet) at kunne benytte hurtige genveje til at løse ofte mødte problemer, let overskuelige løsninger og mulighed for at ændre design uden at skulle pille direkte i kode - og alle disse ting er MailDefinition med til at løse når udfordringen er at sende emails fra vores ASP.NET applikation.

Det er en ret simpel operation at sende emails i .NET da vi har adgang MailMessage i System.Net.Mail - hvordan MailMessage nærmere fungerer og hvilke muligheder vi har i den vil jeg ikke komme ind på da den er forholdsvis lige til samt rimelig velbeskrevet på nettet i forvejen, men jeg vil lige give et hurtigt eksempel på hvordan jeg så godt som altid ser MailMessage blive brugt - altså uden MailDefinition - så alle er med på hvad vi taler om.

Web.Config

Først sætter vi vores SMTP konfiguration op i Web.Config så vi kan slippe for at have fx mail og standard fra-mailadresse indtastet flere steder direkte i vores applikation;

<system.net>
  <
mailSettings
>
    <
smtp deliveryMethod="Network" from="noreply@domain.dk
">
      <
network defaultCredentials="true" host="smtpservername"
/>
    </
smtp
>
  </
mailSettings
>
</
system.net>


Send mail uden MailDefinition

Herefter kan vi sende sende emails på denne måde;

string oVariabel = "skabelon";

MailMessage oMailMessage = new MailMessage();
oMailMessage.From =
new MailAddress("webmaster@domain.dk");
oMailMessage.To.Add(
new MailAddress("modtager@otherdomain.dk"));
oMailMessage.Subject =
"Mail emne";
oMailMessage.Body =
"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"><html><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /></head><body>Mail indhold - din super hemmelige variabel er: " + oVariabel + ".</html></body>";
oMailMessage.IsBodyHtml =
true;

SmtpClient oSmtpClient = new SmtpClient();
oSmtpClient.Send(oMailMessage);

Ovenstående kode fejler for så vidt intet, vores email bliver sendt ud med det ønskede indhold og udseende til de ønskede modtagere. Udfordringerne i ovenstående metode er bare dels, at opsætningen af indholdet - i dette tilfælde vores HTML - kan være lidt besværlig at overskue da den bare består af en lang tekst-streng og dels, at ændringer i mailens opsætning eller indhold kræver ændringer direkte i vores kode hvilket vil kræve ny build eller publish af vores kode.

Disse ting kan vi selvfølgelig vælge at leve med - men hvorfor ikke vælge en lettere mulighed, nemlig den ofte oversete MailDefinition, som netop gør, at vi fx kan have vores mailskabeloner liggende adskilt fra vores kode, hvilket giver let mulighed for at opsætte vores HTML, og som ikke kræver ændring i vores kode? Det ville jeg vælge så her kommer et eksempel.

Skabelonen

Det første vi gør er at oprette vores skabelon og det gør vi i form af fx en ganske almindelig HTML-fil - de "magiske" ting i skabelonen er de to variabler EMAIL og MESSAGE omgivet af << >> da det er disse vi igennem vores MailDefinition kan erstatte til at være den dynamiske del af indholdet;

<!
DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<
html xmlns="http://www.w3.org/1999/xhtml">
<
head>
<title>Kontakt</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</
head>
<
body>
<h1>Henvendelse fra domain.dk</h1>
<h2>Fra email</h2>
<<EMAIL>>
<br />
<h2>Besked</h2>
<<MESSAGE>>
</body>
</
html>

Send mail med MailDefinition

Herefter benytter vi selvfølgelig stadig MailMessage, men indholdet styrer vi nu ud fra vores MailDefinition og skabelon;

MailDefinition oMailDefinition = new MailDefinition();
oMailDefinition.BodyFileName =
"~/skabeloner/skabelon.html";
oMailDefinition.From = "webmaster@domain.dk";

Dictionary<string, string> oReplacements = new Dictionary<string, string>();
oReplacements.Add(
"<<EMAIL>>", "modtager@rotherdomain.dk");
oReplacements.Add(
"<<MESSAGE>>", "Her er en besked");

MailMessage oMailMessage = oMailDefinition.CreateMailMessage("dinmail@domain.dk", oReplacements, new LiteralControl());
oMailMessage.Subject =
"Ny mail fra domain.dk";
oMailMessage.IsBodyHtml =
true;

SmtpClient oSmtpClient = new SmtpClient();
oSmtpClient.Send(oMailMessage);


Der der sker i ovenstående kode er, at vi selvfølgelig importerer skabelonen, dernæst laves en Dictonary med det formål at erstatte variablerne i skabelonen med vores reele ønskede værdier, så laver vi et MailMessage-objekt ud fra MailDefinition-objektet og til sidst sender vi mailen afsted. Dette er selvfølgelig lidt mere kode end det første eksempel - men ofte kan det være lettere både at opbygge og vedligeholde sådan en løsning.

Ovenstående eksempler er kun simple eksempler men det er tilstrækkeligt for at komme i gang med denne ofte oversete MailDefinition. Ved siden af disse eksempler, uanset om du benytter skabeloner gennem MailDefinition eller ej, er det også vigtigt at overveje korrekt håndtering af adresser hvis man sender ud til mere end én email-adresse (så ikke alle modtagere kan se andre modtageres adresser) ligesom det, hvis man vælger at sende HTML-mails ud, bestemt også er værd at overveje at sende en plaintext-version ud sammen med HTML-versionen da mailprotokollen netop understøtter dette.

Nyttige links

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.maildefinition.aspx - MailDefinition Class

http://msdn.microsoft.com/en-us/library/system.net.mail.mailmessage.aspx - MailMessage Class

ASP.NET

Health Monitoring - overset feature

2. juli 2009

I desværre rigtig mange applikationer lægges der meget lidt eller måske endda slet ingen vægt på overvågning - og det gælder både den generelle brug af applikationen, applikationens helbred men i højere grad også fejl i systemet. Og jo - selv du kan overse mulige fejl-kilder så din applikation fejler! Overvågning er da også klart et let område at springe over da det jo som sådan ikke bidrager til noget synligt funktionalitet i applikationen men bare kører usynligt (og måske endda ubrugt) i baggrunden og det har let kunnet koste en masse tid at udvikle eller betydet implementering af 3. parts software - og med det i tankerne er det underligt at så umiddelbart få kender til Health Monitoring i ASP.NET.

Health Monitoring kom med i ASP.NET 2.0 og er, modsat hvad navnet ellers måske kunne antyde, ikke kun et en låst overvågnings-feature men et lille og udvidelsesmuligt framework til at fange og sende events i din applikation - kort fortalt vil det være muligt fx at sende egne events, fange systemfejl og sende "heartbeats" med nyttig runtime information og informationerne kan fx sendes pr email, gemmes i SQL Server eller i Windows Event Log. Opsætningen af Health Monitoring sker alene i din web.config og det er meget simpelt og lynhurtigt - for at have bare et lille overblik over hvad det hele handler om kan vi opsætte et hurtigt eksempel.

Fang alle fejl og send til en email

Først opsættes mail-informationerne:

<system.net>
  <
mailSettings>
    <
smtp deliveryMethod="Network">
      <
network defaultCredentials="true" host="smtpservername" />
    </
smtp>
  </
mailSettings>
</
system.net>

Herefter selve Health Monitoring:

<
system.web>
 
<healthMonitoring enabled="true">
    <
eventMappings>
      <
add name="AlleFejl" type="System.Web.Management.WebBaseErrorEvent, System.Web,Version=2.0.0.0,Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" startEventCode="0" endEventCode="2147483647" />
    </
eventMappings>

    <
providers>
      <
add name="MinMailWebEventProvider" type="System.Web.Management.SimpleMailWebEventProvider" to="minmail@domain.dk" from="noreply@domain.dk" buffer="false" subjectPrefix="Applikationsfejl på domain.dk" />
    </
providers>

    <
rules>
      <
add name="Fang alle fejl" eventName="AlleFejl" provider="MinMailWebEventProvider" minInterval="00:05:00" />
    </
rules>
  </
healthMonitoring>
</system.web>


Med dette i vores web.config vil vi nu modtage en fejlmeddelelse indeholdende vigtige informationer via email om fx selve fejlen og hvorfra forespørgslen kom hver gang der opstår et problem i vores applikation. Vi vil dog maximalt modtage en mail hver femte minut pr opstået event, det vil altså sige, at hvis den samme event opstår 7 gange inden for 5 minutter fra første gang eventen opstod vil vi stadig kun modtage én mail - dette forhindrer os i at blive helt oversvømmet af mulige periodiske fejl.

Kort fortalt om de tre elementer i Health Monitoring, så benyttes eventMappings til at opsætte en brugbart og let læseligt navn for de ønskede events, providers er en liste bestående af hvad vi kan kalde "modtagere" af de ønskede events og i rules-sektionen sammensætter vi hvilke modtagere, der skal modtage hvilke events. Dette betyder, at vi har rigtig mange muligheder for konfigurationen - vi kan fx gemme informationer flere steder samtidig eller dirigere fejlbeskeder hen til relevante modtagere ud fra eksempelvis typen af fejl.

Log fejl i database

Ovenstående eksempel er ret lige til - lidt kode i web.config-filen og vi er kørende - men vil vi i stedet gemme Health Monitor oplysningerne i databasen skal vi forberede databasen på det først. Databasen forberedes ved at køre ASP.NET SQL Server Registration Tool (aspnet_regsql.exe i %WINDOWS%\Microsoft.NET\Framework\version) - dette gøres i en command-promt ved at eksekvere "aspnet_regsql.exe -E -S servernavn -d databasenavn -A w" for en trusted connection eller "aspnet_regsql.exe -U brugernavn -P password -S servernavn -d databasenavn -A w" hvis der benyttes SQL authentication. Denne operation tilføjer fx nødvendige tabeller og stored procedures til databasen.

Til sidst skal vi lige have tilpasset web.config-filen så vi dels sørger for at have en connection til databasen og dels sørge for at Health Monitoring også benytter denne connection.

Først forbindelsen til databasen:

<connectionStrings>
  <
add name="MinConnection" connectionString="Data Source=localhost;Initial Catalog=DinDatabase;Integrated Security=SSPI;" />
</
connectionStrings>

Dernæst sætter vi healthMonitoring-elementet op præcis som i mail-eksemplet, dog med den undtagelse at vi altså nu benytter en anden provider:

<system.web>
  <
healthMonitoring enabled="true">
    <
eventMappings>
      <
add name="AlleFejl" type="System.Web.Management.WebBaseErrorEvent, System.Web,Version=2.0.0.0,Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" startEventCode="0" endEventCode="2147483647" />
    </
eventMappings>

    <
providers>
      <
add name="MinSqlWebEventProvider" type="System.Web.Management.SqlWebEventProvider" buffer="false" subjectPrefix="Applikationsfejl på domain.dk" />
    </
providers>

    <
rules>
      <
add name="Fang alle fejl" eventName="AlleFejl" provider="MinSqlWebEventProvider" minInterval="00:05:00" />
    </
rules>
  </
healthMonitoring>
</
system.web>

Kun en lille del af det

De to nævnte eksempler er utrolig brugbare og her taler jeg af egen erfaring - selvom jeg selvfølgelig nødigt vil indrømme, at jeg også kan lave fejl - men heldigvis skal det nævnes, at langt de fleste fejl-meldinger jeg støder på er forsøg på misbrug i applikationerne - fx manipulation med URL eller forsøg på spam.

Eksemplerne er ikke kun brugbare i mange specielt mindre applikationer - de er også meget meget grundlæggende og simple eksempler på de muligheder man har i Health Monitoring. Specielt er mulighederne for at lave custom events en god feature - fx kunne man forestille sig relevansen i at sende events afsted når der kom til- og frameldinger på et nyhedsbrev; i stedet for at programmere sig ud det kunne man lave 2 custom events og fange dem med Health Monitoring og hvis man på et tidspunkt kun ville modtage besked om tilmeldinger men ikke frameldinger skulle der kun en ændring i web-config til og ingen kode-ændringer. Også heartbeat-muligheden er spændende da vi med denne kan bestemme et interval hvor ud fra vi vælger at logge om applikationen er kørende - men nu hvor du har fået kendskabet til denne alt for oversete feature skal der også være lidt tilbage til egne opdagelser.

Herfra er tilbage kun at sige held og lykke med at fange dine ukendte fejl.

Nyttige links

http://msdn.microsoft.com/en-us/library/bb398933.aspx - ASP.NET Health Monitoring Overview
http://msdn.microsoft.com/en-us/library/ms998306.aspx - How To: Use Health Monitoring in ASP.NET 2.0

ASP.NET

SQL injections - mere end bare et pling

14. juli 2008

Den seneste tid har jeg rundt omkring i diverse fora og nyhedssites set en masse tråde, flere end hvad jeg husker er normalt og derfor denne artikel, omkring sites hvis udseende eller indhold pludselig er blevet ændret - og i mange tilfælde skælder man ud på fx webhotellet fordi man mener at der her er et sikkerhedshul. I langt de fleste tilfælde skyldes det dog formentlig bare dårlig kode; deres sites er nemlig åben for SQL injections.

SQL Injections er et spørgsmål om, at ens applikation er åben over for, at udefrakommende personer med triste hensigter kan udnytte huller i ens kode til at eksekvere utiltænkte databasekald - hvilket kan føre til usikre loginsystemer eller i værste fald direkte manipulering af data i databasen. Før jeg går videre kan du kigge på dette eksempel;

Det normale

Den mest normale opfattelse er, at SQL injection udelukkende handler om at sikre sine databasekald mod bestemte tegn, der kommer fra brugerinput på en side - har vi fx en (usikker) loginformular til et adminsystemt, hvor der skal angives brugernavn og password kunne vores SQL-sætning se sådan ud i ASP;

SQL =
"SELECT id FROM [users] WHERE [username] = '" & Request.Form("txtusername") & "' AND [password] = '" & Request.Form("txtpassword") & "'"

Denne formular ville kunne udnyttes ved fx at skrive ' OR 1=1; -- i txtusername-formfeltet og det ville resultere i dette databasekald;

SELECT id FROM [users] WHERE [username] = '' OR 1=1; --' AND [password] = 'xxx'

I dette tilfælde vil alt efter -- bliver ignoreret, tilbage står kun sammenligningen at username skal være lig '' eller at 1 skal være lig 1 og da det jo er en korrekt sammenligning har vi lige udnyttet muligheden for SQL injection og logget os ind med fri adgang til adminsystemet.

Sikringen af vores loginformular er - i hvert fald ifølge de fleste artikler om emnet - ret lige til da vi bare skal sikre os imod pling (') da det er dette tegn der laver al balladen. Dette kan være gøre vha en simpel replace i vores SQL;

SQL = "SELECT id FROM [users] WHERE [username] = '" & Replace(Request.Form("txtusername"),"'","''") & "' AND [password] = '" & Replace(Request.Form("txtpassword"),"'","''") & "'"

Nu vil forsøget med at indtaste ' OR 1=1; -- i txtusername-formfeltet resultere i en afvisning af loginforsøget (medmindre der da er en bruger der hedder sådan) da vores replace sikrer at plingen i brugernavnet escapes så den rigtige sammenligning sker.

Men vi mangler stadig noget

Det er somregel her de fleste stopper - men så prøv at se nedenstående eksempel. Først har vi vores SQL;

SQL = "SELECT name, description FROM product WHERE id = " & Request.Querystring("id")

Siden hvor ovenstående SQL benyttes kalder vi så vha;

domain.dk/produkt.asp?id=3

Fint nok, nu får vi produkt nummer 3 frem - men hvad sker der så nu;

domain.dk/produkt.asp?id=3;DELETE * FROM product

Nu får vi rigtig nok stadig produkt nummer 3 vist på siden men vores reele databasekald kommer til at se sådan ud;

SELECT name, description FROM product WHERE id = 3;DELETE * FROM product

Hvilket er et tilladt kald og kommer den igennem slettes alle data fra tabellen produkt umiddelbart efter vores select er udført. Ikke godt.

Løsningen 

Som det kan ses ud fra ovenstående eksempler er det altså nødvendigt at sikre sig imod SQL injections da det ellers kan få fatale konsekvenser overfor hele databasen. En mulighed er at validere alle data inden de bruges til databasekald - dvs fx sikre sig, at variablen fra ens querystring også virkelig er et tal hvis det skal bruges til at trække data ud fra product-tabellen. Men når nu der findes en bedre løsning, parameters, hvorfor så ikke benytte den? Parametre gør, at man ikke behøver at bekymre sig om SQL injection og selvom det ved første øjekast måske virker lidt mindre tilgængeligt end de sædvanlige simple SQL-statements så er de bestemt til at arbejde med og på sigt kan de endda gøre arbejdet lettere da de giver mere gennemsigtighed over for databasen. Der kunne skrives en hel artikel bare om at arbejde med parametre (og det kommer der måske også), men i første omgang vil jeg bare lægge en muligh løsning for vores to cases ovenover.

Eksempel på login

<%
Set Conn = Server.CreateObject("ADODB.Connection")
Conn.Open
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:\test\test.mdb"
Set Cmd = Server.CreateObject("ADODB.Command")
Cmd.ActiveConnection = Conn
Cmd.CommandText =
"SELECT id FROM [users] WHERE [username] = @username AND [password] = @password"
Cmd.Parameters.Append(Cmd.CreateParameter("@username", 200, 1, 50))
Cmd.Parameters.Append(Cmd.CreateParameter(
"@password", 200, 1, 50))
Cmd.Parameters(
"@username") = Request.Form("username")
Cmd.Parameters("@password") = Request.Form("password")
Set login = Cmd.Execute
  'Gør noget med login("id")
login.Close
Set login = Nothing
Set
Cmd = Nothing
Conn.Close
Set Conn = Nothing
%>

Eksempel på querystring

<%
Set Conn = Server.CreateObject("ADODB.Connection")
Conn.Open
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:\test\test.mdb"
Set Cmd = Server.CreateObject("ADODB.Command")
Cmd.ActiveConnection = Conn
Cmd.CommandText =
"SELECT navn FROM [product] WHERE [id] = @id"
Cmd.Parameters.Append(Cmd.CreateParameter("@id", 3, 1, 50, Request.Querystring("id")))
Set product = Cmd.Execute
If Not product.eof Then
 
'Gør noget med product("navn")
End If
product.Close
Set product = Nothing
Set
Cmd = Nothing
Conn.Close
Set Conn = Nothing
%>

Jeg håber at denne artikel har givet en god idé både omkring hvad SQL injections er samt ikke mindst forslag på løsninger.

ASP, ASP.NET , ,