开发者

Powershell 2.0 - SqlDataReader closing when passed into a function

I am interacting with a set of custom .Net 2.0 assemblies, with Powershell 2.0, to automate a current task. I load all the required dlls and call a DAL method, in the dll, to retrieve a System.Data.SqlDataReader. When I pass the SqlDataReader into a constructor in the same custom assembly I receive a "Invalid attempt to call HasRows when reader is closed." exception.

Code sample:

dir D:\stuff\*.dll | foreach { [Reflection.Assembly]::LoadFrom($_.FullName) } | out-null
[CustomAssembly.DataConfig]::ConnectionString = "Valid Connection String"
$reader=[CustomAssembly.DAL.Thing]::Get(123)
new-object Custom开发者_运维知识库Assembly.BusinessObjects.Thing($reader)

The $reader is open, and has data, before I call the Thing constructor.

I must be missing something, but I am not sure what it is.

Edit 1:

$reader appears to be read, and closed, anytime it is passed to a function, in powershell or in an assembly. Is there a way to prevent this?

Edit 2:

Powershell automatic unrolling strikes again

How to stop PowerShell from unpacking an Enumerable object?

Strange behavior in PowerShell function returning DataSet/DataTable

The following modified code sample works by wrapping the result in a single element array, so the automatic unrolling does not affect the SqlDataReader. Note the single comma after the "$reader=" statement. That is not a typo.

dir D:\stuff\*.dll | foreach { [Reflection.Assembly]::LoadFrom($_.FullName) } | out-null
[CustomAssembly.DataConfig]::ConnectionString = "Valid Connection String"
$reader=,[CustomAssembly.DAL.Thing]::Get(123)
new-object CustomAssembly.BusinessObjects.Thing($reader)


I ran into similar issues some time ago. Look at this code:

I create my own Enumerator that prints some information about when it is called. It's same as your SqlDataReader that (I think) implements IEnumerator as well.

PS> Add-Type -TypeDefinition @"
    using System;
    using System.Collections;
    public class MyEnumerator2 : IEnumerator
    {
        private int _count = 10;
        private Random r = new Random();

        public MyEnumerator2(int count)
        {
            _count = count;
        }

        public bool MoveNext()
        {
            Console.WriteLine("Moving!");
            _count--;
            return _count >= 0;
        }

        public void Reset()
        {
            throw new NotImplementedException();
        }

        public object Current
        {
            get
            {
                Console.WriteLine("Current!");
                return r.Next();
            }
        }
    }
"@

Then let's create an object of the type and try to output it:

PS> $mye = New-Object MyEnumerator2 5
PS> $mye | % -begin { write-host 'starting' } -Process { write-host 'next is ' $_ }
starting
Moving!
Current!
next is  2081278528
Moving!
Current!
next is  2000135673
Moving!
Current!
next is  692162542
Moving!
Current!
next is  1531746038
Moving!
Current!
next is  1550381634
Moving!

Everything is as expected. But.. now

PS> function iteratemye($o) {
    $o | % -begin { write-host 'starting' } -Process { write-host 'next is ' $_ }
}
PS> $mye = New-Object MyEnumerator2 5
PS> iteratemye $mye
Moving!
Current!
Moving!
Current!
Moving!
Current!
Moving!
Current!
Moving!
Current!
Moving!
starting
Moving!

If you pass this enumerator to a function, it is read before it reaches the body. That's very bad.

So have a look at your code. If you use some function like my iteratemye, that's the cause of your problems.

Update: it doesn't implement IEnumerator, but IEnumerable. I see that you just pass the object to some constructor, which is not the same problem I had, but I believe PowerShell will still try to get enumerator and do some magic.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜