Follow me on Twitter

Our greatest glory is not in never falling, but in rising every time we fall. (Confucius)

Tags

My Books

Recent blog posts

User login

Home | Blogs | Stephane Eyskens's blog

SharePoint 2010, deploying a BCS Model using a farm property bag to have a dynamic siteurl

Hi,

As you probably noticed and as I've observed on the web, many people complain about the fact that when deploying a BCS model with Visual Studio, you have to specify a value for the feature property SiteUrl. If you don't, you might have troubles depending on your topology as described in the following blog posts http://trentacular.com/2011/05/deploying-sharepoint-bdc-models-via-features-without-specifying-a-siteurl/ and http://blogs.msdn.com/b/vssharepointtoolsblog/archive/2010/07/30/deploy-your-bdc-model-to-a-specific-bcs-service-using-visual-studio-2010.aspx

The problem with the static approach is that usually the URL varies according to the environment (dev, test, acceptance, production...) and you do not want to create several packages. The approaches described in the above posts are ok but seem a bit overkill to me.

As an alternative, it is also possible to implement your own deployment routine with a little bit of effort. By default, when you create a BCS Project with Visual Studio or with BCS Meta Man, it creates a farm feature to deploy your model. This farm features has a feature receiver pointing to a built-in class :

ReceiverAssembly="Microsoft.Office.SharePoint.ClientExtensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" ReceiverClass="Microsoft.Office.SharePoint.ClientExtensions.Deployment.ImportModelReceiver".

The idea is to make your own feature receiver calling a helper class deriving from the built-in class. Then, you can use the property SiteUrl but instead of specifying a static URL, getting its value from a Farm property bag dynamically.

Here are the steps to do that:

  • Create a BCS Meta Man Project or a Visual Studio Project


  • Click on the model and go to its properties, empty the feature receiver associated to it


  • Add the properties SiteUrl and SiteUrlProp as part of your feature properties and specify the name of the farm property bag


  • Add a reference to Microsoft.Office.SharePoint.ClientExtensions.dll


  • Add a new event receiver to your feature and implement the following code :
    public class SiteUrlBCSEventReceiver : SPFeatureReceiver
    {
        const string SiteUrl = "SiteUrl";
        const string SiteUrlProp ="SiteUrlProp";
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            ReworkProperty(properties);
            DynamicBCSDeployment d = new DynamicBCSDeployment();               
            d.FeatureActivated(properties);
        }
        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            ReworkProperty(properties);
            DynamicBCSDeployment d = new DynamicBCSDeployment();
            d.FeatureDeactivating(properties);
        }
    
        void ReworkProperty(SPFeatureReceiverProperties properties){
    	  SPFarm LocalFarm=((SPWebService)properties.Feature.Parent).Farm;
              if (LocalFarm.Properties[properties.Definition.Properties[SiteUrlProp].Value] == null)
                throw new ArgumentException("Missing farm property");
              
    	  properties.Definition.Properties[SiteUrl].Value = LocalFarm.Properties[properties.Definition.Properties[SiteUrlProp].Value].ToString();
              properties.Feature.Properties.Update();
    
        }
                
    }
    public class DynamicBCSDeployment : ImportModelReceiver
    {
        public DynamicBCSDeployment() { }
    }
    


Of course, you should make it a generic helper but for clarity reasons, I regroup everything in a single code block. The ReworkProperty method is also called when deactivating the feature to make sure that if you changed the value of the farm property, that change is taken into account.


Before deploying, just ensure you have created your farm property with the right value. As said earlier, each farm (dev, acceptance, prod...) will have its own property with its own value but with the same name, so your code does not need to be changed and you don't have to fiddle with dummy web applications or urls. Moreover, if you have several possible deployment URLS, just create as many farm properties as possible deployment URLS in each of your different environments and you chose the appropriate property key in the SiteUrl parameter.

If you want, you can of course work with something else than farm properties but the idea is to have something flexible enough.

No you can just deploy and enjoy!

Happy Coding!

Comments

You're smarter than others

Your workaround is a real production scenario workaround ! thanks for this usefull tips !

Thanks :)

Thanks :)

Good Solution!

I feel that the other solutions that were linked in your blog post are not practical, especially when you dont have control over creating web apps or changing host headers in a staging and/or production environment. Which is usually the case.

I like the implementation here, it is much more elegant. Thanks for the post!

Reddy

Simpler way

You can get the site URL from the feature properties.
private void ReworkProperty(SPFeatureReceiverProperties properties)
{
string siteUrl = string.Empty;
SPWebService webService = (SPWebService)properties.Feature.Parent;
SPWebApplication webApp = webService.WebApplications.Where(
wa => wa.Sites.Count > 0 &&
wa.IsAdministrationWebApplication == false).FirstOrDefault();
if (webApp != null)
{
using (SPSite site = webApp.Sites[0])
{
siteUrl = site.Url;
}

if (properties.Definition.Properties[SiteUrl] == null)
{
properties.Definition.Properties.Add(new SPFeatureProperty(SiteUrl, siteUrl));
}
else
{
properties.Definition.Properties[SiteUrl].Value = siteUrl;
}

properties.Feature.Properties.Update();
}
}

see example at: http://zormim.wordpress.com/2012/10/01/integrating-sharepoint-and-system...

Hi, Thanks for your comment.

Hi,

Thanks for your comment. However my way is dynamic not yours. Indeed you always take the first site collection of the first webapp that has at least one site col and that is not the admin app.

With my way, you can define the URL of your choice in a property bag.

Best Regards