Egen ordning på samling av data (nyckel och värde)

Vi behövde visa en samling av data i en egen ordning och varje rad skulle innehålla nyckel samt värde. Värdena skulle gå att få ut i samma ordning som vi la till dem med andra ord.

HashTable fungerar ju inte alls eftersom denna typ av samling sorteras efter de hashade nycklarna. SortedList trodde vi först skulle göra jobbet men, det framgick sen att den alltid sorterar samlingen efter nycklarna.

Efter ha läst på lite om namnrymden Collections och Collections.Specialized så hittade jag en typ av samling som klarade det vi behövde, nämligen NameValueCollection.

Här är ett kodexempel som lagrar kultur-beteckningarna tillsammans med namnet på länderna.

string strOutput=string.Empty;
NameValueCollection nvc = new NameValueCollection();
nvc.Add("sv-SE", "Swedish");
nvc.Add("da-DK", "Danish");
nvc.Add("en-GB", "English");

IEnumerator iEnumerator = nvc.GetEnumerator();
while (iEnumerator.MoveNext())
{
string strCulture = myEnumerator.Current.ToString();
string strLanguage = nvc.GetValues(strCulture)[0];
strOutput+=strLanguage+"<br />";
}

labelOutput.Text=strOutput;

Koden kommer skriva ut länderna i den ordning som de lades till i samlingen, alltså:

Swedish
Danish
English

Några artiklar som hjälpte på vägen

.NET Collection Madness Part 1

.NET Collection Madness Part 2

Hashlist - Hashtable meets ArrayList

Processing multiple string values in a collection

MSDN: NameValueCollection Class

By Jesper Lind

RSS Toolkit - Publicera och konsumera RSS-flöden

Hittade en intressant artikel av Steve Clements där han visar hur man kan bygga en RSS-läsare för att lägga in på en webbplats. Den använder AJAX-funktioner för att öppna inläggen när man läser dem. Till kodexemplet används ett speciellt RSS Toolkit som finns att läsa om på Dmitry’s blog. Där finns även en zip-fil med verktygslådan att ladda hem.

Har inte testat den själv men det verkar intressant, skriv gärna en kommentar ifall du provar på detta. Är jättenyfiken på hur det fungerar.

Man kan också läsa samma artikel om RSS-läsaren på The Code Project.

By Jesper Lind

ASP.NET AJAX 1.0 levereras i skarp version

http://www.codeodyssey.se/upload/resource/blog/NET-AJAX.png

Nu meddelas fantastiska nyheter i .NET-världen, ramverket ASP.NET AJAX 1.0 är klart och finns att ladda ner på den officiella hemsidan. Kolla även in dokumentationen som har utökats en hel del sedan beta-versionerna.

I AJAX Control Toolkit har även några nya kontroller lagts till och det finns demonstrationer på AutoComplete, Calendar, MaskedEdit och Tabs.

Så nu är det äntligen läge att börja använda denna nya teknik från Microsoft på sina skarpa projekt, utan att riskera att behöva koda om för förändringar mellan versionerna.

Via: Nikhilk.net

Läs även mer om releasen på Scott Guthries blogg där han förklarar lite om de senaste ändringarna. Värt att notera är att produkten blir historiskt, i den bemärkelsen att det är den första produkten från Microsoft som släpps som öppen källkod. Supporten kommer vara igång 24 timmar om dygnet i åtminstonde 10 år framåt.

By Jesper Lind

W3C Markup Validation Service med .NET-sidor

Körde en test med W3C Markup Validation Service för att se att min sida validerar mot XHTML 1.0 Transitional standarden och märkte att så var inte fallet. Jag har gjort lite förändringar på sidan och något hade gått snett. En bild som rendereras av en ImageButton hade helt plötsligt fått ett border-attribut. Detta är inte giltig XHTML-kod och W3C-validatorn gav följande fel:

Error Line 240, column 577: there is no attribute "border". ..."", false, false))" border="0" />

När jag kollade källkoden på sidan såg jag dock inget border-attribut på bilden. Märkligt..

Efter lite undersökning så hittade jag posten "XHTML Validation Fails due to renders a BORDER="0" output" på Microsofts forum. Det verkar röra sig om ett missförstånd mellan W3C validator and ASP.NET ramverket. Lösningen är enkel, lägg till detta i Web.Config:

<browserCaps>
<case match="W3C_Validator*">
TagWriter = System.Web.UI.HtmlTextWriter
W3CDomVersion = 1.0
</case>
</browserCaps>

By Jesper Lind

Klass-referenser till dynamiska instanser av User Controls

User Controls är smidiga att använda i .NET och ofta vill man ladda in dem dynamiskt. Då måste man referera till dem med deras egna klasstyp.

I version 1.1 var det lättare än i version 2.0 eftersom alla referenser fanns i samma assembly. Man kunde då använda kod som enligt följande.

MyUserControl_ascx myUserControl = (MyUserControl_ascx)LoadControl("MyUserControl.ascx");
myUserControl.IntProperty = 123;
myPlaceHolder.Controls.Add(myUserControl);

På många projekt som jag konverterar från 1.1 till 2.0 får jag felet:

Det gick inte att hitta typ- eller namnområdesnamnet MyUserControl_ascx (saknas ett using-direktiv eller en sammansättningsreferens?

I version 2.0 har nämligen komplileringsmodellen gjorts om en hel del och varje sida och kontroll kompileras i egna assemblys. Man måste nu tänka på att lägga in en referens på de sidorna som ska kunna använda kontrollens klasstyp. En alternativ lösning kan vara att lägga kontrollen i den speciella App_Code-mappen, men då kan man endast använda "inline-code"-modellen.

Jag tänkte nu visa några ett exempel på hur man kan referera till dynamiskt laddade User Controls, tilldela dem egenskaper och lägga till dem på sidan i en PlaceHolder. Exemplet visar hur man gör detta med både "code behind"- och "inline"-modell.

Det som är viktigt att tänka på är att referera till kontrollen med "Reference"-taggen som i mitt exempel ligger i mappen "ctrl". Observera också att när om kontrollen använder inline-kod så måste prefixet "ASP." användas på referensen till instansen.

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Reference Control="ctrl/WebUserControl_InlineCode.ascx" %>
<%@ Reference Control="ctrl/WebUserControl_CodeBehind.ascx" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Set Properties to dynamicly loaded UserControls</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:PlaceHolder ID="ph" runat="server" />
</div>
</form>
</body>
</html>

Default.aspx.cs


using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Control ctrl = LoadControl("ctrl/WebUserControl_CodeBehind.ascx");
((WebUserControl_CodeBehind)ctrl).StrProperty = "First string";
ph.Controls.Add(ctrl);

//Add linebreak
ph.Controls.Add(new LiteralControl("<br />"));

Control ctrl2 = LoadControl("ctrl/WebUserControl_InlineCode.ascx");
((ASP.WebUserControl_InlineCode)ctrl2).StrProperty = "Second string";
ph.Controls.Add(ctrl2);
}
}

ctrl/WebUserControl_InlineCode.ascx

<%@ Control Language="C#" ClassName="WebUserControl_InlineCode" %>

<script runat="server">

string strProperty = string.Empty;

public string StrProperty
{
get { return strProperty; }
set { strProperty = value; }
}
void Page_Load()
{
lbl.Text = "Property from inline-code User Control: " + strProperty;
}

</script>
<asp:Label ID="lbl" runat="server" />

ctrl/WebUserControl_CodeBehind.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUserControl_CodeBehind.ascx.cs" Inherits="WebUserControl_CodeBehind" %>
<asp:Label ID="lbl" runat="server" />

ctrl/WebUserControl_CodeBehind.ascx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class WebUserControl_CodeBehind : System.Web.UI.UserControl
{
string strProperty = string.Empty;

public string StrProperty
{
get { return strProperty; }
set { strProperty = value; }
}
void Page_Load()
{
lbl.Text = "Property from code-behind User Control: " + strProperty;
}
}


MSDN: "Creating Instances of User Controls Programmatically"

 

By Jesper Lind

Källkod för blogg-system från Castleproject.org

För ett tag sen läste jag att Castle Project går in i version beta 2, blev nyfiken och kollade hemsidan som finns på Castleproject.org. Som ofta när det gäller öppen källkod finns det mycket roligt att läsa om och välarbetade exempel.

På sidan presenteras project som t ex MonoRail (AJAX-ramverk inspirerat av Actionpack Ruby on rails) och ActiveRecord (Implementering av Wiki: Active record pattern).

Just Caste ActiveRecord tyckte jag var väldigt intressant och i handledningen visas ett riktigt bra exempel på hur en blogg-applikation kan konstrueras. Rekommendas till dig som vill lära dig mer om active records eller se hur en bra databasdesign för ett blogg-system kan se ut. Man visar sen klasserna och även hur man lägger till relationerna.

By Jesper Lind

Vackra URL:er med ASP.NET (en bit kvar)

För ett tag sen skrev jag inlägget om hur man kan skriva om webbadresser med Asp.Net (eller snarare om alla de svårigheter som är involverade). Många utvecklare har tacklats med problemet och jag tänker inte gå något djupare på de tekniska detaljerna nu. Ska dock spara lite nya länkar här som jag hittat.

Först en artikel som inte har med just ASP.NET att göra men visar exempel på hur bra och beskrivande webbadresser bör se ut.

Sen en adress till en Wiki helt dedikerad åt välskrivna url:er, där man kan läsa "ASP.NET - Well Designed Urls Wiki", och innehåller många relaterade länkar.

Vad jag kommit fram till är att det nog är smartast att vänta tills IIS 7 finns att installera till Window 2003 (om detta någonsin blir möjligt, uppgradera till Longhorn Server blir nog det som gäller). IIS 7 kommer nämligen innefatta ett mycket bättre stöd för detta som man kan läsa på Scott Guthrie's blogg:

Several people have asked why the built-in URL Mapper in ASP.NET 2.0 doesn't support regular expressions. There were actually a few reasons for this -- one of the big ones being that just about the time we were about to consider adding it my team started also working on IIS7. We realized that a full-featured version would want/need to take advantage of some of the new features in IIS7 as well as the support all content types (in particular -- images and directories). So we postponed making it feature rich until a future version.

Själv är jag glad att jag inte har börjat försöka skriva om url:er på IIS 6 ännu, speciellt när man läser inlägg som "Making URL rewriting on IIS 7 work like IIS 6". Frågan är bara om man kan vänta, att ha snygga webbadresser känns ganska lockande, speciellt ur sökoptimerings-synpunkt. Men tänkt bara på att när IIS 7 släpps som riktig server-version så kan du tvingas att göra om det hela igen.

Om du vill ha några begynnande tankar från en som börjat testa url-omskrivning med IIS 7 på Vista, kan du läsa Dennis' blog.

By Jesper Lind

Få fram antal rader i en GridView

En kort beskrivning hur man kan få fram antal raden som visas i en GridView, som är kopplat till en SqlDataSource, genom OnSelected event. Och då snackar vi som vanligt .NET. Koden för GridView och SqlDataSource:

<asp:Label id="lblProductTitle"><asp:GridView ID="gvProduct" EnableViewState="true"
DataSourceID="sdsProduct"
DataKeyNames="Id"
AllowPaging="true"
AllowSorting="true"
AutoGenerateColumns="false"
runat="server">

<Columns>
<asp:TemplateField HeaderText="Bild">
<ItemTemplate>
<asp:PlaceHolder ID="phThumb" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="Artnr" DataField="Id" ItemStyle-Wrap="false" SortExpression="Id" />
<asp:BoundField HeaderText="Produktnamn" DataField="ProductName" ItemStyle-Wrap="false" SortExpression="ProductName" />
<asp:BoundField HeaderText="Märke" DataField="Brand" ItemStyle-Wrap="false" SortExpression="Brand" />
<asp:BoundField HeaderText="Kategori" DataField="Category" ItemStyle-Wrap="false" SortExpression="Category" />
<asp:BoundField HeaderText="Pris" DataField="Price" ItemStyle-Wrap="false" SortExpression="Price" DataFormatString="{0:c0} kr" />
</Columns>
</asp:GridView>

<asp:SqlDataSource
ID="sdsProduct"
runat="server"
EnableViewState="true"
SelectCommand="SELECT * FROM Product"
OnSelected="sdsProduct_Selected"
ConnectionString="<%$ appSettings:ConnectionString %>"
DataSourceMode="DataSet">
</asp:SqlDataSource>

 

Och koden bakom som skriver ut antalet rader i gridden:

protected void sdsProduct_Selected(object sender, SqlDataSourceStatusEventArgs e)
{
int intTotalRecord = Convert.ToInt32(e.AffectedRows.ToString());
if (intTotalRecord > 0)
{
lblProductTitle.Text = intTotalRecord.ToString() + " produkter hittades";
}
else
{
lblProductTitle.Text = "Inga produkter hittades";
}
Trace.Write("intTotalRecord = " + intTotalRecord);

}

By Jesper Lind

Farväl World Wide Web

Begreppet World Wide Web blev enligt Wikipedia allmänt känt för lite mer än 15 år sedan, närmare bestämt den 6 augusti 1991. Alla som surfar på nätet känner till förkortningen och har med största säkerhet knappat in kombinationen ett antal gånger.

Själv är jag, precis som QuadsZilla på seoblackhat.com, inget stort fan av onödiga tecken. Företeelsen att använda www i web-adresser är definitivt på väg att försvinna och fler och fler förutspråkar nu för pensioneringen av www.

På min egen webbplats bestämde jag mig således för att slopa den onödiga förkortningen för gott. Om man knappar in www före hemsidans adress så ser en kodsnutt till att lämna ett "301 Moved permanently"-meddelande och skickar vidare till adressen utan www.

Jag genomförde förändringen för några dagar sedan och nu väntar jag bara på hur sökmotorerna kommer att hantera förändringen. Förhoppningsvis kommer alla länkar i Google och resten av sökmotorerna bara visa den kortare varianten utan www.

Gjorde även en annan förändring som jag hoppas ska förbättra mina resultat i sökmotorerna. Tidigare gick länken "Blog" till sidan default.aspx och jag tror att detta resulterade i att sökmotorerna hittade två olika versioner av min förstasida. Det har känts lite som att sökmotor-botsen har haft lite "hicka" när de har spindlar sajten och min första sida har antagligen hamnat i "duplicate content"-filtret. Så ett tips är att se till att inga länkar på din hemsida leder till index.htm, index.php, default.aspx eller liknande, utan istället direkt till förstasidan som i mitt fall är http://codeodyssey.se/. Förhoppningsvis ska det bli lite bättre nu.

Här under kan ni koden från min Global.asax som tar hand om detta.

<%@ Application Language="C#" %>

<script runat="server">

static string strRootUrl = ConfigurationManager.AppSettings["RootUrl"];

void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup

}

void Application_End(object sender, EventArgs e)
{
// Code that runs on application shutdown

}

protected void Application_BeginRequest(Object sender, EventArgs e)
{
string strFullPath = HttpContext.Current.Request.Url.ToString();
//Response.Write(strFullPath);
string strCurrentPath = HttpContext.Current.Request.RawUrl.ToLower().Remove(0, 1);
if(strFullPath.IndexOf("http://www")!=-1)
{
string strNewUrl = strRootUrl + strCurrentPath.Replace("default.aspx","");
Response.Clear();
Response.Status = "301 Moved Permanently";
Response.AddHeader("Location", strNewUrl);
Response.End();
}
}

void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs

}

void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started

}

void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends.
// Note: The Session_End event is raised only when the sessionstate mode
// is set to InProc in the Web.config file. If session mode is set to StateServer
// or SQLServer, the event is not raised.

}

</script>

Läs mer om 301 redirect med ASP.NET i ett inlägg jag skrivit tidigare.

By Jesper Lind