COM+ and .Net practical approach
This article is actually made up from three main parts. The first part handles all the aspect of using COM+. After reading this part you will know what the options that you have to host your assembly in COM+, impact on ASP.NET application performance of any option and what are, if any, limitations impose by selecting certain COM+ hosting option.
The second part describes all the administrative benefits that your application can gain from COM+. This part includes details about improving availability and stability using COM+ and who to monitor and use monitor data to detect quickly and easily problems sources.
The third part describes daily programming tasks that can be archive easily by using COM+ features. COM+ include many features that can reduce the number of code lines and time that you might invest in order to fulfill common programming tasks. This part outlines those programming tasks and explains demonstrates how to use COM+ to achieve them.
Introduction
COM+ is living but not much kicking on our WEB servers since windows 2000. COM+ even deserves to be upgrade to version 1.5 in XP and Windows 2003 operation system. COM+ was useful for DNA programs but seems to loose it’s glorious in the .Net age. Most of programmers use COM+ to manage transactions over database but COM+ offers many others options that can be use to create much more scalable and available application and to simplified programming tasks. This article will take practicable path to COM+ (1.0 and 1.5) by explaining and demonstrating when and how you can use COM+ with .Net.
Defining the Problem
COM+ name is one of its biggest disadvantages. Interpolation of the COM words combination misleads many programmers to think that COM+ is base on COM and to prevent using an old technology from the new brand .NET WEB application. While for some cases COM+ is really based on COM using its abilities can have huge contribute to WEB application and server. .Net creators thought about the consequences of using COM to access COM+ application and create the CLR in such a way that access to .Net component that register in the COM+ might be without any usage of COM. This architecture let us use COM+ services such as Queued Components, Loosely coupled events, Pooling, JITA (Just In Time Activation), SWC (Services Without Component) and others to simplify programming tasks.
In this article I will show how we can register .Net components in COM+ and what effect this registration got on performance, and limitations. After understanding what are the consequences of using COM+ we will see how COM+ contribute application and web server availability and stability. Continue with the practical approach we will see how COM+ features can simplify daily task that we face while creating WEB applications.
This article addresses COM+ 1.0 and 1.5. Wherever COM+ is mention I refer feature exist both in COM+ 1.0 and 1.5. Where COM+ 1.5 explicitly use the refer feature exists only in COM+ 1.5 version (windows XP or .Net servers).
Article Structure
- Com+ application types and how they effect your application performance
o Performance
o Accessing and limitations
- Make your application scalable as possible
o Maximum isolation
o Component Monitoring and quick problem solving
o Application Recycling
o Scale your objects
o Process dump
o Enable different version of COM+ application simultaneously running
o Looking for bright future
o
- Applying security
- Increase server output and application income.
- Monitoring and squeezing licenses usage.
- Notify others when your application change state
- Picking COM+ fruit without need to nourish COM+ tree.
- Notify ASP.NET from COM+ server application.
- Transactions, just for the record.
(a) Com+ application types and how they effect your application performance
There are two ways that COM+ can host .Net components: Library application and Server application. Library application run the component in the caller process while Server application run component in dedicate process that COM+ create, called Dllhost.exe. COM+ application type influences every aspect of the hosted component. Server application run in separate process affecting the overall performance of application that needs to cross the process boundary to call component services. Cross process communication is the major factor in the differences regarding performance and limitations between Library and Server applications.
COM+ is based on context. Context is environment for objects with the same execution requirements. Context can intercept method call or object activation and execute one of the COM+ services as a result. In order to register .Net class in COM+ the class must inherit from ServicedComponent. ServicedComponent implementation is based on Remoting that easily can be used to intercept method calling. When CLR required to instance new derived ServicedComponent object a call to managed C++ is made. The managed C++ call CoCreateInstance that allow COM+ to bind the object to unmanaged context and supply unmanaged services that predefined to the register class in the COM+ catalog. CLR is also capable of taking advantage the attributes programmer relate to a class, in order to set class metadata in COM+, if not previously set. During the registration the InProcServer32 key that usually points to the COM DLL or COM EXE path points to mscoree.dll which is the .NET JIT engine (ironically mscoree.dll is COM DLL). Since the call back to CLR the actual object created is real managed object.
The describe process happened when COM+ library object requires and in the end of the road a pure managed class create by CLR. Objects registered as server application got another instantiation path. The cross process nature of server application requires Remoting as long as DCOM to call the registered object from managed code. Actually there are two Remoting calls during object activation one for getting the server object URI and one for the actual activation. COM interop calls are made during activation and data un-marshaling. In both cases (library, server) the object is managed object created by CLR just the server object need Remoting and DCOM to activate the object and for every call to un-marshal parameters. We will see the impact of those differences in the performance section.
(i) Performance
After understanding the steps related to activation of library and server application lets see how every one of this options influence our web application performance. As I state earlier this article is about practical approach so while we check for COM+ applications performance we will check other COM+ services that might influence web application performance in certain situations. Those services include JIT, object pooling, and synchronization support. I’m not intending to go deep into the details of those services, you can find full coverage of them at http://www.ondotnet.com/pub/a/dotnet/excerpt/com_dotnet_ch10/index.html?page=1. or on MSDN documentations.
The performance test is based on regular ASP.NET application build in the conservative layer architecture. The ASP.NET application construct from 6 pages :
1) GetDataNoCom.aspx : page that Get about 20 records from Database and display them..
2) GetDaataCom.apsx : page that call class registered in COM+ to retrieve about 20 records from Database and display them.
3) GetLargeDataNoCom.aspx : page that Get about 1000 records from Database and display part of them
4) GetLargeDataCom.aspx : page that call class registered in COM+ to retrieve about 1000 records from Database and display part of them.
5) LongInit.aspx : page that call resource with long initialization time.
6) LongInitCom : page that call class register in COM+ . The com+ class use resource with long initialization time.
Every one of the COM+ objects will be test while running as Library and Server with JIT, object Pooling and methods call time. The test made on machine with single Intel 4 1,80GHz CPU and 500 MB of RAM. Result numbers are RPS (Request per second) returned by ACT (Application Center Test). Each test runs for 5 Seconds with 10 simultaneous users.
Table 1.0 test results | |||||||||
|
No COM+ |
Library |
Server | ||||||
|
|
Pooling |
JITA |
Call Time |
PRS |
Pooling |
JITA |
Call Time |
RPS |
GetDataNoCom – 90 records |
300 |
X |
X |
X |
X |
X |
X |
X |
X |
GetDaataCom – 90 records |
X |
- |
- |
- |
233 |
- |
- |
- |
111 |
|
X |
+ |
+ |
- |
200 |
+ |
+ |
- |
105 |
|
X |
+ |
+ |
+ |
200 |
+ |
+ |
+ |
105 |
GetLargeDataNoCom - 900 records |
50 |
X |
X |
X |
X |
X |
X |
X |
X |
GetLargeDataCom – 900 records |
X |
- |
- |
- |
49 |
- |
- |
- |
36 |
|
X |
+ |
+ |
- |
48 |
+ |
+ |
- |
28 |
|
X |
+ |
+ |
+ |
48 |
+ |
+ |
+ |
28 |
LongInit |
1 |
X |
X |
X |
X |
X |
X |
X |
X |
LongInitCom |
X |
- |
- |
- |
1 |
- |
- |
- |
1 |
|
X |
+ |
+ |
- |
0.3 |
+ |
+ |
- |
100 |
|
X |
+ |
+ |
+ |
0.3 |
+ |
+ |
+ |
100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
As you can see in Table 1.0 there is difference in performance between non COM+ pages and pages that use COM+ Library. The performance differences are minimizing as the page perform more time consuming tasks. On the contrary we can see that pages using COM+ server application is 2 time slower then pages using COM+ library applications. One exception is handling a task that requires long initialization time you can see that using pooling can improve performance dramatically. We will address this issue in details later. You can also see that using Call time data to enable us to monitor application components don’t have any impact on page output. Later on we will see how we can use that data to inspect application problems in run time.
Using ACT can help you in the development process. Checking your page for RPS as you develop can help you find problems and bottlenecks as you or other programmer making them. Solving problems founds early in the development process are usually more easy then solving them when the development processes done. I strongly recommend to use ACT as much as possible to get good grasp of application status at every development phase.
(ii) Accessing and limitations
Beside the performance aspect we need to consider limitation that we need to be aware of if we choose to use COM+ applications. Limitation actually related just to COM+ server application mainly due to it’s out of process nature. Server library class can’t access the ASP.NET intrinsic object. Actually it can be done if the page multi threaded state change to single thread by using ASPCOMPAT attribute but using this attribute will harm application performance.
Hosting .Net assembly in DLLHOST.exe which is a process running in system directory result in limitation due to the fact that ASP.NET application and the called COM+ server assembly running in different location enforce the programmer to host assemblies that holds common data (interfaces, enumerations, etc) in the GAC. Putting common data assemblies in the GAC prevent deployment of those assemblies to several physical locations.
Using Remoting to call COM+ server application from ASP.NET application imposes several other limitations. If ASP.NET calls COM+ class and ask for data every thing working smooth since CLR handle the Remoting for the register COM+ class. But if COM+ class needs to create callback to the calling ASP.NET application or to return reference type (like DataReader) some action must be taken in order to make the page class Remoting server. Later on I’ll show how to achieve this behavior.
Another limitation derived from Remoting is the requirement to pass parameters that support serialization. Remoting serialize object to move them across the Remoting channel. Passing object that don’t support serialization as parameter will cause runtime error.
Due to DCOM and Remoting usage of every call to class register as COM+ server application its better to use chunky over chatty calls. Create few calls with parameters rather then using properties for classes that will be called from ASP.NET applications. To be clarify chunky over chatty is right just for "entry point" classes. Other classes that used as part of the request process should use the classic OO approach.
(b) Make your application available as possible
One of the strategic targets that .Net is just a tactic to achieve is the Enterprise software market. Microsoft wants to penetrate that market that was dominated for years by Oracle and SUN (Java and java application server suppliers). The enterprise market demands are different from those of E-commerce market. Usually enterprise software use to handle large different databases with set of intranet applications that stand from the end enterprise user as one big software. Those applications (usually tens) use to be host by the same server which is part of load balancing cluster. Building set of application by different development teams, with high volume of connectivity between them, that eventually will be treating as one application and host on the same server demands different set of requirements from building single client server application or E-commerce one. Microsoft starts to release more and more software tools and development tools that help enterprises to build their software. One of those tools is COM+ and one of the COM+ donation is strong support to availability and scalability.
Hosting many applications on the same server have many advantages for the enterprise. This configuration supply best performance due to the connectivity between applications and save money (Imagine the cost of buying and maintaining server for each application). But there is one big disadvantage. If the hour report system run into problem and consume 100% CPU all other applications that run under the same IIS will also harm. Such a situation can damage the availability of application and even data and must be prevent or at least monitor and stop.
One of the obvious conclusions from performance and limitation is that it’s better not to use COM+ server application. Even though that conclusion is based on solid evidences COM+ server application can solve the availability issue easily but with performance tax. In most cases the performance tax is irrelevant for enterprise software that need to serve in the extreme case tens thousands of users split between three servers or more.
(i) Maximum isolation
Registration of class as COM+ server application ends up with dedicated process named dllhost.exe that will run the class objects, when they will be created. This paradigm isolates those class objects from the address space of the calling application and let us terminates the class objects without terminating the calling web application.
As a matter of fact IIS5 and IIS6 supply other isolation mechanism. IIS 5.0 catch request for .Net application and by using pipe transfer the request to dedicated process for handling ASP.NET applications - aspnet_wp.exe. There is just one aspnet_wp process in the server and every web application got its own application domain inside aspnet_wp. ASP.NET takes advantage of that architecture and restart application by restarting web application’s application domain. While ASP.NET can restart application in given situations administrators can’t. What you can do as administrator is to use ASP.NET mechanism of restarting web application when any change is made to the application bin directory. That workaround will work just if your application not processing incoming request. In that case application restart will be happened just after the request is done. If one of the request processing steps enters never ending loop, the web application won’t restart.
This IIS5 behavior together with in process activation mode of assemblies used by the web application can end up with unavailability of more then one application even if just one application misbehaves. To overcome this situation administrator need to restart aspnet_wp process that as result restarts all applications running on the server. The only way to prevent this situation is to use layer separation and to host non GUI layers as COM+ applications so the administrator can use COM+ MMC to restart the dedicate process without harm the aspnet_wp process.
IIS6 introduce Application Polls that can host one or more web application. Applications pools has their own w3_wp process that can be recycled by administrator thus enable to terminate one web application without harm others. This IIS6 option let administrators terminate one application but it still missing the monitoring abilities build in COM+ that enable administrators to find quickly the misbehave assembly.
Now let’s see isolation in practice. We will build simple web application (AvailabilityCheck) with assembly containing one class register in COM+. That class contains two methods DoItRight and NeverEndingStory which contain never ending loop. The web form contain two buttons each one calls class method.
Figure 1.0
//Class code
namespace AvailabilityCheckDll
{
/// <summary>
/// simple COM+ class without attributes. just inherit from
/// ServicedComponent
/// </summary>
public class AC : System.EnterpriseServices.ServicedComponent
{
public AC()
{
}
public string DoItRight()
{
return DateTime.Now.ToString ();
}
public string NeverEndingStory()
{
// simulate unfinish recursive
for(;;)
{
}
return DateTime.Now.ToString ();
}
}
}
// Page Code
public class WebForm1 : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Button btnDoItRight;
protected System.Web.UI.WebControls.Button btnNeverEndingStory;
private void Page_Load(object sender, System.EventArgs e)
{
// Put user code to initialize the page here
}
+#region Web Form Designer generated code
private void btnDoItRight_Click(object sender, System.EventArgs e)
{
AvailabilityCheckDll.AC oAc = new AvailabilityCheckDll.AC();
Response.Write ( oAc.DoItRight ());
}
private void btnNeverEndingStory_Click(object sender, System.EventArgs e)
{
AvailabilityCheckDll.AC oAc = new AvailabilityCheckDll.AC();
Response.Write ( oAc.NeverEndingStory());
}
}
Running the web application cause AC class to register as Library application. Clicking on DoItRight button return page with printed date and time. Clicking on NeverEndingStory cause the CPU to reach 100%. The only way to finish 100% CPU utilization is by restarting the aspnet_wp (IIS5) or recycling Application Pool (IIS6). Now change the AC metadata, on COM+ MMC, to run as server application and press NeverEndingStory button. After you notice that the CPU consumption reached 100% simply shutdown the COM+ application. Note that the CPU usage return to be normal and you get error page indicating some problem in your application. This scenario shows the strength of using COM+ server application. You saw how easily is to stop malicious code, without harming other web applications.
Another option to gain isolation is to use Remoting and host assemblies on dedicated Windows service. Administrator can shutdown the dedicated service without harm other application. There are two disadvantages to this approach. Shutdown the service influences all assemblies that hosted in that service and there are no statistics to take advantage of.
As you see register class as COM+ Server application result in more available applications and in conjunction with monitoring can reduce dramatically application unavailability period. Just don’t forget that registration class as COM+ application will harm your application performance. As I state, before decide if to register your assembly as Server application its better to check with ACT (Application Center Test) for RPS (Request per Second) and just then to make your decision.
(ii) Component Monitoring and quick problem solving
COM+ Server application supply set of data and statistic that can be used to fast allocate of malicious code. If all the assemblies that the web application uses are load into the application domain memory address the only way to know where error happened (if you get error message at all) is by bubbling exceptions and writing them to log file. Even if the programmer follows that practice the server administrator is likely won’t understand those logs. Registration of classes as COM+ server might help administrators in several ways:
- Process information. Every class that registers as server application got its own dedicates process. COM+ MMC let you know what the process ID of every application is. You can use this data to look for high CPU usage processes at the Task Manager. Comparing PID (PID column can be added from View->Select Columns menu) from task manager with status view of com+ applications can help you determine quickly which COM+ application responsible for high CPU utilization.
- Component information. First of all to use this data EventTrackingEnabled attribute must be set in the class declaration. Setting this attributes yield in statistic for every application component that can be seen in the status view of the components folder. The most important data is CallTime. This parameter shows how much time in milliseconds object is performing its task. Using this data administrator can find bottleneck components or components that cause the application to misbehave (components with huge call time). Furthermore if every component present one of the application layer administrators can easily find if the application problem roots are deep in database or logic layers.
As you see the application and components data exported by COM+ can be used by Administrator to minimize the time for problem tracking and therefore maximize the total availability time of application. As isolation, component and application data can be gather just if the application set as server (for components call time collect just if application set as server. Other statistic data collect for library and application but there aren’t useful as call time).
You can use the previous code sample to see how the describe data goes into practice and help you to find the problematic process and class. Set the COM+ application to run as server and run the web application. Press NeverEndingStory button. When CPU usage reaches 100% open task manager and switch to processes tab. Order the data by CPU usage. On the top of the list you should se DllHost.exe. Recall the DllHost.exe PID and open COM+ MMC status view of COM+ applications folder. Look for application with the same PID, you will found that AvailabilityCheckDll match the same PID. Till now you know which application causes the problem what left is to find the responsible class. Open the application components status view. This application contains only one class but you can easily see that one component call time is keep growing. This component is responsible for the high CPU usage.
(iii) Application Recycling (COM+ 1.5)
Version 1.5 of COM+ takes the availability and stability of COM+ application one step farther. COM+ application can cause expected and unexpected problems such as memory leaks or usage of unscaleable resource. COM+ let administrator set in which circumstances your application will be recycle automatically. COM+ let you set recycling by process lifetime, memory consumption, number of method calls and object activations.
(iv) Scale your objects (COM+ 1.5)
COM+ 1.5 introduce new feature that enable to scale legacy single threaded applications (such as components build by VB 6.0). That feature allow administrator to set the number of DllHost process that can be start for the given application and serve incoming requests. When application pool size is greater then one, COM+ start to rout requests between DllHost processes in round robin manner. You can see all the process including their PID in the running processes folder of COM+ MMC. Besides improving scalability Application pooling can be very useful for availability and recovery. If for some reason error happened in one DllHost new request can rout and use other DllHost from the pool.
(v) Process dump (COM+ 1.5)
Full process memory dump is very useful for monitoring, analyzing and debugging purpose. Dumps are crucial to find and fix problems that cause application exceptions. COM+ 1.5 address this issue by adding a tab that let the administrator to set automatically generation of process memory dump when exception occurred. COM+ MMC let you set the location of the dump file and the number of dump files that will be kept before recycling them on the disk. Beside auto generation of dump file you can dump application memory whenever you want by using the dump menu on application context menu of applications in running processes folder. After creating the dump file you can use WinDbg to open the dump file and analyze the data.
(vi) Enable different version of COM+ application simultaneously running (COM+ 1.5 on .NET server)
This feature can be found only on .Net servers. You have to enable com+ partitions by enabling partition option in Options tag of your computer in COM+ MMC. Partitions enabled administrator to create number of partitions that every partition hosts Server or Library application with different setting of metadata. This option enables hosting of several COM+ application versions with different COM+ catalog data on the same machine. When COM+ application Component activation required COM+ decide to activate object in partition by the user that activate the component and users that attach to given partition. You can also take advantage of this feature to separate data between different groups of developers or users by setting different connect string as COM+ constructor string
(vii) Looking for bright future
I hope that until this part you got the impression how much COM+ Server Application can help you to create much more scalable and available systems and on the contrary how COM+ Server Application harm performance mainly due to the DCOM involve in the activation and marshaling process. I hope that Microsoft get the picture and newer versions of COM+ will be .Net based and turn DCOM obsolete. Until then you need to make your own decision for performance or stability and availability. Theoretically switching from Server to Library application is just a meter of changing the activation type but practically there are Server imitations (that I mention previous) and slight code changes (that you can see in the test application) between the two activation types. My advice is to take in account the limitations and code changes when you create class that should be host as COM+ component. Doing so leave administrator and project manager to decide how your assembly will be run eventually.
(c) Applying security
COM+ and role based security are fully integrated. Both of those abilities let administrators to create groups of user, which are roles, and to assign those groups security rights regarding COM+ components and methods. All this process can be done easily in COM+ MMC.
Role base security can be use to enforce security checking and authorization for performing database actions (Insert, Update, Delete and Select). In order to use role base security you need to create your application in layer fashion. When crafting the data layer you need to create classes that implement interfaces consist on insert, update, delete and select functions. Doing so enables administrators to create roles such as managers, users, sales or others and assign roles to those class's database interface functions. Administrators can add or remove users from groups and impose authorization on database actions.
Library applications and server applications that called from web application based on windows authentication, impersonate and set to interactive user identity can use ContextUtil.IsUserInRole() function to check if the current user exist in a given role. After determine the user role we can use that data against the Database to enforce data compartmentalization. Every Database and organization got their own implementation for data compartmentalization. One of the common and easy uses is to add compartmentalization letter or to use bitwise field for each row and to use it when selecting data. Alternatively, calling different store procedures can be employ so every member of each group will get other set of data from Database.
As you probably figure out you can use attributes to set COM+ role base security and roles for Application, component and methods (ApplicationAccessControlAttribute
, ComponentAccessControlAttribute, SecureMethodAttribute). You can use SecurityRoleAttribute Attribute to set the role or roles (you need to use the attribute for each role) for application, component or method. Using this attribute will add the role but won’t add users to role. Entering users to role it’s a task that must perform by administrators unless SecurityRoleAttribute use with its second constructor parameter set to true. Using that constructor will end everyone group as role users.
Let’s gather all that information into one sample page in our application. Our page (ContractsLogic.aspx) need to show data from array list that holds list of company contracts. Contract data should be compartmentalization between manager that can see all the list and workers that can see only certain contracts. The application is build utilizing layers application paradigm. The page class calls ContractsLogic class that calls ContractsData to get data from the DataBase, and return arraylist back to the ContractsLogic. ContractsLogic implies the security requirements and return arrayList holding the data per user to the page that bind arraylist to grid.
Figure 2.0
The page class calls ContractsLogic class, that set as COM+ library application, to get data and bind it to DataGrid..
private void Page_Load(object sender, System.EventArgs e)
{
try
{
IContractsLogic oLogic = new Contracts.ContractsLogic();
this.DataGrid1.DataSource = oLogic.GetByUser ();
DataGrid1.DataBind();
}
catch (Exception err)
{
string s = err.Message ;
}
}
In order to work with security within the assemblies classes we must use the ApplicationAccessControl attribute.
using System;
using System.EnterpriseServices;
using DemoInterfaces;
//[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl]
Our next step is to use ComponentAccessControlAttribute to set security access to the class and SecurityRoleAttribute to add users and managers Roles. We use SecurityRoleAttribute constructor that let us set everyone group to users role.
[ComponentAccessControlAttribute(true), SecurityRoleAttribute ("users",true), SecurityRoleAttribute ("managers")]
public class ContractsLogic : ServicedComponent ,IContractsLogic
{
The interesting part here is GetByUser implementation of IContractsLogic interface. In order to enable security settings to method Interfaces should be use. Although we aren’t going to implement method security I use them to let administrator the option to authorize database actions. Interfaces should be in separate assembly at the GAC to enable web application and COM+ server application to share interfaces. GetByUser calls ContractsData to get contract data. For this demo ContractsData simply create array list but its original destination is to retrieve data from Database and apply Compartmentalization in that call. In that demo, compartmentalization is done by checking user in role and using bitwise to get the right data.
System.Collections.ArrayList IContractsLogic.GetByUser()
{
IHandleData oData = new ContractsData();
System.Collections.ArrayList oArr = oData.Get();
System.Collections.ArrayList oRetArr = new System.Collections.ArrayList();
if (ContextUtil.IsCallerInRole("users") )
{
System.Collections.IEnumerator oEnum = oArr.GetEnumerator ();
while (oEnum.MoveNext ())
{
if ((((Contracts)oEnum.Current).Comp & 2) == 2 ) oRetArr.Add(((Contracts)oEnum.Current).ContractName );
}
}
if (ContextUtil.IsCallerInRole("managers") )
{
System.Collections.IEnumerator oEnum = oArr.GetEnumerator ();
while (oEnum.MoveNext ())
{
if ((((Contracts)oEnum.Current).Comp & 1) == 1 )
oRetArr.Add(((Contracts)oEnum.Current).ContractName );
}
}
return oRetArr;
}
Running the demo for the first time will create the COM+ application with roles. You will see just part of the data since we set everyone group to users role. Now add with COM+ MMC to manager role everyone group and just refresh the page. This time you will see all the contracts since your user now is part of managers.
Although it’s not directly connected to COM+ I just want to mention that using role base security can achieve compartmentalization of data via manipulation of visual control. ASP.NET function IsUserInRole can be use to determine the user role and controls can be set to visible or invisible as a result of that determination. ASP.NET does the job with .Net implementation of role base security. .Net mechanism is more flexible since you can use it to work with users that aren’t windows accounts, its more integrated into .Net component (functions, interfaces, attributes, classes) and can be impose not just in run time. Note that .NET Framework and COM+ role-based security mechanisms are independent, and you can use only one mechanism within a single application.
(d) Increase server output and application income.
.Net un-synchronic mechanism imposes both the caller and called object to be alive when un-synchronic call occurred. Some times this behavior can cause our application to run into unstable situation since that called object isn’t available for some reason. Even if we will catch that situation and will notify our user that the service isn’t available it will still cause financial damage. To overcome this situation we can save the request details and handle it later. But we need to find mechanism to ensure availability of the cached request until the application successfully process the user request.
Instead of implement such mechanism you can use COM+ queued components (QC). QC on behalf of you calls MSMQ queue with component name, method to activate and parameters. As a result COM+ will activate the request component on the request server. Writing message into MSMQ enables us to call component a-synchronically since there isn’t any connection between caller and called object. Request to activate object data exists in MSMQ queue and will stay there as long as COM+ won't activate the request COM+ component. Writing message to MSMQ also ensure us that the message will be persist until retrieval of the message from the queue.
Let's see how using COM+ QC will help us in real life scenario. Assume that you are building E-commerce application that enable users to buy goods. User selects his goods and then submits them for process on the server, along with his credit card details. The server beginning long workflow starting with credit card validation and ending with notify the customer that the goods shipped. The order process, of course, builds from several components: credit card validation, validation of goods existence, credit card debit, send order request to storehouse and inform customer about goods shipment. That's a long process to go through with several potential fails points. This process can be split into two parts front end and back end. Front end responsible for getting the user request, ensure goods existence, validate credit card and debit. Back end part responsible for other order process tasks. Separating back end tasks components co-existence is obvious. Every task takes its own time, result in a need to call next process component just when given task ends. Register back end components as QC ensure that the process continue to work even if one of the tasks components is temporary unavailable.
Front end component can be handling in two ways. They can be process in sequence order until credit card debit, or also split to unconnected components. Choosing the second method present advantages as you will see. The debit component needs to call credit card Company to process the credit card debit. This process is usually engaged with network call to the credit card company that can cause long time period and unavailability of credit card company service. Long response time can end up with server ability to handle fewer requests. Furthermore unavailability of Credit Card Company won't enable the server to fulfilled client request. Thus separating the credit card debit component and register it as COM+ QC can solve lot of problems and contribute to the server production. Our ASP.NET application will get the request and validate the credit card. Then request to continue the request process will be sending to the QC debit component via MSMQ and the client will be notifying that his request received and being process. When the debit component finish its work an e-mail notification will be sends to the client and the request will be send to the next QC component to continue the process.
To see what the actual effects of that theory are we will build new page and classes that will demonstrate such e-commerce application. We will build just the front end components and run the sample with debit component as QC component and as regular components, collect RPS and watch the results. Figure 3.0 shows the general design of our e-commerce application. Note that option "A" register debit component as QC.
Figure 3.0
We will add two pages (BuyQC.aspx, BuyNoQC.aspx) to AvailabilityCheck web project to simulate the debit action with or without Queued Component. BuyNoQC.aspx will call new class (MyClass) that I add to AvailabilityCheckDll library with one function that simulated the debit action simply by suspend the thread for 1 second. The more interesting part is BuyQC.aspx which calls new assembly (QCClass) and class (MyClass), with the same function as I add to AvailabilityCheckDll library. MyClass will be register as queued component due to using of ApplicationQueuing attribute, that set to enable queuing and listening, at AssemblyInfo file.
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationQueuing(Enabled = true,QueueListenerEnabled = true)]
[assembly: ApplicationName("QCDemoSrv")]
[assembly: AssemblyTitle("")]
The second step is to create an Interface and mark it with InterfaceQueuing attribute to enable queuing support. Both the queued component and calling page will use that interface as their calling contract. When you design Interface that will be used for queued components remember no to use out or ref parameters due to the a-synchronic working pattern of QC.
[InterfaceQueuing]
public interface IMyInterface
{
void CreditDebit(string CardNumber, double amount);
};
Finally we build up a class that will be inheriting from ComponentServices and implement IMyInterface interface. Note that it’s a regular class, nothing should be done in order to use it as queued component. I just add security attribute to the class to enable it working with the default security enabling of COM+ server application registered by CLR 1.1.
[ComponentAccessControl(true), SecurityRoleAttribute("users",true)]
public class MyClass : ServicedComponent,IMyInterface
{
public MyClass()
{}
public void CreditDebit(string CardNumber, double amount)
{
System.Threading.Thread.Sleep (1000);
// Optional – write to eventLog
//System.Diagnostics.EventLog.WriteEntry ("QC check","Debit finished");
MessageBox.Show("Debit finished","Queued Component");
return;
}
}
To use lazy registration of our COM+ application I add instantiation of the class in Application_OnStart event. Those lines of code save us from the need to start the COM+ application manually from COM+ MMC.
protected void Application_Start(Object sender, EventArgs e)
{
QCAssembly.MyClass o = new QCAssembly .MyClass ();
System .EnterpriseServices .ServicedComponent .DisposeObject (o);
}
BuyQC.aspx is calling the queued component class by using BindToMoniker function of Marshal class. A moniker acts as a name that uniquely identifies a COM object. You can find good explanation on Queued Components moniker syntax in MSDN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cossdk/htm/pgservices_queuedcomponents_786q.asp). I use the syntax to create object from local queue but you can use the syntax to call remote queue. After getting the object and casting it to IMyInterface interface we can use the interface methods and release the object from COM+.
private void Page_Load(object sender, System.EventArgs e)
{
IMyInterface myObj;
myObj=(IMyInterface)System.Runtime.InteropServices.Marshal.BindToMoniker("queue:/new:QCAssembly.MyClass");
myObj.CreditDebit ("423423423423",10.0);
System.Runtime.InteropServices.Marshal.ReleaseComObject(myObj);
Response.Write("Order received and processed");
}
This page simply use queued component to generate new message into the component queue and return indication that the process done. When the queued component listener find new message inside the component queue COM+ will activate and run the given function with given parameters, ending up with messagebox popup.
Below (table 2.0) you can see results of running BuyQC.aspx, and BuyNoQC.aspx using ACT against 5, 10, 50 concurrent users. As you can see queued component scenario is at least 17 times faster when performed task take 1 second.
Table 2.0 | ||
Number of simulate users |
BuyNoQC.aspx |
BuyQC.aspx |
5 |
5 (RPS) |
212 (RPS) |
10 |
10 (RPS) |
216 (RPS) |
50 |
12 (RPS) |
211 (RPS) |
MQ components can be mark as transactional components ensuring that components request won't be removed from Queue until the function finished its work and successfully end transaction flag is raised.
(e) Monitoring and squeezing licenses usage
One of the common issues especially inside enterprises is licenses usage. Most of the third party components that used by IT department are based on licensing agreement usually with limitation of the licenses concurrent usage (such as ESRI products). Our IT department needs to ensure that the license policy is enforced and that enforcing license policy won’t cause any user working with the product to receive error due to license policy validation. This section will show you how you can achieve those goals and even enable usage of few licenses by much many users by using COM+ features.
To deal smoothly with license issue we can use COM+ polling service. Creating component that will use the license product and register this component as COM+ server application using object pooling can let administrator to control license usage. Setting maximum pool size to specific number enables COM+ to create that number of objects where each and every one of them using one of third party application license. Furthermore COM+ queue requests that exceed the specific objects that set by administrator until one object finished his services. This ability save us the code needed to be writing for prevents errors if license not available, to process client request.
Using COM+ not just let administrators to control dynamically the maximum number of pooled object. By using Just In Time Activation (JITA) COM+ can serve many users by few components object thus enable many users to use few licenses. JITA actually “connect” client to object just when the client call to one of the objects methods or properties. On the first call to the object COM+ creates context object for the client but a real object creates only upon the client first request for object properties or methods. Before COM+ creates an object for client request COM+ check if such an object already exist and isn’t serve any call. If such an object found COM+ use that object instead of creating new one. As you can see JITA behavior lets COM+ to use much less components to serve much more clients.
COM+ object pooling let the programmer to decide programmatically if an object will return to the pool or not by overloading CanBePooled protected method. This opportunity enables programmers to get out malicious or misbehaved object from the pool.
For this sample I created simple COM EXE C++ application. I add a member data to CComModule class for licenses usage and override FinalConstruct and FinalRelease COM class methods to imitate license application that limited to two licenses.
Figure 4.0
STDMETHODIMP CLicensesApplicationCls::FinalConstruct ()
{
if (_Module.UsageCount == 2)
{
Error(L"No more licenses available for usage!",IID_ILicensesApplicationCls,(HRESULT)-111111);
return (HRESULT)-111111;
}
_Module.UsageCount += 1;
return S_OK;
}
void CLicensesApplicationCls::FinalRelease ()
{
_Module.UsageCount -= 1;
}
To work smoothly with the EXE application I use tlbimp.exe and sn.exe utilities to create managed wrapper for the COM EXE application. Next step is to create two new COM+ class LicensesUsageCls and LicensesUsagePoolJitaCls. One for using COM object with Pool set to maximum two objects and JITA options and the other without.
[ObjectPooling(true,2,2), JustInTimeActivation (true),EventTrackingEnabled (true)]
public class LicensesUsagePoolJitaCls : ServicedComponent
{
public LicensesUsagePoolJitaCls()
{
//
// TODO: Add constructor logic here
//
}
public void UseOneLicense()
{
licensesapplicationNet.LicensesApplicationClsClass oLA = new licensesapplicationNet.LicensesApplicationClsClass();
oLA.GetName();
}
}
public class LicensesUsageCls : ServicedComponent
{
public LicensesUsageCls()
{
}
public void UseOneLicense()
{
licensesapplicationNet.LicensesApplicationClsClass oLA = new licensesapplicationNet.LicensesApplicationClsClass();
oLA.GetName();
}
}
What left are two pages, each one of them will call its equivalent class.
public class LicensesUsage : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
try
{
LicensesUsageClass.LicensesUsageCls o = new LicensesUsageClass.LicensesUsageCls();
o.UseOneLicense ();
System.EnterpriseServices.ServicedComponent.DisposeObject (o);
}
catch(Exception Err)
{
throw Err;
}
}
public class LicensesUsagePoolJita : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
LicensesUsageClass.LicensesUsagePoolJitaCls o = new LicensesUsageClass.LicensesUsagePoolJitaCls ();
o.UseOneLicense ();
System.EnterpriseServices.ServicedComponent.DisposeObject (o);
}
To check the pages behavior we will stress them using ACT with at least 5 concurrent users. You will find out that LicensesUsagePoolJita page run without any errors while LicensesUsage return approximately 10% of errors due to licenses over use. If you will inspect the RPC you will see that using this technique we enable approximately 26 concurrent users to use our 2 license application.
(f) Notify others when your application change state
Loosely Coupled Events (LCE) is one of the COM+ features that can be very useful. LCE enable COM+ component to initiate event that eventually will be raise on unknown clients. Clients should be register as COM+ event component subscriber, by using COM+ MMC or dynamically. Publisher calls one of the COM+ event components methods that cause event to be send and rose in all of the subscribers. The contract between event component subscribers and publisher is single interface that should be implements by all of the contract parties.
LCE can be used to create notification to components or application without knowing in advance who will be those applications or components. In order to enable those applications or components to get notifications they need to implement that event interface and subscribe to the COM+ event component. Every other task’s that should be dome are being taken care of by COM+.
To simulate the power of LCE we will create mechanism that enable desire web application to get notification when certain Database table changed by one of web applications or any other application. To enable that mechanism we need to control all of the applications access to database. This task can be achieved by creating new COM+ server application that implement Select, Insert, Update and Delete functions. Every data layer class in every application should use this class when sending SQL statements to database. That database pipe class is actually the publisher. Every database command will end up with call to class register as COM+ library and serve as the event class. Every web application that wants to be notifies needs to implement subscriber class and register it (subscriber class) as the event subscriber.
Let's start with the event component – LCEventLibrary.Dll. It's a simple assembly containing the interface and a class that register as COM+ library serving as event class using EventClass attribute. Note that this class shouldn’t implement anything and shouldn’t be call directly. This class is used by COM+ to call subscribers.
Figure 5.0
public interface IMySink
{
void OnDBChange(string Action, string DBEntity);
}
[EventClass(FireInParallel = true)]
public class MyEventClass : ServicedComponent,IMySink
{
public void OnDBChange(string Action, string DBEntity)
{
throw(new NotImplementedException("You should not call an event class directly! "));
}
}
To enable Web application subscription to MyEventClass we will create service class (TransientSubscription) that encapsulates all the lines that should be write to add subscriber dynamically. Dynamic subscribing can be done by manipulating COM+ metadata. To manipulate COM+ metadata we need to use COM+ COM + 1.0 Admin Type Library so I use tlbimp.exe to create managed wrapper for that COM library. TransientSubscription expose static function to add and remove subscribers. To add subscriber one should send unique name, the event class type and subscriber class. Sink interface can be found by looping through subscriber class interfaces.
static public void Add(string subName,Type eventClass,Type sinkInterface,string method,object subscriber)
{
Type sinkType = subscriber.GetType();
if(method != "")
{
MethodInfo info = sinkInterface.GetMethod(method);
}
//Adding a new transient subscription to the catalog
ICOMAdminCatalog catalog;
ICatalogCollection transientCollection;
ICatalogObject subscription = null;
catalog = (ICOMAdminCatalog)new COMAdminCatalog();
transientCollection = (ICatalogCollection)catalog.GetCollection("TransientSubscriptions");
subscription = (ICatalogObject)transientCollection.Add();
subscription.set_Value("Name",subName);
subscription.set_Value("SubscriberInterface",subscriber);
string eventClassString = "{"+eventClass.GUID.ToString()+"}";
subscription.set_Value("EventCLSID",eventClassString);
string sinkString = "{" +sinkInterface.GUID.ToString()+ "}";
subscription.set_Value("InterfaceID",sinkString);
subscription.set_Value("MethodName",method);
subscription.set_Value("FilterCriteria","");
subscription.set_Value("PublisherID","");
transientCollection.SaveChanges();
}
The subscriber class (MySubscriber) is implemented as part of the web application. MySubscriber implements IMySink interface and write the code that should be called when the event class calls its subscribers. In this demo I simply update application variable that something changed. One problem that needs workaround is updating Application object. I can’t use HTTPContext.Current since subscriber call isn’t connect to any request. To workaround that problem I add constructor that get HttpApplicationState as parameter and set internal member to it.
public class MySubscriber : LCEventLibrary.IMySink
{
private System.Web.HttpApplicationState App;
public MySubscriber()
{
}
public MySubscriber(System.Web.HttpApplicationState inApp)
{
App = inApp;
}
public void OnDBChange(string Action, string DBEntity)
{
App["DbChange"] = true;
}
}
The actual subscribing happened in Application_start event.
m_Subscriber = new MySubscriber(System.Web.HttpContext.Current.Application);
TransientSubMgr.TransientSubscription.Add("MySub",typeof(LCEventLibrary.MyEventClass),m_Subscriber);
Application["DbChange"] = false;
PublisherClass assembly contain PubClass class that act as the publisher. PubClass serve as single connection point to database thus register as COM+ application with methods for all database actions. Every method create instance of MyEventClass based on IMySink Interface and call OnDBChange with right parameters. UpdateData extract table name from SQL statement and send it as parameter.
public class PubClass : System.EnterpriseServices.ServicedComponent
{
public PubClass()
{
}
public void UpdateData(string SQL)
{
LCEventLibrary.IMySink sink;
sink = new LCEventLibrary.MyEventClass();
string[] arr = SQL.Split (' ');
sink.OnDBChange("Update",arr[1]);
}
To activate the publisher I add new page (CallPublisher.aspx) to the web application. That page contain two buttons one for calling PubClass UpdateData Method and one to simply refresh the page. On page_load I check for application DbChange variable. If it set to true one of the database actions execute and Notification print into the render HTML.
private void Page_Load(object sender, System.EventArgs e)
{
if ((bool)Application["DbChange"] == true)
{
Response.Write ("DB data changed!");
}
}
private void Button1_Click(object sender, System.EventArgs e)
{
PublisherClass.PubClass oPC = new PublisherClass.PubClass();
oPC.UpdateData("update MyTable set MyField=value");
}
private void Button2_Click(object sender, System.EventArgs e)
{
}
Running the page for the first time will show the form with just the two buttons. Clicking on Update button will cause publisher to call event class method followed by calling to all subscribers. The subscriber class in that web application will update given application variable. Pushing the refresh button now will end up with page containing text notification about the change.
(g) Picking COM+ fruit without need to nourish COM+ tree.(COM+ 1.5 / CLR 1.1)
COM+ 1.5 introduce new working paradigm that enables classes builders to use part of COM+ services without registering classes as COM+ application (Services Without Components - SWC). That ability introduced to C++ developers that performance is their main concern. C++ developers can use CServiceConfig class to query interface of one of the services and then use APIs to use the chosen COM+ services as inline block or in batch mode.
Although SWC can be used by .NET application using interop CLR 1.1 introduce new class (ServiceConfig) in EnterpriceServices namespace that enable using COM+ SWC using .NET objects. ServiceConfig simply encapsulate the needed API functions to enable SWC. Using of this class if straight forward. You need to create an instance, set the features that you want to use by setting attributes, use Enter and Leave to mark the block that will use those COM+ features and write code inside that block.
public void HandleUser(string UID)
{
DataLayerClass oDLC = new DataLayerClass();
try
{
ServiceConfig sc = new ServiceConfig();
sc.Transaction = TransactionOption.RequiresNew;
sc.TransactionTimeout = 30;
sc.TrackingAppName = "SWC Test";
sc.TransactionDescription = "Test";
sc.TrackingEnabled = true;
//start block
ServiceDomain.Enter(sc);
// cal data layer to set DB
oDLC.DeleteUser(UID);
ContextUtil.SetComplete();
}
catch(Exception ex)
{
ContextUtil.SetAbort();
}
finally
{
// end block
ServiceDomain.Leave();
}
}
As I mention SWC enable just part of COM+ services. To be more accurate those are COM+ services that might be use by SWC:
- COMTIIntrinsic.
- IISIntrinsic.
- Context switching.
- Isolation level.
- Partitions
- Side by side assemblies
- Synchronization
- Thread pool
- Transactions.
Although its long list of attributes the most useful services such as Object pooling, JITA, Queued Components and Loosely coupled events aren’t include. As you saw throughout this article those COM+ features used to solve daily problems and to turn your application to be more robust and available.
(h) Notify ASP.NET from COM+ server application.
If you convinced that registration Class as COM+ server application can turn your application to become more stable and available you need also to remember the limitations that I already mention. One cause for limitation is the need to use Remoting between the COM+ component and the caller application. If you call COM+ component Remoting is done by CLR for you but if you need to call Application from COM+ application some work should be done in order to enable it.
One of the common scenarios is call back events from COM+ application to the calling application. When COM+ application needs to call your application its now your application turns to serve as Remoting server. To enable your application to behave as Remoting server you need to register to TCP port.
Let’s take a real life situation and see how we can do it with COM+ server applications and callback events. Suppose you need to read from database very large amount of data, manipulate that data and display all the data to the user. If we will follow the default page process paradigm we will get all the data format it and send it to the client in single buffer. We will supply very slow application to the end user. When we need to deal with large amount of data its better to read chunk of total data, format it and send it directly to the user. Using this paradigm will give the use sense of well operated system. The user quickly can see some data and as the time grows he can see more and more data until all the data send.
To enable that page process sequence we need to A- set buffering to false, so we can send chunks of data. B- Read data from Database using DataReader, collect chunk of records, format them and send them to the client. To make our application more stable its better to put data reading in class that will be register as COM+ application. To enable COM+ components to send chunks of data to the application we will implement call back events that will be notify the caller when chunk of data ready to be format and send.
The sample project is made from new web application (ASPNET_COMPLUSE_CALLBACK), regular assembly (ComPlusFacade) and COM+ server application class (ComPlusLib). ComPlusFacade task is to get the COM+ component events and write the received data to output buffer. ComPlusFacade is separate assembly because both the caller application and called COM+ component needs to be in GAC to enable each and every one of them to use other. Before running this sample, don’t forget to register those assemblies in GAC.
Figure 5.0
ComPlusLib contain two classes: XMLArg that decorate with Serializable attribute to enable transfer of event argument over Remoting channel.
[Serializable()]
public class XMLArg : EventArgs
{
string XMLBuffer;
public XMLArg()
{
}
public XMLArg(string XMLBufferArg)
{
this.XMLBuffer = XMLBufferArg;
}
public string XMLBufferArg
{
get
{
return this.XMLBuffer;
}
set
{
this.XMLBuffer = value;
}
}
public override string ToString()
{
return this.XMLBuffer;
}
}
clsComPlusLib is typical COM+ component contained declared event that fire every loop through for statement inside ProcessData method.
[ProgId("clsComPlusLib"),
Transaction(TransactionOption.NotSupported),
MustRunInClientContextAttribute(false),
EventTrackingEnabledAttribute(true),
JustInTimeActivation(true),
Synchronization(SynchronizationOption.Required),
Serializable
]
public class clsComPlusLib : ServicedComponent
{
public new event EventHandler DataArrive;
public clsComPlusLib()
{
}
public void ProcessData()
{
for (int i=0 ; i<100000 ; i++)
{
EventArgs XML = new XMLArg ("i=" + i + "<br>\n");
this.DataArrive(null,XML);
}
}
}
ComPlusLib will be register in COM+ by CLR you just need to register it in GAC by drag and drop or gacutil.exe.
ComPlusFacade is the interesting part in this sample. ComPlusFacade is the glue between WEB application and COM+ server application. FacadeObjByRef also decorated with Serialization to enable transfer the class over Remoting. To enable FacadeObjByRef to serve as Remoting server it derived from MarshalByRefObject and declared TcpChannel type member.
[Serializable()]
public class FacadeObjByRef : MarshalByRefObject
{
protected ComPlusLib.clsComPlusLib eventHandler = new ComPlusLib.clsComPlusLib();
protected System.IO.Stream outStream;
public static TcpChannel theChannel;
Class contractor get Stream as a parameter. The send stream should be page response output stream, that will be use to write received data to the client. Inside the constructor I register TcpChannel to let the remoting runtime choose an available port and set event handler to COM+ component event.
public FacadeObjByRef(System.IO.Stream outStream)
{
lock(this)
{
if (theChannel == null)
{
theChannel = new TcpChannel(0); ChannelServices.RegisterChannel(theChannel);
}
}
if (textEncoder == null)
{
textEncoder = Encoding.UTF8;
}
this.outStream = outStream;
this.eventHandler.DataArrive += new System.EventHandler(this.DataArive);
}
ProcessData is the class public method that will be called by WEB page and calls COM+ application synchronously to start its work.
public void proccessData()
{
eventHandler.ProcessData();
this.CloseStream();
this.cleanUp();
}
While COM+ application does its work an event is raising and handling by DataArrive. DataArrive converts event argument to byte array and send that byte array to the client using internal member that holds calling page response stream buffer.
public void DataArive(object sender, System.EventArgs e)
{
byte[] toWrite = textEncoder.GetBytes(((ComPlusLib.XMLArg)e).XMLBufferArg + "\n");
outStream.Write(toWrite, 0, toWrite.Length);
}
ComPlusFacade run under web application process you just need to register it in GAC.
ASPNET_COMPLUSE_CALLBACK web application got just one aspx page (webform1.aspx) that disable default buffering behavior and create object from FacadeObjByRef class and call ProcessData method.
private void Page_Load(object sender, System.EventArgs e)
{
Response.BufferOutput = false;
ComPlusFacade.FacadeObjByRef oObj = new ComPlusFacade.FacadeObjByRef (Response.OutputStream );
oObj.proccessData ();
}
What left to be done us to run ASPNET_COMPLUSE_CALLBACK and to see its behavior. As I explain the page is quickly up showing chunks of data that keeps arriving and adds to the browser HTML.
Conclusion
This article aim is to show how you can use COM+ services to solve common programming tasks while developing web applications. We start by seeing the impact of COM+ server and library application on performance and what are the limitations derived from server application usage.
After understanding performance consequences I try to explain and show what is the tremendous contribute of using COM+ server application to applications stability, robust and monitoring. By solving daily task such as long component initialization, long components task, notification and other we see how we can use COM+ services and especially COM+ server services save code writing and programmers efforts.
COM+ can supply powerful services that can help you to create quickly sophisticated and stable application. The main drawback of using COM+ services is performance penalty. We saw that we can use part of COM+ services with Services without Components without penalty and COM+ library application with acceptable penalty. COM+ server that provides most of the interesting services has bad influence over performance mainly due to its usage of DCOM.
Before using COM+ services its better to create concept application and to test it with ACT to see if using COM+ server will fit application performance goals. I hope that next versions of window such as Longhorn will ship with COM+ services that won’t be based on DCOM and will enable more applications to use COM+ server application.
Related Links
Any useful links, internal to ASPToday or external, that would be useful to our readers.