My slides from VSLive Orlando 2008

I just finished up doing VSLive Orlando 2008 this week.  To all of you who were in my sessions, thanks for coming.  For those of you who missed the conference, you should go to the next VSLive.

Here are my slides from this year's talks:

If you'd like to try the TFS 2008 report customization that I demo'd, I've blogged a howto here.  I'll be posting my code for the WiX talk sometime over the next few days.

-Ben

Team Foundation Server 2008: Edit the Remaining Work Report to Use Non-Default Status Values

In Team Foundation Server 2005 and Team Foundation Server 2008, one of the best ways to break the out-of-the-box Team Project reports is to add new status values for your work items.  Unfortunately, adding new work item status values is one of the first things that most customers need to do.  For example, I always add an initial status of "Proposed" for my Task and Bug work items in my MSF for Agile Team Projects.  This allows me to add work items to my project without having to decide if I'm actually going to do them. This might seem like a slightly weird idea -- if I don't know if I want to do something then why should I put it in TFS at all? -- but this allows me to "brain dump" into TFS and gives me a place to track all the things I think I MIGHT have to or want to do in the future on my project.  This brain dump frees me up from having to actively remember stuff and lets me worry about actually doing my job rather than trying to be some memorization expert.

This blog post will walk you through the process of modifying the Remaining Work report in an MSF for Agile v4.2 Team Project.  This is a slightly modified version of a lab in my 5-day Visual Studio Team System & Team Foundation Server class.  If you're looking for help installing or configuring Team Foundation Server or want guidance on using and adopting Visual Studio Team System, please contact me via http://www.benday.com.

Pre-requisites:

  • You have already exported the MSF for Agile 4.2 Process Template to your local disk at C:\labs\MSF for Agile Software Development – v4.2.
  • You have installed the Business Intelligence Design Studio (BIDS) 2005 from the SQL Server 2005 installer disk and applied any relevant service packs. Currently, there is no Visual Studio 2008 equivalent of BIDS and therefore this lab requires you to use some Visual Studio 2005 tools.
  • You have customized at least one of the work items in your Team Project to introduce a “Proposed” work item state value (System.State).

The completed version of this lab is available for download from here.

clip_image002

To begin, open up Visual Studio 2005 and create a new project.

clip_image004

- Choose: Report Server Project

- Name: TfsReportCustomization.Reports

- Location: c:\labs\

- Solution Name: TfsReportCustomization

- Click: OK

In Solution Explorer you should now see your new project.

clip_image006

Now, we’ll import the report definition files from the exported MSF for Agile process template.

- In Solution Explorer, right-click the Reports folder | Add… | Existing Item…

clip_image008

- In the Add Existing Item dialog, navigate to:
C:\labs\MSF for Agile Software Development - v4.2\Reports

- Select: All .rdl files

- Click: Add

In the Solution Explorer, you should now see all the files you just added to the project.

clip_image010

The TFS reports reference two Shared Data Sources: TfsReportDS and TfsOlapReportDS. In order to make these reports run in Visual Studio, we’ll need to re-create these data sources.

- In Solution Explorer, right-click the Shared Data Sources folder | Add New Data Source

You should now be on the Shared Data Source dialog.

clip_image012

- Name: TfsReportDS

- Type: Microsoft SQL Server

- Connection string: Data source=TFS2008;initial catalog=TfsWarehouse

NOTE: you should replace “TFS2008” with the name of your Team Foundation Server data tier in the connection string. You may also have to provide the appropriate credentials on the Credentials tab of the Shared Data Source dialog.

- Click: OK

The new TfsReportDS data source should now be visible in the TfsReportCustomization.Reports project as “TfsReportDS.rds”.

clip_image014

Now, let’s repeat this process and create the Shared Data Source for the reporting OLAP connection.

- In Solution Explorer, right-click the Shared Data Sources folder | Add New Data Source

clip_image016

- Name: TfsOlapReportDS

- Type: Microsoft SQL Server Analysis Services

- Connection string: Data source=TFS2008;initial catalog=TfsWarehouse

NOTE: you should replace “TFS2008” with the name of your Team Foundation Server data tier in the connection string. You may also have to provide the appropriate credentials on the Credentials tab of the Shared Data Source dialog.

You should now see the TfsOlapReportDS.rds in the Shared Data Sources folder.

clip_image018

Now let’s begin editing the Remaining Work report.

- In Solution Explorer, double-click “Remaining Work.rdl”

You should now see the Layout tab of the Remaining Work report and the development view of the report. Notice that at the top of the report only the Closed, Resolved, and Active status values are shown.

clip_image020

Best practice: Before you start customizing the report, you should add this project to source control and check in your code. This will give you a baseline version that you can roll back to if you make mistakes.

Ok. Now is when we’ll start adding support for our additional status values. First, we’ll modify the parameters for the dsWorkItemHistory dataset.

clip_image022

- Click the “Data” tab

- Dataset: dsWorkItemHistory

- Click the “…” button

You should now see the Dataset dialog.

clip_image024

- Click the “Parameters” tab

- Add a new parameter to the bottom of the list

o Name: Proposed

o Value: =Parameters!Proposed.Value

- Click: OK

You should now see the dataset query window for dsWorkItemHistory again. Let’s modify the query to pull back the count of Proposed work items.

Locate the following section of the query.

MEMBER [Measures].[Resolved Cumulative Count] AS

Sum(

(StrToMember("[Work Item].[System_State].[System_State].[" + @Resolved + "]")),

[Measures].[Cumulative Count]

)

SELECT

{

[Measures].[Date Value],

[Measures].[Active Cumulative Count],

[Measures].[Closed Cumulative Count],

[Measures].[Resolved Cumulative Count]

} ON COLUMNS,

Now we’ll add the code to bring back the proposed work item count.

MEMBER [Measures].[Resolved Cumulative Count] AS

Sum(

(StrToMember("[Work Item].[System_State].[System_State].[" + @Resolved + "]")),

[Measures].[Cumulative Count]

)

MEMBER [Measures].[Proposed Cumulative Count] AS

Sum(

(StrToMember("[Work Item].[System_State].[System_State].[" + @Proposed + "]")),

[Measures].[Cumulative Count]

)

SELECT

{

[Measures].[Date Value],

[Measures].[Active Cumulative Count],

[Measures].[Closed Cumulative Count],

[Measures].[Resolved Cumulative Count],
[Measures].[Proposed Cumulative Count]

} ON COLUMNS,

- Add the highlighted code as shown above

Now we have to modify the query parameters.

clip_image026

- Click the “Query Parameters” button (circled above)

You should now be on the Query Parameters dialog. We’ll now add the Proposed value to the bottom of the list.

clip_image028

- In the Parameter column, click “<Enter Parameter>”

- In the Parameter column, type: Proposed

- In the Default column, type: Proposed

- Tab off of the newly added row to activate the “OK” button

- Click: OK

The dsWorkItemHistory dataset configuration changes are now complete. In the “Datasets” window (probably in the left pane), you should now see a field named “Proposed_Cumulative_Count”.

clip_image030

- Go to the Datasets pane

- Expand: dsWorkItemHistory

- Verify that “Proposed_Cumulative_Count” is in the list.

If “Proposed_Cumulative_Count” is not in the list, go back and check the “SELECT” portion of the query.

We’ll now start editing the display of the query to use the Proposed count.

clip_image032

- Click on the “Layout” tab

This next part is a little bit tricky. We need to drag the Proposed_Cumulative_Count field from the Datasets window and drop it in a field on the Layout designer that’s hidden until we hover over it. Making this next step work might take a little bit of trial and error.

clip_image034

- In the Datasets window, click and drag the “Proposed_Cumulative_Count” as shown in the diagram above to point #2

- Pause briefly at point #2 to make the data fields list appear

- Continue dragging the Proposed_Cumulative_Count to point #3 and drop it onto the words “Drop data fields here”

If you were successful, you should now see the Proposed Cumulative Count in both the data fields box and in the chart’s legend.

clip_image036

In order to fix the chart’s legend so that it says “Proposed” instead of “Proposed Cumulative Count”, we’ll need to edit the properties for the chart field.

clip_image038

- In the data fields box, right-click: Proposed Cumulative Count | Properties

You should now be on the Edit Chart Value dialog.

clip_image040

- Series label: Proposed

- Click: OK

On the chart layout, you should now see the legend with the value of “Proposed” instead of “Proposed Cumulative Count”.

clip_image042

Only a little bit more to do. We need to make a tiny tweek to one of the report parameters.

clip_image044

- Go to the Properties window for the report

- From the drop-down, choose: Report

- Click: ReportParameters

- Click: “…”

Clicking “…” should have brought up the Report Parameters dialog.

clip_image046

- In the Parameters listbox, choose: Proposed

- Locate the “Internal” checkbox

- Check: Internal

- Click: OK

Now let’s see if we made the edits correctly.

clip_image048

- Click the “Preview” tab

- Set the “ExplicitProject” value to be the name of your team project (example: Agile 2008)

The ExplicitProject field is only visible at development time and is used to say which Team Project you want to query for. During production, this value is retrieved at runtime by looking at the name of the folder that the .rdl file is running from.

- Tab off of the ExplicitProject field.

Moving away from the ExplicitProject field causes the rest of the report execution fields to populate with values. (NOTE: the values you see may not be the same as what is in the image below.)

clip_image050

- Set the start and end date values to a time range that has data

- Click: View Report

You should now see your populated Remaining Work report with values for Proposed work items.

clip_image052

The report customization is finished. If you’re developing under source control, you should check in your changes.

Alright. So we’ve got the report customized. Let’s publish it back to our TFS report server we can actually use it.

- Open Internet Explorer

- Navigate to: http://your_tfs_name/Reports

You should now be on the SQL Server Reporting Services home page and you should see a list of your available Team Project folders.

clip_image054

- Click on the folder for the Team Project you’re customizing. (example: Agile 2008)

Clicking the project link will take you a list of Reports for that project.

clip_image056

- Locate the “Remaining Work” report

- Click: Remaining Work

You’ll now be taken in to the Remaining Work page.

- Click the “Properties” tab

You should now see the Remaining Work report’s properties page.

clip_image058

- Locate the “Update” link

- Click: “Update”

You should now be on the “Import Report” page for Remaining Work.

clip_image060

- Click: Browse…

- Choose the Remaining Work.rdl file on your local disk. If you set up your code as described at the start of this lab, the path should be
C:\labs\TfsReportCustomization\TfsReportCustomization.Reports\Remaining Work.rdl

- Click: OK

You should be on the Properties screen again.

- Click the “View” tab

You should now see your updated Remaining Work report with the Proposed value displayed in the chart.

clip_image062

You’ve completed the customization of the Remaining Work report.

 

If you're looking for help installing or configuring Team Foundation Server or want guidance on using and adopting Visual Studio Team System, please contact me via http://www.benday.com.

"Session state is not available in this context" exception accessing ASP.NET Session in PreRequestHandlerExecute event

I'm doing my final preparations today for speaking at VSLive San Francisco 2008 on Wednesday and Thursday.  I went to check one of my demos and code that used to work started throwing an exception.

System.Web.HttpException was unhandled by user code
  Message="Session state is not available in this context."
  Source="System.Web"
  ErrorCode=-2147467259
  StackTrace:
       at System.Web.HttpApplication.get_Session()
       at UiDesignForTestability.WebUI.Global.InitializeMultiSessionFactoryNHibernate() in C:\code\bendaytfs2\BDC\branches\UiDesignForTestabilityMultiDb\UiDesignForTestability.WebUI\Global.asax.cs:line 24
       at UiDesignForTestability.WebUI.Global.Application_PreRequestHandlerExecute(Object sender, EventArgs e) in C:\code\bendaytfs2\BDC\branches\UiDesignForTestabilityMultiDb\UiDesignForTestability.WebUI\Global.asax.cs:line 45
       at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
       at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
  InnerException:

<ben:Panic operation="Start" intensity="Extreme" />

The offending code was trying to access the ASP.NET Session object from the PreRequestHandlerExecute event in my Global.asax.cs.  This exception shouldn't be possible.  In fact, it should be IMPOSSIBLE because according to the documentation, AquireRequestState should have fired already.  (Can you tell that I was getting anxious?  Getting on a plane tomorrow and the demos aren't working anymore.  I fixed it but I'm still anxious anyway, actually.)

Ok.  Well, it turns out that during Global.asax's processing, it fires all the events for each of the HttpHandlers in the pipeline.  Well, not all HttpHandlers implement IRequiresSessionState.  For example, System.Web.Handlers.AssemblyResourceLoader doesn't and that's what was causing the exception when InitializeMultiSessionFactoryNHibernate() was getting called. 

        protected void Session_Start(object sender, EventArgs e)
        {
            InitializeMultiSessionFactoryNHibernate();
        }

        public void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
        {
            InitializeMultiSessionFactoryNHibernate();            
        }

        private void InitializeMultiSessionFactoryNHibernate()
        {
            if (Session["NHibernateConfiguration"] == null)
            {
                Session["NHibernateConfiguration"] = "UiDesignForTestability";
            }

            SessionFacade.ConfigurationName = Session["NHibernateConfiguration"] as string;
        }

Well, back on 5/30/2006 at 2:33am, Brock Allen wrote the solution into a comment here.  The answer is to check that the current handler implements either IRequiresSessionState or IReadOnlySessionState.

        public void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
        {
            if (Context.Handler is IRequiresSessionState || Context.Handler is IReadOnlySessionState)
            {
                InitializeMultiSessionFactoryNHibernate();           
            }           
        }

Thanks, Brock.  This helped IMMENSELY.

Now the real question is why did that code work before? 

-Ben

Call to IIS-Hosted WCF Service Hangs IIS (well, not exactly)

I ran into this problem a couple of days ago.  I'm working on an n-tier application that uses WCF services hosted in IIS under Vista & Windows 2008.  We've got unit tests to test each tier and they were mostly passing.

We unit test our service code both directly by reference (unhosted) and then unit test them again when they're hosted in IIS.  They worked great when they were unhosted but the hosted ones had intermittent problems.  More and more it looked like IIS was hanging and once the hosted tests started failing, the only way to make them pass again was to restart IIS by running iisreset. 

A weird thing was that all of these unit tests ran just fine on their own.  They only failed when you ran them with other tests but there wasn't any particular test that failed every time.  The tests would run at normal speed and then one of them would just sit there forever and would eventually time out. Once you got the first failure/timeout, all the rest of the tests would fail, too. 

Here's the error:

PeopleManagement.UnitTests.HostedServiceTests.HostedPeopleManagementServiceMembershipSearchFixture.HostedServiceSearchMembershipsByMembershipType threw exception:  System.TimeoutException: The request channel timed out while waiting for a reply after 00:00:59.9990001. Increase the timeout value passed to the call to Request or increase the SendTimeout value on the Binding. The time allotted to this operation may have been a portion of a longer timeout. --->  System.TimeoutException: The HTTP request to 'http://localhost/PeopleManagement.IisServiceHost/PeopleManagementService.svc' has exceeded the allotted timeout of 00:01:00. The time allotted to this operation may have been a portion of a longer timeout. --->  System.Net.WebException: The operation has timed out.

Something about this had the smell of a threading problem. 

I started discussing this problem with my friend and co-worker, Michael Stiefel, and he agreed that this sounded like a threading problem.  Once we were both thinking "threading problem", I started thinking about where there's something multi-threaded in this unit test.  The only multi-threaded part is IIS.  Then like a flash of lightning, I noticed that it didn't matter which tests I ran but HOW MANY I ran.  It was always the 11th test that failed.  Pick any 11 tests -- the first 10 passed and the 11th always failed!

Then another flash of mental lightning and I realized that I'm probably doing something dumb in my code. 

Answer: My team and I were creating instances of the Service Reference proxies to the WCF service but we never called Close() on the proxy.  (Duh.)

Since we're writing services that are only HTTP and since HTTP is stateless, it never occurred to me that I'd have any connection to close.  (Nope.  Not true.)  Michael Stiefel dug up this quote from Michele Bustamante:

Don't forget to close your proxy. If you forget, you will find some interesting results. You will get unexpected behavior and will not know why.

Whew! Ain't that the truth!

-Ben

Convert a column data type on the fly with LINQ To SQL

I got an email yesterday from a reader with this LINQ To SQL problem. 

He was working with an existing database and some of the columns in his database weren't the same type as what he wanted to use in his C# classes.  The database column is a string but in the LINQ To SQL entity, they wanted the C# property type to be a long.  When they tried to do it, they got all kinds of errors saying that the type can't be converted on the fly. 

The solution is to map the column to a private member variable that is the same type as in the database and then provide a public property that wraps that member variable and exposes it as the proper, required type.  Essentially, you're solving the problem by not solving the problem.

Here's what their database table looks like.  Notice that Longitude and Latitude is stored as an NVARCHAR(4000).

Here's the class that they wanted to use with LINQ to SQL.  Notice that the Latitude and Longitude properties are of type long.

Here's the solution.  Add a wrapper property with a private member variable. 

[Column(Name = "Latitude", Storage = "m_latitudeAsString")]
private string m_latitudeAsString;

public long Latitude
{
    get
    {
        return Int64.Parse(m_latitudeAsString);
    }
    set
    {
        m_latitudeAsString = value.ToString();
    }
}

The key piece here is the [Column] attribute
[Column(Name = "Longitude", Storage = "m_longitudeAsString")]
and the column's Storage value.  The Column's Storage value allows you to tell LINQ to SQL to store/retrieve the mapped value from a variable rather than the public property.  So, what we're doing here is using our public Latitude property to handle the data-type conversion logic and wrap access to m_latitudeAsString.  The public Latitude property actually isn't mapped to the database. 

Here's a link to download the sample code.  In order to make the unit test run, you'll need to edit the connection string in the app.config in the unit test project.  You don't have to create the database schema yourself, you just have to make sure that the database referenced in the connection string exists in your SQL Server. 

-Ben

Fix: Team Foundation Server Reports broken after upgrade from TFS 2008 Beta 2 to TFS 2008 RTM

I did an upgrade today from TFS beta2 to RTM.  Everything worked fine except for the reports.

All the reports gave the following error:

“Logon failed. (rsLogonFailed) Logon failure: unknown user name or bad password. (Exception from HRESULT: 0x8007052E)”

After a few minutes, the error message has changed over to:

“Logon failed. (rsLogonFailed) The referenced account is currently locked out and may not be logged on to. (Exception from HRESULT: 0x80070775)”

The fix came from Grant Holliday via this link.  (Thanks, Grant!)

On the TFS application tier machine, run the Reporting Services Configuration editor.

Click the "Execution Account" tab.

Uncheck "Specify an execution account" and click Apply.

That fixes the problem.

-Ben

 

-- Need help setting up Team Foundation Server and/or Visual Studio Team System?  Need training on VSTS and TFS?  Want help configuring your source control, work items, and Team Builds?  Contact me via http://www.benday.com.

Beantown .NET Meeting in Waltham on 1/31 with David Chappell

Beantown .NET is doing a special joint meeting with Boston .NET, Boston .NET Architecture, and New England Visual Basic Professionals user groups at Microsoft in Waltham on Thursday, January 31.  (Thanks to Chris Bowen for organizing this.)

For this meeting we have David Chappell presenting “Understanding Software + Services”.

As always, our meeting is open to everyone so bring your friends and co-workers.  For this meeting, there is no need to RSVP.

Future meetings:

• No meeting on February 7
• March 6 – Adam Machanic – SQL Server 2008
• April 10 – Benjamin Day – NHibernate & Other .NET ORMs
• May 1 –Mario Cardinal – “Best Practices to Decrease Coupling and Raise Cohesion”

Beantown Meeting Details

When: Thursday, January 31, 2007, 6:00 – 8:00pm

Where:
Microsoft
201 Jones Rd., 6th Floor
Waltham, MA 02451
http://www.microsoft.com/about/companyinformation/usaoffices/northeast/waltham.mspx


Map:
http://tinyurl.com/2myyaf

Title:
Understanding Software + Services

Abstract:
The move to service-orientation is well underway, both inside enterprises and on the Internet. What role does traditional software play in a world of on-line services? In particular, how is Microsoft approaching the combination of software plus services? This presentation provides an overview of this area, giving an introduction to and a perspective on this emerging combination.

Bio:
David Chappell is Principal of Chappell & Associates in San Francisco, California. Through his speaking, writing, and consulting, he helps IT professionals around the world understand, use, and make better decisions about enterprise software.

David has been the keynote speaker for dozens of conferences and events in the U.S., Europe, Asia, and Latin America. His popular seminars have been attended by tens of thousands of developers, architects, and decision makers in forty countries. He has also spoken at many universities, including the National University of Singapore, Moscow State University, and Sweden's Uppsala University.

David's books have been published in ten languages and used regularly in courses at MIT, ETH Zurich, and other educational institutions. He is Series Editor for Addison-Wesley's award-winning Independent Technology Guides, and he's been a columnist for several publications. In his consulting practice, David has helped clients such as Hewlett-Packard, IBM, Microsoft, Stanford University, and Target Corporation adopt new technologies, market new products, train their sales staffs, and create business plans.

David's comments have appeared in The New York Times, CNN.com, and many other publications. Earlier in his career, he wrote software for supercomputers, chaired a U.S. national standardization working group, and played keyboards with the Peabody-award-winning Children's Radio Theater. David holds a B.S. in Economics and an M.S. in Computer Science, both from the University of Wisconsin-Madison. You can reach him at: www.davidchappell.com

Quoted in an article on multicore development

Newsflash-- I got quoted last week in an article about Microsoft's Parallel Extensions for .NET 3.5 by Jack Vaughn.  (Thanks, Jack!)

-Ben

Could not connect to Virtual Server 2005 R2 SP1 admin web site on Win2003 x64

This problem had been plaguing me all week.  Every time that I'd try to connect to the admin site for my Virtual Server 2005 box, I'd get an http 500 error and Virtual Server would hang.  If I tried to shut down the Virtual Server service through the Services applet or via "net stop" it would just spin and spin and spin.  The only solution was to kill the Virtual Server process.  Conveniently enough, nothing would show up in the event log to help diagnose the problem other than a warning that the service stopped unexpectedly.  (Really? You don't say? -- Of course it did! I'd just killed it myself!  DUH!)

After much gnashing of teeth, I found a solution in Spanish and thanks to Google's "translate" functionality, I was able to actually read it.  Here's the post.  Here's the machine translated quote that helped:

And it had not tested and works when this problem occurs. Obviously the common VMRC does not work either.

The solution by which I will choose to change the Virtual Server by one who does not have SP1 installed. I think it is too serious a mistake that a VM is that it saves the state can not be lifted again and also not be able to access the site administration.

Sure.  It's not the best translation ever but it got me wondering if there was saved state.  So I took another suggestion from that same forum thread to download the VMRCPlus client and connect to Virtual Server without the admin site (via COM?).

Turns out there was a guest OS with saved state.  I dumped the state and now the Virtual Server Admin Site comes up without problems. 

My guess on how this happened is that Windows Update applied a patch on the host machine and then rebooted the server.  When the host server came back up, something was dreadfully wrong with the saved state for that guest machine and it horked Virtual Server. 

-Ben

The Windows Process Activation Service service terminated with the following error: The system cannot find the file specified."

I'm not sure if this is related to the Vista Service Pack 1 Beta but I installed the SP1 beta recently and then within the next week or so I couldn't start IIS (W3SVC).  When I'd try to start W3SVC I'd get an error saying "The dependency service or group failed to start."  A little digging and I found out that the Windows Process Activation Service (WAS) wasn't started and that that was the dependency.

(A little side note: trying to search the internet on something called "was" is annoying because either the search service discards "was" as a noise word or I get a match on the past tense form of the verb 'to be'.  Mountains of useless results.)

When I tried to start WAS, I'd get an error saying "The Windows Process Activation Service service terminated with the following error: The system cannot find the file specified."  What made this extra fun to diagnose was that the "file specified" didn't show up in the error message. 

Eventually, I found a page on technet that provided the answer.  The path that WAS was looking for was "c:\inetpub\temp\appPools".  I re-created it and set the permissions as shown in the technet article and everything was working again.

-Ben