BizTalk Assembly file-versioning - and documentation of what is deployed

by Lars W. Andersen 19. March 2013 23:22

I finally got around to setting up a descriptive versioning of my BizTalk assemblies the other day. What I wanted was to have something that made it possible to trace different versions of the assemblies back to the sourcecode. And to make it easily visible that an assembly had changed. I took it one step further and came up with an easy to implement way of showing which versions of code is deployed on the servers. 

The build process

I build the entire solution, using an MSBUILD script, that handles copying dll’s to an output folder on a drop share. I then deploy assemblies using powershell and the BizTalk Powershell Provider. I have a full deploy script that tears down the applications and recreates them, and a “hotfix” deployment that have a minimal impact on running applications. I don’t particularly like MSI package deployments for BizTalk as IMO they add a “fog of war” to the deployment. Especially when something goes wrong. I know some might consider such an “xcopy deployment” of DLL’s to be medieval, but there is a transparency to what is happening, and the end result is the same. My binding files are created using the XMLPreprocesor / excel spreadsheet method.

I don’t currently need to update the AssemblyVersion with all the problems of updating references in maps and orchestrations etc. If you should go there, make sure to look at the documentation. I only need to update the AssemblyFileVersion to communicate the versioning of applications. The AssemblyFileVersion will show up as displayed here on another windows file:

image

all the build artifacts are stored in a separate empty Class project as part of the solution. A project that I exclude from the solution build configuration. All the scripts and the build file shown below are part of that project.

Incrementing the Build number

To add some value to the version number I wanted to add the SVN revision number to identify the assembly back to my sourcecode revision.

The client I currently work for uses SVN, my favorite easy to use and understand source control system. (I still think GIT is overly complicated and I rarely need my code to be social anyway).

For this I use the MSBuild Community Tasks and the SvnVersion Task, added to the solution through Nuget like this:

Install-Package msbuildtasks

In the MSBuild script I reference the SvnVersion and the FileUpdate tasks like this:

<UsingTask TaskName="SvnVersion" AssemblyFile="..\.build\MSBuild.Community.Tasks.dll" />
<UsingTask TaskName="FileUpdate" AssemblyFile="..\.build\MSBuild.Community.Tasks.dll" />

In a separate target in the MSbuild file, I update my assemblyfileversion template with the SVN revision number

<Target Name="SubVersionBeforeBuildVersionTagItUp" DependsOnTargets="BeforeBuild">
    <ItemGroup>
      <AssemblyInfoFiles Include="$(ProjectDir)\**\*AssemblyInfo.cs" />
    </ItemGroup>
    <SvnVersion LocalPath="$(MSBuildProjectDirectory)" ToolPath="$(SVNToolPath)">
      <Output TaskParameter="Revision" PropertyName="MySubVersionRevision" />
    </SvnVersion>
    <FileUpdate Files="AssemblyFileInfo.cs"
            Regex="(AssemblyFileVersion\(\&quot;)(\d+)\.(\d+)\.(\d+)\.(\d+)"
            ReplacementText="$1$2.$3.$4.$(MySubVersionRevision)" />
  </Target>

I make sure to ONLY update the AssemblyFileVersion and not the AssemblyVersion number, which I leave at 1.0.0.0  - this is handled by the regular expression in the <FileUpdate> section of the build  target.

Now I don’t want to check in the now changed AssemblyVersion files, so what I do is to store a Template of the AssemblyFileVersion.cs  in SVN. I do this in my build project, and this is referenced as a linked file, in my other Visual Studio projects.

I split the version properties out into a separate AssemblyFileInfo.cs file as I have both BizTalk projects and C# class projects that I wanted to version. The AssemblyInfo.cs files for BizTalk projects have these declarations added to them, so I couldn’t just use the Assemblyinfo.cs file in a c# Class project.

using Microsoft.XLANGs.BaseTypes;
using Microsoft.BizTalk.XLANGs.BTXEngine;
[assembly: Microsoft.XLANGs.BaseTypes.BizTalkAssemblyAttribute(typeof(BTXService))]

Instead, I removed the two AssemblyVersion declarations from the original Assemblyinfo.cs and put hem into [Beskriv AssemblyFileVersion.cs.template]

using System.Reflection;
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.1.2.179")]

Last – I add the AssemblyFileInfo.cs file to my other projects as a link. So I only need to update the AssemblyInfo.cs file in my build project.

I then chose to “Ignore” the AssemblyFileInfo.cs file from SVN, so I SVN ignore that it changes on every build.

Reporting on what is deployed

I wanted to produce something to make it easy to identify the version of assemblies that is deployed into the different environments. Something that could answer questions like: Is it the same version of assemblies deployed to production as there is to test? What revision of sourcecode does the assemblies relate to? And so on. I also “tag” a branch in SVN of the entire solution for any builds that I consider to be “Production worthy” to easily get at it, but that is a manual process.

To report on assembly versions, I opted for doing it at the end of a deployment, and to add to the PowerShell scripts that already did the deployment. I wanted something that looked at Biztalk and discovered all the assemblies that are included in my applications. I also wanted to produce a HTML document and to make it easily available, I chose to publish it to a local website on the server.

There is ample room for improvement on how to document this, but I like the idea of going to a URL, in a server for that specific environment, to check up on what is deployed there.

This PowerShell code could most likely be shorter and more effective, but it does the job. I like to write out the commands and not use abbreviations. Makes it easier to read IMO. Feel free to come up with suggestions for improvements to this code - I don't mind. As Scott Hanselman wrote. I am NOT my code. So I don’t take criticism of my code personally.

First I declare a funtion I use to get the assemblyversion and the assemblyfileversion numbers from an array of file-paths.

Then I load the BizTalk PowerShell provider, and then I look for the the BizTalk related assemblies in the BizTalk:\All Artifacts\Resources' folder.

$BizTalkAssemblies = get-childitem 'BizTalk:\All Artifacts\Resources' 

Then I select to work with just the assemblies with names that contains text I know is part of my solution, through doing a “match” with some text I know is part of the namespace of my projects.

I then call the function declared earlier, and pipe output out to a HTML file, and feed it a CSS file that pretties up the result a little.

Get-AssemblyVersion -assemblies $BizTalkAssemblies | ConvertTo-Html -CssUri "BizTalkDocumentation.css" -Title "BizTalk Version information" |Out-File -FilePath C:\inetpub\wwwroot\default.html

At last I copy the file to a website I know I can use for documentation purposes, and I add a timestamp to the end of the HTML file to show when it was last updated.

Copy-Item  BizTalkDocumentation.css C:\inetpub\wwwroot\BizTalkDocumentation.css -Force
Add-Content -Path C:\inetpub\wwwroot\default.html  -Value  "<br /> Last Updated: $(Get-Date -Format F)"

This produces an output like this:

image001

 

Here is the entire Powershell script for reference:

 
function Get-AssemblyVersion ($assemblies)
{
 
foreach ($item in $assemblies)
{
    if ($item.Name -MATCH 'FTC')
        {
       Get-Item  $item.SourceLocation | ForEach-Object {
                                                            try {
                                                                $_ | Add-Member NoteProperty FileVersion ($_.VersionInfo.FileVersion)
                                                                $_ | Add-Member NoteProperty AssemblyVersion (
                                                                [Reflection.Assembly]::LoadFile($_.FullName).GetName().Version)
                                                                } catch {} $_
                                                        } | Select-Object Name,FileVersion,AssemblyVersion
        }
    }
   
} #End function
 

$BizTalkMgmtDBName = "BizTalkMgmtDB"
$sqlInstance = "localhost"
 
If ((Get-PSSnapin | Select-Object Name | Select-String "BizTalkFactory.Powershell.Extensions") -eq $null)
{
            Write-Host "Adding PSSnapin as it was not there...`r"
            $InitializeDefaultBTSDrive=$false
            Add-PSSnapIn BizTalkFactory.PowerShell.Extensions
}
 
If (!(Test-Path -Path "BizTalk:\"))
{
Write-Host "Adding BizTalk:\ as it was not mounted ... With SqlInstance:`r " $sqlInstance
New-PSDrive -name BizTalk -PSProvider BizTalk -Root BizTalk:\ -instance $sqlInstance -database $BizTalkMgmtDBName
}
 
 
$BizTalkAssemblies = get-childitem 'BizTalk:\All Artifacts\Resources' #| % {$_.Name -match "FTC"}
Get-AssemblyVersion -assemblies $BizTalkAssemblies | ConvertTo-Html -CssUri "BizTalkDocumentation.css" -Title "BizTalk Version information" |Out-File -FilePath C:\inetpub\wwwroot\default.html
Copy-Item  BizTalkDocumentation.css C:\inetpub\wwwroot\BizTalkDocumentation.css -Force
Add-Content -Path C:\inetpub\wwwroot\default.html  -Value  "<br /> Last Updated: $(Get-Date -Format F)"

If you are interested in the deployment and build files, let me know.

 

Missing stuff – not hard to implement, just haven’t gotten around to it yet:

  • I still need to version and document the services that are deployed
  • It would be great to have a history as well as the current snapshot, for that a db would probably be the right solution
  • I would like for my BuildScript to also Automatically svn tag the current revision, every time I do a release build.
  • Any other ideas for improvements?

Tags:

BizTalk Assembly file-versioning - and documentation of what is deployed

by Lars W. Andersen 19. March 2013 14:52

I finally got around to setting up a descriptive versioning of my BizTalk assemblies the other day. What I wanted was to have something that made it possible to trace different versions of the assemblies back to the sourcecode. And to make it easily visible that an assembly had changed. I took it one step further and came up with an easy to implement way of showing which versions of code is deployed on the servers. 

The build process

I build the entire solution, using an MSBUILD script, that handles copying dll’s to an output folder on a drop share. I then deploy assemblies using powershell and the BizTalk Powershell Provider. I have a full deploy script that tears down the applications and recreates them, and a “hotfix” deployment that have a minimal impact on running applications. I don’t particularly like MSI package deployments for BizTalk as IMO they add a “fog of war” to the deployment. Especially when something goes wrong. I know some might consider such an “xcopy deployment” of DLL’s to be medieval, but there is a transparency to what is happening, and the end result is the same. My binding files are created using the XMLPreprocesor / excel spreadsheet method.

I don’t currently need to update the AssemblyVersion with all the problems of updating references in maps and orchestrations etc. If you should go there, make sure to look at the documentation. I only need to update the AssemblyFileVersion to communicate the versioning of applications. The AssemblyFileVersion will show up as displayed here on another windows file:

image

all the build artifacts are stored in a separate empty Class project as part of the solution. A project that I exclude from the solution build configuration. All the scripts and the build file shown below are part of that project.

Incrementing the Build number

To add some value to the version number I wanted to add the SVN revision number to identify the assembly back to my sourcecode revision.

The client I currently work for uses SVN, my favorite easy to use and understand source control system. (I still think GIT is overly complicated and I rarely need my code to be social anyway).

For this I use the MSBuild Community Tasks and the SvnVersion Task, added to the solution through Nuget like this:

Install-Package msbuildtasks

In the MSBuild script I reference the SvnVersion and the FileUpdate tasks like this:

<UsingTask TaskName="SvnVersion" AssemblyFile="..\.build\MSBuild.Community.Tasks.dll" />
<UsingTask TaskName="FileUpdate" AssemblyFile="..\.build\MSBuild.Community.Tasks.dll" />

In a separate target in the MSbuild file, I update my assemblyfileversion template with the SVN revision number

<Target Name="SubVersionBeforeBuildVersionTagItUp" DependsOnTargets="BeforeBuild">
    <ItemGroup>
      <AssemblyInfoFiles Include="$(ProjectDir)\**\*AssemblyInfo.cs" />
    </ItemGroup>
    <SvnVersion LocalPath="$(MSBuildProjectDirectory)" ToolPath="$(SVNToolPath)">
      <Output TaskParameter="Revision" PropertyName="MySubVersionRevision" />
    </SvnVersion>
    <FileUpdate Files="AssemblyFileInfo.cs"
            Regex="(AssemblyFileVersion\(\&quot;)(\d+)\.(\d+)\.(\d+)\.(\d+)"
            ReplacementText="$1$2.$3.$4.$(MySubVersionRevision)" />
  </Target>

I make sure to ONLY update the AssemblyFileVersion and not the AssemblyVersion number, which I leave at 1.0.0.0  - this is handled by the regular expression in the <FileUpdate> section of the build  target.

Now I don’t want to check in the now changed AssemblyVersion files, so what I do is to store a Template of the AssemblyFileVersion.cs  in SVN. I do this in my build project, and this is referenced as a linked file, in my other Visual Studio projects.

I split the version properties out into a separate AssemblyFileInfo.cs file as I have both BizTalk projects and C# class projects that I wanted to version. The AssemblyInfo.cs files for BizTalk projects have these declarations added to them, so I couldn’t just use the Assemblyinfo.cs file in a c# Class project.

using Microsoft.XLANGs.BaseTypes;
using Microsoft.BizTalk.XLANGs.BTXEngine;
[assembly: Microsoft.XLANGs.BaseTypes.BizTalkAssemblyAttribute(typeof(BTXService))]

Instead, I removed the two AssemblyVersion declarations from the original Assemblyinfo.cs and put hem into [Beskriv AssemblyFileVersion.cs.template]

using System.Reflection;
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.1.2.179")]

Last – I add the AssemblyFileInfo.cs file to my other projects as a link. So I only need to update the AssemblyInfo.cs file in my build project.

I then chose to “Ignore” the AssemblyFileInfo.cs file from SVN, so I SVN ignore that it changes on every build.

Reporting on what is deployed

I wanted to produce something to make it easy to identify the version of assemblies that is deployed into the different environments. Something that could answer questions like: Is it the same version of assemblies deployed to production as there is to test? What revision of sourcecode does the assemblies relate to? And so on. I also “tag” a branch in SVN of the entire solution for any builds that I consider to be “Production worthy” to easily get at it, but that is a manual process.

To report on assembly versions, I opted for doing it at the end of a deployment, and to add to the PowerShell scripts that already did the deployment. I wanted something that looked at Biztalk and discovered all the assemblies that are included in my applications. I also wanted to produce a HTML document and to make it easily available, I chose to publish it to a local website on the server.

There is ample room for improvement on how to document this, but I like the idea of going to a URL, in a server for that specific environment, to check up on what is deployed there.

This PowerShell code could most likely be shorter and more effective, but it does the job. I like to write out the commands and not use abbreviations. Makes it easier to read IMO. Feel free to come up with suggestions for improvements to this code - I don't mind. As Scott Hanselman wrote. I am NOT my code. So I don’t take criticism of my code personally.

First I declare a funtion I use to get the assemblyversion and the assemblyfileversion numbers from an array of file-paths.

Then I load the BizTalk PowerShell provider, and then I look for the the BizTalk related assemblies in the BizTalk:\All Artifacts\Resources' folder.

[sourcecode language='powershell' ]
$BizTalkAssemblies = get-childitem 'BizTalk:\All Artifacts\Resources'
[/sourcecode]

Then I select to work with just the assemblies with names that contains text I know is part of my solution, through doing a “match” with some text I know is part of the namespace of my projects.

I then call the function declared earlier, and pipe output out to a HTML file, and feed it a CSS file that pretties up the result a little.

[sourcecode language='powershell' ]
Get-AssemblyVersion -assemblies $BizTalkAssemblies | ConvertTo-Html -CssUri "BizTalkDocumentation.css" -Title "BizTalk Version information" |Out-File -FilePath
[/sourcecode]

At last I copy the file to a website I know I can use for documentation purposes, and I add a timestamp to the end of the HTML file to show when it was last updated.

[sourcecode language='powershell' ]
Copy-Item  BizTalkDocumentation.css C:\inetpub\wwwroot\BizTalkDocumentation.css -Force
Add-Content -Path C:\inetpub\wwwroot\default.html  -Value  "<br /> Last Updated: $(Get-Date -Format F)"
[/sourcecode]

 

Here is the entire Powershell script

[sourcecode language='powershell'  padlinenumbers='true' gutter='false']
function Get-AssemblyVersion ($assemblies)
{
 
foreach ($item in $assemblies)
{
    if ($item.Name -MATCH 'FTC')
        {
       Get-Item  $item.SourceLocation | ForEach-Object {
                                                            try {
                                                                $_ | Add-Member NoteProperty FileVersion ($_.VersionInfo.FileVersion)
                                                                $_ | Add-Member NoteProperty AssemblyVersion (
                                                                [Reflection.Assembly]::LoadFile($_.FullName).GetName().Version)
                                                                } catch {} $_
                                                        } | Select-Object Name,FileVersion,AssemblyVersion
        }
    }
   
} #End function
 

$BizTalkMgmtDBName = "BizTalkMgmtDB"
$sqlInstance = "localhost"
 
If ((Get-PSSnapin | Select-Object Name | Select-String "BizTalkFactory.Powershell.Extensions") -eq $null)
{
            Write-Host "Adding PSSnapin as it was not there...`r"
            $InitializeDefaultBTSDrive=$false
            Add-PSSnapIn BizTalkFactory.PowerShell.Extensions
}
 
If (!(Test-Path -Path "BizTalk:\"))
{
  Write-Host "Adding BizTalk:\ as it was not mounted ... With SqlInstance:`r " $sqlInstance
  New-PSDrive -name BizTalk -PSProvider BizTalk -Root BizTalk:\ -instance $sqlInstance -database $BizTalkMgmtDBName
}

 
$BizTalkAssemblies = get-childitem 'BizTalk:\All Artifacts\Resources'
Get-AssemblyVersion -assemblies $BizTalkAssemblies | ConvertTo-Html -CssUri "BizTalkDocumentation.css" -Title "BizTalk Version information" |Out-File -FilePath C:\inetpub\wwwroot\default.html
Copy-Item  BizTalkDocumentation.css C:\inetpub\wwwroot\BizTalkDocumentation.css -Force
Add-Content -Path C:\inetpub\wwwroot\default.html  -Value  "<br /> Last Updated: $(Get-Date -Format F)"
 
[/sourcecode]

 

If you are interested in the deployment and build files, let me know.

Tags:

BizTalk 2010 | BizTalk Operations | BizTalk installation

Quick fix for looking into a copy of the Tracking Database

by Lars W. Andersen 28. January 2013 11:45

When I do consulting at clients that use the tracking database it can be a problem scheduling time with an operations person with access to querying the tracking database. While it is easy to get a copy of it, and there are lots of good queries floating around on the internet, it is easier for a quick problem-solving session to look into the restored production copy through the BizTalk Admin Console. 

The queries aimed at stuff that is stuck in the messagebox, like Suspended Service instances and In-progress stuff will not show you production data, but if you just need to slice through tracking data, this will hook you up.

You can do this quite easily on your dev box, by updating the name of the tracking database like this:

!!!!NOTE!!!!   Do only play with this setting on your dev box, or a client dev/test server ….

If you have a BizTalk development server setup already, restore the database onto your SQL server. Name it something like ‘ProdTracking’

Then dive into the Management database and in the adm_Group table, set the TrackingDBName to your newly restored prod database. Restart your BizTalk Admin console to pick up the new TrackingDB, and the queries aimed at the trackingdatabase will now search stuff in that copy from production.

To get your dev setup back, just update the adm_group with the original tracking db name.

Here is a query to update the table if you’re lazy. (like me).

UPDATE [BizTalkMgmtDb].dbo.adm_Group 
SET TrackingDBName = 'BizTalkDtaDb'

 

Also a friendly reminder about data security: There is likely to be sensitive data in that tracking database copy, so make sure you know where it is, and delete it when you are done with it. We're seeing too many news stories on the interwebs about social security id's and creditcard numbers found on random laptops...

Tags:

BizTalk 2010 | BizTalk Operations

Set BizTalk services to automatic (Delayed Start)

by Lars W. Andersen 20. December 2012 11:45

I finally got around to putting this oneliner together. Posting it here so I can find it again. 

The problem is that Set-Service does not support setting the service –StartUpType to Automatic (Delayed Start) so we are left with playing with the SC.EXE or the registry to do this. I prefer the registry – its simpler than playing with a commandline tool.

It gets all the BizTalk services and enumerates through them to set the key.

 1: Get-Service -Name 'BTSSvc$*' | %{Set-ItemProperty -Path "Registry::HKLM\System\CurrentControlSet\Services\$($_.Name)" -Name "DelayedAutostart" -Value 1 -Type DWORD}

I haven’t set this for the ESSO svc as it was no problem on the environment I am working on now. If it was, just change the –Name property for Get-Service ….

Tags:

BizTalk 2010 | BizTalk installation

Change the PrtSc key on your new Thinkpad Keyboard …

by Lars W. Andersen 8. October 2012 13:11

If you  were used to the old Thinkpad keyboards and got one of the new Chiclet style ones, you might miss the old “Context Menu” button that used to be down there next to the Win and the AltGr button.  I did.

To fix it, download SharpKeys- a freeware application that will allow you to remap keys on your keyboard. It produces registry entries for you, instead of hacking them together yourselves and understanding scanmap codes, and when you are satisfied, it will write them into the registry for you. Next time you start it up, it will show you what you mapped, and let you change it. So you don’t have to have it running all the time.

To change the PrtSc to the Contect Menu, map the “Special: PrtSc” to the “Special: Application” button, and you are good to go!

image

Tags:

Thinkpads

Blogical SFTP Adapter with append functionality

by Lars W. Andersen 28. August 2012 21:29

I couldn’t get in touch with Mikael Håkonsson who wrote the SFTP adapter, so I am just going to post my version of the adapter with my added SFTP append functionality here….

My additions are commented with a TODO: so you can see what I added, and maybe change it to suit your needs.  Enjoy!

Blogical.Adapters.Sftp.With.Append.zip (9,31 mb)

Tags:

Adapters | BizTalk 2009 | BizTalk 2010 | SFTP

How to use Web Platform Installer to get Azure SDK 1.7

by Lars W. Andersen 8. June 2012 21:45

The version of Web Platform Installer available from the “official” page is still 3.0 and it doesn’t list the 1.7 June version of the Azure SDK and tools. I’ve been waiting around

However, if you go here, to the official Azure pages,  and get the file named VWDOrVs11AzurePack_RC.3f.3f.3fnew.exe (clever name there!) it will install the Web Platform Installer version 4.0, and this will show all the same stuff as the 3.0 Platform Installer, but also all the new goodies.

Or if you only want to install the Azure stuff, and not have to pick it out from the many options in the Web Platform Installer, go here where it will install and launch the Web Platform Installer 4.0, but select the Azure stuff for you.

Saves you time from figuring out what you need and don’t need from the original Azure SDK V1.7 June release list from MS Download …. http://www.microsoft.com/en-us/download/details.aspx?id=29988

 

EDIT:  There is another link to the Web Platform Installer 4, on the MS download link, at the end of the listed application packages. That will work as well ...

Tags:

Windows Server 8 Beta on VMware - blank screen after installing VMware tools

by Lars W. Andersen 9. March 2012 04:33

If you selected a Windows Server as the Guest OS for a Windows 8 Server like this:

image

and wondered why you got a blank screen after installing VMware tools, here is how to fix it.

Just enable “Accelerate 3D Graphics” in the VM settings. This is apparently needed to get the UI working after installing VMware tools. No idea which bits needed flipping between the Display driver and the new Windows UI Api’s to require this.  But on the next boot all is well again ….

image

Tags:

BizTalk 2010 and SQL server 2012?

by Lars W. Andersen 8. March 2012 22:15

While Microsoft have not released any information (to my knowledge) about the support for Running BizTalk 2010 on top of SQL 2012 that have just been RTM, I can see  that it works fine on my development server here at home. The official requirements still only states up to SQL 2008R2 though.

I did an in-place upgrade of SQL 2008R2 SP1 to SQL 2012, BizTalk just keeps humming along and processing of messages like nothing happened. All the SQL agent jobs are working as well.

UPDATE!!!   22/10-2012

While the inplace upgrade was running fine for me for laptop development a couple months, please note that a clean new installation of BizTalk 2010 on SQL 2012 is not possible ... Just so you know. I know it says so in the documentation, but I gave it a shot and I ran into all sorts of problems. So don't do it kids.

Tags:

BizTalk 2010 CU4 is already released

by Lars W. Andersen 1. March 2012 20:04

Get it here

The CRT takes suggestions for fixes going into the next CU – check it out here:  CRT blog

Tags:

About Me

A Microsoft Infrastructure, BizTalk developer, Sharepoint interested, freelance consultant. Working out of Copenhagen, Denmark.

On the front page you find my blog about BizTalk, integration, Windows, .NET and everything else that I either find may be of interest to others, or stuff that I have to write down to remember.

Check out my info and CV on this page

Check my google calendar showing free/available time here (Opens in a new window).

Lars W. Andersen

Month List

Widget Twitter not found.

Root element is missing.X