Today I attempted to deploy a BDC model to my client’s SharePoint farm. I used the Visual Studio 2010 SharePoint project template and the Business Data Catalog Model item template to create the model, and I had no issues using the convenient Deploy command from within Visual Studio to deploy the model and make use of it in my virtual development environment. But when I deployed my solution to my client’s farm and attempted to activate the BDC model’s Feature, the activation would fail with the following error:
The default web application could not be determined. Set the SiteUrl property in feature “My BDC Model Feature” to the URL of the desired site and retry activation.
Parameter name: properties
I soon found Frederik Prijck’s blog post that explained that I am supposed to specify a SiteUrl as a property of the model that can be used to resolve a Web application and mapped BCS service application to deploy the model to. So why was it I was able to deploy the model in my development environment?
The answer is that in my development environment, I have one and only one Web application that is hosted on port 80. As Frederik explained:
Strange enough this BCS entity will automatically attach an event receiver (Microsoft.Office.SharePoint.ClientExtensions.Deployment.ImportModelReceiver) to the feature. This event receiver has a method named GetDefaultWebApp which will be called when there is no SiteUrl property set in the manifest file. GetDefaultWebApp (as you can see using reflector) will search for a webapplication on port 80 or port 443 (not 100% sure about port 443, but you will understand what i mean i hope).
Frederik then goes on to talk of a dirty solution involving creating an empty Web application on port 80 just to support deploying BDC models without having to hard code a SiteUrl in the model.
The problem for me though is my client’s farm already has a Web application on port 80. Actually they have 8 Web applications using port 80, all with different host headers.
Opening up ILSpy to see exactly what was going on in the GetDefaultWebAppUrl method reveals that there is a little more to the logic. First of all, Web applications on port 80 will take precedence over Web applications on port 443. If there is only a single Web application on port 80 or 443, the method returns that Web application’s default zone URL. If there are multiple Web applications, the method then attempts to choose the Web application whose default zone’s host name has the least number of parts when split by the period character. For example, intranet.contoso.com would take precedence over test.intranet.contoso.com. If there is still ambiguity, the method makes one last check to see if one of the default zone’s host name begins with ‘www’. If ambiguity remains, the method throws the above quoted exception.
I can’t explain why Microsoft has chosen to implement this method in such a way, nor why they choose not to document it, but knowing this behavior provides another workaround. Taking a similar approach as Frederik, I created a dummy Web application having a host header beginning with ‘www’, created the root Site Collection, and my BDC model now deploys like a charm without a hardcoded SiteUrl.