Thursday, January 22, 2009

Watin working with window.showModalDialog()

I've been using Watin for UI testing on the front end of our web site.  For those who are not familiar with Watin I highly recommend checking it out.  It will work for ANY web front end (SharePoint etc.).

So assuming you are familiar with Watin...

I run tests against a browser window that opens up another window with Javascript. So I have:

  • Parent Window
    This window opens the Child Window using Javascript
  • Child Window
    This window is the one I want to test.

The Problem:

I could not get Watin to pickup the Child Window when it opened.   Originally I was using Javascript's window.open() method to open the Child Window but this was not working. There were two tricks to get this to run:

  1. Javascript: use showModalDialog and not window.open()
  2. C#: user ClickNoWait(). If you use Click() it waits for the window to close so makes the test code ‘hang’.

 

The Solution:

Javascript Code (Sits on Parent Window):

window.showModalDialog("MyFlyout.htm");

Watin Test C# Code:

ie.Div("articlesRSSDiv").ClickNoWait();

using (HtmlDialog htmlDialog = ie.HtmlDialog(Find.ByTitle("My Flyout")))

{

// test code

}

Wednesday, December 3, 2008

WCF web.config file for SharePoint Development Environment

I have recently gotten wcf services running in my SharePoint Development Machine.  Most of the issues I had were, and it warms my heart to say had nothing to do with SharePoint, they were around setting up the wcf web.config.

I dedicate this post to Sahil Malik for without his blog postings and codeplex SPWCFSupport Project project I would probably still be trying to get wcf running in SharePoint.

Surprisingly I found very few full wcf config file samples online and what I did find were only snippets, not the full config file.

After scratching across the informationsuperhighwaygooglemachineweb and a number of hours of 'trying different stuff' I came up with the config file below. 


This is the wcf web.config file that I am using on my Development Machine which is running wcf web services inside SharePoint.  I will no use this config on a production box. For production I will use wsHttBinding.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.web>
        <compilation debug="true" />
    </system.web>
    <system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
        <bindings>
            <basicHttpBinding>
                <binding name="NewBinding0">
                    <security mode="TransportCredentialOnly">
                        <transport clientCredentialType="Ntlm" />                       
                    </security>
                </binding>
            </basicHttpBinding>           
        </bindings>
        <services>
            <service behaviorConfiguration="WcfServiceLibrary1.HelloWorldBehavior"
             name="WcfServiceLibrary1.HelloWorld">
                <endpoint address="" binding="basicHttpBinding" name="myep" bindingConfiguration="NewBinding0"
                 contract="WcfServiceLibrary1.IHelloWorld" />               
                <host>
                    <baseAddresses>
                        <add baseAddress=http://MyDevServer/dev/_wcf/ />                       
                    </baseAddresses>
                </host>
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="WcfServiceLibrary1.HelloWorldBehavior">
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="true" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </system.serviceModel>
</configuration>

Friday, November 28, 2008

SharePoint Custom RSS Feed Aggregator

We're looking to put in an rss feed aggregator on one of our SharePoint Publishing Site Collections.  For now I'm looking at the code to produce the feed for the rss. I want the feed to take the top 20 items of anything that has changed in a site and all the subsites below it. I plan to expose the feed as a wcf service running on the SharePoint box and then use the service as a data source for a web part that we'll add either via SharePoint Designer or by C# Coded web part.  The wcf service is not required you could put the code into a web part and then cache the web part. Whatever makes sense when we get there.

Some issues in the back of my mind that I forsee popping up:

  • The query on the site for the data is quite a heavy call so I plan to cache the data. My current planned cache location will be in the wcf service. I hope that some wcf config setting will sort this out (about time those wcf configs gave me some love for all the pain I've put into them).  Then get the cache to timeout every 30 min or so.
  • What items do we show?
    Two different users could have two very different views of data.  Someone with admin rights can see alot more than someone else.  To cache everyone's rss feed data is potentially quiet heavy.  Resolution: only show items that have been published (I've not yet put this in the CAML sample below).
  • I build up a list using an item's Display Form.  In Publishing Sites this is by default locked down and not accessible to the public. 
    Resolutions: make Display Forms public, or put a new url for the Display Form with some other url location when I build up the rss feed in the code below.
  • At runtime anything that has been modified will get returned. The items could be a doc lib item, a custom list item, a page, etc.   What I get back as having been 'modified' might not be presentable.
    Resolution: write code to ignore or redirect depending on what the item is, deal with this on an item type per item type basis.

I used this as my starting point:
http://darrinbishop.com/blog/archive/2007/04/08/47.aspx

I then modified the code to get the sample below.
It does the following:

  • Get the latest 20 items in a site collection (will modify this to be sub site relative by editing  "dt = w.GetSiteData(q)")
  • Loops through all the returned items and looks for their Display Form ( see "where n.Type == PAGETYPE.PAGE_DISPLAYFORM")
  • Builds up a string using the item's url, Display Form & ID.
    NOTE:
    This is where things could go wrong...
    What if a custom Display Form is being used that is not set in the form.ServerRelativeUrl?
    What if the Display Form is not actually what you want to show to the public (i.e. a Publishing Page's Display Form).
    Resolution: Deal with these on an item type per item type basis.

What I have below is where I am now and I can proudly say that when I put a break on rssItems after the code has run and randomly browse to the urls that has been generated they all work. 

If you want more info on this as I go along then drop a comment or contact me and I'll add more as I go along.

The code is done in ASP.Net 3.5. I opened Visual Studio 2008 created a new windows application and made a reference to Microsoft.SharePoint.dll. That was it. I will move this code into a class library and break it up into objects at a later date.

I apologise for the code not being styled, cut and paste it into Visual Studio and it'll sort itself out.
My Live Writer "Insert Code..." plugin is full of hate.
I'll clean it up at some point.

List<string> rssItems = new List<string>();            SPSiteDataQuery q = new SPSiteDataQuery();            q.ViewFields = "<FieldRef Name=\"Title\"/>"                + "<FieldRef Name=\"Modified\"/>"                + "<FieldRef Name=\"ID\"/>"                + "<FieldRef Name=\"EncodedAbsUrl\"/>";             //q.Lists = "<Lists ServerTemplate=\"1100\"/>";            q.Webs = "<Webs Scope=\"SiteCollection\"/>";            q.Query = "<OrderBy><FieldRef Name=\"Modified\" Ascending=\"FALSE\" /></OrderBy>";// +            q.RowLimit = 20;             DataTable dt = null;            using (SPSite site = new SPSite(http://MyServer))            {                SPWeb w = site.OpenWeb();                dt = w.GetSiteData(q);                w = null;                 Dictionary<Guid, SPWeb> webs = new Dictionary<Guid, SPWeb>();                Dictionary<Guid, SPList> lists = new Dictionary<Guid, SPList>();                                 try                {                    foreach (DataRow row in dt.Rows)                    {                        Guid webId = new Guid(row["WebId"].ToString());                        Guid listId = new Guid(row["ListId"].ToString());                                                if (!webs.ContainsKey(webId))                        {                            SPWeb newWeb = site.OpenWeb(webId);                            webs.Add(webId, newWeb);                        }                         SPWeb web = webs[webId];                        SPList list = web.Lists[listId];                         IEnumerable<SPForm> forms = list.Forms.Cast<SPForm>();                        SPForm form = (from n in forms                                       where n.Type == PAGETYPE.PAGE_DISPLAYFORM                                       select n                                      ).FirstOrDefault();                         if (form != null)                        {                            rssItems.Add(form.ServerRelativeUrl + "?ID=" + row["ID"].ToString());                        }                     }                }                finally                {                    // Dispose webs                    foreach (Guid webId in webs.Keys)                    {                        webs[webId].Dispose();                    }                 }            }


Update (1 Dec 2008):
Here's another rss aggregator created by Zlatan.(http://www.codeplex.com/AJAXRSSAggregator) This aggregates already existing rss feeds into one feed.  So one could expose your lists as rss feeds and then get this aggregator consolidate them.  You'd need to tweak the code a little to get the different feeds to order stuff by date.

Thursday, November 20, 2008

Dev Environment: Setting up Visual Studio 2008 SP 1 for Silverlight 2 RTW 2.0.31005.0

I've just setup my development environment for working in Silverlight 2 RTW 2.0.31005.0.  This is the most recent release of Silverlight to date.  It was somewhat painful and I'm putting down the steps I had to go through so hopefully someone else can avoid them. 

My current dev environment when I started the install:

  • Windows Server 2003
  • Silverlight 2 Beta 2 (although this was not obvious as in "Control Panel > Add Remove Programs" it was called "Microsoft Silverlight" with no mention of versions)
  • Visual Studio 2008 SP 1
    To see if SP 1 is installed look here "Visual Studio 2008 > Help > About Microsoft Visual Studio" and look for "Version 9.0.30729.1 SP".  It is NOT listed in the "Installed Products" it's part of the heading above it. Note: I'm not sure if this the right version or latest version of VS 2008. I could not find anything that said "SP 1" I could only find "SP".
  • Internet Explorer 7
  • Firefox 3
  • Deep Zoom Composer
  • NOTE: I have not installed Expression Blend

Steps:

Remove Existing Silverlight Versions

  1. Assuming you already have some version of Silverlight on your machine.
  2. I had Version 2 Beta 2 (2.0.30523.8) running when I started this exercise.  In "Control Panel > Add Remove Programs" I found that the Silverlight Version is not listed so even thought it says Silverlight is installed it does not say which version. 
  3. What version of silverlight are you currently running?
    Here is a useful link which shows the releases (http://en.wikipedia.org/wiki/Silverlight).  At the time of writing this article the most recent release was (2 RTW     2.0.31005.0 October 14, 2008) and this is what I am running.
  4. Open windows explorer and browse to (C:\Program Files\Microsoft Silverlight).  Under that folder is a list of the versions (it works like .net does with a new folder per version).  I had this folder (C:\Program Files\Microsoft Silverlight\2.0.30523.8) which means I was running Version 2 Beta 2. Thus I had to remove it.
  5. Via "Control Panel > Add Remove Programs" I clicked "Remove" for "Microsoft Silverlight" and got an error. I could not remove nor upgrade Silverlight Version 2 Beta 2.
  6. I was getting an errror (0x80070643) which basically means to the best of my knowledge that "something went wrong with an MSI install/removal". Following the link below I downloaded the "Windows Installer CleanUp Utility" and removed the Silverlight MSI references. Then removed Silverlight from the registry.
    How to manually remove Silverlight:(http://blogs.msdn.com/rpomeroy/archive/2008/06/10/how-to-manually-clean-up-a-bad-silverlight-installation.aspx).
  7. I now had no Silverlight versions running on my machine.

Install  Silverlight 2 RTW & Silverlight Tools

  1. Go here http://silverlight.net/GetStarted/
  2. From there follow the link to download (Microsoft® Silverlight™ Tools for Visual Studio 2008 SP1) and download it.
    File Details:
    Name: Silverlight_Tools.exe
    Version: 9.0.30729.146
    Download Size: 72.7 MB
  3. Once you have downloaded the file double click to run it.
  4. It will download a file called "Silverlight.2.0_Developer.exe" and try and install it.  This looks like Silverlight 2 RTW for developers. 
    This did not work for me.  I had Silverlight 2 Beta 2 on my machine and got an error message with the code 0x80070643.  So I had to go through the steps inthe section above to remove Silverlight from my machine completely.
  5. I now did a manual install using the "Silverlight_Tools.exe" file and the following posting(http://timheuer.com/blog/archive/2008/09/29/install-silverlight-2-rc0-offline.aspx)
  6. I now have the following folder on my machine (C:\Program Files\Microsoft Silverlight\2.0.31005.0) which is Silverlight 2 RTW.

Some Funnies

Wednesday, September 3, 2008

MOSS CAML Getting Month and Date Overlapping

Ever wanted to find overlapping date ranges?
For example if you have two date ranges and want to see if they overlap with existing date fields in MOSS.

Here's a picture of what I'm talking about:

imagePicture 1
Where..
MS = Parameter Month Start Date
ME = Parameter Month End Date
SD = MOSS Field Storing Start Date
ED = MOSS Field Storing End Date

The Picture 1 above produces the following logic:
 image Picture 2

There are three possible scenarios:

  • Overlapping dates on the start
  • Overlapping dates in the middle
  • Overlapping dates at the end

Here is the code to reproduce this:

The Code:



DateTime startDateToSearchOn; // parameter
DateTime endDateToSearchOn; // parameter
string startDateFieldName; // existing MOSS Field Internal name
string endDateFieldName; // existing MOSS Field Internal name
string startDateToSearchOnString = startDateToSearchOn.ToString("s");
string endDateToSearchOnString = endDateToSearchOn.ToString("s")
string startDateToSearchOnString = startDateToSearchOn.ToString("s");
string endDateToSearchOnString = endDateToSearchOn.ToString("s");
string queryXml = "<Query>"
+ fields.ToString()
+ "<Where>"
+ "<Or>"
+ "<Or>"
+ "<And>"
+ "<Leq>"
+ "<FieldRef Name='" + startDateFieldName + "' />"
+ "<Value Type='DateTime'>" + startDateToSearchOnString + "</Value>"
+ "</Leq>"
+ "<Geq>"
+ "<FieldRef Name='" + endDateFieldName + "' />"
+ "<Value Type='DateTime'>" + startDateToSearchOnString + "</Value>"
+ "</Geq>"
+ "</And>"
+ "<And>"
+ "<Geq>"
+ "<FieldRef Name='" + startDateFieldName + "' />"
+ "<Value Type='DateTime'>" + startDateToSearchOnString + "</Value>"
+ "</Geq>"
+ "<Leq>"
+ "<FieldRef Name='" + endDateFieldName + "' />"
+ "<Value Type='DateTime'>" + endDateToSearchOnString + "</Value>"
+ "</Leq>"
+ "</And>"
+ "</Or>"
+ "<And>"
+ "<Leq>"
+ "<FieldRef Name='" + startDateFieldName + "' />"
+ "<Value Type='DateTime'>" + endDateToSearchOnString + "</Value>"
+ "</Leq>"
+ "<Geq>"
+ "<FieldRef Name='" + endDateFieldName + "' />"
+ "<Value Type='DateTime'>" + endDateToSearchOnString + "</Value>"
+ "</Geq>"
+ "</And>"
+ "</Or>"
+ "</Where>"
+ "</Query>";



Monday, July 21, 2008

Visual Studio Web Test - Finding Out What Went Wrong

Starting Point

One has a set of Web Tests in Visual Studio and has just done a run of all the tests.  We want to now figure out where something went wrong.

Steps

  • Run all the tests.
    We will now be able to see the state of the system with the click of a button.  In the pic below I can see that 2 tests failed and two passed.
    image 
  • I one double clicks on a particular test case then we can see visually what happened on that run with each request.  See below, I double clicked on a test case that failed and I can now see that it was on the 3rd request where that test failed and it will also show a screen shot of the page. At a glance I can see some broken links (look at the 'header' image that has not appeared)
    image
  • If one now expands a particular request it will show all of the items that are required to make that request valid. And it also show which items failed. See the pic below I can now see that 3 items were not found (see the '404 NOT FOUND' error).
    image

Saturday, July 19, 2008

WebTesting - Fiddler, Visual Studio 2008, MOSS

Goal

  • To enable a team of mixed skills to record webtests.
  • These users must not be restricted to having an installation of Visual Studio 2008.
  • It must be quick and easy to record a test.
  • The tests need to be ported into Visual Studio 2008 for web testing.

Resolution

  • Users create tests with Fiddler2
  • Tests are saved as Archive Zip Files (.saz)
  • The Archive Zip are emailed or stored in a central repository
  • Developers (someone with Visual Studio 2008 with web testing tools installed on it, this is not a default install) open the Archive Zip files and re-save them as webtest files (.webtest).
  • The webtest files are loaded into Visual Studio 2008 and are now available for web testing.
  • If testing that requires scripting is required the webtest can be converted to a code (in Visual Studio 2008)

Steps:

1) Get Fiddler

Install Fiddler2 on all the user's machines. It takes a few minutes to download and get up and running. This blog is written using Fiddler Version (V2.1.6.2).

image

2) Record a web session (Staff Member)
  • Open Fiddler2
  • Open IE (fiddler only runs on I.E. but the idea is just to record the actual testing can be done on different platforms)
  • Record your session.
    In the pic below I have IE & Fiddler2 open.
    I recorded a session by opening up IE and going to google and doing a search for Fiddler2. You will see the captured requests being caught in Fiddler as you browse in IE. image
  • When you are done highlight all the lines in the "Web Sessions" pane image
  • Click "File > Save > Session(s) > in Archive Zip..."
  • Save the .saz file to your disk.image
  • At this point the user recording the test's job is done. The rest of the work is for the developers to get it into Visual Studio 2008.
3) Get the Test Into Visual Studio (Developer)
  • Assuming this is the first time you have loaded up fiddler2 and are using Visual Studio 2008 with web testing tools installed. Testing tools is not a default install of Visual Studio 2008. I have the following installed in VS and think it's this:
    "Microsoft Visual Studio Team System 2008 Test Edition"
  • You have a "Archive Zip File" (.saz) that someone has recorded.
  • Open the .saz file up in Fiddler2
    "File > Load Archive..."
  • Now save the file as a Visual Studio Web Test. First highlight all the lines in the Web Sessions pane of fiddler then click:
    "File > Save > Session(s) > as Visual Studio Web Test"
  • I have called the sample file "BlogTest.webtest"
  • If you get the following error:
    "One or more plugins returned an error, but the remaining plugins executed and the Web Test was written.

    Could not load file or assembly 'Microsoft.VisualStudio.QualityTools.WebTestFramework, Version=8.0.0.0,... "image

  • It is because the Fidder2 plugins are expecting Visual Studio 2005. To get around this:
    • goto the Fiddler2 install folder
    • open "fiddler.exe.config"
    • paste the following code over the existing xml that's in the config file:
      <configuration>
        <runtime>
            <legacyUnhandledExceptionPolicy enabled="1" />
            <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
                <dependentAssembly>
                    <assemblyIdentity name="Microsoft.VisualStudio.QualityTools.WebTestFramework"
                    publicKeyToken="b03f5f7f11d50a3a"
                    culture="Neutral" />
                    <bindingRedirect oldVersion="8.0.0.0"
                    newVersion="9.0.0.0"/>
                    <codeBase version="" href="C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.WebTestFramework.dll"/>
                </dependentAssembly>
            </assemblyBinding>
        </runtime>
      </configuration>
  • Open Visual Studio 2008
  • Create a new Test Projectimage 
  • Add the BlogTest.webtest to your projectimage
  • The test will now be available to run from within the Visual Studio 2008 Web Testing Tools.

    As can be seen below I am running this from within a Virtual Machine that has decided (as per one of it's moods) to have a no talkies to the internet so the test fails.image
  • Done. 
    You now have a webtest in visual studio.  This can be automated to run at regular intervals or can be run after a new piece of functionality has been deployed.
4) Scripting against an existing webtest within Visual Studio

Let us assume one has followed the steps above and we now have a webtest sitting in Visual Studio 2008. What if we now want to do some more in depth testing. For example I have a SharePoint 2007 list that I'd like to try hit all the items in the list. To do so I would get a list of all the items programmatically and then try hit each of these. This will be the topic of another post when I get around to it.

For now here are the steps to convert a webtest into a scripted test.

  • Double click the webtest in Visual Studio to open the testimage
  • In the main pane right click on the Root of the test. In my example it's "BlogTest"image 
  • Click"Generate Code..."
    Visual Studio will now create a class in your solution.image 
  • To test this code:
    • Set a break point in the codeimage
    • open the "Test View Pane" and click:
      "Debug Selection"image 
    • Your break point will now be hitimage
    • Happy Testing!

Conclusion

Using the steps above a team can now build up a library of test Archive Files (.saz) files. This archive can be generated by team members who do not need Visual Studio on their machines. If there are errors with a site then I would suggest

  • whoever finds the error records it
  • saves it in a central repository
  • a developer then brings it into Visual Studio
  • the test then becomes part of an ever growing Test Library.