CRS Webbproduktion
Webbproduktion när den är som bäst

Förenkla 301-redirect

juni 23, 2010 18:41 by Admin

Jag använder mig mycket av 301-redirect (permanently moved) istället för 302-redirect (temporarily moved), när jag vill hänvisa en besökare till en ny adress, till exempel om jag byter URL till mer lättlästa (från /default.aspx?p=forum&t=324 till /forum/301-redirect/ ). Detta gör jag eftersom sökmotorer då för över eventuell länkkraft som pekar på den gamla adressen, till den nya.

Som du säkert vet är en vanlig Response.Redirect en 302-redirect. Att göra en 301-redirect är lite mer omständigt. Därför har jag följande statiska metod i min static Utilities-klass:

        public static void Redirect301(string url)
        {
            HttpContext.Current.Response.Status = "301 Moved Permanently";
            HttpContext.Current.Response.AddHeader("Location", url);
        }

Det gör att jag kan göra en 301-redirect genom att skriva Utilities.Redirect301("/forum/301-redirect/");


Tags: ,
Categories: Webbutveckling
Actions: E-mail | Permalink | Kommentarer (3) | Comment RSSRSS comment feed

Microsoft AJAX CDN

september 16, 2009 17:01 by Admin

Microsoft presenterar nu ASP.NET AJAX och jQuery via CND (Content Delivery Network), vilket gör att dina (och mina) besökare kan få en bättre upplevelse. Detta påverkar framför allt dig som har besökare från hela världen, då CDN ser till att innehållet finns cachat så nära besökaren som möjligt.

Själv använder jag inte ASP.NET AJAX så mycket, men däremot jQuery, och allt jag behöver göra för att detta ska fungera är att ändra sökvägen till jQuery, på följande vis:

<script src="http://ajax.Microsoft.com/ajax/jQuery/jquery-1.3.2.min.js" type="text/javascript"> </script>

Klicka här för att besöka Microsofts sida om detta.


Meta_Description och Meta_Keywords

september 15, 2009 17:29 by Admin

Har du försökt sökmotoroptimera en sajt du byggt i ASP.NET? Jag har gjort det, och det är inte så lätt.
En av de finesser i ASP.NET som jag absolut inte skulle klara mig utan, är MasterPages. När du använder MasterPages får du lite problem med MetaDescription och MetaKeywords.

En vanlig lösning är att ha en ContentPlaceHolder i Head, och lägga in meta-taggarna den vägen. I ASP.NET 4.0 kommer du att komma åt dessa, precis som du gör med Title idag. Det tycker jag verkar otroligt smidigt, och därför tänkte jag dela med mig av hur du kan göra precis så redan i version 2.0.

Jag har en basklass som alla mina sidor ärver. Jag tycker att allting blir så mycket enklare då, och den använder jag till detta också. Där har jag följande

private string _keywords;
public string Meta_Keywords

{
    get
    {
        return _keywords;
    }
    set
    {
        // strip out any excessive white-space, newlines and linefeeds
        _keywords = Regex.Replace(value, "\\s+", " ");
    }
}

Detta gör att jag får en egenskap i Page för Meta_Keywords. Jag har motsvarande för Meta_Description. För att sedan ställa in egenskaperna gör jag så här:

<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFileBaseClass="BasePageClass" CodeFile="Default.aspx.cs" Inherits="Support" Title="<%$ Resources:PageTitle %>" Meta_Keywords="Keyword1, Keyword2" Meta_Description="This is my site" %>

Det går naturligtvis även att komma åt från CodeBehind om man vill det. Detta räcker dock inte riktigt, vi måste också på något sätt peta ut detta i den renderade html-koden. Det gör vii PreRender, så här:

public BasePageClass()
{
            PreRender += new EventHandler(BasePage_PreRender);
}
void BasePage_PreRender(object sender, EventArgs e)
{
    if (!string.IsNullOrEmpty(Meta_Keywords))
    {
        HtmlMeta tag = new HtmlMeta();
        tag.Name = "keywords";
        tag.Content = Meta_Keywords;
        this.Page.Header.Controls.Add(tag);
    }

    if (!string.IsNullOrEmpty(Meta_Description))
    {
        HtmlMeta tag = new HtmlMeta();
        tag.Name = "description";
        tag.Content = Meta_Description;
        Header.Controls.Add(tag);
    }
}

Det är allt som behövs.


Redirect till ett ankare

september 7, 2009 13:37 by Admin

Härom dagen ställdes jag inför problemet att jag behövde Redirecta en sida tillbaka till sig själv, fast med ett ankare. Det fungerade naturligtvis utan problem, utom i Internet Explorer. Efter en del trixande hittade jag en lösning, baserad på javascript.

Jag fixade min redirect så här:

if (Request.Browser.Browser.ToLower() == "ie")
{
    Response.Redirect("sida.aspx?hash=mitt_ankare#mitt_ankare");
}
else
{
    Response.Redirect("sida.aspx#mitt_ankare");
}

På så vis lägger jag alltså till en QueryString om besökaren använder Internet Explorer. Jag skickar ändå med ankaret, ifall att Microsoft skulle få för sig att fixa buggen i framtiden.
Sedan på klientsidan lägger jag följande javascript:

<!--[if IE]>
<script type="text/javascript">
    function getQuerystring(key, default_) {
        if (default_ == null) default_ = "";
        key = key.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
        var regex = new RegExp("[\\?&]" + key + "=([^&#]*)");
        var qs = regex.exec(window.location.href);
        if (qs == null)
            return default_;
        else
            return qs[1];
    }
    self.location.hash = "#" + getQuerystring("hash");
</script>
<![endif]-->

Det körs alltså endast om besökaren använder Internet Explorer, och hämtar ut QueryStringen "hash" och skickar besökaren till rätt position på sidan.

Ganska enkelt men det krävdes en del letande för att hitta på lösningen. Nu har jag presenterat den här för dig, varsågod.


Minimera både CSS och JavaScript

juli 1, 2009 09:46 by Admin

Igår skrev jag om hur du kan minimera datatrafiken genom att sammanfoga CSS-filer och ta bort whitespaces.

Idag har jag utökat funktionaliteten så att den även fixar dina JavaScript på samma sätt. Det enda krångliga var att hantera kommentarer, vilket jag fick hjälp med via en tråd på webmasterworld.

Här är den uppdaterade koden:

<%@ WebHandler Language="C#" Class="CssCompact" %>

using System;
using System.Web;
using System.IO;
using System.Text.RegularExpressions;

public class CssCompact : IHttpHandler
{
    private static Regex _remove = new Regex(@"^\s+|/\*([^*\\\\]|\*(?!/))+\*/|\r|\n|\t|((^[\/]{2}[^\n]*)|([\n]{1,}[\/]{2}[^\n]*)/g)", RegexOptions.Multiline | RegexOptions.Compiled);
    public void ProcessRequest(HttpContext c)
    {
        string cachename = "";
        string content = "";
        string[] resources = c.Request.QueryString["resource"].Split(',');
        for (int i = 0; i < resources.Length; i++)
        {
            cachename += resources[i];
            if (resources[i].EndsWith(".css"))
            {
                c.Response.ContentType = "text/css";
            }
            else if (resources[i].EndsWith(".js"))
            {
                c.Response.ContentType = "text/javascript";
            }
            else
            {
                c.Response.End();
            }
        }
        //c.Cache.Remove(cachename);
        try
        {
            content = c.Cache[cachename].ToString();
        }
        catch
        {
            for (int i = 0; i < resources.Length; i++)
            {
                string resource = resources[i];
                if (resource != null)
                {
                    string filename = c.Server.MapPath(resource);
                    if (File.Exists(filename))
                    {
                        FileInfo f = new FileInfo(filename);
                        c.Response.AddHeader("Last-Modified", f.LastWriteTime.ToString("U"));
                        c.Response.Expires = 10000;
                        if (c.Request.HttpMethod != "HEAD")
                        {
                            using (StreamReader stream = f.OpenText())
                            {
                                // remove linebreaks, whitespace and comments
                                content += stream.ReadToEnd();
                            }
                        }
                    }
                }
            }
            content = _remove.Replace(content, "");
            c.Cache.Add(cachename, content, null, DateTime.Now.AddHours(1), TimeSpan.Zero, System.Web.Caching.CacheItemPriority.Default, null);
        }
        c.Response.Write(content);
        c.Response.End();
    }
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

}

Nu är koden uppdaterad för att både kompilera uttrycket, samt implementera cache. Viktigt att notera är att om du byter ordning på dina Querystrings så blir det en ny cache. För mig är det oftast inget problem, då jag refererar i min MasterPage.


Minimera dina CSS-filer

juni 30, 2009 17:20 by Admin

Idag satt jag och ändrade i mina CSS-filer, tog bort lite radbrytningar och liknande, för att minimera mängden data som måste skickas till klienten. Efter ett tag tänkte jag att det måste finnas ett sätt att automatisera detta. Först tänkte jag mig att jag skulle parsa igenom den renderade html-koden för att hitta <link>-taggar som pekade på css-filer, och sedan hänvisa om dessa till en WebHandler som parsar igenom samtliga filer och slår ihop dem, och tar bort radbrytningar och onödiga mellanslag.

Sen tänkte jag om, jag kom nämligen på att jag inte kan vara den första som har haft denna idé. Således gav jag mig på min favoritsökmotor (jag tänker inte säga vilken). Jag hittade på en blogg där någon beskrivit WebHandlern CssCompact, som verkade passa mina behov alldeles utmärkt. Den tar bort whitespaces och radbrytningar och annat onödigt från CSS-filen, men den fungerar bara för en CSS-fil åt gången. Jag valde därför att modifiera den något, så den kan ta mot flera parametrar, och på så vis slå ihop dem.

Anledningen till detta är dels att minska antalet Requests, men det hade jag ju kunnat göra genom att manuellt slå samman CSS-filerna. Nej, som Peter Westlund (Agilerate Design) påpekade för mig så gör det att jag kan hålla isär olika delar av designen, i olika filer. Det underlättar ju mycket för mig som utvecklare. Den färdiga koden ser ut som följer:

<%@ WebHandler Language="C#" Class="CssCompact" %>

using System;
using System.Web;
using System.IO;
using System.Text.RegularExpressions;

public class CssCompact : IHttpHandler
{
    public void ProcessRequest(HttpContext c)
    {
        string[] stylesheets = c.Request.QueryString["stylesheet"].Split(',');
        for (int i = 0; i < stylesheets.Length; i++ )
        {
            string stylesheet = stylesheets[i];
            c.Response.ContentType = "text/css";
            if (stylesheet != null)
            {
                string filename = c.Server.MapPath(stylesheet);
                if (filename.EndsWith(".css"))
                {
                    if (File.Exists(filename))
                    {
                        FileInfo f = new FileInfo(filename);
                        c.Response.AddHeader("Last-Modified", f.LastWriteTime.ToString("U"));
                        c.Response.Expires = 0;
                        if (c.Request.HttpMethod != "HEAD")
                        {
                            using (StreamReader cssStream = f.OpenText())
                            {
                                // remove linebreaks, whitespace and comments
                                Regex remove = new Regex(@"^\s+|/\*([^*\\\\]|\*(?!/))+\*/|\r|\n|\t", RegexOptions.Multiline);
                                string cssContent = cssStream.ReadToEnd();
                                cssContent = remove.Replace(cssContent, "");
                                c.Response.Write(cssContent);
                            }
                        }
                    }
                }
            }
        }
        c.Response.End();
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

}

Det är två ändringar jag har gjort från grundkoden. Dels har jag lagt in en kontroll att det faktiskt är en CSS-fil du försöker parsa. Det är ett stort säkerhetshål i grundkoden, som gör att du kan hämta vilken fil som helst, till exempel web.config som kanske innehåller ConnectionString med både användarnamn och lösenord till databasen. Mycket slarvigt... Dessutom har jag gjort så att du kan skicka in flera stylesheets som QueryStrings, det är bara att ha ?stylesheet=MyStyle.css&stylesheet=OtherStyle.css osv. Hur många som helst.

Det man eventuellt skulle vilja göra är att implementera cache.


Bygg en modal popup

april 21, 2009 19:03 by Admin

Var en fråga idag på aspsidan, där någon ville visa en annons över hela sidan, som första sidvisning för varje besökare. Det är inga problem, så jag tänkte beskriva tillvägagångssättet här.

Vi börjar med en vanlig (x)html-sida. Den kan naturligtvis vara genererad av en server-kod om du vill det, det spelar ingen som helst roll.

<!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>     <title>Min exempelsida</title> </head> <body>     <h1>Min exempelsida</h1>     <p>Innehållet kommer här.</p> </body> </html> 

Där har vi en bra start. Du bygger naturligtvis ditt innehåll precis hur du vill. Nu ska vi lägga till koden för annonsen på sidan.

 <body>     <div id="annonsen">         <a href="http://blog.crswebb.se">CRS Webbproduktion</a>     </div>    <h1>Min exempelsida</h1>

Vi ska nu bygga så att annonsen visas ensam på sidan, det gör vi med CSS.

 <style type="text/css">     #crsannons {         position: absolute;         top: 0px;         left: 0px;         width: 100%;         height: 100%;         text-align: center;         padding-top: 25%;         display: none;     } </style> 

Vi positionerar lagret absolut, längst upp i vänstra hörnet. Vi gör det 100% både på bredd och höjd, centrerar texten, och låter den börja 25% ner på skärmen. Vi låter också lagret vara dolt från början, detta för att de som eventuellt inte har javascript aktiverat ska missa annonsen istället för resten av innehållet på sidan. Vad är det nu som fattas? Jo först och främst måste man ju kunna dölja lagret.

 <div id="crsannons">     <a href="#" id="crsannonsclose">Stäng</a>     <a href="http://blog.crswebb.se">CRS Webbproduktion</a> </div> 

Där har vi fått in länken för att stänga. Nu fattas en del javascript för att få det att fungera som man vill, samt lite css på stäng-länken. Jag har inkluderat jQuery i mitt projekt, och tänker nyttja det

 <script type="text/javascript">     $(document).ready(function() {         $("#crsannons").fadeIn();         $("#crsannonsclose").click(function() {             $("#crsannons").fadeOut();         });     }); </script> <style type="text/css">     #crsannonsclose {         position: absolute;         top: 10px;         right: 10px;     } </style> 

Nu så, fungerar det. Den kommer att visa vid varje sidvisning, det löser du enklast på serversidan, även om det går att pilla med cookies på klientsidan också.


Varför betala mer?

januari 16, 2009 15:51 by Admin

Vissa utvecklare tar mer betalt än andra, och det kan ju vara svårt att motivera dig att betala det högre priset. I vissa fall kan dock det högre priset bli lägre i slutändan. Det gäller att du väljer en kompetent utvecklare som skapar din applikation på bästa möjliga sätt, så att du slipper tråkiga överraskningar.

Att en utvecklare tar mer betalt än en annan betyder inte per automatik att utvecklaren är bättre. Jag har baserat mitt pris på hur bra applikationer jag gör, och hur snabbt jag gör det. Om det är prisvärt eller inte är ju upp till mina kunder, men jag har försökt lägga mig på en bra nivå. Jag känner folk som tar både mer och mindre betalt. I vissa fall är prisskillnaden befogad, i andra fall är den inte det.

Det ställer höga krav på dig som beställare, för du kan ju inte bara fråga mig. Det bör du naturligtvis OCKSÅ göra, men titta på referenser, och om det behövs kan du kontakta tidigare kunder.

Det står lite om det på IDG idag.


Kriget om länkarna

januari 16, 2009 12:27 by Admin

Det pågår ett krig där ute, ett krig som aldrig kommer att ta slut!
Och då pratar jag inte om kriget mellan Israel och Palestina.

Jag pratar om kriget om förstaplatsen i sökmotorernas resultatlista, fortsättningsvis kallat SERP (Search Engine Result Page).
För att klättra i SERPen krävs att du bygger en sida som sökmotorerna förstår vad den handlar om. Det gör du genom att sätta relevanta rubriker, och betona viktiga delar av texten.
Det är också en fördel om din webbsida växer, och får mer och mer innehåll. Det gör att du kan ranka högt på fler nyckelord. Ofta är det enklare att ranka riktigt högt på lite mer udda fraser (kallas Long-Tail). Till exempel är det väl inte så många som söker efter Kapybara (vattensvin) men det ger mig ändå en del trafik. Det har dock ingenting med mina huvudord att göra.

Det kräver också att andra länkar till din sajt. Ofta pysslar webbutvecklare och sökmotoroptimerare med länkbyten och registrerar sig i olika länksamlingar (kataloger) för att få länkar. Ibland betalas till och med en hel del pengar för en viktig länk, något som sökmotorerna säger att de ogillar. De vill inte gärna att man ska kunna köpa sig en plats i SERPen. Med riktigt bra innehåll kan du dock få länkar utan att du ber om det. Dessa kallas för spontana länkar, och är den allra bästa sorten.

När det gäller bloggar finns det lite andra knep man kan ta till för att få länkar. När jag länkar till en annan blogg från min blogg, så försöker den automatiskt kommentera det blogginlägg jag länkade till, och ge länken till mitt inlägg. Det ger mig ju automatiskt en länk, om jag länkar till någon annan. Jag skickar också information till några sökmotorer bara för bloggar. Även tjänster som listar nyligen uppdaterade bloggar får veta att jag har uppdaterat.

Detta är som sagt ett krig som aldrig kommer att ta slut. Det kommer fler och fler sätt att skapa länkar till din sajt, men det viktigaste är ändå att du har ett bra innehåll. Då kan besökare komma tillbaka, och rekommendera dig till andra.

Läs mer om blogglänkar på IDG


Internet Explorer 8 blir automatisk uppdatering

januari 8, 2009 10:36 by Admin

Internet Explorer 8 kommer att distribueras som en automatisk uppdatering via Windows Update, vilket uppskattas av mig i egenskap av utvecklare. Internet Explorer 8 tolkar html mycket bättre än tidigare versioner, vilket underlättar när webbsidor ska designas för att se lika ut för alla. Ännu är Internet Explorer 6 ganska stort, men jag hoppas att den versionen försvinner helt, eller nästan helt, i och med denna uppdatering.

Det ska bli riktigt spännande att se, jag har använt Internet Explorer 8 ett tag, vid sidan om Firefox 3, och tycker att den fungerar riktigt bra. Jag rekommenderar dig varmt att uppdatera du också.

Källa: IDG