Resources for IT Professionals > BizTalk Server Forums > BizTalk Server General > Anybody figured out a way to modify Resources in a BT Application in code ?

Answered Anybody figured out a way to modify Resources in a BT Application in code ?

  • Thursday, April 02, 2009 8:56 AM
     
     

    Just to explain what i want...

    If you deploy a file from Visual studio to BizTalk and you look at the application. Then go to resources...
    Then look at Source and Destination location.

    You will see that if you do nothing... and export the MSI ... It will create your entire DEVELOPEMENT Folder stucture on the Production Server.
    So you have to edit the Destination location before you export.

    This is something that is easy to forget. So that's why i have this question.

    I know of a very dirty way of doing this. But is there a clean way of doing this ?


    Well0549

Answers

  • Monday, April 06, 2009 10:28 AM
    Moderator
     
     Answered Has Code
    Hi,


    Although I must say I agree with Pauls opinion on IDE driven deployment here is something that might help.

    I did some BizTalk MSI related stuff using C# in the past (see code below). Although it is probably not exactly what you need you can use it as a starting point.

    The code unpacks a BizTalk MSI, deserializes the contained application definition file and finally packs everything back into an MSI file. If you extent this code to modify the resource source and/or destination location in the application definition class the final MSI will contain the amended paths.

    It should also be possible the change these settings directly in the biztalk application (not in the MSI) but you have to dive a little deeper in the BizTalk code using Reflector. Again you can use my sample code as starting point.

     

    HTH,

    Randal van Splunteren
    http://biztalkmessages.vansplunteren.net

    Please mark answered if this answers your question.



        class Program
        {
            static void Main(string[] args)
            {
                string path = @"C:\Appplication.msi";
                    
                string tempPath = Unpack(path);
    
                ApplicationDefinition applicationDefinition = DeserializeAdf(tempPath);
    
                Pack(tempPath, applicationDefinition, path);
            }
    
            private static string Unpack(string path)
            {
                Assembly assembly = System.Reflection.Assembly.Load("Microsoft.BizTalk.ApplicationDeployment.Engine, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
                System.Type msiHelperType = assembly.GetType("Microsoft.BizTalk.ApplicationDeployment.MsiHelper", true);
                MethodInfo methodInfo = msiHelperType.GetMethod("ExtractFiles", BindingFlags.Static | BindingFlags.Public);
                object returnVal = methodInfo.Invoke(msiHelperType, new object[] { path });
    
                return returnVal as string;
            }
    
            private static void Pack(string tempPath, ApplicationDefinition applicationDefinition, string path)
            {
                Assembly assembly = Assembly.Load("Microsoft.BizTalk.ApplicationDeployment.Engine, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
                System.Type applicationPackageType = assembly.GetType("Microsoft.BizTalk.ApplicationDeployment.ApplicationPackage", true);
                
                object instance = assembly.CreateInstance("Microsoft.BizTalk.ApplicationDeployment.ApplicationPackage");
    
                MethodInfo methodInfo = applicationPackageType.GetMethod("GenerateMSI",
                    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                    null, 
                    new Type[] { typeof(System.String)
                                , typeof(System.String)
                                , typeof(System.String)
                                , typeof(System.String)
                                , typeof(System.String)
                                , typeof(System.Int32) }
                    , null);
    
                methodInfo.Invoke(instance, 
                    new object[] { GetPropertyFromAppDef(applicationDefinition, ApplicationDefinitionPropertyName.DisplayName), 
                                   GetPropertyFromAppDef(applicationDefinition, ApplicationDefinitionPropertyName.ApplicationDescription), 
                                   String.Format(CultureInfo.InvariantCulture, "{0}.new.msi", path), 
                                   tempPath, 
                                   String.Format(CultureInfo.InvariantCulture, @"{0}\ApplicationDefinition.adf", tempPath), 
                                   applicationDefinition.Resources.Length });
            }
    
            private static ApplicationDefinition DeserializeAdf(string tempPath)
            {
                string file = String.Format(CultureInfo.InvariantCulture, @"{0}\ApplicationDefinition.adf", tempPath);
    
                XmlDocument XmlDocument = new XmlDocument();
                XmlDocument.Load(file);
                XmlNodeReader reader = new XmlNodeReader(XmlDocument.DocumentElement);
                XmlSerializer serializer = new XmlSerializer(typeof(ApplicationDefinition));
                object deserializedObject = serializer.Deserialize(reader);
                return (ApplicationDefinition)deserializedObject;
    
            }
    
            private static string GetPropertyFromAppDef(ApplicationDefinition a, ApplicationDefinitionPropertyName propertyName)
            {
                foreach (ApplicationDefinitionProperty appDefProperty in a.Properties)
                {
                    if (appDefProperty.Name == propertyName)
                    {
                        return appDefProperty.Value;
                    }
                }
    
                throw new NullReferenceException(String.Format(CultureInfo.InvariantCulture, "Value of '{0}' could not be fetched from application definition file."));
            }
        }
    


All Replies

  • Thursday, April 02, 2009 3:47 PM
    Answerer
     
     
    The clean way is not to use IDE driven deployment for building installation packages. IDE way is only for developer workstation. Use btstask or MSBuild BizTalk tasks to do that. Command option btstask AddResource /Destination:<path> will set desired destination path.
    http://geekswithblogs.net/paulp/
  • Friday, April 03, 2009 2:40 PM
     
     
    I don't agree with you....

    I use IDE to deploy to BizTalk in the first place. It figures out the order of deployment for you, If you decide to add a sub project you don't have to start editing a zillion scripts.

    No I really like deployment from the IDE.

    After I have done a Deploy (from within IDE) I start a small C# console apllication that adds lot's of resource (SSO configuration Business rules Binding files etc) files to the BizTalk Application. The it will add a couple of batch scripts as well to import Business Rules SSo config and stuff.

    This works like a charm and is very fast.

    So the Build order is ..... Deploy Solution, Start Console app, Export MSI.

    This method works really great, the only thing I hate is to have to edit the Destination location once for every dll that's deployed from the IDE




    Well0549
  • Friday, April 03, 2009 4:00 PM
    Answerer
     
     
    I don't agree with you....

    Prefer to edit it manually? :) You described three step process plus tedious manual work. I suggest one-click process.

    Wouldn't it be much easier to execute just one script that does all of the things above and no manual work required? There are plenty of ways for build automation starting from simple batch command calling btstask (http://geekswithblogs.net/paulp/archive/2006/03/07/71644.aspx) down to fancy tools like BizTalk Deployment Framework and TFS.
    http://geekswithblogs.net/paulp/
  • Saturday, April 04, 2009 1:03 PM
     
     

    Paul,

    I have never seen ANY toold that works out of the box beside the IDE. All those tools you mention have config files where you have to enter stuff.

    And you have to enter stuff in the right order... For example starting orchestrations that call other orchestrations. (You have to start the called orchestration first)

    And I have worked with the deployment framework and I was really not pleased with the number of files that came up in a solution. I know it does the job but it's not my style...

    Then build scripts... They also do the job but everyutime you change something (or add somethin) you have to modify the scripts.

    If you could point me to a site where a solution is that does a NO CONFIG AT ALL deployment like the IDE... SO no config, works at once
    with the possibillity to add additional files as a resource i would be very gratefull.

    The way i do it right now is much like the one described by Brian loesgen in this link here : http://geekswithblogs.net/bloesgen/archive/2008/01/28/119003.aspx

    He does everything in a batch file and therefore has to know wich assemblies are to be deployed (and the order).

    I do similar stuff but then from within the IDE where i leave the deply stuff to the IDE i only have to add some resourxces and i am done.
    NO CONFIG or SCRIPT chanegs needed....


    Well0549
  • Sunday, April 05, 2009 11:15 PM
    Answerer
     
     

    I guess as you say there's no easy way. You can:

    Update column "properties" of table "adpl_sat" in BizTalkMgMtDb
    Run BTSTask.exe AddResource with the -Overwrite parameter
    Thiago Almeida - http://connectedthoughts.wordpress.com
  • Monday, April 06, 2009 8:58 AM
     
     
    Hmmm,

    Could do that, but I was hoping somebody played around with Reflector and found the API to do it....
    BTSTask is not really an option cause the stuff is already deployed by the IDE and I don't know what kind
    of build was done (so I am not absolutely sure where to get the DLL that will override)

    Second, then i could run into dependency problems..... If I try to update a DLL (orchestration) that's beeing called
    by another orch... It will fail because of the dependency. And then I am editing config scripts and then i could
    better start with one of the suggestions of Paul Petrov.



    Well0549
  • Monday, April 06, 2009 10:28 AM
    Moderator
     
     Answered Has Code
    Hi,


    Although I must say I agree with Pauls opinion on IDE driven deployment here is something that might help.

    I did some BizTalk MSI related stuff using C# in the past (see code below). Although it is probably not exactly what you need you can use it as a starting point.

    The code unpacks a BizTalk MSI, deserializes the contained application definition file and finally packs everything back into an MSI file. If you extent this code to modify the resource source and/or destination location in the application definition class the final MSI will contain the amended paths.

    It should also be possible the change these settings directly in the biztalk application (not in the MSI) but you have to dive a little deeper in the BizTalk code using Reflector. Again you can use my sample code as starting point.

     

    HTH,

    Randal van Splunteren
    http://biztalkmessages.vansplunteren.net

    Please mark answered if this answers your question.



        class Program
        {
            static void Main(string[] args)
            {
                string path = @"C:\Appplication.msi";
                    
                string tempPath = Unpack(path);
    
                ApplicationDefinition applicationDefinition = DeserializeAdf(tempPath);
    
                Pack(tempPath, applicationDefinition, path);
            }
    
            private static string Unpack(string path)
            {
                Assembly assembly = System.Reflection.Assembly.Load("Microsoft.BizTalk.ApplicationDeployment.Engine, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
                System.Type msiHelperType = assembly.GetType("Microsoft.BizTalk.ApplicationDeployment.MsiHelper", true);
                MethodInfo methodInfo = msiHelperType.GetMethod("ExtractFiles", BindingFlags.Static | BindingFlags.Public);
                object returnVal = methodInfo.Invoke(msiHelperType, new object[] { path });
    
                return returnVal as string;
            }
    
            private static void Pack(string tempPath, ApplicationDefinition applicationDefinition, string path)
            {
                Assembly assembly = Assembly.Load("Microsoft.BizTalk.ApplicationDeployment.Engine, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
                System.Type applicationPackageType = assembly.GetType("Microsoft.BizTalk.ApplicationDeployment.ApplicationPackage", true);
                
                object instance = assembly.CreateInstance("Microsoft.BizTalk.ApplicationDeployment.ApplicationPackage");
    
                MethodInfo methodInfo = applicationPackageType.GetMethod("GenerateMSI",
                    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                    null, 
                    new Type[] { typeof(System.String)
                                , typeof(System.String)
                                , typeof(System.String)
                                , typeof(System.String)
                                , typeof(System.String)
                                , typeof(System.Int32) }
                    , null);
    
                methodInfo.Invoke(instance, 
                    new object[] { GetPropertyFromAppDef(applicationDefinition, ApplicationDefinitionPropertyName.DisplayName), 
                                   GetPropertyFromAppDef(applicationDefinition, ApplicationDefinitionPropertyName.ApplicationDescription), 
                                   String.Format(CultureInfo.InvariantCulture, "{0}.new.msi", path), 
                                   tempPath, 
                                   String.Format(CultureInfo.InvariantCulture, @"{0}\ApplicationDefinition.adf", tempPath), 
                                   applicationDefinition.Resources.Length });
            }
    
            private static ApplicationDefinition DeserializeAdf(string tempPath)
            {
                string file = String.Format(CultureInfo.InvariantCulture, @"{0}\ApplicationDefinition.adf", tempPath);
    
                XmlDocument XmlDocument = new XmlDocument();
                XmlDocument.Load(file);
                XmlNodeReader reader = new XmlNodeReader(XmlDocument.DocumentElement);
                XmlSerializer serializer = new XmlSerializer(typeof(ApplicationDefinition));
                object deserializedObject = serializer.Deserialize(reader);
                return (ApplicationDefinition)deserializedObject;
    
            }
    
            private static string GetPropertyFromAppDef(ApplicationDefinition a, ApplicationDefinitionPropertyName propertyName)
            {
                foreach (ApplicationDefinitionProperty appDefProperty in a.Properties)
                {
                    if (appDefProperty.Name == propertyName)
                    {
                        return appDefProperty.Value;
                    }
                }
    
                throw new NullReferenceException(String.Format(CultureInfo.InvariantCulture, "Value of '{0}' could not be fetched from application definition file."));
            }
        }
    


  • Monday, April 06, 2009 4:10 PM
     
     
    Randal this rocks!  I have been thinking about make an MSI Bindings viewer for some time and this did a large amount of the work for me. 

    Thanks Randal!
  • Tuesday, April 07, 2009 8:16 AM
     
     
    Welllll...

    It's almost what I am looking for, but it is not what I am really after.
    I was hoping someone would have stayed longer in reflector than I did and found a way
    to modify a deployed resource...

    But this is indeed very interesting stuff !

    Well0549