Teknikdagboken En blogg om teknik i vardagen

26Nov/130

Dustin lagrar lösenord i klartext och visar dem för supporten

Det senaste dagarna har Dustin fått det hett om öronen då de sparar användares lösenord i klartext och deras support-personal kan se det i klartext. Jag vet inte vad jag tycker är värst av att de över huvud taget byggde det så från början, att deras personal ser lösenorden eller att de inte fixat till det sen de uppmärksammades på problemet redan 2009.

19Mar/120

Databasproblem i MVC Music Store

Jag har börjat lyft av jonkopingsok.nu från ASP/VBScript till MVC3 och ville titta på lite andra lösningar för att se hur de fungerar. En av de mest kända är MVC Music Store men när jag försökte starta den fick jag felkod Unable to find the requested .Net framework data provider. Jag hade SQL Server 2008 R2 och VS2010 Premium SP1 men tydligen saknades ändå någon data provider för SQL Server Compact 4.0. Följ länken och installera så bör det fungera.

Om du testar applikationne och försöker logga in på admin-delen måste du först ge ditt nya konto rollen Administrator. Detta kan göras via ASP.Net Web Site Administration Tool som man kommer åt via Visual Studio -> Project -> ASP.Net Configuration. Eller så loggar du in med det förskapade administratörskontot som jag inte vet lösenordet på men som borde stå i guiden på asp.net.

15Nov/110

Problem att deploya till Sharepoint 2010

Idag fick jag problem med att deploya till Sharepoint och fick följande felmeddelanden:

An object in the SharePoint administrative framework, "SPSolutionLanguagePack Name=0 Parent=SPSolution Name=il.sharepoint.workflows.wsp", depends on other objects which do not exist.  Ensure that all of the objects dependencies are created and retry this operation.

Error occurred in deployment step 'Retract Solution': The solution does not have a WSP file associated with it.

Error occurred in deployment step 'Retract Solution': The language-neutral solution package was not found.

För att lösa det fick jag göra följande:

  1. net stop "SharePoint 2010 Timer"
  2. Ta backup av .ini-filen.
  3. Ta bort alla xml-filer i C:\ProgramData\Microsoft\SharePoint\Config\{GUID} eller C:\Documents and Settings\All Users\Application Data\Microsoft\SharePoint\Config\<<GUID>> folder
  4. Öppna .ini-filen och ändra värdet till 1.
  5. net start "SharePoint 2010 Timer"
4Jul/110

Loopa över stored procedures

Idag behövde jag exekvera en Stored Procedure några tusen gånger för att korrekt kunna plocka bort några poster inklusive relaterad data. För att kunna göra detta använde jag mig av följande loop i SQL Server Management Studio.

declare @counter int
set @counter = 0
while @counter < 10
begin
set @counter = @counter + 1
exec pr_StoredProcedureName @counter
end
22Jun/110

Illegala tecken från Sharepoint vid webbtjänstanrop

För att göra anrop från en extern klient kan man använda Sharepoints webbtjänster, men vissa av dem är för avancerade för att använda WCF Test Client som hänger med VS 2008/2010 eller Web Service Studio på Codeplex. Nyligen hittade jag ytterligare ett program som heter SharePoint Utilities for Developers (SPUD). I det programmet får man hjälp med att göra en massa saker såsom att bygga och verifiera att CAML är korrekt skriven.

Sist jag hade användning för programmet var när en lista med filer inte kunde hämtas från Sharepoint via GetListItems pga ett illegalt tecken (ascii 15, carriage return). Jag trodde först det var fel på min kod men SPUD visade samma fel. Problemet när jag testade var att felet kastades att den autogenererade asmx-kodklassen som jag inte har någon kontroll över och jag kan inte be Sharepoints webbtjänst att sluta skicka illegala tecken i sin XML...

För att få veta vilket dokument det var som hade det konstiga tecknet laddade jag ner och startade Fiddler2 samt SPUD. Letade sedan upp min lista, högerklickade på den, valde Get List Items, lade in min CAML fråga och körde. Fiddler fångade svaret från Sharepoint och jag kunde se XML-svaret jag fick tillbaka. För att hittade det felaktiga tecknet körde jag W3Validator. Då såg jag vilka tecken som var illegala och kunde lokalisera vilken fil som orsakade felet.

I mitt fall var det metadata på en wordfil som hade _x0015_ i något metadatakommentarsfält. När jag tog bort _x0015_ från kommentaren försvann problemet.

Hur man kan undvika problem i framtiden har jag ingen aning om men just nu fungerar det i alla fall igen! 🙂

4Mar/110

Serialisera objekt till json med camelCase

För att serialisera ett objekt till json i MVC3 kan man använda Json(), men då skapas objektet som serialiseras med fel namn i JavaScript där camelCase används. För att fixa detta kan man använda DataContractJsonSerializer. Här är min lösning:

public class JsonHelper
{
    public static string Serialize<T>(T obj)
    {
        var serializer = new DataContractJsonSerializer(obj.GetType());
        var ms = new MemoryStream();
        serializer.WriteObject(ms, obj);
        string retVal = Encoding.UTF8.GetString(ms.ToArray());
        ms.Dispose();
        return retVal;
    }

    public static T Deserialize<T>(string json)
    {
        T obj = Activator.CreateInstance<T>();
        var ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
        var serializer = new DataContractJsonSerializer(obj.GetType());
        obj = (T)serializer.ReadObject(ms);
        ms.Close();
        ms.Dispose();
        return obj;
    }
}

Objektet som skall serialiseras behöver några extra taggar på sig ex:

[DataContract]
public class Person
{
    [DataMember(Name="firstName")]
    public string FirstName { get; set; }

    [DataMember(Name="lastName")]
    public string LastName { get; set; }
}

För att serialisera/deserialisera skriver man så här:

var myPerson = new Person()
{
    FirstName = "John",
    LastName = "Doe"
};

// Serialize
string json = JSONHelper.Serialize<Person>(myPerson);

// Deserialize
myPerson = JSONHelper.Deserialize<Person>(json);

Koden är i princip identisk med http://pietschsoft.com/post/2008/02/NET-35-JSON-Serialization-using-the-DataContractJsonSerializer.aspx. Jag har bara ändrat från default encoding till utf8.

26Feb/110

Lång tid att ladda sidor i Firefox med Visual Studio

Jag upptäckte för någon månad sedan att när man kör VS2008/VS2010 för att utveckla webbapplikationer tar det nästan en sekund innan sidorna börjar laddas. Dumt tänkt jag och fortsatte arbeta som om inget hade hänt. Några veckor senare stötte jag på sidor i projekt som tog flera sekunder att ladda i Firefox medan de laddades direkt i IE. För att se vad som tog tid använde jag det mycket användbara verktyget Firebug i Firefox.

Efter att ha googlat lite hittade jag en lösning som sa att detta är en bugg när man kör Firefox mot den inbyggda webbservern i Visual Studio. Tydligen har det något att göra med att Firefox frågar efter en IPv6 adress men får en IPv4 adress tillbaka. Vad jag förstår är inte detta en bugg i Firefox utan en bugg i DNS servern som finns i VS inbyggda webbserver.

Buggen kan enkelt undvikas genom att ändra en inställning i Firefox så att den alltid använder IPv4 mot localhost. Skriv about:config i adressfältet, leta upp network.dns.ipv4OnlyDomains och skriv in en kommaseparerad lista med domäner där FF inte skall använda IPv6. Om det inte står något där ska det alltså stå localhost. Du kanske behöver starta om Firefox för att ändringen skall slå igenom.

En annan lösning är att sätta network.dns.disableIPv6 men då stänger man av IPv6 för alla webbsidor och inte bara localhost och påverkar alltså inte bara sin utvecklingsmiljö.

network.dns.disableIPv6
28Dec/100

Dagens tips – Laga användare efter återställning i MS SQL

Som utvecklare tar jag hyfsat ofta backup och göra återläsningar av databaser. När man gör detta tappar SQL användarna sina inloggningar och jag har inte funderat så mycket på det utan bara tagit bort och skapat upp dem igen. Naturligtvis finns det ett mer elegant sätt. Man kan köra en stored procedure på databasen i fråga så fixas detta.

EXEC sp_change_users_login 'Auto_Fix', 'Användarnamn', NULL, 'Lösenord' 

Kanske helt uppenbart för vissa personer men jag och många andra hade missat detta.

8Dec/100

Köra en stored procedure för varje rad i SELECT

Idag behövde jag ta bort ca 300 rader och kunde få ut berörda rader med en SELECT fråga. För att ta bort en rad behövde jag köra en stored procedure för att även ta bort relaterande data. Detta löstes smidigt genom följande script som jag hittade på Stackoverflow:

declare @field1 int
declare @field2 int
declare cur CURSOR LOCAL for
    select field1, field2 from sometable where someotherfield is null

open cur

fetch next from cur into @field1, @field2

while @@FETCH_STATUS = 0 BEGIN

    --execute your sproc on each row
    exec uspYourSproc @field1, @field2

    fetch next from cur into @field1, @field2
END

close cur
deallocate cur
7Feb/100

Litebox som anpassar sig efter webbläsarfönstret

Jag tycker att bildvisning med hjälp av Lightbox2 / Litebox är riktigt snyggt på webbsidor och har nyligen installerat det på en av mina hemsidor.

Jag hittade då ett problem där applikationen inte tar hänsyn till hur stora bilderna är relaterat till webbläsaren vilken ibland gjorde att inte hela bilderna syntes. När man använder dessa skript får man inte heller någon skrollbar så man kunde inte bläddra för att se hela bilden.

Enkelt löst tänkte jag och googlade vidare efter liknande applikation som gör just detta, men jag hittade inget bra och bestämde mig för att lösa detta själv.

Det som behöver göras är att lägga in ny funktionalitet i litebox-1.0.js för att ta hänsyn till storleken på webbläsarfönstret. Förändringen som behövs är liten och enkel att införa. Byt bara ut

imgPreloader.onload=function(){
	Element.setSrc('lightboxImage', imageArray[activeImage][0]);
	myLightbox.resizeImageContainer(imgPreloader.width, imgPreloader.height);
}

mot

imgPreloader.onload=function(){
	Element.setSrc('lightboxImage', imageArray[activeImage][0]);
	
	var innerWidth = arrayPageSize[2];
	var innerHeight = arrayPageSize[3];
	
	if(imgPreloader.width>(innerWidth-100) || imgPreloader.height>(innerHeight-130)){
		if(imgPreloader.width>(innerWidth-100)){
			var width=(innerWidth-100);
			var height=imgPreloader.height/(imgPreloader.width/(innerWidth-100));
			if(height>(innerHeight-130) ){
				var height=(innerHeight-130);
				var width=imgPreloader.width/(imgPreloader.height/(innerHeight-130));
			}
		} else if(imgPreloader.height>(innerHeight-130)){
			var height=(innerHeight-130);
			var width=imgPreloader.width/(imgPreloader.height/(innerHeight-130));
		}
		
		height = Math.floor(height);
		width = Math.floor(width);
		
		document.getElementById('lightboxImage').height=height;
		document.getElementById('lightboxImage').width=width;
		document.getElementById('lightboxImage').style.width=width;
		document.getElementById('lightboxImage').style.height=height;
		myLightbox.resizeImageContainer(width, height);
	} else {
		document.getElementById('lightboxImage').height=imgPreloader.height;
		document.getElementById('lightboxImage').width=imgPreloader.width;
		document.getElementById('lightboxImage').style.width=imgPreloader.width;
		document.getElementById('lightboxImage').style.height=imgPreloader.height;
		myLightbox.resizeImageContainer(imgPreloader.width, imgPreloader.height);
	}
}

så skall det fungera.

Skillnaden mellan Litebox och Lightbox är liten och ligger främst i vilket bakomliggande JavaScript-ramverk som används, vilket gör att detta därför går att applicera på båda applikationerna.