开发者

c# solution to a list of system commands

开发者 https://www.devze.com 2023-02-23 01:43 出处:网络
I currently have a c# utility that runs a very long list of steps, for instance: copy a file from here to there

I currently have a c# utility that runs a very long list of steps, for instance:

  • copy a file from here to there i.e.: foreach(file in list) File.Copy ()
  • create a bunch of directories foreach (dir in list) Directory.Create
  • Loop into a list of directories and create a file. foreach (dir in list) File.Create()
  • Take a know list of files and replace some text inside foreach (file in list) Execute ("replace.exe", text1, text2)

etc.

What I did was to take all these steps and create a bunch of methods in c# that do those steps. The advantage of that is, I get to check for each command I run, log any problems and s开发者_JS百科o on. The downside of that is, it is hard coded.

I would like to (and I need to) move those steps out of the code, like in a configuration file or xml file and then read the commands one at a time and run them inside c#. In this way I still have the advantage of checking for return errors, creating logs, etc. but I don't have the actual list and commands hard coded.

I don't want to use a script (like Perl or batch) because I want to be able to monitor some of the steps I do. In other words, I really want to keep the actual execution inside my c# program but have the program being guided by the configuration file that I feed to it.

xml is quite flexible but I am not sure I can do all that with it. For instance how do I turn into xml something like:

list1 = {file1, file2};
list2  = {dir1,dir2,dir3};
foreach (file in list1)
 File.Copy(file,dir2\\file);
 File.Copy(file,dir3\\file);

Any ideas on what I could/should use to accomplish that?

Thanks Tony


Here is my loop task

    [XmlAttribute]
    public string DataTableName { get; set; }

    public TaskListClass TaskList { get; set; }

    public override void Execute(WorkContainer container)
    {
        int iteration = 0;
        string originalTaskName=String.Empty;

        // Log Start
        base.Execute(container);

        // Get the Data Table Based upon the ContainerKey
        DataTable loopTable = container.GetKeyValue<DataTable>(DataTableName);

        // If not found throw exception and exit
        if (loopTable == null)
        {
            throw new ArgumentException(
                "DataTable Not Found or Initialized For Loop Variable",
                DataTableName);
        }

        // For each row returned run the task in order as a mini-process
        foreach (DataRow row in loopTable.Rows)
        {
            iteration++;

            foreach (TaskBase task in TaskList.Tasks)
            {
                // If it is the first iteration then create a new string with the iteration number
                // else just replace the last iteration number with the current iteration number
                if (iteration == 1)
                {
                    task.Name = String.Format("Iteration {0} - {1}", iteration, task.Name);
                }
                else
                {
                    task.Name = task.Name.Replace(String.Format("Iteration {0}",iteration-1),String.Format("Iteration {0}",iteration));
                }

                // Call the task Constructor to Initialize the object
                task.GetType().GetConstructor(new Type[0]).Invoke(null);

                foreach (DataColumn dc in loopTable.Columns)
                {
                    // Store in Stack Variable
                    string propertyName = dc.ColumnName;

                    // If a field in the table matches a 
                    // property Name set that property
                    PropertyInfo propInfo = task.GetType().GetProperty(propertyName);
                    if (propInfo != null)
                    {
                        propInfo.SetValue(task, row[dc], null);
                    }                        
                    else
                    {
                        // Else if the task has a Parameters collection add the 
                        // name of the column and value to the Parameter Collection
                        propInfo = task.GetType().GetProperty("Parameters");

                        if (propInfo != null)
                        {
                            List<Parameter> parameters = propInfo.GetValue(task, null) as List<Parameter>;

                            // If the parameter Name already Exist then Override it
                            // This means that the values in the DataTable override the values in the XML
                            if (parameters.Contains(new Parameter { Name = propertyName }))
                            {
                                parameters.Remove(new Parameter { Name = propertyName });
                            }

                            parameters.Add(new Parameter { Name = propertyName, Value = row[dc].ToString(), Type="String" });
                        }
                        else
                        {
                            ParameterNotFoundException pExp = new ParameterNotFoundException(propertyName, task.GetType().ToString());
                            throw new TaskException("Unable to assign a Parameter", pExp.Message, pExp);
                        }

                    }
                }

                task.Execute(container);
            }
        }

        base.Finish(container);
    }

The XML looks something like this

    <LoopTask Name="Loop Report Creation" DataTableName="[? DistributionList ?]">
      <TaskList>
        <ReportBatchTask Name="Report In Loop">
          <ConnectionName>xxx</ConnectionName>
          <Parameters />
        </ReportBatchTask>
      </TaskList>
    </LoopTask>


To do what you're asking, you would have to have each possible action defined in code, so if you create a new action, that would require editing your program. There shouldn't be any problem configuring existing actions any way you want, though.

<TaskList>
  <MyTask>
    <Action type="CreateDirectory">
      <target>dir1</target>
      <target>dir2</target>
    </Action>
  </MyTask>
  <MyTask>
    <SourceFiles>
      <file>mypath\file1.txt</file>
      <file>mypath\file2.txt</file>
    </SourceFile>
    <Action type="Replace">
      <originalText>Text to replace</originalText>
      <replacementText>Some new text</replacementText>
    </Action>
    <Action type="Copy">
      <target>dir1</target>
      <target>dir2</target>
    </Action>
  </MyTask>
</TaskList>

If you had a separate class for each possible Action your would then create and execute an appropriate Action using what you read in from the XML.


Yes I have done a similar project: Here are some idea's without having to type the whole thing.

I created Tasks and every Task inherieted from Task class for basic logging and

 public virtual void Execute(WorkContainer container)

But every class did something so the Copy Class would have a source, destination and overwrite properties.

Then I would create a Task List which was a List of Task that could then be serialized into xml

would look something like

   <TaskList>
    <TransactionSqlTask Name="Get Interest Register Data">
      <Parameters>
        <Parameter>
          <Type>String</Type>
          <Value>M</Value>
          <Name>PaymentInd</Name>
        </Parameter>
      </Parameters>
      <DataTableName>
        <string>InterestRegisterData</string>
      </DataTableName>
      <IgnoreOutputDataTable>false</IgnoreOutputDataTable>
      <StoredProcName>proc_Report_NotesInterestRegister</StoredProcName>
      <ConnectionName>xxx</ConnectionName>
    </TransactionSqlTask>

...

That Xml would be a command line argument which would be read in, deserialized and turn back into a List of Task

Then I would just loop through the List and Call .Execute

Now there was also a Work Container to pass values from one task to another. See this post

Using Generics to return a literal string or from Dictionary<string, object>

I can provide more detail later, right now I do not have the project infront of me but hopefully this gave you some ideas.


Have you considered rewriting your functions as MSBuild tasks?

That way you can leverage the pre-existing msbuild tasks, and write your script as an msbuild file (which fits nicely in any build process). You can even debug MSBuild tasks

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号