none
System invalidcastexception "Unable to cast object of type" RRS feed

  • Question

  • Hi, I'm getting an error...

    System.InvalidCastException: "Unable to cast object of type

    'Mircrosoft.SqlServer.Dts.Runtime.Sequence' to type

    'Mircrosoft.SqlServer.Dts.Runtime.taskHost'.

      string pkgLocation;
                DtsRuntime.Package pkg;
                DtsRuntime.Application app;
                
                pkgLocation = path;
                app = new DtsRuntime.Application();
                pkg = app.LoadPackage(pkgLocation, null);

                //List Executables (Tasks)
                foreach (DtsRuntime.Executable tsk in pkg.Executables)
                {
                    DtsRuntime.TaskHost TH = (DtsRuntime.TaskHost)tsk; //getting an error here
                    treeView1.Nodes["Executables"].Nodes.Add(TH.Name, TH.Name);
                    //Data Flow Task components
                    if (TH.InnerObject.ToString() == "System.__ComObject")
                    {
                        try
                        {
                            DtsWrapper.MainPipe m = (DtsWrapper.MainPipe)TH.InnerObject;
                            DtsWrapper.IDTSComponentMetaDataCollection100 mdc = m.ComponentMetaDataCollection;

                            foreach (DtsWrapper.IDTSComponentMetaData100 md in mdc)
                            {
                                //MessageBox.Show(TH.Name.ToString() + " - " + md.Name.ToString());
                                treeView1.Nodes["Executables"].Nodes[TH.Name].Nodes.Add(md.Name, md.Name);
                            }

                        }
                        catch
                        {
                        }
    Thursday, May 21, 2020 5:40 AM

All replies

  • DtsRuntime.TaskHost TH = (DtsRuntime.TaskHost)tsk; //getting an error here

    System.InvalidCastException: "Unable to cast object of type

    'Mircrosoft.SqlServer.Dts.Runtime.Sequence' to type

    'Mircrosoft.SqlServer.Dts.Runtime.taskHost'.

    Well the object 'tsk' is a Mircrosoft.SqlServer.Dts.Runtime.Sequence type,  and TH is a 

     Mircrosoft.SqlServer.Dts.Runtime.taskHost' type.

    You can't make a Sequence be a taskHost, becuase they are two different objects defined by two different classes/types.


    • Edited by DA924x Thursday, May 21, 2020 6:06 AM
    Thursday, May 21, 2020 6:02 AM
  • Hi kdinuk,

    Thank you for posting here.

    Executable is the parent class of TaskHost, but it should be noted that not all parent classes can be cast into child classes.

    As if we can say that a dog is an animal, but an animal is not necessarily a dog, it may also be a cat.

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, May 21, 2020 6:27 AM
  • Thanks for all your support. Basically, am loading SSIS package related info. When I select package that is having 'sequence container' then it is failing. If it is having only sql task then it is working. How to fix it?
    Thursday, May 21, 2020 1:32 PM
  • `Executables` is going to return all the executables in the package. This may include task hosts but can include anything that derives from Executable. If you only want tasks then do a runtime safe cast instead.

    foreach (var task in pkg.Executables.OfType<DtsRuntime.TaskHost>())
    {
       ...
    };

    The above code enumerates each object in `Executables`. If that object is compatible with `TaskHost` then it returns it. `task` is of type `TaskHost`. So the above code will only return tasks which is what you're looking for. The above requires LINQ so you might need to add a namespace using.

    Note also that your check for a COM object is not a good solution. Firstly you should never compare types by string. But even then you're making a bad assumption here. If the inner object is a COM object you're casting it to DtsWrapper.MainPipe and there is zero guarantee on that. At a minimum you should do a runtime safe cast again. Here though it only works (in both cases actually) if the COM object supports it. COM objects get to decide what interfaces they implement. If the underlying COM object doesn't implement the appropriate COM interface it blows up. So you should handle this correctly in either case so the fact that it is a COM object isn't even relevant here.

    //Using newer C# 7.x feature
    if (TH.InnerObject is DtsWrapper.MainPipeline pipeline)
    {
       foreach (var md in pipeline.ComponentMetaDataCollection.OfType<DtsWrapper.IDTSComponentMetaData100>())
       {
          ...
       };
    };

    Note also that COM sometimes doesn't play nice with LINQ so if the above doesn't work then use the `as` operator instead. Also if you aren't using the newer compiler then the `is` syntax doesn't work so you have to do it the long way.

    //Pre 7.X version
    var pipeline = TH.InnerObject as DtsWrapper.MainPipeline;
    if (pipeline != null)
    {
       //LINQ doesn't always play nice with COM
       foreach (var item in pipeline.ComponentMetaDataCollection)
       {
          var md = item as DtsWrapper.IDTSComponentMetaData100;
          if (md != null)
          {
             ...
          };
       };
    }


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, May 21, 2020 2:41 PM
    Moderator
  • `Executables` is going to return all the executables in the package. This may include task hosts but can include anything that derives from Executable. If you only want tasks then do a runtime safe cast instead.

    foreach (var task in pkg.Executables.OfType<DtsRuntime.TaskHost>())
    {
       ...
    };

    The above code enumerates each object in `Executables`. If that object is compatible with `TaskHost` then it returns it. `task` is of type `TaskHost`. So the above code will only return tasks which is what you're looking for. The above requires LINQ so you might need to add a namespace using.

    Note also that your check for a COM object is not a good solution. Firstly you should never compare types by string. But even then you're making a bad assumption here. If the inner object is a COM object you're casting it to DtsWrapper.MainPipe and there is zero guarantee on that. At a minimum you should do a runtime safe cast again. Here though it only works (in both cases actually) if the COM object supports it. COM objects get to decide what interfaces they implement. If the underlying COM object doesn't implement the appropriate COM interface it blows up. So you should handle this correctly in either case so the fact that it is a COM object isn't even relevant here.

    //Using newer C# 7.x feature
    if (TH.InnerObject is DtsWrapper.MainPipeline pipeline)
    {
       foreach (var md in pipeline.ComponentMetaDataCollection.OfType<DtsWrapper.IDTSComponentMetaData100>())
       {
          ...
       };
    };

    Note also that COM sometimes doesn't play nice with LINQ so if the above doesn't work then use the `as` operator instead. Also if you aren't using the newer compiler then the `is` syntax doesn't work so you have to do it the long way.

    //Pre 7.X version
    var pipeline = TH.InnerObject as DtsWrapper.MainPipeline;
    if (pipeline != null)
    {
       //LINQ doesn't always play nice with COM
       foreach (var item in pipeline.ComponentMetaDataCollection)
       {
          var md = item as DtsWrapper.IDTSComponentMetaData100;
          if (md != null)
          {
             ...
          };
       };
    }


    Michael Taylor http://www.michaeltaylorp3.net

    Thanks. Also looking for containers. Does it return containers and different tasks in package? If I want containers, executables and different controls(bulkinsertask, ftptask etc. How do I get this info from package?
    Thursday, May 21, 2020 3:07 PM
  • Executables returns anything that derives from Executable. If your "containers" derive from it then it should. You should be able to easily test this though. The only container that the docs indicate is DtsContainer. If that is what you're looking for then it should work. If you want to enumerate once then you'll need to move the runtime type check into the foreach loop and use `as`. If you are fine enumerating multiple times then use a separate foreach for each type in combination with OfType. Either approach will work. 

    As for what will and won't it find you'll need to step through the code. Put a breakpoint on the foreach and look at the values in `Executables`. That will help direct you with what type(s) you need to look for. The as/OfType code will work for the type(s) you need.


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, May 21, 2020 3:53 PM
    Moderator
  • Hi, I'm sorry for late responding. I'm new to .net. What is the code I have to use to get all different task and containers to get it from SSIS package. Could you please help me.
    Sunday, May 24, 2020 6:42 PM
  • The code I posted gives you all the tasks. I don't know what you mean by container so my recommendation is to create a simple SSIS package with the various components you want in it. Then run your code against it. Using the foreach statement should give you all the tasks. Identify what is missing from that initial pass, if anything. If something is missing then look at everything inside the Executables property to see what type(s) are missing.

    foreach (var executable in pgk.Executables.OfType<Executable>())
    { 
       if (executable is TaskHost task)
       { 
          //Tasks
       } else if (executable is ISomethingElse somethingElse)
       { 
          //Next type
       } else
       {
          //Everything else
       };
    };


    Michael Taylor http://www.michaeltaylorp3.net

    Sunday, May 24, 2020 7:04 PM
    Moderator