Understanding Contexts

[Previous] [Next]

This section is critical to your understanding of how configured components work. Attribute-based programming relies on a mechanism known as interception. When a client creates an object from a component that's been configured in a COM+ application, the underlying runtime inserts an interception layer between them. This layer represents a hook that allows the COM+ runtime to perform system-supplied preprocessing and post-processing on a per-method-call basis. The system steals away control right before and right after an object executes its method implementation.

The COM+ interception layer is set up based on the notion of contexts. A context can be loosely defined as a set of objects running in a process. In actuality, processes are subdivided into apartments and apartments are subdivided into contexts. (Apartments are discussed in the next chapter.) The COM+ runtime performs interception whenever a call crosses over a context boundary.

Every object created in a COM+ application is created within the scope of a specific context, as shown in Figure 6-7. COM+ doesn't intercept calls when a caller and an object live in the same context. However, COM+ does intercept calls that go across contexts. The term context switch refers to system-supplied code that's run automatically whenever a call crosses over a context boundary.

click to view at full size.

Figure 6-7 The COM+ runtime sets up an interception scheme based on the notion of contexts. A system-provided proxy performs a context switch whenever a call crosses over a context boundary.

Thread-Switching Proxies vs. Lightweight Proxies

When one object creates another object in a separate process, by definition the two objects live in different contexts. Therefore, the COM+ runtime builds the appropriate interception code into the proxy/stub layer. Note that this Windows 2000 version of a proxy/stub layer is more sophisticated than the one I described at the end of Chapter 3. Now the proxy/stub pair has two responsibilities. First, it must remote a method call across process and host boundaries by performing a thread switch and marshaling parameters. Second, it must perform the required context switch. This represents a big change from versions of Windows before Windows 2000, in which the proxy/stub layer didn't know anything about contexts or interception.

Windows 2000 introduces a new type of proxy to deal with the situation in which the caller and the object run in different contexts but run in the same process on the same thread. As you can see in Figure 6-6 (shown earlier), there is no need for a proxy/stub pair, only a simple lightweight proxy. This proxy performs a context switch but doesn't need to perform a thread switch. As in the case of the thread-switching proxy, the COM+ runtime builds a lightweight proxy by inspecting an interface definition in a type library at runtime.

MOVING FROM MTS

Context Wrappers Have Gone Away

The interception layer in MTS is set up through an invisible system-supplied object called a context wrapper. Like context-aware proxies in COM+, the MTS context wrapper conducts preprocessing and post-processing on each method call. However, in MTS a single context wrapper is created when a client activates a new object. This means that there's only one context wrapper per MTS object. In COM+, an object can have many associated context-aware proxies. The new interception scheme in Windows 2000 is more flexible because the COM+ runtime continues to create context-aware proxies for an object on an as-needed basis.

When Are Contexts Created?

Contexts are typically created by the SCM when a client activates a new object by calling the COM library function CoCreateInstance. As you know from earlier chapters, the Visual Basic runtime calls CoCreateInstance when a client application creates an object using the CreateObject function or the New operator. (There's a gotcha with the New operator that I'll discuss in a moment.) However, you should note that the SCM doesn't always create a new context when you create an object. Sometimes it does and sometimes it doesn't.

Let's cover the basic rules. Every object activated in a COM+ application is created within a valid context. The SCM has three different ways to handle an activation request:

  • Create the new object in the context of its creator.
  • Create the new object in a newly created context.
  • Create the new object in the default context of a different apartment.

It turns out that the first two approaches are much more common than the third, so let's look at them first. At activation time, the SCM must decide whether a new object needs its own set of contextual information to describe its COM+ attributes. When COM+ creates a context, it creates a private object known as the object context, which it uses to store context-specific information for all objects that belong to that context. If a new object needs its own contextual information, COM+ creates a new context for it. If a new object doesn't need its own contextual information, COM+ adds it to the context of its creator.

In most cases, an object created from a nonconfigured component is created in the context of its creator, while an object created from a configured component gets its own new context. Figure 6-8 shows what happens when a COM+ object creates an ADO object such as a connection or a recordset. Like any other object created from a nonconfigured component, an ADO object doesn't need its own context because it doesn't have any declarative attributes.

click to view at full size.

Figure 6-8 In most cases, an object created from a configured component get its own new context while an object created from a nonconfigured component is created in the context of its creator.

In almost every situation, an object created from a configured component needs its own context because the COM+ runtime needs to know about quite a few things in order to run the interception code correctly and provide reliable system services. The object context holds valuable information such as an object's association with a specific activity and a specific transaction.

MOVING FROM MTS

Calls to CreateInstance Are No Longer Needed

One of the most significant programming changes you'll experience as you move from MTS to COM+ is that you don't need to call the CreateInstance method of the ObjectContext interface anymore. In MTS, you must call CreateInstance to send an object activation request to the MTS runtime instead of to the SCM.

In COM+, the SCM is context-aware. This means that in contrast to the SCM in Windows NT 4, the SCM built into Windows 2000 knows how to activate an object in an appropriate context. Calls to CreateObject are always handled correctly. Calls to CreateInstance are still supported, but only for backward compatibility. A call to CreateInstance does the same things as a call to CreateObject.

Of the three ways that the SCM can handle an activation request, the last is by far the least common. The SCM creates a new object in the default context of a different apartment only when the creator and the object being created have incompatible threading models and thus can't run on the same thread. An example of this is when an apartment-threaded object creates an object from a nonconfigured component that's free-threaded. The new object can't run in the context of its creator because it's the wrong apartment type. (A context must live in one specific apartment.) However, COM+ doesn't need to create a new context for the object because it doesn't carry any COM+ attributes. In such situations, the COM+ runtime creates the new object in the default context of another apartment. If you're using only apartment-threaded components such as the ones created with Visual Basic, you don't have to worry about this third scenario.

Watch Out for the New Operator

You have to be careful not to get into trouble when you write code in one configured component that calls New on another configured component. When you use the New operator, you must consider two scenarios. In the first scenario, the creator component and the component used to create the new object live in separate DLLs. In this case, a call to New is sent down to the SCM just like a call to CreateObject. This allows the SCM to create the new object in the proper fashion. In the second scenario, the creator component and the component from which the new object is being created are compiled into the same DLL. The problem here is fairly subtle, but it can lead to lots of frustration when you're trying to determine why your code isn't working correctly.

When a Visual Basic object calls New on a class name that's compiled into the same DLL, the Visual Basic runtime creates and binds the object on its own without involving the SCM. The new object isn't properly created by the SCM and the COM+ runtime doesn't even know it exists. COM+ doesn't have the opportunity to set up the interception scheme correctly. The bottom line is that if you call New at the wrong time, your code can exhibit strange and mysterious behavior.

As it turns out, sometimes you can use the New operator in a method of a COM+ component. You can always use New to create objects from components that are external to the creator's DLL. For example, you can use New whenever you create a new ADO object.

Contexts and Object References

The COM+ rules concerning object references are fairly straightforward. A client is directly bound to an object when they both live in the same context. A client must communicate with an object through a system-provided proxy if it lives in a different context. So, when and how are these proxies created? The answer is refreshing: The COM+ runtime creates proxies transparently whenever they're needed.

As a COM+ programmer, you'll commonly do two things that result in the transparent creation of a context-aware proxy: You'll activate new objects from a configured component with the CreateObject function, and you'll pass object references in standard method calls using parameters and return values.

When you create an object from a configured component, the COM+ runtime will more than likely create a new context. However, the COM+ runtime doesn't return a direct reference back to the creator. COM+ determines that the object and creator live in different contexts, so it creates a context-aware proxy and returns that to the creator instead. This means that all calls from the creator to the object go through the proxy. The proxy performs the required context switch at runtime whenever control passes back and forth between these two contexts.

As you've seen, COM+ automatically creates a proxy when an object is created in a different context from its creator. The second common case in which COM+ creates a proxy is when an object reference is passed across context boundaries in a standard method call. Because the COM+ runtime intercepts calls as they travel across context boundaries, it can also determine when the recipient of an object reference needs a new proxy.

Let me present an example to illustrate how things work. Look at Figure 6-9. Assume that Object1 creates Object2 by calling the CreateObject function. Object1 is in Context A while Object2 is in Context B. Now assume that Object1 calls the following method on Object2:

 Function CreateObject3() As Class3     Dim obj As Class3     Set obj = CreateObject("MyDll.Class3")     Set CreateObject3 = obj End Function 

When Object2 creates Object3, it's passed a reference to a proxy that knows how to perform a context switch between Context B and Context C. You should note that Object1 can't use this proxy because it lives in Context A. Object1 needs a different proxy that can perform the proper context switch between Context A and Context C. However, things work out fine. When the call to CreateObject3 returns from Context B back to Context A, the COM+ runtime automatically builds a new proxy for Object3 that can be used in Context A.

Figure 6-9 Object references are always context-relative. You can think of a context-aware proxy as an adapter between two specific contexts.

This example demonstrates an important point about the COM+ programming model: All object references are context-relative. If you follow the rules, things are pretty easy. When you need to share an object reference between two or more objects, you should design methods to pass references between them. However, you still have to watch out. You can get into trouble if you try to share object references using other techniques. For instance, it's a bad idea to place an object reference in a public variable in a .BAS module.

Let's revisit our example. What happens if Object2 creates Object3 and stores the returned reference in a .BAS module variable? You should see that the reference can be legally used only by code running in Context B.

If Object1 accesses the .BAS module variable and acquires the reference, things don't work correctly. Object1 needs a proxy that knows how to perform the context switch between Context A and Context C. However, the reference held by the .BAS module variable points to a proxy that was built to perform the context switch between Context B and Context C. You should see that this style of programming breaks the interception scheme set up by COM+. Likewise, it's a bad idea to store object references with other shared memory mechanisms using the Shared Property Manager. (You'll see how to use the Shared Property Manager in the next chapter; for now, just remember that you'll use it to store raw data as opposed to object references.)

MOVING FROM MTS

Calls to SafeRef Are No Longer Needed

In MTS, any object with an associated context wrapper must always call SafeRef when passing some other entity a reference to itself. A call to SafeRef passes a reference to the context wrapper as opposed to a raw reference to the object itself. If you don't call SafeRef at the appropriate times, you can defeat the MTS interception scheme.

The way that COM+ sets up the interception scheme is more transparent and more adaptable. There's no need to call SafeRef. As long as you follow the rules outlined in this chapter, the COM+ runtime builds context-aware proxies whenever they're needed.



Programming Distributed Applications with COM+ and Microsoft Visual Basic 6.0
Programming Distributed Applications with Com and Microsoft Visual Basic 6.0 (Programming/Visual Basic)
ISBN: 1572319615
EAN: 2147483647
Year: 2000
Pages: 70
Authors: Ted Pattison

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net