1
\$\begingroup\$

We have a bunch of SSIS packages that use .dtsxConfig files for various variable transformations, but mainly for the connection strings. While doing some SQL tracing, we noticed that almost all our packages have the same application name since they're mostly copies of each other. To make tracing clearer, I want to replace all the existing ApplicationName values in the config files with the filename.

This worked on two sample files in the test directory (and didn't run on the two files with different extensions so that's good), but because I'm going to run this against production files, I'd like to make sure there's no gaping logic holes or possibility of bad replacements (and code improvements since I'm pretty new)

Sample file below code

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RenameConfigApplicationNames
{
    class Program
    {
        static void Main(string[] args)
        {

            string filepath = "C:\\SSIS\\Development\\Configurations";
            DirectoryInfo d = new DirectoryInfo(filepath);

            foreach (var file in d.GetFiles("*.dtsConfig"))
            {
                string fName = file.Name.ToString();
                string fPath = file.FullName.ToString();
                string pureFileName = Path.GetFileNameWithoutExtension(fName);
                string fileContent = GetFileContent(fPath, pureFileName);
                string newFileName = Path.Combine(file.DirectoryName, pureFileName + "_Temp.txt");

                File.WriteAllText(newFileName, fileContent);
                file.Delete();
                File.Move(newFileName, fPath);
            }       
        }

        private static string GetFileContent(string fPath,string fName)
        {
            string[] fInfo = File.ReadAllLines(fPath);
            StringBuilder sb = new StringBuilder(1024);
            foreach (string line in fInfo)
            {
                if (line.Contains(";Application Name="))
                {
                    int start = line.IndexOf(";Application Name=") + 18;
                    int end = line.IndexOf(";", start + 1);
                    int len = line.Length - end;
                    string prefix = line.Substring(0, start);
                    string suffix = line.Substring(end, len);
                    string final = prefix + fName + suffix;
                    sb.AppendLine(final);
                }
                else
                {
                    sb.AppendLine(line);
                }
            }
            return sb.ToString();
        }    
    }
}

SAMPLE FILE

<?xml version="1.0"?>
<DTSConfiguration>
    <DTSConfigurationHeading>
        <DTSConfigurationFileInfo GeneratedBy="Domain\User" GeneratedFromPackageName="SomeOldPackage" GeneratedFromPackageID="{big GUID}" GeneratedDate="4/01/2010 11:00:00 AM"/>
    </DTSConfigurationHeading>
    <Configuration ConfiguredType="Property" Path="\Package.Connections[CN-Destination1].Properties[ConnectionString]" ValueType="String">
        <ConfiguredValue>Data Source=SERVERNAME\NAMEDINSTANCE;Initial Catalog=Database;Integrated Security=Maybe;Application Name=SSIS-SomeOldPackage-{another GUID}Servername,Database;</ConfiguredValue>
    </Configuration>
    <Configuration ConfiguredType="Property" Path="\Package.Connections[CN-Destination2].Properties[ConnectionString]" ValueType="String">
        <ConfiguredValue>Data Source=SERVERNAME;Initial Catalog=Database;Integrated Security=Maybe;Application Name=SSIS-SomeOldPackage-{another GUID}Servername,Database;</ConfiguredValue>
    </Configuration>
    <Configuration ConfiguredType="Property" Path="\Package.Variables[User::EmailDistribution].Properties[Value]" ValueType="String">
        <ConfiguredValue>emailaddress@company.org</ConfiguredValue>
    </Configuration>
</DTSConfiguration>

The only change in the file is the ApplicationName in these two lines:

    <ConfiguredValue>Data Source=SERVERNAME\NAMEDINSTANCE;Initial Catalog=Database;Integrated Security=Maybe;Application Name=*FileNameNoExtension;</ConfiguredValue>
</Configuration>
<Configuration ConfiguredType="Property" Path="\Package.Connections[CN-Destination2].Properties[ConnectionString]" ValueType="String">
    <ConfiguredValue>Data Source=SERVERNAME;Initial Catalog=Database;Integrated Security=Maybe;Application Name=FileNameNoExtension;</ConfiguredValue>
</Configuration>
\$\endgroup\$
1
\$\begingroup\$

You're doing a lot of unnecessary work there.

DirectoryInfo d = new DirectoryInfo(filepath);

Instead of DirectoryInfo you can simply use Directory.EnumerateFiles which will lazily enumerate the directory.

string fName = file.Name.ToString();
string fPath = file.FullName.ToString();

Calling ToString on a string (Name is a string) is meaningless. You don't need any of these variables.

We also don't use abbreviations in C#. They are confusing so instead of fName you should use fileName.


private static string GetFileContent(string fPath,string fName)

You should use names that precisely describe what a method is doing. This one is not just getting file content. It changes it! This is not clear for anyone that would use it. Instead you should call it ReplaceApplicationName because this is what it does or rather should. Currently it does not only changes the applincation name but also reads the file. Then the foreach does everything else like creating paths and saving and replacing the file. All this should be separated. You should read about the SRP - Single Responsibility Principle - it's the first step to maintainable and testable code.

After applying all the suggestions you code could look like this. You have now not just two but four methods. Each of them doing only a small part of the job. Should you need to adjust something then you most likely need to do it in one place which is the goal.

Notice also that ReplaceApplicationName is not lazy by using the yield return so we call .ToArray() to actually execute it get the results.

static void Main(string[] args)
{

    string filepath = "C:\\Temp";

    foreach (var fileName in Directory.EnumerateFiles(filepath, "*.dtsConfig"))
    {
        var lines = File.ReadAllLines(fileName);    
        var updatedDtsConfig = ReplaceApplicationName(lines, fileName).ToArray();
        ReplaceConfigFile(fileName, updatedDtsConfig);
    }
}

private static string CreateTempFileName(string fileName)
{
    return
        Path.Combine(
            Path.GetDirectoryName(fileName),
            Path.GetFileNameWithoutExtension(fileName) + "_Temp.txt");
}

private static void ReplaceConfigFile(string fileName, string[] content)
{
    var tempFileName = CreateTempFileName(fileName);

    File.WriteAllLines(tempFileName, content);
    File.Delete(fileName);
    File.Move(tempFileName, fileName);
}

private static IEnumerable<string> ReplaceApplicationName(string[] lines, string fileName)
{
    const int lengthOfSomething = 18;

    foreach (var line in lines)
    {
        if (line.Contains(";Application Name="))
        {
            var start = line.IndexOf(";Application Name=") + lengthOfSomething;
            var end = line.IndexOf(";", start + 1);
            var len = line.Length - end;
            var prefix = line.Substring(0, start);
            var suffix = line.Substring(end, len);
            var final = prefix + Path.GetFileNameWithoutExtension(fileName) + suffix;
            yield return final;
        }
        else
        {
            yield return line;
        }
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.