tags:

views:

283

answers:

1

I have a .NET 3.5 web application for which I have implemented a class called CalculationsCounterManager (code below). This class has some shared/static members that manage the creation and incrementing of two custom performance counters that monitor data calls to a SQL Server database. Execution of these data calls drives the creation of the counters if the don't exist. Of course, everything works fine through the unit tests that are executed through the nUnit GUI for this class. The counters are created and incremented fine.

However, when the same code executes through the ASPNET worker process, the following error message occurs: "Requested registry access is not allowed.". This error happens on line 44 in the CalculationsCounterManager class when a read is done to check if the counter category already exists.

Does anyone know a way to provide enough priveledges to the worker process account in order to allow it to create the counters in a production environment without opening the server up to security problems?

Thanks in advance!

Namespace eA.Analytics.DataLayer.PerformanceMetrics
    ''' <summary>
    ''' Manages performance counters for the calculatioins data layer assembly
    ''' </summary>
    ''' <remarks>GAJ 09/10/08 - Initial coding and testing</remarks>
    Public Class CalculationCounterManager

        Private Shared _AvgRetrieval As PerformanceCounter
        Private Shared _TotalRequests As PerformanceCounter
        Private Shared _ManagerInitialized As Boolean
        Private Shared _SW As Stopwatch

        ''' <summary>
        ''' Creates/recreates the perf. counters if they don't exist
        ''' </summary>
        ''' <param name="recreate"></param>
        ''' <remarks></remarks>
        Public Shared Sub SetupCalculationsCounters(ByVal recreate As Boolean)

            If PerformanceCounterCategory.Exists(CollectionSettings.CalculationMetricsCollectionName) = False Or recreate = True Then

                Dim AvgCalcsProductRetrieval As New CounterCreationData(CounterSettings.AvgProductRetrievalTimeCounterName, _
                                                                        CounterSettings.AvgProductRetrievalTimeCounterHelp, _
                                                                        CounterSettings.AvgProductRetrievalTimeCounterType)

                Dim TotalCalcsProductRetrievalRequests As New CounterCreationData(CounterSettings.TotalRequestsCounterName, _
                                                                                  CounterSettings.AvgProductRetrievalTimeCounterHelp, _
                                                                                  CounterSettings.TotalRequestsCounterType)

                Dim CounterData As New CounterCreationDataCollection()

                ' Add counters to the collection.
                CounterData.Add(AvgCalcsProductRetrieval)
                CounterData.Add(TotalCalcsProductRetrievalRequests)

                If recreate = True Then
                    If PerformanceCounterCategory.Exists(CollectionSettings.CalculationMetricsCollectionName) = True Then
                        PerformanceCounterCategory.Delete(CollectionSettings.CalculationMetricsCollectionName)
                    End If
                End If

                If PerformanceCounterCategory.Exists(CollectionSettings.CalculationMetricsCollectionName) = False Then
                    PerformanceCounterCategory.Create(CollectionSettings.CalculationMetricsCollectionName, CollectionSettings.CalculationMetricsDescription, _
                                                  PerformanceCounterCategoryType.SingleInstance, CounterData)
                End If

            End If

            _AvgRetrieval = New PerformanceCounter(CollectionSettings.CalculationMetricsCollectionName, CounterSettings.AvgProductRetrievalTimeCounterName, False)
            _TotalRequests = New PerformanceCounter(CollectionSettings.CalculationMetricsCollectionName, CounterSettings.TotalRequestsCounterName, False)
            _ManagerInitialized = True

        End Sub

        Public Shared ReadOnly Property CategoryName() As String
            Get
                Return CollectionSettings.CalculationMetricsCollectionName
            End Get
        End Property

        ''' <summary>
        ''' Determines if the performance counters have been initialized
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared ReadOnly Property ManagerInitializaed() As Boolean
            Get
                Return _ManagerInitialized
            End Get
        End Property

        Public Shared ReadOnly Property AvgRetrieval() As PerformanceCounter
            Get
                Return _AvgRetrieval
            End Get
        End Property

        Public Shared ReadOnly Property TotalRequests() As PerformanceCounter
            Get
                Return _TotalRequests
            End Get
        End Property

        ''' <summary>
        ''' Initializes the Average Retrieval Time counter by starting a stopwatch
        ''' </summary>
        ''' <remarks></remarks>
        Public Shared Sub BeginIncrementAvgRetrieval()

            If _SW Is Nothing Then
                _SW = New Stopwatch
            End If

            _SW.Start()

        End Sub

        ''' <summary>
        ''' Increments the Average Retrieval Time counter by stopping the stopwatch and changing the
        ''' raw value of the perf counter.
        ''' </summary>
        ''' <remarks></remarks>
        Public Shared Sub EndIncrementAvgRetrieval(ByVal resetStopwatch As Boolean, ByVal outputToTrace As Boolean)
            _SW.Stop()
            _AvgRetrieval.RawValue = CLng(_SW.ElapsedMilliseconds)
            If outPutToTrace = True Then
                Trace.WriteLine(_AvgRetrieval.NextValue.ToString)
            End If
            If resetStopwatch = True Then
                _SW.Reset()
            End If
        End Sub

        ''' <summary>
        ''' Increments the total requests counter
        ''' </summary>
        ''' <remarks></remarks>
        Public Shared Sub IncrementTotalRequests()
            _TotalRequests.IncrementBy(1)
        End Sub

        Public Shared Sub DeleteAll()
            If PerformanceCounterCategory.Exists(CollectionSettings.CalculationMetricsCollectionName) = True Then
                PerformanceCounterCategory.Delete(CollectionSettings.CalculationMetricsCollectionName)
            End If
        End Sub

    End Class
End Namespace
+3  A: 

Yes, it’s not possible. You can’t add privileges to the worker process without opening the server up to potential security / DOS problems in a production environment. An installer (like a MSI) usually runs with elevated permissions, and installs / uninstalls the performance counter categories and counters as well as other locked down objects.

For example, Windows Installer XML (WiX) has support for Performance Counters...

George Tsiokos