0

My website application uses C# COM+ components running under a particular identity to access SQL Server, invoked from classic ASP.

There's also a web service that utilises a \bin DLL in the website application that contains a method to insert some data into the SQL Server database (let's call it MyApp.Database.dll).

From the website front end, I want to be able to provide authenticated users with this same functionality.

I don't want to duplicate code in MyApp.Database.dll within the COM+ component for obvious reasons.

My idea was to utilise the COM+ component from ASP to invoke the MyApp.Database.dll method to access the SQL database using the application credential since the ASP is running as the user and has no access to SQL Server.

Problem I've seem to run into is that although I can reference MyApp.Database.dll in my COM+ component project (under 'References' and 'using MyApp.Database.dll'), when it comes to actually running or debugging the COM+ component, when it tries to invoke the method from MyApp.Database.dll, it tells me 'Could not load files or assembly 'MyApp.Database, Version=3.3.3.11658, Culture=neutral, PublicKeyToken=.....' or one of its dependencies.'

The MyApp.Database.dll is not registered in GAC (trying to avoid this, it's also used by other applications as well), and hasn't had its codebase registered in the registry using regasm (I tried this and still didn't work). The version is correct, and I've placed MyApp.Database.dll in the application folder of the COM+ component.

Am I missing something or is it not possible to do this?

Thanks in advance for your help.

Dom G
  • 13
  • 6

1 Answers1

0

This is a common mistaken expectation: just because your .NET COM DLL was found in some given folder (the folder set by the /codebase argument or RegAsm) -- it doesn't mean .NET will look on that folder for anything else.

Generally speaking, it won't. Loading a .NET assemblies via COM interop is a special case. For everything else, assemblies will be loaded in the AppDomain based on the Fusion binding policy for the process - which has nothing to do with where your .NET COM DLL is. The process is actually (depending on your version of IIS) either dllhost.exe, iisexpress.exe or w3wp.exe.

You have a few options.

First, the obvious solution is putting MyApp.Database.dll in the GAC, since .NET always looks there. Sometimes that's the right choice (I've done that and it works). You have declined to do so and you have your reasons; that's Ok.

Second, I believe you can change the binding policy with a web.config file. See here: http://msdn.microsoft.com/en-us/library/823z9h8w(v=vs.110).aspx. Yes, your ASP Classic project can have a web.config. Obviously it has no effect on your ASP Classic scripts, but (depending on the version of IIS), .NET and/or IIS itself use it for configuration. I'm afraid that I can't help you much with this alternative because I've never had to try it before, but you're welcome to explore that option - let me know how it goes.

Third option - my personal choice: You said this DLL is already a web service, right? Just call the functionality with a web service call from your COM DLL. That doesn't require mucking with magic folders, GAC and binding policies. Much cleaner. The only mild complication is tracking in configuration where your web service is located - and I bet you already do that for your database connection anyway, so it shouldn't be hard to add.

If you are curious to know where .NET is looking for the DLL, read up on these guys:

Good luck, and please let us know what worked for you.

Community
  • 1
  • 1
Euro Micelli
  • 33,285
  • 8
  • 51
  • 70
  • Thanks for the feedback. Can't do 3rd option as the WS isn't in that DLL. The WS is in another DLL that invokes methods in the MyApp.Database.dll. Want to also avoid using WS from ASP within the same web application if possible. In fact, previously, all the code to insert into the SQL database was inside the web service DLL, but moved it out into a more independent DLL that other classes could invoke, therefore keeping one central place for amending the insertion code which is likely to change periodically. Thus, I moved it into the MyApp.Databast.dll, but COM+ can't reference it. – Dom G May 28 '14 at 06:54
  • Just to clarify further, the ASP is, as you say, running under the w3wp.exe process. Users log into the IIS using domain authentication, so this means that the classic ASP is run as the logged in user. This VB ASP does 'set oDocRepo = Server.CreateObject("CRepository.DocRepository")', then invokes the method from that object. This means that COM+ is running as the specified user under the COM+ app property as I specified in Component Services. So this COM+ application is running under w3wp.exe. The MyApp.Database.dll is also under the \bin folder for the website application, but not found... – Dom G May 28 '14 at 07:18
  • @DomG, have you had a chance to try the second alternative (binding policy in web.config)? – Euro Micelli May 28 '14 at 10:18
  • Didn't try the binding as that seemed like going too far for what I expected, and proved to be true. Your suggestion of using Fusion Logging helped resolve the issue. My finding in next comment. – Dom G May 29 '14 at 07:08
  • What was happening was this: My COM+ component is a .NET assembly. This meant when I was creating it from my website classic ASP using 'Server.CreateObject', the COM+ was actually running not under w3wp.exe, but system32\dllhost.exe. This is because Fusion gets involved as it's a .NET assembly and finds it in GAC. So when I referenced MyApp.Database.dll within the COM+ .NET code (i.e. 'MyApp.Database.RepositoryApi repoApi = new MyApp.Database.RepositoryApi();'), it can't find it in GAC, ignores codebase in registry (it's .NET), and looks in execution folder which is C:\Windows\System32\. – Dom G May 29 '14 at 07:11
  • So ultimately, I either need to: (1) Take my COM+ component out of the GAC, (2) put MyApp.Database.dll into GAC, (3) Place the MyApp.Database.dll into C:\Windows\System32\ or (4) Possibly use your second alternative which by all means should work. Currently I've got it working by using (2), but as mentioned, that may not be ideal in my environment. That's something I'll have to look at in more detail which is out of scope of my original question. Thanks for all your help, and for the pointer to using Fusion logging which helped me find out what the exact problem was! – Dom G May 29 '14 at 07:18
  • Please let us know what your final solution is. I'm 99.99% sure that moving the COM+ DLL out of the GAC doesn't solve the problem (using /codebase shouldn't make .NET look for other assemblies in the codebase folder), but you can go ahead and surprise me. – Euro Micelli May 29 '14 at 15:42
  • I had to create an application manifest for the COM+ component, and once the component was installed, had to add the installation path into the Application Root Directory field under the COM+ component's Properties -> Activation tab. This allowed the COM+ component to find the required MyApp.Database.dll file and load it. – Dom G Feb 21 '19 at 04:19