Archives

Archives / 2004 / June
  • A crowded unit testing BoF

    This mornings BoF lead by James Newkirk was truly crowded and goes to prove that .NET developers are taking testing seriously. Considering the level of participation in the discussions there might actually have been too many participants as there were no real discussions, more statements regarding to experience summed up and commented by James Newkirk.

  • Sharepoint Portal Architecture and autogenerating WSS site forests

    I've been checking out the Sharepoint content on this years teched, and some of the hands-on labs might be somewhat interesting. My major interest regarding sharepoint these days, however, is how to design the Portal architecture. How do you efficiently design the relationship between SPS and WSS and how can automatic generation of WSS sites support structured growth of the portal.

  • Microsoft CRM Blogs

    A couple of weeks ago I took the Microsoft CRM Customization Certification, probably as the first in Norway. Internally we've been starting up a dog-fooding project and today I started working with a client that are implementing Microsoft CRM in the current project.

  • New version of CruiseControl.NET

    Took me a week to notice, but CruiseControl.NET 0.6.1 is now released. New features include auto-get of VSS source code (man that took me a while to realize was missing from the last release), support for ClearCase plus support for a light-weight integration with devenv (VS.NET) to avoid using NAnt for smaller projects. The devenv feature makes testing kinda hard so they also included possibilities for running NUnit directly aswell.

  • QueryStringPageViewer WebPart for Sharepoint

        /// <summary>
        /// Mads Haugbø Nissen 2003(c)
        /// Objectware AS
        /// Norway
        /// 
        /// http://weblogs.asp.net/mnissen
        /// 
        /// The QueryStringPageViewer provides the same functionality as the regular PageViewerWebPart
        /// but allows providing a selection of querystring parameters from the page that hosts this webpart
        /// to the page viewed in the QueryStringPageViewer.
        /// </summary>
        [DefaultProperty("ContentLink"),
        ToolboxData("<{0}:QueryStringPageViewer runat=server></{0}:QueryStringPageViewer>"),
        XmlRoot(Namespace="http://www.objectware.no/Lawyer/Sharepoint/Webparts/QueryStringPageViewer")]
        public class QueryStringPageViewer : Microsoft.SharePoint.WebPartPages.WebPart
        {
            private string _contentLink = "";
            [Browsable(true)]
            [Category("Content")]
            [DefaultValue("")]
            [WebPartStorage(Storage.Shared)]
            [FriendlyName("The url of the content to show.")]
            [Description("Supply Querystring params to be passed like this: Page.aspx?Param1&Param2&Param3")]
            public string ContentLink
            {
                get
                {
                    return this._contentLink;
                }
                set
                {
                    this._contentLink = value;
                }
            }
            
            protected string BaseUrl
            {
                get
                {
                    int endIndex = this.ContentLink.IndexOf("?");
                    if(endIndex != -1)
                        return this.ContentLink.Substring(0, endIndex + 1);
                    else
                        return "";
                }
            }
            /// <summary>
            /// Render this Web Part to the output parameter specified.
            /// </summary>
            /// <param name="output"> The HTML writer to write out to </param>
            protected override void RenderWebPart(HtmlTextWriter output)
            {
                string url = this.UrlWithQueryStringGet();
                if(url.Length > 0)
                {
                    string name = "QueryStringPageViewer_" + this.UniqueID;
                    output.AddAttribute(HtmlTextWriterAttribute.Id, name, false);
                    output.AddAttribute(HtmlTextWriterAttribute.Name, name, false);
                    output.AddAttribute(HtmlTextWriterAttribute.Width, "100%", false);
                    output.AddAttribute(HtmlTextWriterAttribute.Height, "100%", false);
                    output.AddAttribute(HtmlTextWriterAttribute.Height, "100%", false);
                    output.AddAttribute(HtmlTextWriterAttribute.Src, url, false);
                    output.AddAttribute("ddf_src", url, false);
                    output.AddAttribute("frameBorder", "0", false);
                    output.RenderBeginTag(HtmlTextWriterTag.Iframe);
                    output.RenderBeginTag(HtmlTextWriterTag.Div);
                    output.Write("IFrames not supported by this browser");
                    output.RenderEndTag();
                    output.RenderEndTag();            
                }
                else
                {
                    Control c = new LiteralControl(string.Format("To link to content, <a href=\"javascript:MSOTlPn_ShowToolPaneWrapper('{0}','{1}','{2}');\">open the tool pane</a> and then type a URL in the ContentLink text box with QueryString parameters formatted like this: 'Page.aspx?Param1&Param2'.", 1, 129, this.ID)); 
                    c.RenderControl(output);
                }
            }
            
            private ArrayList QueryStringKeysGet()
            {
                int startIndex = this.ContentLink.IndexOf("?");
                ArrayList queryStrings = new ArrayList();
                if(startIndex > -1 && this.ContentLink.Length > startIndex + 1)
                {
                    string queryStringRaw = this.ContentLink.Substring(startIndex + 1);
                    if(queryStringRaw.IndexOf("&") != -1)
                    {    
                        string[] tokens = queryStringRaw.Split(new char[]{'&'});
                        for(int i = 0; i < tokens.Length; i++)
                            queryStrings.Add(tokens[i].ToLower());
                    }
                    else
                    {
                        queryStrings.Add(queryStringRaw.ToLower());
                    }
                }
                return queryStrings;
            }
            protected virtual string UrlWithQueryStringGet()
            {
                ArrayList queryStringsToPass = this.QueryStringKeysGet();
                string url = this.BaseUrl;
                
                for(int i=0; i < Page.Request.QueryString.Count; i++)
                {
                    string queryStringKey = Page.Request.QueryString.Keys[i];
                    string queryStringValue =  Page.Request.QueryString[i];
                    if(queryStringsToPass.IndexOf(queryStringKey.ToLower()) != -1)
                    {
                        url += queryStringKey + "=" + queryStringValue + "&";
                    }
                }
                
                url = url.TrimEnd(new char[]{'&'});
                return url;
            }
        }
    
    <?xml version="1.0" encoding="utf-8"?>
    <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2" >
        <Title>QueryStringPageViewer</Title>
        <Description>Passes querystring parameters to the page in the viewer.</Description>
        <Assembly>Objectware.Lawyer.Sharepoint</Assembly>
        <TypeName>Objectware.Lawyer.Sharepoint.WebParts.QueryStringPageViewer</TypeName>
        <!-- Specify initial values for any additional base class or custom properties here. -->
        <ContentLink xmlns="http://www.objectware.no/Lawyer/Sharepoint/Webparts/QueryStringPageViewer"></ContentLink>
    </WebPart>

  • Using an XmlPublisher in the ExceptionManagement ApplicationBlock

    I've been using the Microsoft ExceptionManagement ApplicationBlock and I spent some time creating a nice ExceptionXmlPublisher because the one described in the docs has some flaws. Using the xml publisher removes the need to run the EventLog installer to be able to create the eventlog. Having the exceptions in Xml also works nicely in a distributed environment, and with continous integration. I will soon create an XSLT stylesheet to integrate the current runtime exceptions into my CruiseControl.NET dashboard, so developers can monitor what's going on during execution on the development testserver.

  • ExceptionXmlPublisher for Microsoft.ApplicationBlocks.ExceptionManagement

    using System;
    using System.Xml;
    using System.Collections.Specialized;
    using System.IO;
    namespace Microsoft.ApplicationBlocks.ExceptionManagement
    {
        /// <summary>
        /// Summary description for ExceptionXmlPublisher.
        /// </summary>
        public class ExceptionXmlPublisher : IExceptionXmlPublisher
        {
            void IExceptionXmlPublisher.Publish(XmlDocument ExceptionInfo, NameValueCollection ConfigSettings)
            {
                string filename;
                if (ConfigSettings != null)
                {
                    filename = ConfigSettings["fileName"];
                }
                else
                {
                    filename = @"C:\ErrorLog.xml";
                }
                XmlDocument xmlTarget = new XmlDocument();
                FileStream fs;
                if(File.Exists(filename))
                {
                    fs =  File.Open(filename, FileMode.Open, FileAccess.Read);
                    try
                    {
                        xmlTarget.Load(fs);
                    }
                    catch
                    {
                        xmlTarget = new XmlDocument();
                        xmlTarget.AppendChild(xmlTarget.CreateXmlDeclaration("1.0", "UTF-8", "yes"));
                        xmlTarget.AppendChild(xmlTarget.CreateElement("RuntimeExceptions"));
                    }
                    finally
                    {
                        fs.Close();
                    }
                }
                else
                {
                    xmlTarget.AppendChild(xmlTarget.CreateXmlDeclaration("1.0", "UTF-8", "yes"));
                    xmlTarget.AppendChild(xmlTarget.CreateElement("RuntimeExceptions"));
                }
                
                XmlDocumentFragment docFrag = xmlTarget.CreateDocumentFragment();
                docFrag.InnerXml = ExceptionInfo.OuterXml;
                XmlNodeList stackTraceNodes = docFrag.SelectNodes("//StackTrace");
                foreach(XmlNode node in stackTraceNodes)
                {
                    node.InnerXml = "<![CDATA[" + node.InnerXml + "]]>";
                }
                
                xmlTarget.DocumentElement.AppendChild(docFrag);
                
                fs = File.Open(filename, FileMode.Create, FileAccess.Write);
                try
                {
                    xmlTarget.Save(fs);
                }
                catch
                {}
                finally
                {
                    fs.Close();
                }
                
            }
        }
    }
    

  • Developers are Athletes, Architects are Coaches/Managers/Trainers

    Kris Syverstad writes about how developers resemble athletes. Reading his post I felt almost as Kris had been reading my final term paper in methodology from last spring where I used the exact same analogy. I wrote about developers as athletes in the context of higher learning, and how some students are suited for the extreme and some are more comfortable with the regular amount of training.