Verktyg för att kontrollera redundans i CSS-mallar

På långvariga projekt är det lätt hänt att CSS-mallarna växer sig väldigt stora, och det är svårt att hålla reda på vilka klasser som verkligen används.

Infovore har försökt tackla detta problem med verktyget CSS Redundancy Checker som finns att ladda hem på Google Code. Man måste ladda hem det och köra det lokalt och enligt beskrivning ska det söka igenom koden och identifiera CSS-klasser som inte används. Det fungerar bara med HTML-filer, ej dynamiskt genererade webbplatser.

Nu väntar vi bara på en online-version. Eller är det nån som vet om det redan finns en sådan tjänst?

By Jesper Lind

Förtydligande: Vi jobbar inte för släktforskningssajten Geni.com!

Många hittar till vår blogg genom sökningar som har med släktforskningssajten Geni.com att göra, som förresten nyligen rapporterade att de nu har fått 5 miljoner registrerade användare på bara 5 månader.

Vi har skrivit om sajten två gånger och det är kul att vi har kunnat tipsa så många om denna fantastiskt roliga sajt.

Men några har tydligen missförstått det hela och tror att vi på något sätt jobbar åt Geni. Vi får en del mail som undrar om vi kan ordna borttappade lösenord eller lösa andra supportfrågor.

Svaret är nej, vi har inte någon möjlighet att fixa några bortglömda lösenord, använd istället formuläret för lösenordspåminnelse på Geni's hemsida.

Men om du vill diskutera sajten och dess funktioner så är du välkommen att skriva en kommentar här nedan.

By Jesper Lind

Ändra owner på tabell i SQL Server 2000

Hur man ändrar owner på en tabell i SQL Server 2000, har jag undrat länge över. Därför värt att göra en minnesanteckning i bloggen, när jag väl har googlat upp det.

En webbgypsy förklarar att man anropar en stored procedure genom Query Analyser, så här:

exec sp_changeobjectowner 'OldOwnerName.MyTableToModify','MyNewOwner'
By Jesper Lind

CSS Friendly Control Adapters

Nu har jag testat att använda CSS Friendly Control Adapters som jag nämde förra året. De fungerar verkligen magiskt bra och man får en mycket mer CSS-vänlig HTML-kod från kontrollerna i Asp.Net.

Hur man installerar adaptrarna

Det finns två olika sätt att lägga till adaptrarna som även CodeClimber förklarar.

Dels det lite omständiga sättet som Microsoft har utvecklat, här måste man lägga till speciella javascript och CSS bibliotek. Då får man dock större kontroll över koden om man vill modifiera den själv.

Vill man göra det enklare för sig så kan man använda Brian DeMarzo's variant som nu finns som ett eget projekt på CodePlex. Microsoft har lämnat sina över hela projektet till CodePlex så det är där som utvecklingen kommer att ske i framtiden.

Instruktionerna är enkla och görs genom tre steg:

  1. Ladda hem det senaste filerna.
  2. Lägg till en referens till CSSFriendly.dll i din webb-applikation.
  3. Lägg till CSSFriendlyAdapters.browser konfigurationen till App_Browsers mappen.

Kan ställa till problem med ViewState

När jag använde de vanliga adaptrarna (inte CSSFriendly.dll) Stötte dock inledningsvis på ett error:

The Controls collection cannot be modified because the control contains code blocks (i.e. <% ... %>).

Är inte säker på vad det berodde på, men hittade en lösning i en tråd på .NET-forumet.

Problemet var i TreeView och efter jag la in följande kod så fungerade det.

private string _strviewState = string.Empty;

private string ViewStateID
{
get { return Control.ClientID + "__VIEWSTATE"; }
}

...

protected override Object SaveAdapterViewState()
{
string retStr = "";
TreeView treeView = Control as TreeView;
if ((treeView != null) && (_viewState != null))
{
if ((_viewState != null) && (Page != null) && (Page.Form != null))
{
Page.ClientScript.RegisterHiddenField(ViewStateID, _strviewState);
string script = "document.getElementById('" + ViewStateID + "').value = GetViewState__AspNetTreeView('" + Extender.MakeChildId("UL") + "');";
Page.ClientScript.RegisterOnSubmitStatement(typeof(TreeViewAdapter), ViewStateID, script);
}
retStr = ViewStateID + "|" + ComposeViewState(treeView.Nodes, "");
}
return retStr;

Observera att jag koden skiljer sig lite från den i forum-tråden. Så jag kan inte lova att viewstate verkligen fungerar med denna modifikation. I mitt fall behöver jag inget viewstate så jag nöjer mig där.

By Jesper Lind

IDG kopplar upp mot Twingly

IDG - Sveriges största samlingsportal för IT, sluter upp ett avtal med Primelabs bloggindexeringstjänst Twingly. Man ger även en förklaring till bloggare hur det går till att få sin blogg indexerad hos Twingly.

Ibörjan av året kopplade DN och SvD upp mot Twingly och det blev väldigt väl bemött av bloggare i sverige.

Det nya tillskottet från IDG tycker jag är kul eftersom det med säkerhet kommer att öka intresset och aktiviteten runt IT-relaterade artiklar i Sverige.

IDG har ju länge haft kommentarsfunktion till artiklarna. Ibland är det intressanta men oftast handlar det om flamewars mellan PC och MAC-användare och än mer ofta kritik mot IDGs artiklar eller funktionaliteten på webbplatsen.

En återkommade kampanj har varit "Jag vill ha tillbaka EDIT-funktionen NU" där kommenterare har använt sina signaturer med denna slogan. Rätt tjatigt kan man tycka och i största allmänhet tycker jag det är rätt tråkig stämning på kommentarerna på IDG.

Nu har dock IDG gett med sig och infört den efterlängtade EDIT-funktionen. Men nu när den väl är införd verkar det finnas an bugg på sajten så att användarna inte kan ändra sina slogans längre, lite ironi. Ser även att en nyfiken användare har testat maxlängden på kommentarerna och lyckats posta en spam-kommentar på inte mindre än 1451531 tecken (ca 1.38MB). Lite väl frikostigt av IDG's programmerare kanske?

Nu kan man hoppas att det blir bättre stämmning när många andra bloggar och flöden kopplas in på sajten och tillför något till diskussionen. Man har även lagt länkar till de sociala nätverken del.icio.us och hypa.

IDG är den första sajten som använder Twinglys nya widgetteknologi som gör det väldigt lätt för sajter att implementera funktionalliteten.

Webbsnack skriver att RSS-flöden för bloggarna syns vid länkarna och underlättar prenumerering.

Men den nya typen av Twingly-teknik har också en dålig mindre bra sida ut sökoptimeringssynpunkt. Eftersom den laddas in med Ajax-teknik så kommer inte sökmotorerna kunna se länkarna alls. Man får alltså ingen länkkraft tillbaks från IDGs webbsajt om man länkar till den.

By Jesper Lind

Hotfix för problem med valideringsfunktioner i .NET Ajax

Validerings-funktionerna i .NET har haft en del problem genom versionerna. I en version (har för mig att det var .NET 1.1) fungerade de knappt över huvudtaget. Men i 2.0 hade Microsoft löst de första problemen.

När sen MS Ajax släpptes blev det återigen en del buggar och problem. Det märkte jag häromdan när jag försökte ha validering på en TextBox i en wizard-kontroll som i sin tur låg inom en UpdatePanel. På första steget hade jag en TextBox med validering och där fungerade den fint. På andra steget så låg javascript-funktionerna kvar utanför UpdatePanel, men textboxen hade ju redan försvunnit och då blev det error som såg ut så här:

control has no properties
ValidatorGetValue("ctl00_mainContentPH_wizard_tbOrderId")WebResource.axd (line 104)
RequiredFieldValidatorEvaluateIsValid(span#ctl00_mainContentPH_wizard_ReqFieldOrderId)WebResource.axd (line 475)
ValidatorValidate(span#ctl00_mainContentPH_wizard_ReqFieldOrderId, "", null)WebResource.axd (line 208)
Page_ClientValidate("")WebResource.axd (line 128)
WebForm_DoPostBackWithOptions(Object)WebResource.axd (line 14)
if (typeof(control.value) == "string") {
 
Microsoft har dock gjort sitt bästa för att lösa även detta problem. Först så rekommenderades att man laddade ner en Validators.dll och mappade upp mot i Web.config.
 
Genom en kommentar hos Guttrie hittade jag info om en ny hotfix. Enligt erfarenhet när jag patchade ett Windows 2003-system fungerar den väldigt bra och man slipper att gör några ändringar i Web.config.
 
Om du inte orkar trixa för mycket med det och kan vänta så kommer en Windows Update snart med lösning.  

By Jesper Lind

Prediktiv analys - inte längre sci-fi

http://www.codeodyssey.se/upload/resource/blog/230px-AsimovOnThrone.png

Johan Röhne har skrivit en väldigt intressant artikelserie på IDG som handlar om hur man kan skåda in i framtiden med hjälp av prediktiv analys.

Det får mig att tänka på science fiction-böckerna Stiftelse-triologin av Isaac Asimov, där forskare spår framtiden baserat på forskningsgrenen psykohistoria.

Än är vi ju inte närheten av framtidsvisionerna i Asimov's böcker men det borde nog inte dröja många år innan denna forskning har förfinats. Vad kan vi för månne se för framtid genom att analysera alla de miljarder blogginlägg och profiler på de sociala nätverken?

I lite närmare tidsperspektiv kan jag definitivt se många användningsområden för prediktiv analys. Man borde t ex kunna räkna ut när sannoliken är som störst för att en kund kommer gör en ny beställning. Och då skicka ut lite extra reklam och erbjudanden för att främja detta.

Prediktiv analys är precis som allt som handlar om att se in i framtiden, väldigt intressant. Något att forska vidare på med andra ord.

Uppdatering: Ungefär på samma ämne. Data Mining skriver om en ny tjänst kallad Reputica. De ska erbjuda företag att spåra hur deras rykte om nya produkter sprider sig via de sociala nätverken. Man kan för tillfället fråga efter en inbjudan till tjänsten på hemsidan.

By Jesper Lind

Virtuellt RSS-flöde med .NET

Vi har tidigare har vi på bloggen visat hur man kan skapa en RSS-fil från poster i en databas.

Nu tänkte jag visa ett snarlikt exempel men här skriver vi flödet direkt till Response-strömmen istället för att skapa en fysisk fil. Kallar denna metoden, att leverera ett RSS-flöde "virtuellt", i brist på bättre term.

Hämtade lite inspiration från Dileno.com men använde istället min egen kod från tidigare exempel.

Själva ASPX-filen sparar jag som Rss.aspx och innehåller endast en rad kod.

<%@ Page Language="C#" Strict="False" Debug="True" Inherits="_Rss" CodeFile="Rss.aspx.cs" %>

I koden bakom hämtas posterna ur en tabell i en Access-databas. Bygger ihop en sträng med xml taggarna för RSS-definitionen och lägger sedan in den i cache. Detta för att det inte ska bli överbelastning ifall flödet anropas ofta.

using System;
using System.Data;
using System.Data.OleDb;
using System.Configuration;
using System.Text;
using System.Web;
using System.IO;
using System.Xml;

public partial class _Rss : System.Web.UI.Page
{
static string strConn = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
static string strRootUrl = "http://codeodyssey.se";

protected void Page_Load(object sender, EventArgs e)
{
Response.ContentType = "text/xml";
Response.ContentEncoding = Encoding.UTF8;
Response.Write(GetRssString());
}

//Kollar om det redan finns en sträng i cache, annars skapas en ny
protected string GetRssString()
{
string cacheName = "rss-feed";

//Hämta chachad data om det finns
if (Cache[cacheName] != null)
{
return Convert.ToString(Cache[cacheName]);
}
else
{
string newlyGeneratedRss = GenerateRss();
Cache.Insert(cacheName, newlyGeneratedRss, null, DateTime.Now.AddMinutes(20), TimeSpan.Zero);
return Convert.ToString(newlyGeneratedRss);
}
}

//Funktion som skapar en textSträng som innehåller rss-feed
protected string GenerateRss()
{
StringWriter sw = new StringWriter();
try
{

XmlTextWriter xtw = new XmlTextWriter(sw);//,System.Text.Encoding.GetEncoding("UTF-8")
xtw.Formatting = Formatting.Indented;
xtw.WriteStartDocument();

//skriv ut <rss version="2.0">
xtw.WriteStartElement("rss");
xtw.WriteAttributeString("version","2.0");

//skriv ut <channel>
xtw.WriteStartElement("channel");

//skriv ut element som tillhör <channel>
xtw.WriteElementString("title","Codeodyssey.se");
xtw.WriteElementString("link","http://www.codeodyssey.se/");
xtw.WriteElementString("description","Code Odyssey - gräver djupt i kodträsket");
xtw.WriteElementString("language","sv-SE");
xtw.WriteElementString("copyright","Copyright (c) 2004-2007 Code Odyssey");

OleDbConnection conn = new OleDbConnection (strConn);
bool boolPermission = false;
OleDbDataReader objDataReader=null;
try
{
string strSQL = "SELECT TOP 10 * FROM News WHERE Published=true ORDER BY PublishDate DESC";

conn.Open();

OleDbCommand objCommand = new OleDbCommand(strSQL, conn);
objDataReader = objCommand.ExecuteReader();
while (objDataReader.Read() == true)
{
int Id = Convert.ToInt32(objDataReader["Id"]);
string Title = Convert.ToString(objDataReader["Title"]);
string Body= Convert.ToString(objDataReader["Body"]);
//Se till att datum följer RFC-822 standard
string PublishDate = Convert.ToString( ((DateTime)objDataReader["PublishDate "]).ToString("r"));


//skriv ut <item> och dess innehåll
xtw.WriteStartElement("item");
xtw.WriteElementString("title",Title);
xtw.WriteElementString("link", strRootUrl.ToLower() + "/news.aspx?id=" + Id);
xtw.WriteElementString("guid", strRootUrl.ToLower() + "/news.aspx?id=" + Id);
xtw.WriteElementString("description",Body);
xtw.WriteElementString("pubDate",PublishDate);
xtw.WriteEndElement();
}
objCommand.Dispose();
objCommand = null;
}
catch (Exception objException)
{
Trace.Warn("GenerateRss() Fel!",objException.Message);
}
finally
{
if(objDataReader!=null)
{
objDataReader.Close();
objDataReader = null;
}
if(conn!=null)
{
conn.Close();
conn = null;
}
}

//skriv ut </channel>
xtw.WriteEndElement();

//skriv ut </rss>
xtw.WriteEndElement();

//Stäng xml skrivaren
xtw.Close();
}
catch (Exception objException)
{
Trace.Warn("GenerateRss() Fel!",objException.Message);
}
return sw.ToString();
}

}

By Jesper Lind

Håll koll på errorloggen för HTTP

Idag larmade en av våra webbservrar för att utrymmet på C:-disken höll på att ta slut. När jag var inne och letade efter utrymme att frigöra hittade jag logg-filer i [%windir%\system32\LogFiles\HTTPERR] som jag inte visste att de fanns. Och de tog relativt stort utrymme.

Här loggas alla fel som sker i HTTP och inte kan tas hand om applikationen. En intressant källa att söka i med andra ord och då kan det vara bra att ha ett verktyg för att logganalys eftersom filerna är stora. 

Det var hos Chrison.net som jag först hittade dessa tips. Hos Microsoft kan man läsa mer om errorloggen för HTTP API och där finns även instruktioner för hur man byter plats på loggfilerna. I mitt fall vill jag hellre ha dem på en disk som är dedikerad för loggfiler och inte på huvuddisken som innehåller operativsystemet.

By Jesper Lind