Julafton kom tidigt för oss .NET-utvecklare i år. Microsoft höll tidschemat och levererade VS 2008 med .NET 3.5 Beta 2.
Men helt smärtfritt var det inte att få igång det för mig. Eftersom jag hade läst att denna version skulle fungerar bra vid sidan om VS 2005 satte jag igång installationen. Denna avbröts dock mitt i pga något fel, och lämnade mig med VS 2005 och hela min utvecklingsmiljö kaputt. Det beror nog på att jag redan hade en del fel på mina installationer, men en liten varning alltså. Installera den inte på din produktionsmijö om du vill slippa problem.
En ominstallation av XP senare, så gick det mycket bättre och nu rullar det fint på min maskin. Än har jag bara känt på det nya utvecklingpaketet, men bara en sån sak som Intellisense på Javascript har gjort det mödan värt.
VS 2008 med ASP.NET AJAX 1.0
Något som är lite lurigt är att få Ajax att fungera i NET2.0 läget på VS 2008. Först måste man se till att köra ett skript för att inte VS 2008 automatiskt ska använda de nya inbyggda Ajax-referenserna.
Sedan är det några fler steg som måste genomföras för att få fram Ajax-kontrollerna i toolboxen och ladda in referenserna. Microsofts utvecklingsteam har gjort en grundläggande förklaring för hur man gör.
Om dessa kontroller är cachade så blir det lite svårare. Speciellt om man ska kunna sätta några properties på dem. Via OdeToCode hittade jag info hos Microsoft om hur man kan göra, och även exempelkod.
// Load the user control Control control = LoadControl("control/MyControl.ascx"); placeHolder.Controls.Add(control);
// Set its properties (if possible) ASP.MyControl uc = control as ASP.MyControl; if (uc == null) { PartialCachingControl pcc = control as PartialCachingControl; if (pcc != null) uc = pcc.CachedControl as ASP.MyControl; } if (uc != null) uc.MyProperty = "This is the value";
Ps. I mitt exempel har jag med ASP-prefixet på klassen för kontrollen. Detta beror på att jag använder inline-code, läs mer om detta i tidigare nämnt inlägg.
TinyMCE är en skön HTML-Editor som har blivit väldigt populär. Den är oftast väldigt enkel att använda och har många konfigureringsmöjligheter.
Men att använda den tillsammans med Ajax och partial update är verkligen ingen lätt match. Jag lyckades tidigare i år, efter stor möda, men det var nog mest tur.
Skrev om det i bloggen, men den postningen blev inte så fullständig eller bra. Det var mest lite egna minnesanteckningar som jag fick till där. Jocke var inne och kollade på beskrivningen men fick inte till det. Så nu tänkte jag visa precis hur man kan göra med ett uppdaterad och fullständig kod.
Problemen
Problem 1. TinyMCE gör om textboxar till en Iframe, som My Portal Project förklarar. Detta leder till att det är svårt att ta emot värden (speciellt i Firefox). Waqas_badas visar hur man kan komma runt detta genom ett javascript på submit-knappen.
Problem 2. Vid Ajax-anrop ritas inte editorn upp igen. Här kan man anropa mceAddControl-kommandot, men det gäller att resetta id-räknaren innan man gör det, här är en som kommit på hur man gör.
Kodexempel
Nu tänkte jag låta koden förklara resten. Missa inte att ladda hem zip-filen längst ner som innehåller ett färdigt project som fungerar i IE7, FF2 och Opera.
Default.aspx
<%@ Page Language="C#" ValidateRequest="false" Trace="false" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>MS Ajax UpdatePanel - TinyMCE</title> <script type="text/javascript"> function SaveMyPreciousValues() { tinyMCE.triggerSave(false,true); TextBox1 = document.getElementById('TextBox1'); alert('Check value when posting: '+ TextBox1.value) } </script> </head> <body>
using System; using System.Data; using System.Configuration; 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) { if(!Page.IsPostBack) LoadTinyMCE(); }
private void LoadTinyMCE() {
//Load tinyMCE HtmlGenericControl Include = new HtmlGenericControl("script"); Include.Attributes.Add("type", "text/javascript"); Include.Attributes.Add("src", "js/tiny_mce/tiny_mce.js"); this.Page.Header.Controls.Add(Include);
Label1.Text = "Content posted from TextBox1: " + inputText;
//Register some javascript to redraw the editor. //Very important to reset the id-counter to "0", or else strange things will happen.. ScriptManager.RegisterClientScriptBlock(UpdatePanel1, this.GetType(), "init", "tinyMCE.idCounter=0;tinyMCE.execCommand('mceAddControl', false, 'TextBox1');", true); } }
Den nuvarande versionen av Visual Studio stödjer inte nästade Masterpages i designläget. Men detta kommer det bli ändring på i den kommande VS 2008 som ScottGu förklarar.
Scott visas samtidigt på att visa en användbar teknik, för att skapa olika layouts, för sidor som har en kolumn respektive två.
Det ryktas för övrigt att Visual Studio 2008 Beta 2 kommer släppas inom tre veckor och då med en "go-live"-licens.
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.
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.
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.
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.
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.
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";
//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"));
När man söker igenom stora textfiler som t ex loggfiler kan det vara bra att ha något specialverktyg till sin hjälp. Det finns säkert massor av såna här program, men tänkte skriva om två stycken som jag provat.
Microsoft Log Parser 2.2 verkar bra, speciellt eftersom den är gjord för att hantera Microsofts egna format på loggfilerna. Tyvärr sker input genom ett CMD-fönster och därför lite väl omständigt att använda enligt mig.
Kollade istället på ett enklare alternativ. Delay släppte igår första publika versionen av sitt verktyg som heter TextAnalysisTool.NET. Har precis testkört det och gillar det verkligen. Genom ett enkelt gränssnitt kan man ladda in loggfiler och sedan välja ut vissa rader man vill granska mer utförligt genom att ange Regular Expressions.
Här gör jag en liten sammanfattning om tips för hur man får en .NET-applikation att validera som XHTML Strict.
Så testar man
För att avgöra om sina sidor validerar mot den webbstandard som man valt att följa så kan man använda valideringsverktyget från WC3.
Vill man vara extrem så kan man ju även testa den nya betaversionen. Märkte just en skillnad från den vanliga versionen. I nya betan måste ange rätt namnrymd i html-taggen för att validera som Strict, så här alltså:
<html xmlns="http://www.w3.org/1999/xhtml">
Ställ in Web.config
Använder man .NET som utvecklingsplattform så finns det några saker man bör ha med i <system.web>-delen av Web.config för att slippa konstiga fel.
Sen även lägga till följande rad så att koden ska följa Strict-standarden. I detta läge får inte form-taggen inte ska få något name-attribut (det får den inte ha i XHTML). Antagligen är det fler saker som händer med koden men vet inte precis.
<xhtmlConformance mode="Strict" />
Den extra diven runt viewstate
I och med .NET 2.0 så har en del förändringar skett så att koden ska bli mer XHTML-kompatibel. Bland annat så läggs numera en extra <div> runt viewstate.
Det här kan dock ställa till problem med CSS formatering. För den nya div-taggen har inte har någon css-klass eller id och är därför svår att styla utan att påverka resten av dokumentet. Den här taggen har flera gånger förstört layouts för mig, så jag förstår de som klagar.
Tabs-kontrollen i Asp.Net Ajax är cool. Men något att tänka på när man använder den är att alla flikar laddas in när den rendereras, även de som är gömda.
Det fick jag själv bittert erfara när jag hade utvecklat en omfattande applikation med Tabs. Den var seg som sirap när jag väl körde den på produktionsservern.
Om man har mycket funktionallitet under varje flik, vore det bättre om denna bara laddades när man klickar på den. Shawn Burke verkar ha en smidig lösning, den artikeln ska jag kolla på nästa gång det är dags för att använda Tabs.