2

Question:

I use System.Data.OracleClient.

System.Data.OracleClient requires OracleInstantClient, which are native dll's. So in order to use System.Data.OracleClient, I need the native dll's installed, or in a folder in the path environment variable.

Now, the base problem is, I don't have administrator rights (company laptop - corporate stupidity - not going to change)...
So I can neither install anything, nor copy anything in a folder in PATH, nor can I add a folder to the path environment variable, nor can I restart/administer IIS or any other service...

So as a test, I just copied oci.dll and oraociei11.dll into the same folder as the WinForms .exe.
This worked fine. I was able to access the Oracle database (SELECT * FROM COUNTRIES) without problems.

But now, I need to perform the same query in an ASP.NET solution. The problem is, ASP.NET dll's get shadow copied to a temporary folder when they execute.

Now to get the dll's to the webapp bin non-the-less,
in Global.asax in

public class MvcApplication : System.Web.HttpApplication

I overwrote Init with this:

public override void Init()
{
    int iBitNess = IntPtr.Size;
    //System.Windows.Forms.MessageBox.Show(iBitNess.ToString());
    // iBitNess = 4, so 32 bit dll's are right



    string strTargetDirectory = System.Reflection.Assembly.GetExecutingAssembly().Location;
    strTargetDirectory = typeof(DB.Abstraction.cDAL).Assembly.Location;
    strTargetDirectory = typeof(MvcApplication).Assembly.Location;
    strTargetDirectory = System.IO.Path.GetDirectoryName(strTargetDirectory);

    string strSourcePath = Server.MapPath("~/bin/dependencies/InstantClient");
    string[] astrAllFiles = System.IO.Directory.GetFiles(strSourcePath, "*.dll");

    foreach (string strSourceFile in astrAllFiles)
    {
        string strTargetFile = System.IO.Path.GetFileName(strSourceFile);
        strTargetFile = System.IO.Path.Combine(strTargetDirectory, strTargetFile);
        System.IO.File.Copy(strSourceFile, strTargetFile);
    }

    base.Init();
} // End Sub Init

in order to copy the native dll's to the supposedly correct location. But I still get DllNotFound Exception...

Where or how do I have to put a native dll in a ASP.NET application ?

I say again: I cannot set environment variables, and I cannot copy the dlls to a folder that is in path. (which would normally solve the problem).

As you see with the multiple occurences of

strTargetDirectory =

I tried several possibilites, none of which worked.

Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
  • All you should have to do it to put the DLL in your app's bin folder. Why are you trying to access the DLL separately in your Init() code? – RickNZ Jan 07 '12 at 09:08
  • @RickNZ: Should is right. But it doesn't. But I solved it now. Added solution. – Stefan Steiger Jan 07 '12 at 09:39
  • @RickNZ: ShadowCopy copies the .NET dlls into another folder, and executes from there. Thus, native dlls in the bin folder are in another folder, and won't get found/loaded. – Stefan Steiger May 20 '15 at 10:01

1 Answers1

3

Solved.
Apparently one still needs to load the native dll's after copying them to the target folder.
OnInit was incorrect, it's for HTTP modules.
We need to do this only once, hence moved to Application_Start.

Here's my code, in case anybody needs it:

   // Hinweis: Anweisungen zum Aktivieren des klassischen Modus von IIS6 oder IIS7 
    // finden Sie unter "http://go.microsoft.com/?LinkId=9394801".
    public class MvcApplication : System.Web.HttpApplication
    {

        [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
        static extern IntPtr LoadLibrary(string lpFileName);

        [System.Runtime.InteropServices.DllImport("kernel32", CharSet = System.Runtime.InteropServices.CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
        static extern UIntPtr GetProcAddress(IntPtr hModule, string procName);

        [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
        [return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
        static extern bool FreeLibrary(IntPtr hModule);


        // See http://mpi4py.googlecode.com/svn/trunk/src/dynload.h
        const int RTLD_LAZY = 1; // for dlopen's flags
        const int RTLD_NOW = 2; // for dlopen's flags

        [System.Runtime.InteropServices.DllImport("libdl")]
        static extern IntPtr dlopen(string filename, int flags);

        [System.Runtime.InteropServices.DllImport("libdl")]
        static extern IntPtr dlsym(IntPtr handle, string symbol);

        [System.Runtime.InteropServices.DllImport("libdl")]
        static extern int dlclose(IntPtr handle);

        [System.Runtime.InteropServices.DllImport("libdl")]
        static extern string dlerror();


        public void LoadSharedObject(string strFileName)
        {
            IntPtr hSO = IntPtr.Zero;

            try
            {

                if (Environment.OSVersion.Platform == PlatformID.Unix)
                {
                    hSO = dlopen(strFileName, RTLD_NOW);
                }
                else
                {
                    hSO = LoadLibrary(strFileName);

                } // End if (Environment.OSVersion.Platform == PlatformID.Unix)

            } // End Try
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            } // End Catch

            if (hSO == IntPtr.Zero)
            {
                throw new ApplicationException("Cannot open " + strFileName);
            } // End if (hExe == IntPtr.Zero)

        } // End Sub LoadSharedObject


        // http://stackoverflow.com/questions/281145/asp-net-hostingenvironment-shadowcopybinassemblies
        public void EnsureOracleDllsLoaded()
        {
            int iBitNess = IntPtr.Size * 8;

            string strTargetDirectory = System.Reflection.Assembly.GetExecutingAssembly().Location;
            strTargetDirectory = System.IO.Path.GetDirectoryName(strTargetDirectory);

            string strSourcePath = "~/bin/dependencies/InstantClient/";

            if (Environment.OSVersion.Platform == PlatformID.Unix)
            {
                strSourcePath += "Linux" + iBitNess.ToString();
            }
            else
            {
                strSourcePath += "Win" + iBitNess.ToString();
            }

            strSourcePath = Server.MapPath(strSourcePath);

            string[] astrAllFiles = System.IO.Directory.GetFiles(strSourcePath, "*.dll");


            foreach (string strSourceFile in astrAllFiles)
            {
                string strTargetFile = System.IO.Path.GetFileName(strSourceFile);
                strTargetFile = System.IO.Path.Combine(strTargetDirectory, strTargetFile);
                System.IO.File.Copy(strSourceFile, strTargetFile, true);

                //if(strTargetFile.EndsWith("orannzsbb11.dll", StringComparison.OrdinalIgnoreCase))
                if (System.Text.RegularExpressions.Regex.IsMatch(strTargetFile, @"^(.*" + RegexDirSeparator + @")?orannzsbb11\.(dll|so|dylib)$", System.Text.RegularExpressions.RegexOptions.IgnoreCase))
                    continue; // Unneeded exception thrower

                try
                {
                    LoadSharedObject(strTargetFile);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }

            } // Next strSourceFile

        } // End Sub EnsureOracleDllsLoaded


        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        } // End Sub RegisterGlobalFilters


        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default", // Routenname
                "{controller}/{action}/{id}", // URL mit Parametern
                //new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameterstandardwerte
                new { controller = "Home", action = "Test", id = UrlParameter.Optional } // Parameterstandardwerte
            );

        } // End Sub RegisterRoutes


        protected void Application_Start()
        {
            EnsureOracleDllsLoaded();
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        } // End Sub Application_Start


    } // End Class MvcApplication : System.Web.HttpApplication
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442