SSIS Script Task reference dll programmatically - dll

I have built software that is capable of exporting DTSX package automatically. This package among other objects has also a ScriptTask (C#). All are compiled and run just fine.
Now the new requirement is to call a class in that ScriptTask, which exists inside an external DLL we have built, so other applications can consume the same code. We did our homework, and we included this DLL into the GAC successfully during the installation of the software.
The problem is that "using our library" is still not recognized in the script.
While searching a little bit, we figured out, that we need to reference this DLL also inside the References folder. This we can do it of course via DataTools / VisualStudio UI.
The issue is that we need to do that programmatically:
We have this piece of code that generates the Project
task.ScriptingEngine.VstaHelper.LoadNewProject(task.ProjectTemplatePath, null, "MyScriptProject");
And also, we have this piece of code that creates the MainScript
task.ScriptingEngine.VstaHelper.AddFileToProject(ScriptName + ".cs", MainScript.ToString());
I am unable to figure out how I can include the reference DLL programmatically.

Updated Answer
You can programmatically update the script task by replacing the appropriate XML node in the the DTSX file
The node path depends on where the script task has been created within the SSIS package, in my case the node path was
/DTS:Executable/DTS:Executables/DTS:Executable/DTS:ObjectData/pipeline/components/component[#refId="Package\Data Flow Task\Script Component"]/properties
The #refId you will be looking for will start with Package \ Dataflow name \ Component name
This node will have sub nodes which contains the C# scripts as well as the binary that was built off this script
The property name "SourceCode" contains the C# scipts in an array called arrayElements, the array will have three sub nodes for each file, these subnodes are called arrayElement, first value is the relative path and name, second is file encoding and third is the file content
The property name "BinaryCode" contains the .dll that was build from the scripts, it also contains an arrayElement array with two entries, first the dll name and the second the base64 encoded dll binary
To get the data to populate these items you will need to create a template of the C# build directory, apply your changes, build the code and take the resulting files and replace them on their appropriate nodes
To create the template open the script via SSIS task,
Click on the project in solution explorer to and go file save VstaProject.sln
Go to the saved folder, you get the folder off the solutions properties dialog
Copy this folder somewhere so that you can reuse it to build your custom stuff
Modify the .cs files in your template directory and add your custom reference dll's to your .csproj file
Call MSBUILD in the same directory as your .csproj to output the dll, its important that you use the VS MSBUILD, VS2017 you can find it in
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\msbuild.exe
Take these files and package them into a XML node in the DTSX file
Initial Answer
Microsoft provides a workaround for loading DLL's that aren't in the GAC
Load assembly that isnt in the GAC
Please see below extract from a SSIS script, I loaded the JSON dll's from the nuget install directory. This DLL is not in the GAC
static ScriptMain()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name.Contains("Newtonsoft.Json"))
{
string path = #"C:\Program Files\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\";
return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "Newtonsoft.Json.dll"));
}
return null;
}

Related

Changing the version information of ironpython .dll assembly

I compiled a .dll file in ironpython, by using the following code:
import clr
clr.CompileModules('C:/example.dll', 'C:/example.py')
It essentially compiles the .py file to .dll.
The only problem with this is that it creates a file with no information about the Company, Language, File Version etc. In fact the File Version is always: 0.0.0.0.
I was wondering if there is a way to at least alter the File Version (change it to something other than 0.0.0.0). I googled and found a similar topic in here on stackoverflow.
I tried three methods:
1) One with Visual Studio (File->Open-> find .dll, Edit->Add Resource->Version click New. In the new Version tab, change FILEVERSION and PRODUCTVERSION)
2) Another one by using the Change version 2012 application
3) And third one by using: Simple Version Resource Tool for Windows 1.0.10
None of them worked.
For some reason looks like the structure of the .dll assembly created with ironpython is different than the .NET one created with VB or C#.
Does anyone know how to change the File Version from 0.0.0.0 to something else?
Thank you.
You can use the pyc.py file packaged into IronPython to compile your file into a .dll file. The file is located in the directory IronPython 2.7\Tools\Scripts.
If we open pyc.py for editing, you'll see the different things it can do.
pyc: The Command-Line Python Compiler
Usage: ipy.exe pyc.py [options] file [file ...]
Options:
/out:output_file Output file name (default is main_file.<extenstion>)
/target:dll Compile only into dll. Default
/target:exe Generate console executable stub for startup in addition to dll.
/target:winexe Generate windows executable stub for startup in addition to dll.
#<file> Specifies a response file to be parsed for input files and command line options (one per line)
/file_version:<version> Set the file/assembly version
/? /h This message
EXE/WinEXE specific options:
/main:main_file.py Main file of the project (module to be executed first)
/platform:x86 Compile for x86 only
/platform:x64 Compile for x64 only
/embed Embeds the generated DLL as a resource into the executable which is loaded at runtime
/standalone Embeds the IronPython assemblies into the stub executable.
/mta Set MTAThreadAttribute on Main instead of STAThreadAttribute, only valid for /target:winexe
/file_info_product:<name> Set product name in executable meta information
/file_info_product_version:<version> Set product version in executable meta information
/file_info_company:<name> Set company name in executable meta information
/file_info_copyright:<info> Set copyright information in executable meta information
/file_info_trademark:<info> Set trademark information in executable meta information
Example:
ipy.exe pyc.py /main:Program.py Form.py /target:winexe
One thing that I personally like to do is move pyc.py from the Scripts folder to the IronPython folder along with my python file as well.
Assuming you also do this, you would open command prompt as administrator and navigate to the IronPython folder.
cd "Program Files (x86)\IronPython 2.7"
Then you would want to compile your python file as a .dll and set the file version using pyc.py. To do that, you're going to want to type in:
ipy.exe pyc.py /main:example.py /target:dll /file_version:0.0.0.1
If you want to add a company name, and other items as well, you simply have to pass those option to the pyc.py script.
ipy.exe pyc.py /main:Program.py Form.py /target:winexe /file_info_company:Company

Augmenting set of project output files in MSBuild

Is it possible in MSBuild 4.0 and/or 4.5 to specify additional files to be treated as a manifest output of a project by its dependencies, and copied with the binary project output, whenever that is copied? Ideally, I want to create some files beside a .dll during build, and would like these files to stay in the same folder as the .dll whenever it is copied to a directory of a project depending on it.
If this is not clear, I am thinking of .pdb and documentation .xml files created by the C# compiler. These files treated specially: Whenever another project requests the .dll be copied locally into its binary directory, these files go with the .dll. Can I augment this set with my own special files?
This is not possible, and here is why. Actually, there is no concept of project output accessible externally between MSBuild projects. Rather, when a reference to a project is added, the SDK-provided build framework (based on MSBuild scripts) looks for a few specific files matching the name of the referenced DLL, and copies these files with the DLL itself into the current project output directory (assuming CopyLocal is set, which is probably true for a referenced project).
In framework v4.0, this is done by the task ResolveAssemblyReference which is called from an identically named target from the file %windir%\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets. The task looks for specially named files placed beside the target DLL, including its matchin PDB files and an XML documentation file. Other files are also discovered, as I infer from the decompiled source.
So nothing in a given project specifically marks these files as somehow "exported" from the project. The magic happens on the pulling side.

Reference VB.NET DLL in Kofax Document Validation Script

We are working on a validation script for Kofax Capture 9.0 / 10.0 in VB.NET 3.5.
We know how to create a script using the Admin Module, and how to get it operational.
The problem is that we need to reference a dll, located on a remote machine. (GAC is no option) This dll holds abstract classes we need in each validation script.
Even when putting the dlls locally (copy local), the Validation Module (index.exe) immediately throws the "cannot find reference" exception, even though the project compiled perfectly.
I guess the basic question comes down to: where do we put the dlls, in order for the Validation Module to find them?
The simple answer is to put the dll in the same folder as the application because this is one of the places which .NET will probe when trying to find it. The Validation module is run from the Capture bin directory which will be something like "C:\Program Files (x86)\Kofax\CaptureSS\ServLib\Bin\". This would need to be done on each client using Validation.
If you have a more complicated scenario, you could look implementing the AppDomain.AssemblyResolve Event and using Assembly.LoadFile to get the assembly from a custom location, but the using the bin path is less complicated.
If you end up having further trouble, you can troubleshoot by using the Assembly Binding Log Viewer (Fuslogvw.exe) which can tell you more details about why the assembly failed to load and where .NET tried to search for it. Assembly loading can fail for reasons other than just the path.
For more detail on how .NET loads assemblies, see the following:
How the Runtime Locates Assemblies
Locating the Assembly through Codebases or Probing
We found a solution: add all library files as "links" to the project. (Add --> Existing File --> small arrow next to "Add" --> Add as Link)
This ensures the files are compiled when you build the project. The Kofax Validation Module can now find the files, whereas when referencing the file, it could not. Why it could not, remains a mystery...

Wix - building files to subdirectories

I am new to WiX and am trying to get my install project to build certain files to a subdirectory of the build output path. For example, if my build output path is: bin\Debug, I would like certain files to be added to a subfolder here: bin\Debug\Images.
Is this possible please?
It looks like you are using a WiX project template with Visual Studio, MSBuild and/or SharpDevelop. If so, you have several options:
Use XCOPY in the Post Build Event.
flexible
somewhat easy to find in your project (on one of the project designer tabs)
not integrated well with the build system
Add the folder and files to your project folder, include them in your project and set the Copy to Output Directory on each file. Note: you can't set that property on a folder. The copying will preserve the folder structure but you have set the property on each file you want copied.
inflexible
very easy to find in your project (solution explorer and properties window)
Open the project file in a text editor and add MSBuild tasks such as Copy to the AfterBuild or other target. Note: To use VS to edit the project file, right click, select Unload Project, then right click and select Edit.
flexible
hard to find in your project (XML in the project file)
uses the build system
In the last case, I sometimes put a REM comment in the Post Build event to clue people into the fact that the project file has been customized.

How to use MSBuild.ExtensionPack

I have to run two targets in parallel to profile iisexpress.exe using OpenCover.
The link below relates to the information about the issue I am having.
https://github.com/sawilde/opencover/issues/92#issuecomment-5143204
This suggested to me to use Msbuild.ExtensionPack from CodePlex.
I have downloaded the source code of MSBuild Extensions.
I compiled it. I copied the MSBuild.ExtensionPack.tasks tasks file in to folder BuildBinaries.
I added the below lines in my projects files.
I was trying to run the ExecMultipleTasks target. But getting the below error.
error MSB4036: The "MSBuild.ExtensionPack.Framework.Parallel" task was not found. Check the following:
1.) The name of the task in the project file is the same as the name of the task class.
2.) The task class is "public" and implements the Microsoft.Build.Framework.ITask interface.
3.) The task is correctly declared with in the project file, or in the *.tasks files located in the "C:\Windows\Microsoft.NET\Framework\v4.0.30319" directory.
Could you please let me know how to fix this issue?
Thanks,
Venkat.
which version of visual studio your application is using ?, if its 32 bit of VS then install 32 bit Extension Pack (MSBuild.Extension.Pack.4.0.12.0.zip\4.0.12.0\x86) else go for 64 bit.
If you open up the file C:\Program Files (x86)\MSBuild\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks ill think you find that the path to the dll for the task MSBuild.ExtensionPack.Framework.Parallel is not correct.
<UsingTask AssemblyFile="$(ExtensionTasksPath)MSBuild.ExtensionPack.dll" TaskName="MSBuild.ExtensionPack.Framework.Parallel"/>
I imagine the variable $(ExtensionTasksPath) does not locate your build path for your version. Either copy the files into that path or change/hardcode the new path.