Windows Azure Diagnostics: Initializing the Configuration and Using a Configuration File

Exclusive offer: get 50% off this eBook here
Microsoft Windows Azure Development Cookbook

Microsoft Windows Azure Development Cookbook — Save 50%

Over 80 advanced recipes for developing scalable services with the Windows Azure platform with this Microsoft Azure book and eBook

$29.99    $15.00
by Neil Mackenzie | August 2011 | Cookbooks Enterprise Articles Microsoft

The default configuration for Windows Azure Diagnostics captures some data but does not persist it. Consequently, the diagnostics configuration should be modified at role startup. In this article by Neil Mackenzie, author of Microsoft Windows Azure Development Cookbook, the Initializing the configuration of Windows Azure Diagnostics recipe, shows us how to do this programmatically, which is the normal way to do it. In the Using a configuration file with Windows Azure Diagnostics recipe, we see how to use a configuration file to do this, which is necessary in a VM role.

 

Microsoft Windows Azure Development Cookbook

Microsoft Windows Azure Development Cookbook

Over 80 advanced recipes for developing scalable services with the Windows Azure platform

        Read more about this book      

(For more resources on this subject, see here.)

The implementation of Windows Azure Diagnostics was changed in Windows Azure SDK v1.3 and it is now one of the pluggable modules that have to be explicitly imported into a role in the service definition file. As Windows Azure Diagnostics persists both its configuration and data to Windows Azure storage, it is necessary to specify a storage service account for diagnostics in the service configuration file. The configuration of Windows Azure Diagnostics is performed at the instance level. The code to do that configuration is at the role level, but the diagnostics configuration for each instance is stored in individual blobs in a container named wad-control-container located in the storage service account configured for Windows Azure Diagnostics.

Initializing the configuration of Windows Azure Diagnostics

The Windows Azure Diagnostics module is imported into a role by the specification of an Import element with a moduleName attribute of Diagnostics in the Imports section of the service definition file (ServiceDefinition.csdef). This further requires the specification, in the service configuration file (ServiceConfiguration.cscfg), of a Windows Azure Storage Service account that can be used to access the instance configuration for diagnostics. This configuration is stored as an XML file in a blob, named for the instance, in a container named wad-control-container in the storage service account configured for diagnostics.

The Diagnostics Agent service is started automatically when a role instance starts provided the diagnostics module has been imported into the role. Note that in Windows Azure SDK versions prior to v1.3, this is not true in that the Diagnostics Agent must be explicitly started through the invocation of DiagnosticMonitor.Start().

On instance startup, the diagnostics configuration for the instance can be set as desired in the overridden RoleEntryPoint.OnStart() method. The general idea is to retrieve the default initial configuration using DiagnosticMonitor.GetDefaultInitialConfiguration() and modify it as necessary before saving it using DiagnosticMonitor.Start(). This name is something of a relic, since Windows Azure SDK v1.3 and later, the Diagnostics Agent service is started automatically.

Another way to modify the diagnostics configuration for the instance is to use RoleInstanceDiagnosticManager.GetCurrentConfiguration() to retrieve the existing instance configuration from wad-control-container. This can be modified and then saved using RoleInstanceDiagnosticManager.SetCurrentConfiguration(). This method can be used both inside and outside the role instance. For example, it can be implemented remotely to request that an on-demand transfer be performed. An issue is that using this technique during instance startup violates the principal that the environment on startup is always the same, as the existing instance configuration may already have been modified. Note that it is not possible to modify the diagnostics configuration for an instance if there is a currently active on-demand transfer.

In this recipe, we will learn how to initialize programmatically the configuration of Windows Azure Diagnostics.

How to do it...

We are going to see how to initialize the configuration for Windows Azure Diagnostics using code. We do this as follows:

  1. Use Visual Studio to create an empty cloud project.
  2. Add a web role to the project (accept the default name of WebRole1).
  3. Add the following assembly reference to the project:

    System.Data.Services.Client

  4. In the WebRole class, replace OnStart() with the following:

    public override bool OnStart()
    {
    WadManagement wadManagement = new WadManagement();
    wadManagement.InitializeConfiguration();

    return base.OnStart();
    }

  5. In the Default.aspx file, replace the asp:Content element named BodyContent with the following:

    <asp:Content ID="BodyContent" runat="server"
    ContentPlaceHolderID="MainContent">
    <div id="xmlInner">
    <pre>
    <asp:label id="xmlLabel" runat="server"/>
    </pre>
    </div>
    </asp:Content>

  6. Add the following using statements to the Default.aspx.cs file:

    using Microsoft.WindowsAzure.ServiceRuntime;

  7. In the Default.aspx.cs file, add the following private members to the _Default class:

    private String deploymentId = RoleEnvironment.DeploymentId;
    private String roleName =
    RoleEnvironment.CurrentRoleInstance.Role.Name;
    private String instanceId =
    RoleEnvironment.CurrentRoleInstance.Id;

  8. In the Default.aspx.cs file, replace Page_Load() with the following:

    protected void Page_Load(object sender, EventArgs e)
    {
    WadManagement wad = new WadManagement();
    String wadConfigurationForInstance =
    wad.GetConfigurationBlob(
    deploymentId, roleName, instanceId);
    xmlLabel.Text =
    Server.HtmlEncode(wadConfigurationForInstance);
    }

  9. Add a class named WadManagement to the project.
  10. Add the following using statements to the WadManagement class:

    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.Diagnostics;
    using Microsoft.WindowsAzure.Diagnostics.Management;
    using Microsoft.WindowsAzure.ServiceRuntime;
    using Microsoft.WindowsAzure.StorageClient;

  11. Add the following private members to the WadManagement class:

    private String wadConnectionString =
    "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString";
    private String wadControlContainerName =
    "wad-control-container";
    private CloudStorageAccount cloudStorageAccount;

  12. Add the following constructor to the WadManagement class:

    public WadManagement()
    {
    cloudStorageAccount = CloudStorageAccount.Parse(
    RoleEnvironment.GetConfigurationSettingValue(
    wadConnectionString));
    }

  13. Add the following methods, retrieving the instance configuration blob from Windows Azure Storage, to the WadManagement class:

    public String GetConfigurationBlob(
    String deploymentId, String roleName, String instanceId)
    {
    DeploymentDiagnosticManager deploymentDiagnosticManager =
    new DeploymentDiagnosticManager(
    cloudStorageAccount, deploymentId);

    String wadConfigurationBlobNameForInstance =
    String.Format("{0}/{1}/{2}", deploymentId, roleName,
    instanceId);
    String wadConfigurationForInstance =
    GetWadConfigurationForInstance(
    wadConfigurationBlobNameForInstance);

    return wadConfigurationForInstance;
    }

    private String GetWadConfigurationForInstance(
    String wadConfigurationInstanceBlobName)
    {
    CloudBlobClient cloudBlobClient =
    cloudStorageAccount.CreateCloudBlobClient();
    CloudBlobContainer cloudBlobContainer =
    cloudBlobClient.GetContainerReference(
    wadControlContainerName);
    CloudBlob cloudBlob = cloudBlobContainer.GetBlobReference(
    wadConfigurationInstanceBlobName);

    String wadConfigurationForInstance =
    cloudBlob.DownloadText();

    return wadConfigurationForInstance;
    }

  14. Add the following method, initializing the configuration of Windows Azure Diagnostics, to the WadManagement class:

    public void InitializeConfiguration()
    {
    String eventLog = "Application!*";
    String performanceCounter =
    @"\Processor(_Total)\% Processor Time";

    DiagnosticMonitorConfiguration dmc =
    DiagnosticMonitor.GetDefaultInitialConfiguration();

    dmc.DiagnosticInfrastructureLogs.BufferQuotaInMB = 100;
    dmc.DiagnosticInfrastructureLogs.ScheduledTransferPeriod =
    TimeSpan.FromHours(1);
    dmc.DiagnosticInfrastructureLogs.
    ScheduledTransferLogLevelFilter = LogLevel.Verbose;

    dmc.WindowsEventLog.BufferQuotaInMB = 100;
    dmc.WindowsEventLog.ScheduledTransferPeriod =
    TimeSpan.FromHours(1);
    dmc.WindowsEventLog.ScheduledTransferLogLevelFilter =
    LogLevel.Verbose;
    dmc.WindowsEventLog.DataSources.Add(eventLog);

    dmc.Logs.BufferQuotaInMB = 100;
    dmc.Logs.ScheduledTransferPeriod = TimeSpan.FromHours(1);
    dmc.Logs.ScheduledTransferLogLevelFilter =
    LogLevel.Verbose;

    dmc.Directories.ScheduledTransferPeriod =
    TimeSpan.FromHours(1);

    PerformanceCounterConfiguration perfCounterConfiguration
    = new PerformanceCounterConfiguration();
    perfCounterConfiguration.CounterSpecifier =
    performanceCounter;
    perfCounterConfiguration.SampleRate =
    System.TimeSpan.FromSeconds(10);
    dmc.PerformanceCounters.DataSources.Add(
    perfCounterConfiguration);
    dmc.PerformanceCounters.BufferQuotaInMB = 100;
    dmc.PerformanceCounters.ScheduledTransferPeriod =
    TimeSpan.FromHours(1);

    DiagnosticMonitor.Start(cloudStorageAccount, dmc);
    }

How it works...

In steps 1 and 2, we create a cloud project with a web role. We add the required assembly reference in step 3.

In step 4, we modify OnStart(), so that it initializes the configuration of Windows Azure Diagnostics.

In step 5, we modify the default web page, so that it displays the content of the blob storing the instance configuration for Windows Azure Diagnostics. In step 6, we add the required using statement to Default.aspx.cs. In step 7, we add some private members to store the deployment ID, the role name, and the instance ID of the current instance. In step 8, we modify the Page_Load() event handler to retrieve the blob content and display it on the default web page.

In step 9, we add the WadManagement class that interacts with the Windows Azure Blob Service. In step 10, we add the required using statements. In step 11, we add some private members to contain the name of the connection string in the service configuration file, and the name of the blob container containing the instance configuration for Windows Azure Diagnostics. We also add a CloudStorageAccount instance, which we initialize in the constructor we add in step 12.

We then add, in step 13, the two methods we use to retrieve the content of the blob containing the instance configuration for Windows Azure Diagnostics. In GetConfigurationBlob(), we first create the name of the blob. We then pass this into the GetWadConfigurationForInstance() method, which invokes various Windows Azure Storage Client Library methods to retrieve the content of the blob.

In step 14, we add the method to initialize the configuration of Windows Azure Diagnostics for the instance. We first specify the names of the event log and performance counter we want to capture and persist. We then retrieve the default initial configuration and configure capture of the Windows Azure infrastructure logs, Windows Event Logs, basic logs, directories, and performance counters. For each of them, we specify a data buffer size of 100 MB and schedule an hourly transfer of logged data.

For Windows Event Logs, we specify that the Application!* event log should be captured locally and persisted to the storage service. The event log is specified using an XPath expression allowing the events to be filtered, if desired. We can add other event logs if desired. We configure the capture and persistence of only one performance counter—the \Processor(_Total)\% Processor Time. We can add other performance counters if desired. Two sections at the end of this recipe provide additional details on the configuration of event logs and performance counters.

We specify a transfer schedule for the directories data buffer. The Diagnostics Agent automatically inserts special directories into the configuration: crash dumps for all roles, and IIS logs and IIS failed request logs for web roles. The Diagnostics Agent does this because the actual location of the directories is not known until the instance is deployed. Note that even though we have configured a persistence schedule for crash dumps, they are not captured by default. We would need to invoke the CrashDumps.EnableCollection() method to enable the capture of crash dumps.

Microsoft Windows Azure Development Cookbook Over 80 advanced recipes for developing scalable services with the Windows Azure platform with this Microsoft Azure book and eBook
Published: August 2011
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on this subject, see here.)

There's more...

We can also modify an existing diagnostics configuration for an instance. We do this by adding the following method to WadManagement class, and then invoking it in the same way we invoked InitializeConfiguration():

public void ModifyConfiguration(
String deploymentId, String roleName, String instanceId)
{
String eventLog =
@"Application!*[System[Provider[@Name='.NET Runtime']]]";
String performanceCounter = @"\ASP.NET\Requests Rejected";

RoleInstanceDiagnosticManager ridm =
cloudStorageAccount.CreateRoleInstanceDiagnosticManager(
deploymentId, roleName, instanceId);
DiagnosticMonitorConfiguration dmc =
ridm.GetCurrentConfiguration();

Int32 countDataSources =
dmc.WindowsEventLog.DataSources.Count(
item => item == eventLog);
if (countDataSources == 0)
{
dmc.WindowsEventLog.DataSources.Add(eventLog);
dmc.WindowsEventLog.ScheduledTransferPeriod =
TimeSpan.FromHours(1);
}

countDataSources =
dmc.PerformanceCounters.DataSources.Count(
item => item.CounterSpecifier == performanceCounter);
if (countDataSources == 0)
{
PerformanceCounterConfiguration perfConfiguration =
new PerformanceCounterConfiguration()
{
CounterSpecifier = performanceCounter,
SampleRate = System.TimeSpan.FromHours(1)
};
dmc.PerformanceCounters.DataSources.Add(
perfConfiguration);
}

IDictionary<DataBufferName, OnDemandTransferInfo>
activeTransfers = ridm.GetActiveTransfers();
if (activeTransfers.Count == 0)
{
ridm.SetCurrentConfiguration(dmc);
}
}

This method can be used locally inside a role, or remotely, to modify the diagnostics configuration for the instance identified by the deploymentId, roleName, and instanceId with which the method is parameterized.

If the method is invoked remotely from an application, then the code to create the CloudStorageAccount must be modified to the following:

CloudStorageAccount cloudStorageAccount =
CloudStorageAccount.Parse(
ConfigurationManager.AppSettings["DataConnectionString"]);

This assumes that DataConnectionString specified in the following canonical format is an app.config file setting:

<Setting name="DataConnectionString"
value="DefaultEndpointsProtocol=http;AccountName=ACCOUNT;AccountK
ey=KEY" />

We also need to add an assembly reference to System.configuration.dll and the related using statement.

In the method, we initialize variables to specify the Windows Event Log and the performance counter we wish to configure. Note that we use an XPath expression to filter the event log to persist only events coming from the .NET Runtime source.

We create a RoleInstanceDiagnosticManager object for the instance and use it to retrieve its DiagnosticMonitorConfiguration. Having ensured that we have not already added the event log and performance counter, we add them to the diagnostics configuration for the instance.

Finally, we invoke RoleInstanceDiagnosticManager.SetCurrentConfiguration() to save the modified configuration to the diagnostics configuration for the instance stored in wad-control-container. We save the configuration only if there is no active on-demand transfer, as SetCurrentConfiguration() throws an exception if an on-demand transfer is in progress.

Configuring the Event Log data buffer

An XPath expression can be used to filter the Windows Event Log events that Windows Azure Diagnostics persists to WADWindowsEventLogsTable table. This recipe contains the following two examples of the filter expression:

  1. Application!*
  2. Application!*[System[Provider[@Name='.NET Runtime']]]

The first persists all events, while the second persists only those events from the .NET Runtime source.

Steve Marx has written a blog post in which he shows how to use the Event Viewer to generate a filter expression at the following URL:

http://blog.smarx.com/posts/capturing-filtered-windows-events-with-windows-azure-diagnostics

Configuring the performance counter data buffer

There are a large number of performance counters which Windows Azure Diagnostics can capture and persist to the WADPerformanceCountersTable table. It is also possible to add custom performance counters to an instance. The typeperf command can be used at the command prompt to generate a list of available performance counters. The following lists all performance counters on the current system:

C:\Users\Administrator>typeperf -q

The following command filters the list to only those performance counters for the ASP.NET object:

C:\Users\Administrator>typeperf -q ASP.NET

Note that there are also performance counters for objects, such as ASP.NET Applications.

Microsoft Windows Azure Development Cookbook Over 80 advanced recipes for developing scalable services with the Windows Azure platform with this Microsoft Azure book and eBook
Published: August 2011
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on this subject, see here.)

Using a configuration file with Windows Azure Diagnostics

Windows Azure Diagnostics stores the diagnostics configuration for an instance as an XML file in a blob, named for the instance, in a container named wad-control-container in the Windows Azure Storage Service account configured for diagnostics. When an instance is started for the first time, a default instance configuration is inserted in the container. This can be modified programmatically, either local to the instance or remotely using methods in the Windows Azure SDK.

Local configuration typically occurs in the OnStart() method for the role and is used to further specify the information captured by Windows Azure Diagnostics and the schedule with which diagnostic data is persisted in the Windows Azure Storage Service. By default, some diagnostics data is captured, but none of it is persisted to the storage service. Remote configuration can also be used to modify the information captured. However, it is used normally to initiate an on-demand transfer of data from an instance when a problem must be investigated before the next scheduled transfer of data to the storage service.

Windows Azure SDK v1.3 introduced a way to specify declaratively the initial configuration of Windows Azure Diagnostics for a role. This requires the placement of a file, named diagnostics.wadcfg, in a specific location in the role package. When an instance is started for the first time, the Diagnostic Agent reads the file and initializes the diagnostic configuration for the instance in wad-control-container with it, instead of using the default configuration.

During instance startup, the Diagnostics Agent uses the following sequence to search for a diagnostics configuration to use:

  1. Diagnostic configuration for the instance in wad-control-container.
  2. Configuration specified programmatically when the instance is started.
  3. Configuration specified in diagnostics.wadcfg.
  4. Default configuration.

The physical location of diagnostics.wadcfg in a hosted service depends on the role type. For a worker role, the location is %RoleRoot% while for a web role, the location is %RoleRoot%\bin. For a VM role, diagnostics.wadcfg must be in the following directory in the uploaded Guest OS image:

%ProgramFiles%\Windows Azure Integration Components\v1.0\Diagnostics

The information contained in diagnostics.wadcfg mirrors that stored in the instance configuration in wad-control-container and exposed through the DiagnosticsMonitorConfiguration class in the Windows Azure SDK.

The intended use of the diagnostics.wadcfg file is in situations where programmatic configuration is not possible. The primary use case is in a VM role where there is no RoleEntryPoint and no OnStart() method in which to perform programmatic configuration. Another example is when special logging is required during a startup task.

In this recipe, we will learn how to configure Windows Azure Diagnostics using the diagnostics.wadcfg file.

How to do it...

We are going to see how to use a configuration file to configure Windows Azure Diagnostics. We do this as follows:

  1. Create a diagnostics.wadcfg file in the root directory of the role.
  2. In the Visual Studio Properties for the diagnostics.wadcfg file, set the Build Action to Content and the Copy to Output Directory to Copy Always.
  3. Insert the following root element in the file:

    <DiagnosticMonitorConfiguration
    xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/
    DiagnosticsConfiguration"
    configurationChangePollInterval="PT1M"
    overallQuotaInMB="4096" />

  4. Insert the following as a child element of the DiagnosticMonitorConfiguration element:

    <DiagnosticInfrastructureLogs
    bufferQuotaInMB="100"
    scheduledTransferLogLevelFilter="Verbose"
    scheduledTransferPeriod="PT1H"/>

  5. Insert the following as a child element of the DiagnosticMonitorConfiguration element:

    <WindowsEventLog
    bufferQuotaInMB="100"
    scheduledTransferLogLevelFilter="Verbose"
    scheduledTransferPeriod="PT1H">
    <DataSource name="Application!*"/>
    </WindowsEventLog>

  6. Insert the following as a child element of the DiagnosticMonitorConfiguration element:

    <Logs
    bufferQuotaInMB="100"
    scheduledTransferLogLevelFilter="Verbose"
    scheduledTransferPeriod="PT1H"/>

  7. Insert the following as a child element of the DiagnosticMonitorConfiguration element:

    <Directories
    bufferQuotaInMB="1024"
    scheduledTransferPeriod="PT1H">
    <CrashDumps container="wad-crash-dumps"
    directoryQuotaInMB="256"/>
    <FailedRequestLogs container="wad-frq"
    directoryQuotaInMB="256"/>
    <IISLogs container="wad-iis-test"
    directoryQuotaInMB="256"/>

    <DataSources>
    <DirectoryConfiguration
    container="wad-custom"
    directoryQuotaInMB="20">
    <LocalResource name="CustomLoggingLocation"
    relativePath="Logs"/>
    </DirectoryConfiguration>
    </DataSources>
    </Directories>

  8. Insert the following as a child element of the DiagnosticMonitorConfiguration element:

    <PerformanceCounters
    bufferQuotaInMB="100" scheduledTransferPeriod="PT20M">
    <PerformanceCounterConfiguration
    counterSpecifier="\Processor(_Total)\% Processor Time"
    sampleRate="PT10S"/>
    </PerformanceCounters>

  9. Add the following as a child element of the WebRole or WorkerRole element in the service definition file, ServiceDefinition.csdef:

    <LocalResources>
    <LocalStorage name="CustomLoggingLocation"
    sizeInMB="20" cleanOnRoleRecycle="false"/>
    </LocalResources>

How it works...

In steps 1 and 2, we create the diagnostics.wadcfg file and set the Visual Studio build action. The appropriate location for the file depends on the role. The Visual Studio tooling ensures that the file is copied to the correct location when the project is built.

In step 3, we create the root element of the file and set the maximum size of the diagnostics data buffer to 4 GB. The configurationChangePollInterval specifies the interval at which the Diagnostics Agent polls the storage service for diagnostic configuration changes. This is provided in ISO 8601 format. For example, with a configurationChangePollInterval of PT1M, the P indicates duration, the T indicates time, and the 1M indicates one minute. The same format is used for other intervals and periods in the configuration file.

In step 4, we configure the diagnostics infrastructure logs into which the Diagnostic Agent logs data about itself. We specify that this data is stored locally in a 100 MB data buffer and that the information is persisted to the storage service once an hour (PT1H). We also filter the persistence of data, so that all events with a level of verbose or higher are transferred.

In step 5, we configure the capture and persistence of the Windows Event Logs. We specify that all verbose or higher events in the Application event log should be transferred once an hour. We can add more DataSource elements to specify the capture and persistence of additional Windows Event Logs. In step 6, we configure the capture and persistence of basic logs from the Windows Azure Diagnostics trace listener.

In step 7, we configure the capture and persistence of data located in directories on the local file system. For crash dumps, failed (IIS) request logs, and IIS logs, we specify the Windows Azure Blob Service container in which the data is persisted, but we don't specify the directory in which the data is located because that is not known until the hosted service starts. The Diagnostics Agent fixes the configuration of these logs when it writes the diagnostics configuration for the instance to wad-control-container.

For custom directories, we must specify the name of a local resource, configured in the service definition file, where we write the logs to. We use the relativePath attribute to specify a directory under the root path of the local resource. We also specify the Windows Azure Blob Service container into which the logs are persisted. We can add more DirectoryConfiguration elements to specify the capture and persistence of files in other directories.

In step 8, we configure the capture and persistence of performance counters data. We specify that the % processor time should be captured every 10 seconds (PT10S) and persisted to the storage service once an hour. We can add more PerformanceCounterConfiguration elements to specify the capture and persistence of other performance counters.

In step 9, we add the definition for the local resource, used in custom logging, to the service definition file.

There's more...

Andy Cross has written a blog post in which he describes how to perform XML validation on the diagnostics.wadcfg file at the following URL:

http://blog.bareweb.eu/2011/02/file-based-diagnostics-config-with-intellisense-in-azure-sdk-1-3/

Summary

In this article we covered:

  • Initializing the configuration of Windows Azure Diagnostics
  • Using a configuration file with Windows Azure Diagnostics

Further resources on this subject:


About the Author :


Neil Mackenzie

Neil Mackenzie has worked with computers for nearly three decades. He started his computer career doing large-scale numerical simulations for scientific research and business planning. Since then, he has been involved primarily in healthcare software, developing electronic medical records systems. He has been using Windows Azure since PDC 2008 and has used nearly all parts of the Windows Azure platform – including those that no longer exist. Neil is very active in the online Windows Azure community – in particular, helping to solve many of the questions raised in the MSDN Windows Azure Forums. He is a Microsoft MVP for Windows Azure.

Books From Packt


Microsoft SQL Azure Enterprise Application Development
Microsoft SQL Azure Enterprise Application Development

Getting Started with Microsoft Application Virtualization 4.6
Getting Started with Microsoft Application Virtualization 4.6

Microsoft Azure: Enterprise Application Development
Microsoft Azure: Enterprise Application Development

Applied Architecture Patterns on the Microsoft Platform
Applied Architecture Patterns on the Microsoft Platform

Microsoft Windows Communication Foundation 4.0 Cookbook for Developing SOA Applications
Microsoft Windows Communication Foundation 4.0 Cookbook for Developing SOA Applications

Microsoft Silverlight 4 and Windows Azure Enterprise Integration: RAW
Microsoft Silverlight 4 and Windows Azure Enterprise Integration: RAW

Microsoft SharePoint 2010 and Windows PowerShell 2.0: Expert Cookbook
Microsoft SharePoint 2010 and Windows PowerShell 2.0: Expert Cookbook

Least Privilege Security for Windows 7, Vista and XP
Least Privilege Security for Windows 7, Vista and XP


No votes yet
Try article by
I really liked the article, and the very cool blog

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
7
M
P
M
C
w
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software