Exercise 1: Debugging an Application in the Cloud
Because Windows Azure Diagnostics is oriented towards operational monitoring and has to cater for gathering information from multiple role instances, it requires that diagnostic data first be transferred from local storage in each role to Windows Azure storage, where it is aggregated. This requires programming scheduled transfers with the diagnostic monitor to copy logging data to Windows Azure storage at regular intervals, or else requesting a transfer of the logs on-demand. Moreover, information obtained in this manner provides a snapshot of the diagnostics data available at the time of the transfer. To retrieve updated data, a new transfer is necessary. When debugging a single role, and especially during the development phase, these actions add unnecessary friction to the process. To simplify the retrieval of diagnostics data from a deployed role, it is simpler to read information directly from Windows Azure storage, without requiring additional steps.
In this exercise, you debug a simple application by configuring a special trace listener that can write its output directly into a table in Windows Azure storage emulator. To produce diagnostic data, you instrument the application to write its trace information using standard methods in the System.Diagnostics namespace. Finally, you create a simple log viewer application that can retrieve and display the contents of the diagnostics table.
The application that you will use for this exercise simulates an online auto insurance policy calculator. It has a single form where users can enter details about their vehicle and then submit the form to obtain an estimate on their insurance premium. Behind the scenes, the controller action that processes the form uses a separate assembly to calculate premiums based on the input from the user. The assembly contains a bug that causes it to raise an exception for input values that fall outside the expected range.
Task 1 – Exploring the Fabrikam Insurance Application
In this task, you build and run the Fabrikam Insurance application in the Web Development Server to become familiar with its operation.
- Open Visual Studio in elevated administrator mode from Start | All Programs | Microsoft Visual Studio 2010 by right clicking the Microsoft Visual Studio 2010 shortcut and choosing Run as administrator.
- If the User Account Control dialog appears, click Continue.
- In the File menu, choose Open and then Project/Solution. In the Open Project dialog, browse to Ex1-LoggingToAzureStorage in the Source folder of the lab and choose the folder for the language of your preference (Visual C# or Visual Basic). Select Begin.sln in the Begin folder and then click Open.
Set the start action of the project. To do this, in Solution Explorer, right-click the FabrikamInsurance project and then select Properties. In the properties window, switch to the Web tab and then, under Start Action, select the Specific Page option. Leave the page value blank.
Figure 1
Configuring the start action of the project
- Press F5 to build and run the solution. The application should launch in the Web Development Server and open its Auto Insurance Quotes page in your browser.
To explore its operation, complete the form by choosing any combination of values from the Vehicle Details drop down lists and then click Calculate to obtain a quote for the insurance premium. Notice that after you submit the form, the page refreshes and shows the calculated amount.
Figure 2
Exploring the Fabrikam Insurance application
- Press SHIFT + F5 to stop debugging and shut down the application.
Task 2 – Running the Application as a Windows Azure Project
In this task, you create a new Windows Azure Project to prepare the application for deployment to Windows Azure.
Add a new Windows Azure Project to the solution. To do this, in the File menu, point to Add and then select New Project. In the AddNew Project dialog, expand the language of your preference (Visual C# or Visual Basic) in the Installed Templates list and then select Cloud. Choose the Windows Azure Project template, set the Name of the project to FabrikamInsuranceService and accept the proposed location in the folder of the solution. Click OK to create the project.
Figure 3
Creating a new Windows Azure Project (C#)
Figure 4
Creating a new Windows Azure Project (Visual Basic)
- In the New Windows Azure Project dialog, click OK without adding any new roles to the solution.
Now, in Solution Explorer, right-click the Roles node in the new FabrikamInsuranceService project, point to Add, and then select Web Role Project in solution. Then, in the Associate with Role Project dialog, select the FabrikamInsurance project, and click OK.
Figure 5
Associating the MVC application with the Windows Azure Project
Add references to the Windows Azure support assemblies. To do this, in Solution Explorer, right-click the FabrikamInsurance project, and then select Add Reference. In the Add Reference dialog, switch to the .NET tab, select the Microsoft.WindowsAzure.Diagnostics, Microsoft.WindowsAzure.ServiceRuntime, and Microsoft.WindowsAzure.StorageClient components, and then click OK.
Figure 6
Adding references to the Windows Azure support assemblies to the project
Now, add a role entry point to the MVC application. To do this, in Solution Explorer, right-click the FabrikamInsurance project, point to Add, and then select Existing Item. In the Add Existing Item dialog, browse to Assets in the Source folder of the lab. Inside this folder, choose the folder for the language of your project (Visual C# or Visual Basic), select WebRole.cs or WebRole.vb, and then click Add.
The WebRole class is a RoleEntryPoint derived class that contains methods that Windows Azure calls when it starts, runs, or stops the role. The provided code is the same that Visual Studio generates when you create a new Windows Azure Project.
- You are now ready to test the Windows Azure Project application. To launch the application in the compute emulator, press F5. Wait until the deployment completes and the browser opens to show its main page.
- Again, complete the entry form by choosing a combination of values from the drop down lists and then click Calculate. Ensure that you receive a valid response with the calculated premium as a result.
Once you have verified that everything works in the compute emulator just as it did when hosted by the Web Development Server, you will now cause an exception by making the application process bad data that it does not handle correctly. To do this, change the values used for the calculation by setting the Make to “PORSCHE” and the Model to “BOXSTER (BAD DATA)”.
Figure 7
Choosing make and model for the insurance premium calculation
Click Calculate to re-submit the form with new values. Notice that an unhandled exception occurs and execution halts in the Visual Studio debugger at the line that caused the error.
Figure 8
Unhandled exception in the application caused by bad data
Within the Visual Studio debugger, you are able to step through code, set breakpoints, and examine the value of program variables. Debugging applications hosted in the compute emulator provides the same experience that you typically have when debugging other programs to which you can attach the Visual Studio debugger. Using the debugger under these conditions is covered extensively and will not be explored here. For more information, see Debugging in Visual Studio.
Press F5 to continue execution and let ASP.NET handle the exception. Notice that the unhandled exception handler provides details about the exception, including the line in the source code that raised the exception.
Figure 9
ASP.NET default unhandled exception handler
Unhandled exceptions are typically handled by ASP.NET, which can report the error in its response including details about an error and the location in the source code where the exception was raised. However, for applications that are available publicly, exposing such information is not recommended to prevent unnecessary disclosure of internal details about the application that may compromise its security. Instead, errors and other diagnostics output should be written to a log that can only be retrieved after proper authorization.
You can configure how information is displayed by ASP.NET when an unhandled error occurs during the execution of a Web request. For more information, see customErrors Element (ASP.NET Settings Schema).
In this case, the unhandled exception error page includes full details for the error because the default mode for the customErrors element is remoteOnly and you are accessing the page locally. When you deploy the application to the cloud and access it remotely, the page shows a generic error message instead.
- Press SHIFT + F5 to stop debugging and shut down the application.
Task 3 – Adding Tracing Support to the Application
In the previous task, you briefly saw how to debug your application with Visual Studio when it executes locally in the compute emulator. To debug the application once you deploy it to the cloud, you need to write debugging information to the logs in order to diagnose an application failure.
In this task, you add a TraceListener to the project capable of logging diagnostics data directly into table storage, where you can easily retrieve it with a simple query. The source code for this project is already provided for you in the Assets folder of the lab. More information on the Trace Listener can be found here: https://msdn.microsoft.com/en-us/library/system.diagnostics.tracelistener.aspx
- In Solution Explorer, right-click the Begin solution, point to Add and then select Existing Project. In the Add Existing Project dialog, browse to Assets in the Source folder of the lab, select the folder for the language of your choice (Visual C# or Visual Basic), then navigate to AzureDiagnostics inside this folder, select the AzureDiagnostics project file and click Open.
- Add a reference to the AzureDiagnostics library in the web role project. To do this, in Solution Explorer, right-click the FabrikamInsurance project, and select Add Reference. In the Add Reference dialog, switch to the Projects tab, select AzureDiagnostics in the list of projects, and then click OK.
Open Global.asax.cs (for Visual C# projects) or Global.asax.vb (for Visual Basic projects) in the FabrikamInsurance project and insert the following namespace directives.
using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime;
Imports Microsoft.WindowsAzure Imports Microsoft.WindowsAzure.ServiceRuntime
Add the following (highlighted) method inside the MvcApplication class.
(Code Snippet – WindowsAzureDebugging-Ex1-ConfigureTraceListener-CS)
public class MvcApplication : System.Web.HttpApplication
FakePre-0d86649541894dcd9039541964017590-de453e7298e6424b88e124e27dd6a9f0FakePre-5b8a2a8f82a64075bb2fecc1dff85545-00116282c3214878a02f9ec9fc8a088e private static void ConfigureTraceListener() { bool enableTraceListener = false; string enableTraceListenerSetting = RoleEnvironment.GetConfigurationSettingValue("EnableTableStorageTraceListener"); if (bool.TryParse(enableTraceListenerSetting, out enableTraceListener)) { if (enableTraceListener) { AzureDiagnostics.TableStorageTraceListener listener = new AzureDiagnostics.TableStorageTraceListener("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString") { Name = "TableStorageTraceListener" }; System.Diagnostics.Trace.Listeners.Add(listener); System.Diagnostics.Trace.AutoFlush = true; } else { System.Diagnostics.Trace.Listeners.Remove("TableStorageTraceListener"); } } }FakePre-4535165d35f44bb299ef77796f4e1118-fb9c2c77a20a4cb7bd7f5d7bb55c5eaf
(Code Snippet – WindowsAzureDebugging-Ex1-ConfigureTraceListener-VB)
Public Class MvcApplication
FakePre-d227ea109f8e47d8942bc622aa887eb0-0982a782debc4562a5ddf4f75fd2deeaFakePre-be0d2351935941fd991615044a99f91c-c4588a05f22b41db90b2dfaecbc5c4c1 Private Shared Sub ConfigureTraceListener() Dim enableTraceListener As Boolean = False Dim enableTraceListenerSetting As String = RoleEnvironment.GetConfigurationSettingValue("EnableTableStorageTraceListener") If Boolean.TryParse(enableTraceListenerSetting, enableTraceListener) Then If enableTraceListener Then Dim listener As New AzureDiagnostics.TableStorageTraceListener("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString") With {.Name = "TableStorageTraceListener"} System.Diagnostics.Trace.Listeners.Add(listener) System.Diagnostics.Trace.AutoFlush = True Else System.Diagnostics.Trace.Listeners.Remove("TableStorageTraceListener") End If End If End SubFakePre-98d7394fb6374038b81644393f05c20d-7d0f033a1fff4228935efb63f9f4588d
The ConfigureTraceListener method retrieves the EnableTableStorageTraceListener configuration setting and, if its value is true, it creates a new instance of the TableStorageTraceListener class, defined in the project that you added to the solution earlier, and then adds it to the collection of available trace listeners. Note that the method also enables the AutoFlush property of the Trace object to ensure that trace messages are written immediately to table storage, allowing you to retrieve them as they occur.
Now, insert the following (highlighted) code in the Application_Start method to set up the Windows Azure storage configuration settings publisher and to enable the TableStorageTraceListener.
(Code Snippet – WindowsAzureDebugging-Ex1- Application_Start-CS)
public class MvcApplication : System.Web.HttpApplication
FakePre-73883ef590bf4bf0afe8bd66b124b139-d60e94ec49214591ae16ac42482d4ca3FakePre-694e8e8198914c3d944fb3fbc2586c57-9049a3a66db54f998b7240fc9658456eFakePre-988982c5d2d943409f1e60ba841024c4-c1d3aa22388c4eaa96d927f659daffe9FakePre-ada68790379b49a9a5eeed7c59ab80df-5e5dc3f8015b4eb4acf37256ef93eecd CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) => { configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)); }); ConfigureTraceListener();FakePre-53f7757913b9448488e13136c5900708-dbba907e59d04742834381c9860756c8FakePre-0868868078ba466c9d2eecf82b048713-635643363ad949dd93c06c7735fa6ee3FakePre-e0008a45f0e44084a7d8ed8d5e62283c-4d3720c7ddb54be2915a48afcb64dc0dFakePre-ede0ad70afbf4d06a92a098a82f3c377-6417b603651a4dbb936d8a13e0659af9FakePre-9b61166bb9af4cb7979e4c7f7a18b7d6-2c3ea0f7cb1e414ba61266ffff2c1820FakePre-a8a4c3877031426b96936b7acd69e5c2-b385c3291586479caebde82956b312ceFakePre-8d162b55a73b4e8b8863f2a8f49cb90b-ab8a812afdcd45af8d75e1f24b151916FakePre-7e94871db8924444ad952f4267432ce0-7d847af5b94540e78480ee1cc583fa76
(Code Snippet – WindowsAzureDebugging-Ex1-Application_Start-VB)
Public Class MvcApplication
FakePre-e59f181622cb4dd5889521c9f5b18f09-bb0d4f517439456480db971b366e05a1FakePre-b695eb76fe1c46458a941a935d3a0f64-7ba5092f9bfa4cb485ce247930043957FakePre-8c73681fa2dc492195f03d53d9edc25c-6ae29265de20441a8ddf0b58bc301619FakePre-75da3f030a3d4c0487e51a940d93eae9-200f8bb1fc724236bafe5095b3925ba4 CloudStorageAccount.SetConfigurationSettingPublisher(Sub(configName, configSetter) configSetter(RoleEnvironment.GetConfigurationSettingValue(configName))) ConfigureTraceListener()FakePre-d15a82bb67cd48738eaa5300bb982218-7554187e59bc4d2b8a8bf071e54cc44bFakePre-a4b610f911694fb5ad00973ce81ade66-90dd91cf85e2495a92ba93e38da74175FakePre-f0a3ebefe25e44dc87756f4ec9c26741-1aef9ba2d658460f8ef89367ae9aed25FakePre-66539ce09e9949ee9206a48916dcfc61-18adf88c41f9411d81a9fda7a02682cdFakePre-772d188d0b4047998480b2557258471e-63d2aecabadf4d2da0d5aa567a6aa35bFakePre-125b40f2612540d49ec398f446beb682-4dfb411c05b248498022c9bbff09b6e5FakePre-d52da1f0edb945d8b7e460fae4813149-10c64ff22c854f68bfa614e0ee83b588
TraceListeners can be added by configuring them in the system.diagnostics section of the configuration file. However, in this case, the role creates the listener programmatically allowing you to enable the listener only when you need it and while the service is running.
Figure 10
Enabling the TableStorageTraceListener in the configuration file
Next, define a configuration setting to control the diagnostics logging with the TableStorageTraceListener. To create the setting, expand the Roles node in the FabrikamInsuranceService project and then double-click the FabrikamInsurance role. In the role properties window, switch to the Settings page, click Add Setting, and then set the name of the new setting to EnableTableStorageTraceListener, the type as String, and the value as false.
Figure 11
Creating a configuration setting to enable the trace listener
Locate the RoleEnvironmentChanging event handler inside the WebRole class and replace its body with the following (highlighted) code.
(Code Snippet – WindowsAzureDebugging-Ex1-WebRole RoleEnvironmentChanging event handler-CS)
public class WebRole : RoleEntryPoint
FakePre-8c163db2dfd448f5ae393dad593d45b4-24b69e603ced4c028bd227743a76eca5FakePre-0842e0568c9a4ec4bb904e52aa79cad7-80f2022396c34c839b7b4bce286a4243FakePre-0aec1c748e0240dc86a4d3d190bd377b-b371b210c9004324960f2d5cd2445d5fFakePre-c9f95a49381047a4aba95b98ef832fc9-85385e3949e64405b9ff0312943fc1b8 // for any configuration setting change except EnableTableStorageTraceListener if (e.Changes.OfType<RoleEnvironmentConfigurationSettingChange>().Any(change => change.ConfigurationSettingName != "EnableTableStorageTraceListener")) { // Set e.Cancel to true to restart this role instance e.Cancel = true; }FakePre-4d79526d2c3042a098efe45892675ae6-26513952c5374e7ebf5f5e0f5754de45FakePre-75fdd18982224c78bd5deb9f99e6487c-1044834aa01a45b5bdf0911f82776663FakePre-a1915fa7805143e7a1c5295dc2268fc3-af06f26e92174783a8cb02d9a7fb74a6
(Code Snippet – WindowsAzureDebugging-Ex1-WebRole RoleEnvironmentChanging event handler-VB)
Public Class WebRole
FakePre-1b5f2e0d5925444e95a7ea5fa23ab6a7-64775729abce4fea9ae9e039970677c1FakePre-4bb3350fddf54b35a440de6f58fb8898-91a28d92a98a4239ad4a4da2568fe56dFakePre-413788c131d748e7bea4e6df2138baeb-b325fdc9aeae4bb6b91b1185d751b49a ' for any configuration setting change except EnableTableStorageTraceListener If e.Changes.OfType(Of RoleEnvironmentConfigurationSettingChange)().Any(Function(change) change.ConfigurationSettingName <> "EnableTableStorageTraceListener") Then ' Set e.Cancel to true to restart this role instance e.Cancel = True End IfFakePre-a29582352bf04806bcf7c66293bf3b04-688daf9c8621481cb43b7e10ed28728aFakePre-1d24d8ade7f7445b829b0c947a8d4c61-af55e1ca6cf7497284c8d733b9aa0132FakePre-06a7e2c7ca994f4482f4cf93bcf40d65-3a5c4322c5dd47118bbfa89c2cf621cc
The RoleEnvironmentChanging event occurs before a change to the service configuration is applied to the running instances of the role. The updated handler scans the collection of changes and restarts the role instance for any configuration setting change, unless the change only involves the value of the EnableTableStorageTraceListener setting. If this particular setting changes, the role instance is allowed to apply the change without restarting it.
Now, add the following (highlighted) code to define a handler for the RoleEnvironmentChanged event into the Global.asax.cs (for Visual C# projects) or Global.asax.vb (for Visual Basic projects).
(Code Snippet – WindowsAzureDebugging-Ex1-Global RoleEnvironmentChanged event handler-CS)
public class MvcApplication : System.Web.HttpApplication
FakePre-052efd8b400e4260bc05b09f78fd6f67-4ee887c7ecf049dbab52966fb1c2740bFakePre-a0117d4a4877464697098624e5837cac-09232e3e2b9744abae78cebb77491e23 private void RoleEnvironmentChanged(object sender, RoleEnvironmentChangedEventArgs e) { // configure trace listener for any changes to EnableTableStorageTraceListener if (e.Changes.OfType<RoleEnvironmentConfigurationSettingChange>().Any(change => change.ConfigurationSettingName == "EnableTableStorageTraceListener")) { ConfigureTraceListener(); } }FakePre-f4f4e0b5dfbd479495d1890d364e24aa-bde8497751164776bd18d78829d0da44FakePre-bdc3339e230c46d8ae3e4657f3a1c0a5-a248cb056686487eba3177e6801398b1
(Code Snippet – WindowsAzureDebugging-Ex1-Global RoleEnvironmentChanged event handler-VB)
Public Class MvcApplication
FakePre-4c665e9414344450b2c02defafc52b36-382969630c2b4e8ca591f015cfc56a7aFakePre-2cf178922cdf457a80b24be98eb4144b-2c6f60bb829e4f6fb9f447c283042bef Private Sub RoleEnvironmentChanged(ByVal sender As Object, ByVal e As RoleEnvironmentChangedEventArgs) ' configure trace listener for any changes to EnableTableStorageTraceListener If e.Changes.OfType(Of RoleEnvironmentConfigurationSettingChange)().Any(Function(change) change.ConfigurationSettingName = "EnableTableStorageTraceListener") Then ConfigureTraceListener() End If End SubFakePre-63a73021eb6947e4b2a7060eb86b061c-1217ce8bde6c40358a21bd57a472818cFakePre-69c5568ad07e4ceca65ce2cbf473a8ec-ed57023d464c4df28409fc23486bb6df
The RoleEnvironmentChanged event handler occurs after a change to the service configuration has been applied to the running instances of the role. If this change involves the EnableTableStorageTraceListener configuration setting, the handler calls the ConfigureTraceListener method to enable or disable the trace listener.
Finally, insert the following (highlighted) line into the Application_Start method, immediately after to the call to the ConfigureTraceListener method, to subscribe to the Changed event of the RoleEnvironment.
public class MvcApplication : System.Web.HttpApplication
FakePre-beda3e7b6f744f258ac2767577a0bfb1-1884d96ff13f4327ad860ea03da758e8FakePre-4b21839c017b4de290c93662dc29a6af-e061646c021a4dbe9d1dcec8c8b71112FakePre-df68a713caa340a69ba3a29c34d48e98-05cc3a7862b34ccfb840968a74c79bb3FakePre-31272777ea754d5f8e38410fc5590e1b-affa6192f8374642b69336a1997d6ee6FakePre-05ac491b8b61448689f9231b1ed621d0-a82c5f42f7ee4924bdf6de49f7e50a8cFakePre-da114850557c4acbb3e2bee0903f70d4-83a899826e4144ebaa0275b69f4aea85FakePre-da1a26abf051462aa17ae6c1adbd9587-6c55acbee65549ca927df49c41e2800fFakePre-12921207a8f04f37aae28079ea604308-89cb8c48268e4ed79ed8a1d9994a6e6fFakePre-366a25775ccb43d3bb67733f04663e9d-d2e74f2ae9d94019a7611f21810b6b1cFakePre-44e2d8da096b44ce87e589702915a2f6-87f505eca0e8405ab75bdbb31c6f5bb3FakePre-74b7e2f7c9fe449b89017b115659231b-9ff95d6e43e64101b300dc89f230fb6c RoleEnvironment.Changed += RoleEnvironmentChanged;FakePre-bcdaacd427a14fca824924c4a12ae728-e54306baf0f844d59579daa3af64f35bFakePre-dccf6b19eb3544e8965af528206a98fa-69811826e0834031b6f8c341d911f9ceFakePre-1eb507f48f1740d6a68d0215cd9c0e6b-9084ddb7fe7946bd92af411e26a84cf9FakePre-84ddfeabc1e74742aab1a12b68cd8b6b-0d88465b945c492c86cbf4ef6e1beb4aFakePre-5e094b0d43ed4afa9879eceecccf3434-91d460c389ca47a7a95c45074b555ac9FakePre-8165a81ab3c04595b592f41af5586890-7d102d5943754928820207458b9d3df4FakePre-9f1611474dcc45f0a0e7da2fbc33f832-8ce653f2d33b4f55b3f19fd91e135ba3
Public Class MvcApplication
FakePre-02da8f5b5a4343c285f60b69460eb6a6-0f396f2bca2e44018f2cc42318004491FakePre-a0320d3f68ad4c5b92c790415df013c1-27398184286b4136b52413ceefd83df9FakePre-59ff8b5619ea4aafb5b2ccbe1ee799c1-7f1b4d9c45fd4b93b5f81445130e37c0FakePre-fd9bd813bb1a40f48782f07262b08f22-48945c46cc5547a2b304158232ee0871FakePre-3d642863aeb44e64bf61cdb917861ae3-be657658e3f84da0b06799c260745181FakePre-177e41411d9a4db68e6dcb15643bb0d7-6a8aaa49beb94a07afb2dd7101209f9eFakePre-38f68e6b09004d8baeb2bcbe4735c9a6-ce41cc07b4dc4b4aac2d294486eeb604FakePre-791210b123ea4e63a6924b68dfc82863-597f0d2dabf348d7bdd04cbe643d33cc AddHandler RoleEnvironment.Changed, AddressOf RoleEnvironmentChangedFakePre-043cba7401504b2eb42fce5b9fae39c3-1d3f2bb7861649f183aaf599c92a8449FakePre-37ace2402086446db61498161dae215d-7c84e28c30764d8ca5d326f5cdaecea3FakePre-aa1a311c531b4a6788fe07a335e3857b-c14806b62aac4a0cbe27fa1c475a9e86FakePre-3b26b0da0b6b462399e674174036093f-5c69cf03f02c4932964c51ab74d70bf8FakePre-7d9b53fd12b94506b701a6b1116dc3f7-aae90f044cf04404849c2457b889b81eFakePre-3effb671f82f4a498375ba32c6a9f7f4-6cf07cc2a4094982af423ff455dc580a
To instrument the application and write diagnostics information to the error log, add a global error handler to the application. To do this, insert the following method into the MVCApplication class.
(Code Snippet – WindowsAzureDebugging-Ex1-Application_Error-CS)
public class MvcApplication : System.Web.HttpApplication
FakePre-3bd19e799d014d39bdbaa2b97b58b757-535827a9c24940b09f213cfb9628bff4FakePre-f0be073594784f63b4f9794d420f2e90-fbf2b25b9b9646e2a262fd62e3e8c0e7 protected void Application_Error() { var lastError = Server.GetLastError(); System.Diagnostics.Trace.TraceError(lastError.Message); }FakePre-d3d7c6b5d2524941a0af9cd9889eba3d-a28fa46303144dad889df20e6c19d9a7
(Code Snippet – WindowsAzureDebugging-Ex1-Application_Error-VB)
Public Class MvcApplication
FakePre-ef77ed5b913c4bd1a3b98d81500fcbb1-ee486163a2a34e33b104a35b11107004FakePre-ee7a81e1aee84ac6b3a9c98525188bab-b699fe46279e498ca7affe86ff3572e1 Protected Sub Application_Error() Dim lastError = Server.GetLastError() System.Diagnostics.Trace.TraceError(lastError.Message) End SubFakePre-b9e7445f27ec4b7084fd26c07f0d0504-d62107b7b72b476ab1171d0a835d1739
The Application_Error event is raised to catch any unhandled ASP.NET errors while processing a request. The event handler shown above retrieves a reference to the unhandled exception object using Server.GetLastError and then uses the TraceError method of the System.Diagnostics.Trace class to log the error message.
Note that the Trace object outputs the message to each listener in its Listeners collection, including the TableStorageTraceListener, provided you enable it in the configuration settings. Typically, the collection also contains instances of the DefaultTraceListener class and, when executing the solution in the compute emulator, the DevelopmentFabricTraceListener. The latter writes its output to a log that you can view from the Compute Emulator UI.
To write to the Windows Azure diagnostics log, a DiagnosticMonitorTraceListener can also be added to the Web.config or App.config file of the role. When using this type of trace listener, the logs are gathered locally in each role. To retrieve them, you first need to instruct the diagnostic monitor to copy the information to storage services. The role project templates included with the Windows Azure Tools for Microsoft Visual Studio already include the settings required to use the DiagnosticMonitorTraceListener in the configuration files it generates.
Figure 12
Trace object Listeners collection showing configured trace listeners
Open the QuoteController.cs (for Visual C# projects) or QuoteController.vb (for Visual Basic projects) file in the Controllers folder of the FabrikamInsurance project and add the following method.
(Code Snippet – WindowsAzureDebugging-Ex1-Controller OnException method-CS)
[HandleError]
FakePre-0d3087f6b1b74fea857ee3c9d8dcce1c-f0cfca86ad3746d39f885bb2d61f590aFakePre-eb1eea7426774e28a233b6c9477eec81-b63e69965a8e49658ca18cb1fa8ab603FakePre-9b0829dc173d40fa8a42a6f638b74902-68bb3f9762ef4b069fda01465c1e3e91 protected override void OnException(ExceptionContext filterContext) { System.Diagnostics.Trace.TraceError(filterContext.Exception.Message); }FakePre-71b2d955fd9f48c8be60e483b6e6fcb9-742482cab3a14f7eb90acd62ba85d142
(Code Snippet – WindowsAzureDebugging-Ex1-Controller OnException method-VB)
<HandleError()>
FakePre-f3a12bd6948d44c2a66cbdaaf0130f66-706108a4536848b1a6099b78dfec8d91FakePre-46fb072e806f4d35beb880650c72d6dd-9f191cb910314025bc684fe4802ad7a8FakePre-9f5721d074d94c8d9aa2bdd17f33cdaa-b1bf2071992246bb8e4bedb96019a6ee Protected Overrides Sub OnException(ByVal filterContext As ExceptionContext) System.Diagnostics.Trace.TraceError(filterContext.Exception.Message) End SubFakePre-2fcd11ca5c164895a2053165ccf4f80e-2ef2550a8d7c4b13b3941f328a99032d
The OnException method is called when an unhandled exception occurs during the processing of an action in a controller. For MVC applications, unhandled errors are typically caught at the controller level, provided they occur during the execution of a controller action and that the action (or controller) has been decorated with a HandleErrorAttribute. To log exceptions in controller actions, you need to override the OnException method of the controller because the Application_Error is bypassed when the error-handling filter catches the exceptions.
By default, when an action method with the HandleErrorAttribute attribute throws any exception, MVC displays the Error view that is located in the ~/Views/Shared folder.
In addition to error logging, tracing can also be useful for recording other significant events during the execution of the application. For example, for registering whenever a given controller action is invoked. To show this feature, insert the following (highlighted) tracing statement at the start of the Calculator method to log a message whenever this action is called.
public class QuoteController : Controller
FakePre-f33f1473e736436b96fa6ade44ca874a-eff3b75aec5c4185b2bcf7b3315be716FakePre-40924a830a434d8f9801f949237863a8-f6fc96f6831a4378b461bda8fbc18432FakePre-1c49f893226949abaf2aa6c7d5feb514-7a5ee10d7bb84dfebe8aeed811806bb3FakePre-4ae977bf510b49288be17961564797b2-8aef8ac26ba447c080cbd52ff21a4a26 System.Diagnostics.Trace.TraceInformation("Calculator called...");FakePre-790c187f656c47d2a354d7391ba5a6d6-7068d0383168446c9f452dc4785604abFakePre-d4a9334eedb14899b16bb5bc337dcf07-bde4ce67626f4b1c8432fe27d0b9d197FakePre-3db53baa701f4834b2f94e2de8f6412e-b2e43e4a6f8145338e0f121dd97fd77bFakePre-6ab0d04308be4819948b65ff28b0154b-fb3f3d3333c347779750087e4611a569FakePre-12afaab978da40429ba030c978081e67-e953278b02da4ced9bdd60526e5f6cfdFakePre-e34756edcf444d97b22ca54de3442754-9db75da1bc4c481fb51b63902843e7a4
Public Class QuoteController
FakePre-a4fa61beab39484c9ca3886a26c38276-e26720ce528e439ab6363a3d4f1ec3c9FakePre-a7462e5b4c62456aad7bf0c32ba3d4b3-8485b51ae2584668b515861b24ef0c50FakePre-e744b6165e114c72b6d4777730d7e324-0503ba0d76944095a82621d54dd8b5a6 System.Diagnostics.Trace.TraceInformation("Calculator called...")FakePre-bd3f558d7f0f41ea8275751911fa3a27-ea9286c27a4b41daa03d544d8cbcd040FakePre-c86f25d2ff9d43cebbee5159d9d78ba3-4ed5e104f7d44508812eef60f1a5d28dFakePre-cdc64a0f7c014455ad4d31f29615d7f9-7db0198317b04b95b2389f36da24938fFakePre-1f22c3834a4642968d112516eb46f32d-4163386173b442f49cfbe38c3fe7e12cFakePre-86f576bca28f464f8e658bc74d1d48f7-6a876d7675954eb485eb982adfd65656FakePre-f075e8eee321415facc07bbae35036be-d35b8a99241c490b8a9b78bec3bfbdd6
Similarly, add a tracing statement to the About action, as shown (highlighted) below.
public class QuoteController : Controller
FakePre-9ac0614523af4c8ab9eaf64887013120-2f9e9bb1bd1e431581bb0807461c3919FakePre-af27ca5bd75543369c8b32ba77fd426a-fb724df30e6c44a69ef2c5977cea5f65FakePre-3cc47829e8a04c9da26e700afefa57df-ca311d219e2248a69233af317eb19827FakePre-fe91fe1ea79a450baa46408708e87de8-5687d87b8ce64bf786bea13e9e5e0271 System.Diagnostics.Trace.TraceInformation("About called...");FakePre-9e8af406293544eeb17413c5ddeb8d79-f878bf1a012f408ab9e16b2f36dbb79bFakePre-4fe3314992694059a7d1fa138c17c359-07f14e1495d54565bfd242970b9824eaFakePre-162b2559c7234c469585d0b2c3e89433-e90551e140ee40aeafd5427ea6e7a059FakePre-18e41d0954c84691ac362f460ff156c8-cca6494fcc224d72b06dbb66c9869823
Public Class QuoteController
FakePre-0e40e09d24ee40ab9dac5173ed9c634b-e99887e2f4ee444ba844a7e2ada30448FakePre-db0057833fb0446695f21bb853ad0c67-f78b5af803e14b46a8daab3f76637dd9FakePre-03307fc853bd489db28563ee99446806-43b27c4d0a9e492483f1e25be103a970 System.Diagnostics.Trace.TraceInformation("About called...")FakePre-b40973fc3b79454dbdcd7d4da9e54c9f-1bd11012c87b4e8294d79f2803a86d8bFakePre-9a230dc558714a559495ad9687ee3dbb-d89f7b2f9eaf4f5f9ebd360aa1deed3fFakePre-2e7ccbed664540fb9989c8de530bd45b-48abe2b464114e4d838f59fc87cfc759FakePre-90f9fd9be5e049c9bf7d08668e911fd4-0c027db44d574a3a9a65b60316ac453e
At this point, the application is ready for tracing and can send all its diagnostics output to a table in storage services. To view the trace logs, you now create a simple log viewer application that will periodically query the table and retrieve all entries added since it was last queried.
- Add a new console application project to the solution. To create the project, in the File menu, point to Add, and then select New Project. In the Add New Project dialog, expand node for the language of your choice (Visual C# or Visual Basic) in the Installed Templates tree view, select the Windows category, and then the Console Application template. Set the name of the project to LogViewer, accept the proposed location inside the solution folder, and then click OK.
Right-click the new LogViewer project in Solution Explorer and select Properties.
For Visual C# projects:
In the properties window, switch to the Application page, and then change the Target framework to .NET Framework 4.
Figure 13
Configuring the target framework for the project (Visual C#)
For Visual Basic projects:
In the properties window, switch to the Compile page and then click Advanced Compile Options. In the Advanced Compiler Settings dialog, select .NET Framework 4 in the Target framework drop down list, and then click OK.
Figure 14
Configuring the target framework for the project (Visual Basic)
The client profile is not suitable in this case because the application will use the StorageClient API to retrieve log data from table storage. This API relies on functionality available only in the full .NET Framework 4 distribution.
If the Target Framework Change dialog appears, click Yes.
Figure 15
Target Framework Change
- Add references to the assemblies required by this project. To do this, in Solution Explorer, right-click the LogViewer project and select Add Reference. In the Add Reference dialog, switch to the .NET tab and, while holding down the CTRL key to select multiple items, select System.Configuration, Microsoft.WindowsAzure.StorageClient, and System.Data.Services.Client, and then click OK.
- Next, add a reference to the diagnostics project in the solution. Repeat the previous step to open the Add Reference dialog, only this time select the Projects tab, select the AzureDiagnostics project and click OK.
- Add a class to display a simple progress indicator in the console window to the project. To do this, in Solution Explorer, right-click LogViewer, point to Add, and select Existing Item. In the Add Existing Item dialog, browse to Assets in the Source folder of the lab, select the folder for the language of the project (Visual C# or Visual Basic), select the ProgressIndicator.[cs|.vb] file, and then click Add.
In Solution Explorer, double-click Program.cs or Module1.vb to open this file and insert the following namespace declarations at the top of the file.
(Code Snippet – WindowsAzureDebugging-Ex1-LogViewer namespaces-CS)
using System.Configuration; using System.Data.Services.Client; using System.Threading; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.StorageClient; using AzureDiagnostics;
(Code Snippet – WindowsAzureDebugging-Ex1-LogViewer namespaces-VB)
Imports System.Configuration Imports System.Data.Services.Client Imports System.Threading Imports Microsoft.WindowsAzure Imports Microsoft.WindowsAzure.StorageClient Imports AzureDiagnostics
For Visual Basic projects only, reformulate the Sub Main making it Public and adding a string array parameter named args.
Module Module1
FakePre-72a0ea63bbe9478b8235f2458e18ed35-2e56bde91670440899a275bc0934cb4b Public Sub Main(ByVal args() As String)FakePre-492c8de4f67b42b4a99f0b2136c4d9d0-4c63f4fef0454a1f917be5052f04a294FakePre-759cf9ca4f9b498f80316f643487b2e4-12a66f86edce478892a3ae91971e5145FakePre-edc5df7283b942a98029413c56cff21f-01f963d6f73e414eae43b5f6c7b8846cFakePre-417b024ca23c480297a009eb478ce2cf-eb9b93acffb846cfa0368b18476d7282
Define the following (highlighted) members in the Program class (for Visual C# projects) or the Module1 module (for Visual Basic projects).
(Code Snippet – WindowsAzureDebugging-Ex1-LogViewer static members-CS)
class Program
FakePre-e209ea624cb6431a840cf6ec96efcc7c-f29533191f964a71959203564c3e866f private static string lastPartitionKey = String.Empty; private static string lastRowKey = String.Empty;FakePre-ecb8505fc34c485abd7fda54bf106ef8-081c2474cca340c9897197398c0a9116FakePre-0a0c6facb4224d75a649cf3cb536935b-4be132f789794b4ca3d3d9bc695a9e1fFakePre-9c14c14c90a64399933cfe089fc50a6d-a8dde48dbdf2426fab59e7334f6d1a7cFakePre-9ba9c3e67e424c309b5191ffa61066ab-0a38b8ddb8834ace9bcbe3e348b66dc3FakePre-24020d2c5e99436db8810508fbecd8d8-4da45e32a5b748249d4987af5660919b
(Code Snippet – WindowsAzureDebugging-Ex1-LogViewer static members-VB)
Module Module1
FakePre-32c91c68948f4c97813640ac3bd121cc-3c3dc0a537eb4b9596aa69b3149c9127 Private lastPartitionKey As String = String.Empty Private lastRowKey As String = String.EmptyFakePre-1edf139e1b454bec986413ae8c27c1cc-8124cf43e27f4046a4142a4b7e860e8bFakePre-d29d942cc2cf452081211bcad8efbe54-ca3cd623021745aa866a297f895b7c7fFakePre-b40e53d549ef40539b7804fa6d909000-967aa70dd85a48c2890cab5ec1fb190dFakePre-2659272c620b4d04a989b31c438d63fa-4538726050204995b4fc6c448c03d162FakePre-18473b882358427eaa71e79632021a4e-7e8f0157260b41a19dcd411229972c2cFakePre-8eba12a0250941b0a3a22996a8d43695-efcdeee5dcb04501afb65c69b818d403
Next, insert the QueryLogTable method into the class or module.
(Code Snippet – WindowsAzureDebugging-Ex1-QueryLogTable method-CS)
class Program
FakePre-0d7318dfd9cb4f59b5a25c474eb9797f-efc2656a1e5d4ccca0fa9244dffdd3c2FakePre-bc9730def5bb44439872d0399acf2da7-b5f1fe93bdb9432fb57e157b33e9c644 private static void QueryLogTable(CloudTableClient tableStorage) { TableServiceContext context = tableStorage.GetDataServiceContext(); DataServiceQuery query = context.CreateQuery<LogEntry>(TableStorageTraceListener.DIAGNOSTICS_TABLE) .Where(entry => entry.PartitionKey.CompareTo(lastPartitionKey) > 0 || (entry.PartitionKey == lastPartitionKey && entry.RowKey.CompareTo(lastRowKey) > 0)) as DataServiceQuery; foreach (AzureDiagnostics.LogEntry entry in query.Execute()) { Console.WriteLine("{0} - {1}", entry.Timestamp, entry.Message); lastPartitionKey = entry.PartitionKey; lastRowKey = entry.RowKey; } }FakePre-f68c154d7a5e434c8e687340885562b7-f1c9e28ad1df496799d683c14427df4eFakePre-e874c93dafce4eeab5263bfc8258176a-14dfab5222e74d0b8b7d7a66076a0a94FakePre-53e337a899cb446aa282c438ef196f35-2fd2d003fb574e38ac72dfec9b477d24
(Code Snippet – WindowsAzureDebugging-Ex1-QueryLogTable method-VB)
Module Module1
FakePre-aaf0fb2e39874f9cb0ba5647f2c5cd0c-5d0fceadf7964cbdaf030967fca36e68 Private Sub QueryLogTable(ByVal tableStorage As CloudTableClient) Dim context As TableServiceContext = tableStorage.GetDataServiceContext() Dim query As DataServiceQuery = TryCast(context.CreateQuery(Of LogEntry)(TableStorageTraceListener.DIAGNOSTICS_TABLE).Where(Function(entry) entry.PartitionKey.CompareTo(lastPartitionKey) > 0 OrElse (entry.PartitionKey = lastPartitionKey AndAlso entry.RowKey.CompareTo(lastRowKey) > 0)), DataServiceQuery) For Each entry As AzureDiagnostics.LogEntry In query.Execute() Console.WriteLine("{0} - {1}", entry.Timestamp, entry.Message) lastPartitionKey = entry.PartitionKey lastRowKey = entry.RowKey Next End SubFakePre-2feaee345df04b3d8783995eebbd8073-f51e34be74e34742bdf26abc8a2aa651FakePre-eb0a438b8aee4567baa33f169c3c04d2-5cd42c815b624135ba8d39dd95368103FakePre-ceef4bbdeb264b6cb69f9b83321b85f2-b216b1836e1b4b3c83a1f232c0579989
The rows in the diagnostic log table are stored with a primary key composed by the partition and row key properties, where both are based on the event tick count of the corresponding log entry and are thus ordered chronologically. The QueryLogTable method queries the table to retrieve all rows whose primary key value is greater than the last value obtained during the previous invocation of this method. This ensures that each time it is called, the method only retrieves new entries added to the log.
Finally, to complete the changes, insert the following (highlighted) code into the body of method Main.
(Code Snippet – WindowsAzureDebugging-Ex1-LogViewer Main method-CS)
class Program
FakePre-f821c062332845eb9025e32a3ba794a3-5604b212c9bf4fbfad72e6a869198772FakePre-a92caba86be342ea8ada79c35941bcbb-83443f29af354a24b7bba63209166cb8FakePre-20f28a0f0e454355af23ad788cc1cd64-3512d296fb594de782ed8de3aef456a2FakePre-a62b7ffebe3a4a318448a012176fcef3-f2c89e4eb2f240db8e8a5b54ef3e2a2a string connectionString = (args.Length == 0) ? "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" : args[0]; CloudStorageAccount account = CloudStorageAccount.Parse(ConfigurationManager.AppSettings[connectionString]); CloudTableClient tableStorage = account.CreateCloudTableClient(); tableStorage.CreateTableIfNotExist(TableStorageTraceListener.DIAGNOSTICS_TABLE); Utils.ProgressIndicator progress = new Utils.ProgressIndicator(); Timer timer = new Timer((state) => { progress.Disable(); QueryLogTable(tableStorage); progress.Enable(); }, null, 0, 10000); Console.ReadKey(true);FakePre-07a0589e7fb248f39ccdb66d42853eb4-f1fa99724f0c481e91e2f9adf07aba56FakePre-f969d78557b04f37b817bfa4019eb78e-0fc2125f29b04e20a2ab051972695ab6FakePre-fc07570ca3b74f048e4ffe6598451dc3-1db1056188bd43c98811458805668ef6FakePre-a0cd0a2259f748c189670907f5e28519-52eac143e08a45739f92814c166dcb18FakePre-40a65c1c45f04cbb80f42cdc6cc7221a-2ba2f6308dc1444eb468fd11822a9ebe
(Code Snippet – WindowsAzureDebugging-Ex1-LogViewer Main method-VB)
Module Module1
FakePre-2bc2279609ff4e189fbd93b3f94559f7-aee6447e45a64a33853d30d6d07f9a44FakePre-a16b641d973447729b0c4018e36e7f11-9b43adebde7c4e2bb562b74c890ba4aa Dim connectionString As String = If((args.Length = 0), "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString", args(0)) Dim account As CloudStorageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings(connectionString)) Dim tableStorage As CloudTableClient = account.CreateCloudTableClient() tableStorage.CreateTableIfNotExist(TableStorageTraceListener.DIAGNOSTICS_TABLE) Dim progress As New ProgressIndicator() Dim timer As New Timer(Sub(state) progress.Disable() QueryLogTable(tableStorage) progress.Enable() End Sub, Nothing, 0, 10000) Console.ReadKey(True)FakePre-893a7cec19ff4d1abb630499daa669a1-f877855f652140d99f8536e28ac91c01FakePre-1bdb9dced1134371b0267ed23af381cf-5ec63bda21854728aa10b82d3c3d687fFakePre-94d570cdd60245e59198825b6871116f-aee35965cb82472d8dd5bce84686c673FakePre-67c1f9bc5e2a469cb426af7d13b617e0-b977ebae66384177996e0e17a82a301bFakePre-edfc9ebfad544296a3a51dfea143d9f0-a6cd34e3d24241b1a4f28037936bbea3FakePre-01f1cb099e6b47fb8301c803f636182b-b1a1a973aec54750afd6f787538955e7
The inserted code initializes the Windows Azure storage account information, creates the diagnostics table if necessary, and then starts a timer that periodically calls the QueryLogMethod defined in the previous step to display new entries in the diagnostics log.
To complete the viewer application, open the App.config file in the LogViewer project and insert the following (highlighted) appSettings section to define the DiagnosticsConnectionString setting required to initialize the storage account information.
(Code Snippet – WindowsAzureDebugging-LogViewer DiagnosticConnectionString)
<configuration>
FakePre-dcabef7c87184b6997af975f29727950-911231a2d90845e7998ca683aa7fcb37 <appSettings> <add key="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="UseDevelopmentStorage=true"/> </appSettings>FakePre-4adfaecddbb6428da2b3b9acbcdfd18c-ebbddac054da471fbaaea9d8b39de45dFakePre-da1940cc2ceb4c79875d9c7e2bb75b12-6623e0034bea4c1da29fa58986490512FakePre-1d13bad9be584118b045e28774289bfc-3b289e9d191b4f9485c8f84fa6a267deFakePre-b638b00c5ec34817b8aa80938a4c11c3-80922d5006d449f0a44768f63c2ac603
Verification
You are now ready to execute the solution in the compute emulator. To enable the Table Storage trace listener dynamically without stopping the running service, you initially deploy the service with the EnableTraceStorageTraceListener setting disabled and then, you change the setting in the configuration file to enable the listener and then upload it to re-configure the running service. Using the log viewer application, you examine the trace messages produced by the application.
Open the Web.config file of the FabrikamInsurance project and insert the following (highlighted) customErrors section as a direct child of the system.web element.
<configuration>
FakePre-95f76caf1ed5486bbfaa42969b8f2bf5-cc6892b230654aff86b731d638545921FakePre-c8bba3883ee74fb49be15c0c17651951-17df340f53fa45f2939ec71a92da0709FakePre-2cde2084663745f1814ee2d3199ee63e-1cda0fbc5d284790a01418ac6be42222 <customErrors mode="On" />FakePre-0b91756b8d7149b0a42e3670570cf73e-05dc4cf319e641fbbbe94b67fef97bf3FakePre-a1d6898e255f4e0faae4c71989cb1a85-3a479115c50d4932b59df6ee05cac082FakePre-4de65823f4074e8f896ecd0389cbfa4a-35d3b28aa52b4607b31ab0d42aafb711
When you set the customErrors mode to On, ASP.NET displays generic error messages for both local and remote clients. With customErrors set to its default setting of RemoteOnly, once the application is deployed to Windows Azure and you access it remotely, you will also see the generic errors, so this step is not strictly necessary. However, it allows you to reproduce locally the behavior that you would observe once you deploy the application to the cloud.
To test the solution, you need to configure the Windows Azure Project and the log viewer application so that they both start simultaneously. To define the start up projects, right-click the solution node in Solution Explorer and select Set StartUp Projects. In the Solution ‘Begin’ Property Pages window, make sure to select Startup Project under Common Properties, and then select the option labeled Multiple startup projects. Next, set the Action for both the LogViewer and FabrikamInsuranceService projects to Start, leaving the remaining projects as None. Click OK to save the changes to the start-up configuration.
Figure 16
Configuring the start-up projects for the solution
- Press CTRL + F5 to launch the application without attaching a debugger. Again, this reproduces the conditions that you would have once you deploy the application to the cloud. Wait until the deployment completes and the browser opens to show its main page.
In the browser window, complete the form making sure that you choose “PORSCHE” for the Make of the vehicle and “BOXSTER (BAD DATA)” for the Model. Notice that this time, because you enabled the customErrors setting in the Web.config file, the application shows a generic error page instead of the exception details that you saw earlier. This is what you would also see had the application been deployed to Windows Azure.
Figure 17
Application error with customErrors enabled
- Examine the output from the log viewer application. Notice that, despite the error, the console window is still empty because the table storage trace listener is currently disabled.
- Switch back to Visual Studio and, in Solution Explorer, expand the Roles node of the FabrikamInsuranceService project, and then double-click the FabrikamInsurance role to open its properties window. Select the Settings page, and then change the value of the EnableTableStorageTraceListener setting to true.
- Press CTRL + S to save the changes to the configuration.
Open the compute emulator console by right-clicking its icon located in the system tray and selecting Show Compute Emulator UI. Record the ID for the current deployment. This is the numeric value shown enclosed in parenthesis, next to the deployment label.
Figure 18
Compute Emulator UI showing the current deployment ID
- Now, open a Windows Azure SDK command prompt from Start | All Programs | Windows Azure SDK v1.X | Windows Azure SDK Command Prompt. To launch the command prompt as an administrator, right-click its shortcut in the Start menu and choose Run as administrator.
- Change the current directory to the location of the FabrikamInsuranceService cloud project inside the current solution’s folder. This folder contains the service configuration files, select ServiceConfiguration.Local.cscfg.
At the command prompt, execute the following command to update the configuration of the running deployment. Replace the [DEPLOYMENTID] placeholder with the value that you recorded earlier.
csrun /update:[DEPLOYMENTID];ServiceConfiguration.Local.cscfg
Figure 19
Updating the configuration of the running service
For applications deployed to the cloud, you would normally update the configuration of your running application through the Windows Azure Developer Portal or by using the Windows Azure Management API to upload a new configuration file.
- Once you have updated the configuration and enabled the trace listener, return to the browser window, browse to the Quotes page, and re-enter the same parameters that caused the error previously (make “PORSCHE”, model “BOXSTER (BAD DATA)”). Then, click Calculate to submit the form again. The response should still show the error page.
Switch to the log viewer window and wait a few seconds until it refreshes. Notice that the console now shows an entry with the error message for the unhandled exception, showing that the trace output generated by the running application is written directly to table storage.
Figure 20
Viewer showing the error logged to table storage
To view the output from other informational trace messages, return to the browser window and click About followed by Quotes to execute both actions in the controller. Recall that you inserted trace messages at the start of each method. Notice that the viewer console now displays a message for each of these actions.
Figure 21
Viewer showing informational trace messages for the controller actions
- In the log viewer window, press any key to exit the program.
- Finally, delete the running deployment in the compute emulator. To do this, right-click the deployment in the Service Deployments tree view and select Remove.
|
|