使用 Impersonation 打开 SQLconnection 时出现 TypeInitializationException

Posted

技术标签:

【中文标题】使用 Impersonation 打开 SQLconnection 时出现 TypeInitializationException【英文标题】:TypeInitializationException when opening SQLconnection with Impersonation 【发布时间】:2018-10-05 17:15:57 【问题描述】:

我在 Windows 窗体应用程序中遇到 TypeInitializationException 问题,在使用模拟时打开 SQLconnection(当模拟删除一切正常时),我不知道如何解决该问题。

这里是 StackTrace:

   v System.Data.SqlClient.SqlConnection..ctor()
   v System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Initialize(IDataServices dataServices, Object connection)
   v System.Data.Linq.DataContext.Init(Object connection, MappingSource mapping)
   v System.Data.Linq.DataContext..ctor(String fileOrServerOrConnection)
   v CallBackCvop.Persistance.UnitOfWork..ctor(String connectionString)
   v CallBackCvop.MainForm.RefreshOrders()
   v CallBackCvop.MainForm.BTN_Search_Click(Object sender, EventArgs e)
   v System.Windows.Forms.Control.OnClick(EventArgs e)
   v System.Windows.Forms.Button.OnClick(EventArgs e)
   v System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   v System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   v System.Windows.Forms.Control.WndProc(Message& m)
   v System.Windows.Forms.ButtonBase.WndProc(Message& m)
   v System.Windows.Forms.Button.WndProc(Message& m)
   v System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   v System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   v System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   v System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   v System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   v System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   v System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   v System.Windows.Forms.Application.Run(Form mainForm)
   v CallBackCvop.Program.Main()

这是 innerException 的 StackTrace

   v System.Diagnostics.FileVersionInfo.GetVersionInfo(String fileName)
   v System.Configuration.ClientConfigPaths.SetNamesAndVersion(String applicationFilename, Assembly exeAssembly, Boolean isHttp)
   v System.Configuration.ClientConfigPaths..ctor(String exePath, Boolean includeUserConfig)
   v System.Configuration.ClientConfigPaths.GetPaths(String exePath, Boolean includeUserConfig)
   v System.Configuration.ClientConfigurationHost.RequireCompleteInit(IInternalConfigRecord record)
   v System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
   v System.Configuration.BaseConfigurationRecord.GetSection(String configKey)
   v System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(String sectionName)
   v System.Data.SqlClient.SqlConnection..cctor()

这是我的模拟代码:

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    public class Impersonation : IDisposable
    
        private readonly SafeTokenHandle _handle;
        private readonly WindowsImpersonationContext _context;

        const int LOGON32_LOGON_NEW_CREDENTIALS = 9;

        public Impersonation(string domain, string username, string password)
        
            var ok = LogonUser(username, domain, password,
                           LOGON32_LOGON_NEW_CREDENTIALS, 0, out this._handle);
            if (!ok)
            
                var errorCode = Marshal.GetLastWin32Error();
                throw new ApplicationException(string.Format("Could not impersonate the elevated user.  LogonUser returned error code 0.", errorCode));
            

            this._context = WindowsIdentity.Impersonate(this._handle.DangerousGetHandle());
        

        public void Dispose()
        
            this._context.Dispose();
            this._handle.Dispose();
        

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);

        public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
        
            private SafeTokenHandle()
                : base(true)  

            [DllImport("kernel32.dll")]
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            [SuppressUnmanagedCodeSecurity]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool CloseHandle(IntPtr handle);

            protected override bool ReleaseHandle()
            
                return CloseHandle(handle);
            
        
    

问题是 - 我之前在不同的应用程序中使用过这个模拟代码并且一切正常。我很绝望,有救吗?谢谢。

这是连接字符串:

private readonly string _connectionString = "data source = xxx\\xxx; initial catalog = xxx; integrated security=True; MultipleActiveResultSets=True";

这里是开场白:

    using (UnitOfWork frt = new UnitOfWork(_connectionString))
    
        _outCalls.DownloadOutCalls(frt, _orders.ReturnSetOfNumbers());
    

UnitOfWork(在这里你会得到 TypeInitializationException):

 public class UnitOfWork : IDisposable
    
        ....repositories...

        private readonly DataContext _context;


        public UnitOfWork(string connectionString)
        
            _context = new DataContext(connectionString);


            ....repositories...
        

        public void Dispose()
        
            Dispose(true);
        

        protected virtual void Dispose(bool disposing)
        
            if (disposing)
            
                if (_context != null)
                    _context.Dispose();
            
        
    

innerexception 是 FileNotFoundException,但它似乎引用了 .exe 本身 - 我不明白。

编辑 - 8.10.2018 我发现当 .exe 在我的桌面上但不在共享的 Intranet 驱动器上时,一切正常。但是被冒充的帐户与我的帐户具有相同的权利。 如前所述,我有一个不同的应用程序,它使用相同的模拟代码、相同的连接字符串,并且一切都在我的桌面和共享驱动器上运行。

编辑 - 8.10.2018 - 11:00 所以它被撞毁了...... System.Diagnostics.FileVersionInfo.GetVersionInfo(pathToExe),

我检查了模拟帐户的权限 - 一切正常, 我在没有假冒和我的帐户的情况下尝试了该应用程序 - 一切正常, 我尝试了模拟我的帐户的应用程序(应该可以) - 不工作

【问题讨论】:

没有帮助? :( ... 【参考方案1】:

所以... 一段时间后,想出了一个解决方法。 似乎出现了错误 --- System.Diagnostics.FileVersionInfo.GetVersionInfo(pathToExe) 所以将我的模拟调用从程序移到了工作单元。改成这样:

public class UnitOfWork : IDisposable

    public IOrderRepository Orders  get; 
    public ICallRepository OutCalls  get; 
    public ILoginRepository Login  get; 

    private readonly DataContext _context;


    public UnitOfWork(string connectionString)
    
        _context = new DataContext(new SqlConnection());

        using (new Impersonation("domain", "user", "password"))
            _context.Connection.ConnectionString = connectionString;

        Orders = new OrderRepository(_context);
        OutCalls = new CallRepository(_context);
        Login = new LoginRepository(_context);
    

    public void Dispose()
    
        Dispose(true);
    

    protected virtual void Dispose(bool disposing)
    
        if (disposing)
        
            if (_context != null)
                _context.Dispose();
        
    

【讨论】:

以上是关于使用 Impersonation 打开 SQLconnection 时出现 TypeInitializationException的主要内容,如果未能解决你的问题,请参考以下文章

WCF:NetworkCredential 和 Impersonation 之间的关系

创建一个dynamics 365 CRM online plugin - plugin当中的Impersonation角色

没有 user_impersonation 的 Azure 资源管理 API,可以吗?

BackgroundWorker 忽略模拟

模拟和目录条目

如何查看集成Sentry后Hive作业的真实用户