代码之家  ›  专栏  ›  技术社区  ›  D3vtr0n

.NET嵌入资源的读取权限问题-访问数据库文件和ssis

  •  0
  • D3vtr0n  · 技术社区  · 15 年前

    我目前正在创建动态SSIS包,用于导入/导出和访问SQL服务器和多个Access DB文件之间的数据。(如果您想获得技术信息,可以使用Jet文件。)

    无论如何,只要我的SSIS包具有访问文件的硬编码连接字符串,测试期间一切都会成功。这很好,效果很好。我对此很满意。

    现在,当我将我的vb.net应用程序更改为使用AccessDB文件的动态连接字符串(目标文件,数据将放在其中)时,问题就开始了。我将AccessDB文件作为“嵌入资源”存储在应用程序中。

    以下是我用来创建访问目标文件的代码:

        Public Sub CreateDestinationFile(ByVal path As String)
    
        'Create destination file from embedded project resources 
        Dim asm = System.Reflection.Assembly.GetExecutingAssembly()
        Dim objStream As System.IO.Stream = asm.GetManifestResourceStream("XXX.XXX_Export.mdb")
        Dim abytResource(objStream.Length) As [Byte]
        Dim intLength As Integer = objStream.Read(abytResource, 0, objStream.Length)
        Dim objFileStream = New FileStream(path + "XXX_Export.mdb", FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite)
    
        Try
    
            While intLength > 0
                'write filestream to create Access DB file
                objFileStream.Write(abytResource, 0, Convert.ToInt32(objStream.Length))
                intLength = objStream.Read(abytResource, 0, objStream.Length)
            End While
    
            'close the file stream
            objFileStream.Close()
    
        Catch ex As Exception
            'write error log here - ** omitted
        Finally
            asm = Nothing
            objStream = Nothing
            objFileStream = Nothing
        End Try
    
    End Sub
    

    这很好地工作,它确实产生了正确的结果,无论我在哪里提供了一个访问数据库文件的路径。当我的SSIS包具有硬编码的连接字符串时,这很好地工作。

    一旦我将连接字符串更改为动态的,并重新运行相同的精确测试,我就会得到以下错误:

    “无法读取记录;对'msysaccessobjects'没有读取权限”

    我的SSIS包中的连接字符串正则表达式如下所示:

    --SQL connection string
    "Data Source=" + @[User::sourceDatabaseLocation] + ";User ID=" + @[User::sourceDBUserID] + ";Password=" + @[User::sourceDBPassword] + ";Initial Catalog=" + @[User::sourceDBName] + ";Provider=SQLOLEDB.1;Persist Security Info=True;Auto Translate=False;"
    
    --Access connection string
    "Data Source=" + @[User::destinationDatabasePath] + ";Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;Password=;"
    

    当我导航到本地硬盘上的这个文件并试图打开它时,它会提示我该文件处于不可恢复状态,并修复它,而这是它从未成功完成的。

    1. 我是否忽略了有关文件创建的一些内容?(IO?)
    2. 我是否忽略了有关嵌入式资源的一些内容? (他们对我来说似乎很直接,但也许我忽略了一些明显的事情?)
    3. 我的文件状态是否已损坏?我可以在vs.net IDE和本地打开它,使用MS访问。
    4. 是否值得重新创建此访问文件?我听说你可以把模式复制到一个新文件中以避免修复?这听起来很危险!!

    最初我认为这是一个权限错误,关于access db文件的用户角色和尝试使用它的ssis。但我不这么认为。用户被设置为管理员,并且应该(理论上)工作。

    我认为要破解/修复这个问题,我目前将尝试不使用嵌入式资源。我将使用fileio调用将文件显式移动到我想要的文件夹中,并从中填充它。有人知道为什么嵌入式资源数据库文件不能工作,但如果不是从嵌入式资源生成的,相同的文件也能工作吗?当我从资源创建文件时,是否有一些事情没有完成?

    非常感谢您的任何反馈或建议。我们也欢迎任何问题。谢谢您。

    ****更新日期:2009年7月18日:**

    我修改了我的[CreateDestinationFile]例程来执行直接文件/IO复制,而不是使用嵌入的资源。

    代码如下:

            Dim sPath As String = My.Application.Info.DirectoryPath + "\databasenamehere.mdb"
    
            FileIO.FileSystem.CopyFile(sPath, path + "databasenamehere.mdb", True)
    

    文件已从项目中正确复制,但我现在收到此错误:

    “发生了一个OLE DB错误。错误代码:0x80040E09。有一个OLE DB记录可用。源:“Microsoft Jet数据库引擎”hresult:0x80040e09描述:“无法读取记录;对'table_uxxxxx'没有读取权限。”

    这使我相信,SSIS没有将本地MS Access DB用作目标文件的适当权限。

    这对我来说很奇怪,因为如果我在SSIS包中将连接字符串硬编码到同一个文件中,那么该文件也可以工作。这是怎么回事?

    正如您在我的连接字符串表达式中看到的,我使用[admin]作为用户。所以这应该有效,对吧?另外,这个问题的另一个可能的罪魁祸首是,这是一个在Access2003中创建的遗留MS Access DB,我在自己的设备上使用的是Access2007。帮助?

    2 回复  |  直到 15 年前
        1
  •  0
  •   David-W-Fenton    15 年前

    这不会是一个非常有用的答案,我不在你工作的环境中工作,所以不必这样做,但我想到了一些事情。

    您正在使用admin作为用户和空白密码,这是默认的jet登录,但可能使用了错误的工作组文件。我记得其他StackOverflow海报在通过某些方法连接到Jet文件时遇到问题,这些方法的连接字符串中没有工作组文件参数。您是否尝试创建了一个ODBC DSN,然后尝试连接到该DSN?DSN允许您指定工作组文件,这样可以改善问题。然后可以尝试将生成的连接字符串转换为无DSN连接字符串,然后将其用作参数化连接字符串的模型。

        2
  •  0
  •   D3vtr0n    15 年前

    为了解决这个问题,我最终使用了在初始项目收集期间提供给我的模板文件。

    我使用的.mdb文件是由许多应用程序和测试项目开发和测试的。这个文件从第一天起就有问题。

    我对这个文件的第一个问题是它的大小是80MB。这对我来说很奇怪,因为里面的数据很少。一旦我意识到我需要“压缩和修复”,它的大小就减少到200kb以下。这使我困惑。但是我继续使用这个文件进行进一步的开发,现在我意识到这是一个很大的禁忌。

    我最终决定从我的电子邮件中挖掘出我继承这个项目时提供的原始.mdb文件。这个原始的.mdb仍然不理想,因为它在我要导出到的表中包含数据。我不得不手动从中删除数千条记录。一旦我做到了,我的SSIS包就神奇地工作了。现在,我可以动态地从SQL导出数据以访问。

    下面是我对ssis包的vb.net执行,它使用由[app.config]配置文件提供的动态连接字符串:

    Public Function ExecuteSSISExportPackage(ByVal parameterValue1 As String, ByVal destinationDatabasePath As String) As Integer
    
        Dim pkg As New Package
        Dim app As New Microsoft.SqlServer.Dts.Runtime.Application
        Dim pkgResults As DTSExecResult
        Dim result As Integer = 1 'defaults to failure
        Dim eventListener As New EventListener()
    
        'create SSIS variables for dynamic parameters, retrieved from the appSettings in the [app.config] file
        Dim SSISPackagePassword As String = ConfigurationManager.AppSettings.Item("SSISPackagePassword")
        Dim SSISExportPackagePath As String = ConfigurationManager.AppSettings.Item("SSISExportPackagePath")
        Dim SSISExportPackageServerName As String = ConfigurationManager.AppSettings.Item("SSISExportPackageServerName")
        Dim SSISExportPackageServerUserName As String = ConfigurationManager.AppSettings.Item("SSISExportPackageServerUserName")
        Dim SSISExportPackageServerPassword As String = ConfigurationManager.AppSettings.Item("SSISExportPackageServerPassword")
        Dim SSISExportPackageDestinationDBName As String = ConfigurationManager.AppSettings.Item("SSISExportPackageDestinationDBName")
    
        Try
            'set package password
            app.PackagePassword = SSISPackagePassword
            pkg.PackagePassword = SSISPackagePassword
    
            'load package from SQL server
            pkg = app.LoadFromSqlServer(SSISExportPackagePath, SSISExportPackageServerName, SSISExportPackageServerUserName, SSISExportPackageServerPassword, eventListener)
    
            'set package-level variables, to supply to the stored procedure parameters/sql calls in the SSIS Export package
            pkg.Variables("xxxx").Value = parameterValue1
    
            'set the package-level variable to supply the Access DB's (SSIS destination) file path
            Dim databaseName As String = ConfigurationManager.AppSettings.Item("XXXClientDatabaseName")
            pkg.Variables("destinationDatabasePath").Value = "C:\" + databaseName 
    
            'Dynamic SQL source connection string values
            pkg.Variables("sourceDatabaseLocation").Value = SSISExportPackageServerName
            pkg.Variables("sourceDBUserID").Value = SSISExportPackageServerUserName
            pkg.Variables("sourceDBName").Value = SSISExportPackageDestinationDBName
            pkg.Variables("sourceDBPassword").Value = SSISExportPackageServerPassword
    
            'Execute the Import SSIS package, add an eventListener object for SSIS reflection
            pkgResults = pkg.Execute(Nothing, Nothing, eventListener, Nothing, Nothing)
    
            'Package execution results
            Select Case pkgResults
    
                Case DTSExecResult.Success
                    result = 0
    
                Case DTSExecResult.Failure
                    result = 1
    
            End Select
    
        Catch ex As Exception
    
            'Log the exception error here - omitted
    
        Finally
            app = Nothing
            pkg = Nothing
        End Try
    
        Return result
    
    End Function