in

ASP.NET Weblogs

This Blog

Syndication

ShowUsYour<Blog>

Irregular expressions regularly

Consume a .NET Assembly from a classic ASP page.

Whenever I think that I'm getting to the bottom of .NET, there's, well: there's always something to remind me...

    http://users.cis.net/sammy/remindme.htm  ( open in new window while you continue reading for the full effect )

I haven't really done a lot with strongly named assemblies or interop so, this morning I thought that I'd be bold and try a little experiment; I thought that I'd create a .dll in Visual Basic .NET and consume it from a classic ASP page - seems pretty trivial, so off I went:

1) Open New Project named “SimpleDLL” - assembly name “SimpleDLL“, namespace “SimpleDLL“
2) Create a class named “SimpleClass”

Public Class SimpleClass
    Public Function WriteName(ByVal name As String) As String
        Return name
    End Function
End Class        
        

 

3) Register the assembly in the Registry
4) Register it for COM

    regasm /tlb SimpleDLL.dll

Voila!  A quick check of the HKEY\LocalMachine\Software\Classes\ tells me that I had (at least) some level of success and that the Assembly is, indeed in the registry.  So, off I go to create my classic asp page and consume it.  So, again...

5) Open Visual Studio
6) Create SimplePage.asp
7) Type the following into a page named SimplePage.asp:

Dim foo 
Set foo = Server.CreateObject("SimpleDLL.SimpleClass")
Response.Write foo.WriteName("blah")

 

Sure enough, it didn't work.

The page cannot be displayed

Error Type:
(0x80070002)
/SimplePage.asp, line 11


After a bit of head scratching it was apparent that the source of my problems was that there was not enough information for the file to be found. Therefore I decided that I needed to create a strong name for my assembly and register it in the GAC

8) Generate a public/private key pair

    sn -k MarkItUp.key

9) Add the attribute to my assembly for registering it:

     <Assembly: AssemblyKeyFile("C:\MarkItUp.key")>

10) Re-build the assembly
11) Install it into the GAC

    gacutil /i SimpleDLL.dll

12) Re-install it into the registry
Fire-up the asp page.

Did it work? Yep :-) Amazing eh?  Now I just have to work out how to get that type library information into the registry so that I can also get intellisense working while coding the asp page.

Finally, because I was having such luck I decided to call the Assembly from a Sql Server Stored Procedure too. That also worked first time!

DECLARE @object int
DECLARE @hr int
DECLARE @return varchar(255)

EXEC @hr = sp_OACreate 'SimpleDLL.SimpleClass', @object OUT
EXEC @hr = sp_OAMethod @object, 'WriteName', @return OUT, 'This is the text'
PRINT @return     -- Displays "This is the text"
EXEC @hr = sp_OADestroy @object
        

Comments

 

Marcus Tucker said:

Here's a thought... would it be possible to create some sort of generic COM object which would act as a generic loader for existing .Net assemblies? Presumably this could be done with reflection, etc.??

This would allow classic ASP (and other COM-aware languages) to use .Net assemblies on demand, with code that would look something like this:

<%
Set objAssemblyLoader = Server.CreateObject("dneimke.assemblyloader")
Set objTestAssembly = objAssemblyLoader.Load("TestAssembly")
Response.Write objTestAssembly.Test("test input")
%>

Is that possible?
February 6, 2004 7:38 AM
 

William Bartholomew said:

Just something to be aware of with the sp_OACreate and .NET assemblies:

http://support.microsoft.com/default.aspx?scid=kb;en-us;322884
February 7, 2004 1:46 AM
 

ananth said:

Consuming a .NET assembly from an asp page is working fine. But at the same time passing an object to any method of NET assembly is not working. I created class A and class B. Class A has a mehod name as "TestMethod" which will accept one parameter as Object which type is Class B. Now i try to call "TestMethod" it shows "Invalid Procedure call or argument"

TestMethod will look like

Public Function TestMethod(Byval obj as TestB) as string
return "Hello"
End Function

Please try to give some solution to pass an object.
My Id is ananth_ss@hotmail.com
February 26, 2004 6:51 PM
 

john said:

Pass the object by referencenot by val
Public Function TestMethod(ByRef obj as TestB) as string
return "Hello"
End Function
April 16, 2004 11:14 AM
 

lev said:

Great article. Here is what I'm trying to achive though. Say a user logs on to the system using Form authentication and then is redirected to an aspx page, on which I can sure capture User.Identity.Name. There is a link on this page, which will redirect to a classic ASP page. I created and registered (using the technique above) a class, that has a method to capture the same value:

using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration;
using System.Web;
using System.Web.SessionState;


namespace ASPNETServer
{
public class UserService
{
public UserService()
{

}
public string GetUserName()
{
string userName = "";
try
{
userName = System.Web.HttpContext.Current.User.Identity.Name;
}
catch(Exception err)
{
userName = "error: " + err.Message;
}
return userName;
}
}
}

I keep getting the "Object reference not set to an instance of an object." error while calling this class from an ASP page:

set aspnetServer = server.CreateObject("ASPNETServer.UserService")
Response.Write aspnetServer.GetUserName()

If I hard code the return value and re-register the assembly, all works fine. And if I call this from an aspc page, works fine as well. Any idea what's going on? Thanks in advance!
June 2, 2004 1:30 PM
 

Matt B said:

Thanks for this. I just spent about 3 hours playing with it until I found this page :)
June 14, 2004 1:14 PM
 

Patrick R said:

This worked fine on my local developer system, but after deploying the assembly to a testsystem i've got the same error:

(0x80070002)
server/Example.asp, line 22

although i execute gacutil and regasm...

so whats the problem now??
if someone got a resolution, send me a mail to pruhnow@dornbracht.de
or msn messenger with same email address.

THX!
June 17, 2004 7:37 AM
 

Boris said:

It's an interesting thread, but I would like to go further: there is .NET assembly, which I need to consume as ActiveX. Is it possible? How can I create downloadable package (CAB file)? How can I create strong name on client machine?

Any help will be appreciated,
Boris
June 27, 2004 3:13 AM
 

Kevin said:

You didn't have to register your assembly into the GAC to get your ASP working. Just use the regasm utility with the /codebase switch and ignore the warning that your assembly should be strongly named.
June 30, 2004 7:03 PM
 

LoveHate w/ dotnet said:

I think Microsoft has made it more painful to get this to work than it is to shove bamboo between your finger nails. I still keep getting Server object, ASP 0177 (0x800401F3) Invalid class string. I'm going to break down and rewrite my classic ASP page to .NET.
July 1, 2004 3:40 PM
 

Lo said:

July 6, 2004 10:14 AM
 

Ryan said:

I have the same issue that lev posted above.

Object reference not set to an instance of an object.

Which tells me that the object isn't being created. What was the solution to this?

Thanks!
August 5, 2004 3:10 PM
 

s.b.dhar said:

I tried as instructed.

But now i get the following error

Error Type:

Server object, ASP 0177 (0x80131509)

80131509

What has gone wrong ...?

Can u help me pl..

regards,

May 17, 2007 8:52 AM
 

jeff said:

make sure to restart iis after loading the dll into the GAC

May 29, 2007 8:40 PM
 

Kevin R said:

I followed your instructions line by line and I still can't instance the object.  I get the following.

Error Type:

Server object, ASP 0177 (0x800401F3)

Invalid class string

June 18, 2007 12:41 PM
 

beer said:

" ... get intellisense working while coding the asp page ..."

It is not the most elegant method but try registering your assembly with gacutil and then drop a copy of the dll(assembly) into:

C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\PublicAssemblies

It has been a while since I've had to do this so you may need to monkey around with it a bit to get it to work.

June 18, 2007 4:36 PM
 

Sisir Das said:

I have Also same issue--

Error Type: Server object, ASP 0177 (0x800401F3)

Invalid class string

Post data....

--bytes

August 1, 2007 8:57 AM
 

Vikas said:

After 1 complete day of r&d I finally figured out how to do it. Here are the steps I follow:

I create a dot net DLL by following msdn.microsoft.com/.../default.asp

Since I have to run this COM Component on diff server - i copy it on some directory

I create a strong key file with sn util

I register the COM into registry using regasm /tbl /codebase mycomdll.dll

On an asp page I instantiate the object with createobject("mycomdll.classname")

It seems to work fine -

Note: I didn't register the assembly in GAC

Now the issue I am facing is that each time I have to add a new method or modify the old one - although i compile a new dll and follow the same process - asp is not able to look for the new dll - (i tried uninstalling and reinstalling). asp still looks for the old dll. I even changed the guid of the assembly but asp still looks for the old one - the only work around i did was to create a new com (with a diff name - mydllcom_ver2.dll) and then follow the same steps and it works fine ..... I found out that its the ASP behavior that does it - the only way to make it look new dll is to restart iiS (if doesn't work - restart computer - i am not going that route)

Hope this helped someone and hope someone has an ans to my concern.....

thanks a lot for the wonderful post......

September 18, 2007 5:47 PM
 

Vikas said:

Alright I figure out my own issue - all i did was change the assembly information (name guid etc) and compile it and put it on the server that i want to run on. and it works.

thx

September 18, 2007 6:47 PM
 

Ashwini said:

I have to consume .NET2.0 DLL in an ASP page, though i followed step by step instructions in  this article i am not able to able to figure out the problem. I am getting the below error.

Error Type:

Server object, ASP 0177 (0x800401F3)

Invalid class string

September 20, 2007 10:16 AM
 

Rusty said:

Object reference not set to an instance of an object

No HttpContext across threads.  Haven't found the answer yet, though

October 10, 2007 10:33 AM
 

Graham said:

The solution I found which worked (after trying lots of different methods ) is the simple one as above

register in GAC

register with regasm /tlb to generate a type lib in asp directory

restart iis

note you can delete the dll in asp dir but not the tlb

in the same dir with /codebase works fine on dev machine but not on windows server presumably due to access rights - not of the dll but the .net assemblies it references

all of the com attribute hacks are unnecessary this way - just define an explicit interface for your objects and decare them public and they will be exported to the tlb as the COM interface

passing parameters is yet more fun as they all need to be able to be accessed by vbscript which can only use COM VARIANT- pass all arrays as arrays of c# objects ie the base class of all built in datatypes (which translates to SAFE_ARRAY(VARIANT) which vbscript can deal with) and when passing from vbscript to c# - pass by val (put brackets round the array parameters in vbscript function call)  - you will then be as happy as I am now - it helps to understand how COM works though but hope this helps anyone who has been as frustrated as I was.....

November 21, 2007 7:16 PM
 

Daniel said:

I'm planning to use. Got question:

What if the .NET assembly (Assembly1) that should be expose to COM, reference another .NET assembly (Assembly2), should I also register Assembly2 to COM?

January 7, 2008 3:02 AM
 

John said:

Great post.  I've recently come into an issue where I needed to implement Impersonation on a legacy classic ASP web site that needs access to a network resource that the local IUSR user can't be added to.  I created a com exposed class library and tada, I can now use Impersonation in indidivual code blocks in a classic ASP page!  

February 13, 2008 2:30 PM
 

brendan said:

Like someone commented above using the codebase flag will eliminate the problem. I had done exactly as the article decribes up to the point where he changed to install into the gac. I had the exact same Error Type:

(0x80070002) /pagename.asp error. If you want to avoid using the gac do this (i signed my .net assembly also)

February 22, 2008 12:57 PM
 

eric said:

I tried using the /codebase suggestion...It solved the 0x80070002 error, so I thought I was set. However, I got a new error:

Object doesn't support this property or method: 'TestFunction'

The following code works in my asp.net page, but fails in classic asp:

Dim myObject

myObject = CreateObject("TestDll.Test")

dim rc

rc = myObject.TestFunction("teststring")

(although I use "set myObject = " instead of "myObject = " in the classic asp page)

It would appear that ASP is finding the DLL, but not seeing the function within it? What am I missing?

February 28, 2008 11:16 AM
 

Jay said:

I have a problem returning an array from the .net dll to an asp page. Does any one have the same issue?

April 10, 2008 11:02 PM
 

Jay said:

I have a problem returning an array from the .net dll to an asp page. Does any one have the same issue?

April 10, 2008 11:02 PM
 

LRN said:

Great Article! very useful.I have problem  .NET assembly (Assembly1)  references .NET assembly (Assembly2) both i have registered as COM.

I creted new method A() in Class1 in Assesmbly1 which calls method B() from Class2 in Assesmbly2.

when i call method A() in asp i get "Invalid string error"

Does anyone know what the issue is? Can we have refernces to the .NET dll? Is there any other way to acheive this?

April 16, 2008 5:38 AM
 

Sri said:

Jay

I have managed find a way around the problem you have, I have used an array list in the example but u should be able to do the same with an Array

example is here tsqldotnet.spaces.live.com

April 25, 2008 9:41 AM
 

Ray said:

Answer to Eric's question:

I had the same problem, my public method was not visible to the ASP page and intellisense would not display the method.

Try designing your application with an explicit public interface  that exposes public method(s) and create a class that implements the interface.

Assign the following attribute on the COM Interface code:

[Guid("<GUID from Create GUID tool>")]

 [InterfaceType(ComInterfaceType.InterfaceIsDual)]

This will create both early and late bound interfaces.

The following code snipnet shows a simple class that displays the traditional "Hello World" as a .Net component with a COM interface.

using System;

using System.Runtime.InteropServices;

namespace HelloCOM

{

   [Guid("DBE0E8C4-1C61-41f3-B6A4-4E2F353D3D05")]      // Unique identifier required from 'Create GUID' tool

   [InterfaceType(ComInterfaceType.InterfaceIsDual)]   // Dual interface provides both early and late binding

   public interface IHelloCOM

   {

       string PrintGreeting(string userName);

   }

   [ComVisible(true)]                                  // Properties and methods of this class will be visible to COM

   [Guid("C6659361-1625-4746-931C-36014B146679")]      // Unique identifier required from 'Create GUID' tool

   [ProgId("HelloCOM.HelloCOMImplementation")]         // Name used when invoking this component [e.g. CreateObject("HelloCOM.HelloCOMImplementation")]

   [ClassInterface(ClassInterfaceType.None)]           // 'ClassInterfaceType.None' is only way to expose functionality through interfaces implemented explicitly by the class

   [ComSourceInterfaces(typeof(IHelloCOM))]            // Identifies the interface that will be exposed as COM event sources for the attributed class

   public class HelloCOMImplementation : IHelloCOM

   {

       public HelloCOMImplementation()  {  }           // Default albeit empty constructor that is required for COM instantiation

       string IHelloCOM.PrintGreeting(string userName) // Implementation of the PrintGreeting() method defined in the interface

       {

           string greeting = string.Empty;

           greeting = "Hello COM world from " + userName;

           return greeting;

       }

   }

}

Hope this helps.

May 15, 2008 9:09 AM
 

how to register net assembly said:

Pingback from  how to register net assembly

June 3, 2008 10:47 AM
 

Deepa said:

I have written .NET2.0 DLL and i am not able to use the same in an ASP page

I have set the assembly to Register for COM Interop.

Used regasm /codebase to register the assmebly.

Loaded the assembly in the GAc

I am able to create the object and set its properties , but when i call any of the methods

i get the following error:

Error Type:

(0x80004003)

Object reference not set to an instance of an object.

But when i try the same for a VBScript , the component works fine without errors.

Any help will be appreciated

June 4, 2008 4:51 PM
 

Jai Gupta said:

i had a J++ dll converted to j# com dll (vs2005)  and want to consume it in ASP. But after creating the dll successfully which is working with VB etc. is not  found to be compatible with the ASP.

1. At application level unable to set the application variable with j# com dll object. Though at session level it is possible to do so.

2. The overloaded methodds of j# com  dll are not callable from ASP as they raise a error saying "Wrong/ invalid argument list"

3. The properties of a class are not accessible from the ASP

e.g

Dim i, o

Set o = CreateObject("MydllClass")

i = o.getId()

Error: Variable uses an Automation type not supported in VBScript

please help.

October 22, 2008 8:48 AM
 

Paulo said:

i get the same problem:

Error Type:

Server object, ASP 0177 (0x800401F3)

Invalid class string

November 25, 2008 2:00 PM
 

John Burns said:

To make it work:

Solution properties > Compile and tick "Register for COM interop"

Solution Properties > Assembly information > tick "Make assembly COM-visible"

Ad make sure your code is importing:

Imports System

Imports System.Runtime.InteropServices

March 3, 2009 12:14 PM

Leave a Comment

(required)  
(optional)
(required)  
Add