PRB: "Application Object Error ASP 0197 : 80004005" Error Message When .NET Components Perform the Agility Test for Application Scope Objects (822828)
The information in this article applies to:
- Microsoft Active Server Pages
- Microsoft Internet Information Services 5.0
- Microsoft Internet Information Services version 5.1
- Microsoft Internet Information Services version 6.0
SYMPTOMSBy default, Microsoft .NET Components fail the agility test
that Active Server Pages (ASP) performs for application scope objects. By
default, the Component Object Model (COM) callable wrapper (CCW) object that is
used for COM interoperability implements the IMarshal interface, and its
implementation is similar to the free-threaded marshaler (FTM) implementation.
However, because the unmarshal class that is returned by the IMarshal::GetUnmarshalClass method is not the class identifier (CLSID) of the FTM (its value
is {3F281000-E95A-11d2-886B-00C04F869F04}), the agility test fails and you
receive the following error message: Application object
error 'ASP 0197 : 80004005' Disallowed object use
/LM/W3SVC/1/Root/SRQ030513600956/global.asa, line 7 Cannot add object with
apartment model behavior to the application intrinsic object.
CAUSEASP performs an agility test for COM objects that are
assigned to the application scope objects in Microsoft Internet Information
Server 5.x or later. The purpose of the test is to make sure that the
component is efficient enough to perform well at application scope. The agility
test looks for COM objects where the ThreadingModel registry entry is Both and then checks that the component uses the FTM for
inter-apartment and intra-process marshaling.
The test explicitly checks that the unmarshaling class that is returned by IMarshal::GetUnmarshalClass is equal to the CLSID (its value is
{0000033A-0000-0000-C000-000000000046}) of the unmarshaling class of the
FTM.RESOLUTIONMicrosoft .NET components can be used at application (and
session) scope by explicitly implementing the IMarshal interface. Typically,
this would be done by aggregating the FTM. For .NET components, you must use
containment. Containment is also known as delegation. Modify the Class1 class as shown in the following code sample:
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace Q822828
{
[
ComImport,
Guid("00000003-0000-0000-c000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
]
interface IMarshal
{
Guid GetUnmarshalClass([In] ref Guid iid,
[MarshalAs(UnmanagedType.Interface)] Object pvInterface,
int dwDestContext, IntPtr pvDestContext, int mshflags);
uint GetMarshalSizeMax([In] ref Guid iid,
[MarshalAs(UnmanagedType.Interface)] Object pvInterface,
int dwDestContext, IntPtr pvDestContext, int mshflags);
void MarshalInterface(UCOMIStream pstm, [In] ref Guid iid,
[MarshalAs(UnmanagedType.Interface)] Object pvInterface,
int dwDestContext, IntPtr pvDestContext, int mshflags);
[return:MarshalAs(UnmanagedType.Interface)]
Object UnmarshalInterface(UCOMIStream pstm, [In] ref Guid iid);
void ReleaseMarshalData(UCOMIStream pstm);
void DisconnectObject(int dwReserved);
}
public class Class1: IMarshal
{
[DllImport("ole32.dll", PreserveSig=false)]
static extern void CoCreateFreeThreadedMarshaler(
[MarshalAs(UnmanagedType.IUnknown)] object punkOuter,
[MarshalAs(UnmanagedType.IUnknown)] out object ppunkMarshaler);
public Class1()
{
try
{
CoCreateFreeThreadedMarshaler(null, out m_pFTM);
}
catch(Exception e)
{
LogEvent("CoCreateFreeThreadedMarshaler failed");
LogEvent(e.Message);
}
}
public void LogEvent(string sMessage)
{
if(!EventLog.SourceExists("Class1"))
{
EventLog.CreateEventSource("Class1", "Application");
//Console.WriteLine("CreatingEventSource");
}
EventLog myLog = new EventLog();
myLog.Source = "FTM Test";
myLog.WriteEntry(sMessage);
}
// IMarshal implementation
public Guid GetUnmarshalClass([In] ref Guid iid,
[MarshalAs(UnmanagedType.Interface)] Object pvInterface,
int dwDestContext, IntPtr pvDestContext, int mshflags)
{
LogEvent("GetUnmarshalClass");
IMarshal m = (IMarshal) m_pFTM;
return m.GetUnmarshalClass(ref iid, pvInterface, dwDestContext, pvDestContext, mshflags);
}
public uint GetMarshalSizeMax([In] ref Guid iid,
[MarshalAs(UnmanagedType.Interface)] Object pvInterface,
int dwDestContext, IntPtr pvDestContext, int mshflags)
{
LogEvent("GetMarshalSizeMax");
IMarshal m = (IMarshal) m_pFTM;
return m.GetMarshalSizeMax(ref iid, pvInterface, dwDestContext, pvDestContext, mshflags);
}
public void MarshalInterface(UCOMIStream pstm, [In] ref Guid iid,
[MarshalAs(UnmanagedType.Interface)] Object pvInterface,
int dwDestContext, IntPtr pvDestContext, int mshflags)
{
LogEvent("MarshalInterface");
IMarshal m = (IMarshal) m_pFTM;
m.MarshalInterface(pstm, ref iid, pvInterface, dwDestContext, pvDestContext, mshflags);
// Safety Net
Marshal.ReleaseComObject(pstm);
}
[return:MarshalAs(UnmanagedType.Interface)]
public Object UnmarshalInterface(UCOMIStream pstm, [In] ref Guid iid)
{
LogEvent("UnmarshalInterface");
IMarshal m = (IMarshal) m_pFTM;
Object o = m.UnmarshalInterface(pstm, ref iid);
Marshal.ReleaseComObject(pstm);
return o;
}
public void ReleaseMarshalData(UCOMIStream pstm)
{
LogEvent("ReleaseMarshalData");
IMarshal m = (IMarshal) m_pFTM;
m.ReleaseMarshalData(pstm);
Marshal.ReleaseComObject(pstm);
}
public void DisconnectObject(int dwReserved)
{
LogEvent("DisconnectObject");
IMarshal m = (IMarshal) m_pFTM;
m.DisconnectObject(dwReserved);
}
object m_pFTM = null;
}
}
Note- Maintenance is easier if you implement IMarshal in a common
base class and then derive all the .NET components that are to be used at
application scope from that class.
- Standard .NET Security applies to this component. Make sure
that both the process identity and the impersonated user have sufficient
permissions to run the code.
STATUS This
behavior is by design.REFERENCESFor more information about improving ASP application
performance, visit the following Microsoft Developer Network (MSDN) Web site:
Modification Type: | Major | Last Reviewed: | 5/10/2006 |
---|
Keywords: | kbprb kbCOMInterop KB822828 kbAudDeveloper |
---|
|