TFS-GIT Release Notes

I was recently having trouble generating some Release Notes for a current project that is using Visual Studio Online Visual Studio Team Services.  With Git as our backing source control system there didn’t seem to be an easy way to see what Work Items were going into a release.  Thankfully we are associating Work Items with commits which makes the following Powershell script work. 

Passing in our current release branch, and our previous release branch we can isolate the new commits and then parse their commit messages looking for the “Related Work Items:” text that Visual Studio appends to commits.  Once we have those WorkItem ids we can use the TFS api to get some info about them and create some release notes.

 

You can find the script on GitHub.

XAML Formatter

I’ve been doing a lot of XAML work lately on a WPF project, and the client is really concerned about sloppy / ugly XAML.  The one problem I found was that Visual Studio 2010 is not really all that great at formatting XAML and it certainly does not format it the way I want it formatted.  So I decided to write something that would do the formatting for me, I started with a PowerShell script that I used via PowerConsole.  Worked great, but with some free time I decided why not write a proper VS2010 extension.

The key principle behind the formatter is that it only concerns itself with indentation, not what should be on any given line.  Visual Studio does offer some options in this regard but the closest thing I could get to what I wanted meant that when I formatted, a typical style Setter was 2 or 3 lines.  Multiplying the size of a style by 2 or 3 times makes for a rather large XAML file, not ideal.  So you worry about what goes on what line, and I’ll take care of making it all nicely aligned. 

Comment indentation is not perfect yet, but it usable, maybe v1.1 will have some improvements.

I’m looking into V2 which will simply intercept the Format Code command.  I didn’t go this way in V1 because of the complexity around formatting a selection.  Currently I format the entire document.  When I finish V2 I’ll post both code samples.

NOTE: I originally wrote this extension back in early October 2010, so there might be a similar tool available now.

BEFORE:

PreFormatting

AFTER:

PostFormatting

Feedback: I’d love to hear some feedback, if you have something that does not format correctly and feel comfortable sending me the XAML snippet, please do.   Any questions, comments, or concerns can be sent to XamlFormatter@danno.ca

Download: You can download the latest version of the XamlFormatter from the Visual Studio Gallery

WCF RIA Services - “Not Found” Error Message

The dreaded “The remote server returned an error: NotFound” error message in RIA Services can be frustrating if you are not aware of what it really means, and more importantly how to diagnose it.

This generic error message is due to network stack limitation in your browser, basically the browser is intercepting the error and not giving it all to Silverlight.  That does not mean there isn’t good information to be found.  Your friend here is Fiddler and/or WCF Service Tracing. 

NotFound vs OnError:  A NotFound generally means that something in the WCF side blew up, OnError will handle errors in your model (or custom code in your DomainService).  So when you see NotFound, overriding OnError will not be much help, break points placed inside of it will most likely not be reached during debugging, but its an easy place to start.

The first tool we are going to us is Fiddler, a web debugging proxy with a WCF Binary Inspector. This will show you all the requests are being made and will show you what error code, and possibly what error is being returned by your service. (Using Fiddler with ASP.Net Development Server / Casini)

Fiddler

If there is no good information in Fiddler then the next step is to hit your service url, which you can find in Fiddler.   In the picture above you can see that my service is at /ClientBin/HockeyStatsService-Web-HockeyStatsDomainService.svc (ProjectName-Web-DomainServiceName.svc).  Remember that RIA Services does not actually generate a .svc file for you, it is handled dynamically by the DomainServiceHttpModule, so don’t go looking for a physical file.

Actual 404:  If you hit your service in the browser and you still get a 404, then something is wrong with your deployment. 

Actual404

Check out Saurabh Pant’s Blog or Tim Heuer for good articles on deploying WCF Ria Services to IIS.

If you are using Casini (ASP.NET development server) then make sure your web.config is correct (Has proper references to DomainServiceHttpModule), and that you have a reference in your ASP.NET project to your service library (if you are using RIA Class Libraries, otherwise you should be fine on this point).

Now if you can hit your service url without a 404, but still get a NotFound, and the Fiddler response tab didn’t give you anymore insight we will move on to some other steps.

SvcTraceViewer: Visual Studio has a tool to help you configure WCF, it can be found under TOOLS | WCF Service Configuration Editor.  Use this tool to open your Web.Config and then on the ‘Diagnostics’ folder, turn on Message Logging and Tracing.  On the ‘Message Logging’ node, LogMessagesAtServiceLevel=true and LogMessagesAtTransportLevel=false.

WCFtraceConfig2

You can view the generated svclog files with C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\SvcTraceViewer.exe

In my example DomainService I am loading a large amount of hockey stats data.  When I open my svclog file and find the error generated I can see that the actual exception being thrown by my service says:

'Maximum number of items that can be serialized or deserialized in an object graph is '65536'. Change the object graph or increase the MaxItemsInObjectGraph quota. '.

WCFTraceViewer

Your message obviously might be different, but with that information you should be able to find a solution or at least provide the right information to the WCF RIA Services Forums so they can help find a solution

Another good debugging tip is to turn off custom errors in your Web.Config.  <customErrors mode="Off"/>  This will provide more informative exceptions to silverlight, however it also exposes information to the user that you may not intend, so do not leave this set to ‘off’ on a publicly available site.

If your error is the same as mine, take a look at Fixing the MaxItemsInObjectGraph.

MaxItemsInObjectGraph – WCF RIA Services Exception

 

The MaxItemsInObjectGraph error message comes up fairly often in the WCF RIA Services forums and I just ran into it on a personal project so I thought I’d write a quick blog on how to fix this error.

The exact error message from WCF Trace is:

'Maximum number of items that can be serialized or deserialized in an object graph is '65536'. Change the object graph or increase the MaxItemsInObjectGraph quota. '.

You need to add the following code to your web.config, and replace the following:

HockeyStatsService-Web-HockeyStatsDomainService with YourRiaProjectName-Web-YourDomainServiceName

HockeyStatsService.Web.HockeyStatsDomainService with YourRiaProjectName.Web.YourDomainServiceName

<services>
  <service name="HockeyStatsService.Web.HockeyStatsDomainService"
          behaviorConfiguration="HockeyStatsService-Web-HockeyStatsDomainService">
  </service>
</services>
<behaviors>
  <serviceBehaviors>
    <behavior name="HockeyStatsService-Web-HockeyStatsDomainService">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="true" />
      <dataContractSerializer maxItemsInObjectGraph="655360"/>
    </behavior>
  </serviceBehaviors>
</behaviors>

Changing timeouts in WCF RIA Services

This article is valid for the RC version and above

In previous versions of WCF RIA Services, it was extremely difficult to change the service timeouts for your DomainService, you were pretty much stuck with the defaults.  The RC release has made it fairly easy, though not all that discoverable.

The single line of code you need is:

((WebDomainClient<LibraryDomainContext.ILibraryDomainServiceContract>)this.DomainClient).ChannelFactory.Endpoint.Binding.SendTimeout = new TimeSpan(0, 5, 0);

There are two options on where to put this line of code.  First is anywhere after you construct a DomainContext, in which case change ‘this’ to the name of your context object. 

The second choice is to create a partial class for your DomainContext and use the partial method OnCreated, which would look like this:

public partial class LibraryDomainContext
{
   partial void OnCreated()
   {
      if(DesignerProperties.GetIsInDesignMode(App.Current.RootVisual))
         ((WebDomainClient<LibraryDomainContext.ILibraryDomainServiceContract>)this.DomainClient).ChannelFactory.Endpoint.Binding.SendTimeout = new TimeSpan(0, 5, 0);
   }
}

If you are not sure of the interface you should be using on WebDomainClient, take a look at the constructor of your DomainContext, it is calling the base constructor with the proper WebDomainClient that you should be using above.

EDIT: March 31st 2010

I added a Designer check to the code, this will stop exceptions from being thrown during design time.  If you found this post for some other reason than WCF RIA Services RC (or higher) be aware that the above designer check has issues with older versions of Visual Studio.  Read this post from Delay's Blog for info

Silverlight Binding Lesson

I learned a very important lesson about binding in Silverlight that I thought I would share. 

Here is what I was trying to do:

<TextBlock Text=”{Binding Path=MyPeople, Converter={StaticResource OldestPersonNameConverter}}” />

MyPeople is a collection of People and the converter is going to take that collection, find the oldest person and return their name.  I thought this would just work and it does the first time.  However in this case, adding a new person to MyPeople will NOT trigger the binding to update, your converter will never run again.

Right? Wrong?  I’ve been debating the point with a few people at Objectsharp, and I didn’t expect this to fail (some did).  I was under the assumption that binding was binding, the magic behind the covers would look for INotifyPropertyChanged or INotifyCollectionChanged regardless of the property you are trying to bind.

This doesn’t work for my example, but in my actual code I was able to bind to myCollection.Count which will fire a PropertyChanged event when you add or remove an item from the collection.  In the actual example above, I don’t have a good answer, they all have drawbacks.

WCF Ria Services vs Entity Framework

This is a quick tip for anyone using WCF RIA Services with Entity Framework.  The WCF RIA Services team has fixed what I consider a fairly annoying ‘bug’ with Entity Framework.  In Entity Framework the EntityCollection class does not implement INotifyCollectionChanged, however the client side EntityCollection class that RIA uses is part of the RIA framework and they have fixed this issue.  They have explicitly implemented the interface however so you will need to cast the EntityCollection to a INotifyCollectionChanged before you see the CollectionChanged event.

RIA Services XMLMetaDataProvider and Dynamic Assemblies

If you are using the XMLMetaDataProvider and have a dynamic assembly reference your service might fail with the following error:

           The invoked member is not supported in a dynamic assembly

There are two fixes for this problem, one is to use the full attribute names.  So ‘DisplayAttribute’ instead of just ‘Display’.  Second option is to fix the code in MetadataSet.cs.  The problem is with the TryGetType method around line 421.  You should be able to find the code below, the GetExportedTypes needs to be changed to GetTypes. 

   1: // TODO : the metadata file might need a way to specify the set
   2: // of source assemblies to load from - for now search all loaded assemblies
   3: foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
   4: {
   5:     foreach (Type t in assembly.GetTypes())
   6:     {
   7:         if (t.Name == typeName || t.FullName == typeName)
   8:         {
   9:             typeMap[typeName] = t;
  10:             return t;
  11:         }
  12:     }
  13: }

 

Thanks to Manfred Lange for the tip on the error message.

WCF RIA Services XMLMetaDataProvider Problem

The current RIA Services project I’m working on has been using the XMLMetaDataProvider due to the fact that our model and DomainService are in different projects.  This rules out defining your metadata in a partial class for each entity.   As the project got bigger we noticed that randomly our metadata was not being created at build time.  Turns out there is a race condition with loading the XML file and the requests for metadata.  Here is the new XmlMetadataProvider.cs file where we now load the dataset in the constructor, not the first time it is requested.  After all that, I think we’ll try using Nikhil Kothari’s fluent API style, I like the look of it over the mass amount of XML.

   1: internal class XmlMetadataProvider : TypeDescriptionProvider
   2:     {
   3:         private Type domainServiceType;
   4:         private MetadataSet metadataSet;
   5:  
   6:         /// <summary>
   7:         /// Constructor that accepts a metadata context to use when generating custom type descriptors
   8:         /// </summary>
   9:         /// <param name="existingProvider">The parent TDP instance</param>
  10:         /// <param name="domainServiceType">The DomainService Type exposing the entity Types this provider will be registered for</param>
  11:         public XmlMetadataProvider(TypeDescriptionProvider existingProvider, Type domainServiceType)
  12:             : base(existingProvider)
  13:         {
  14:             this.domainServiceType = domainServiceType;
  15:             LoadMetadataSet();
  16:         }
  17:  
  18:         public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
  19:         {
  20:             return new XmlMetadataTypeDescriptor(this.MetadataSet, objectType, base.GetTypeDescriptor(objectType, instance));
  21:         }
  22:  
  23:         private MetadataSet MetadataSet
  24:         {
  25:             get
  26:             {
  27:                 if (metadataSet == null)
  28:                 {
  29:                     LoadMetadataSet();
  30:                 }
  31:                 return metadataSet;
  32:             }
  33:         }
  34:  
  35:         private void LoadMetadataSet()
  36:         {
  37:             metadataSet = new MetadataSet();
  38:  
  39:             // load all the metadata files found
  40:             IEnumerable<string> metadataFiles = domainServiceType.Assembly.GetManifestResourceNames().Where(p => p.EndsWith(".metadata.xml", StringComparison.OrdinalIgnoreCase));
  41:             foreach (string metadataFile in metadataFiles)
  42:             {
  43:                 Stream stream = domainServiceType.Assembly.GetManifestResourceStream(metadataFile);
  44:                 StreamReader streamReader = new StreamReader(stream);
  45:                 String metadata = streamReader.ReadToEnd();
  46:  
  47:                 try
  48:                 {
  49:                     metadataSet.Load(metadata);
  50:                 }
  51:                 catch (Exception e)
  52:                 {
  53:                     string msg = string.Format(CultureInfo.CurrentCulture, Resource.MetadataLoadError, metadataFile) + " : " + e.Message;
  54:                     throw new InvalidOperationException(msg, e);
  55:                 }
  56:  
  57:             }
  58:         }
  59:     }
  60: }

Windows 7 RC1 and VMWare Workstation

I just finished upgrading Vista to win7 RC1 on my work laptop.  Everything went smoothly right up until I got to work this morning and tried to use VMWare Workstation, which booted up without issue, but the network wasn’t working.

“The network bridge on device VMnet0 is not running”  and “VMNet0: Overlapped I/O operation is in progress  which failed to connect” were the messages I was getting.   The problem was that thewin7 upgrade failed to add the VMWare Bridge Protocol back to my network card.  You could probably add this manually, but I just did a repair from my original msi and a reboot later I was up and running.