Preparing for Application and Service Deployment - Windows Azure Development Deep Dive: Working Wi
来源:互联网 发布:北京java学校地址 编辑:程序博客网 时间:2024/05/08 03:31
http://azure.snagy.name/blog/?tag=configuration
Introduction
One of the things you have to consider in any application is configuration. In windows and web forms we have *.config files to help configure our application prior to start. They are a useful place to store things like provider configuration, IOC container configuration, connection strings, service end points, etc. Let’s face it – we use configuration files a lot.
In this article I will discuss the different types of configuration available to you, how they can be leveraged in your application, and how configuration items can be changed at runtime without causing your application roles to restart.
The Problems With Configuration in the Cloud
In Windows Azure applications, configuration can work exactly the same as standard .Net applications. If you have a web role, then you have a web.config. And if you have a worker role, you get an app.config. This allows you to provide configuration information to your role when it starts.
But what about configuration values you want to change after your app is deployed and running? It certainly is a lot harder to get in and change a few angle brackets in your web.config after it is deployed to production in the cloud. Do you really want to have to upload a whole new version of the app package with the new web.config file in it?
Or what about being able to change configuration aspects of all your running instances in one go, andnot having to stop them from running to do so? Why should a configuration change necessitate a restart, such as is needed with web.config and app.config files?
In Windows Azure we have a new method of configuring our roles that gives us flexibility and consistency in our applications.
Service Configuration and Service Definition Files
In Windows Azure we can get the above benefits of flexibility and consistency in our configuration, via the service configuration file: ServiceConfiguration.cscfg.
This file contains information about your app that can be used at start-up, and can be changed at runtime without requiring a new package upload.This includes the number of running instances, certificate information, and specific application configuration settings, such as connection strings, port numbers, REST endpoints, etc.
The service configuration works in partnership with the service definition file: ServiceDefinition.csdef.
Both files are located in your main cloud project. The service definition is the “boss”. It can not be changed at run time. When you upload your Azure application, the service configuration is part of the application package, but theservice definition is uploaded separately. This is because the service definition containsall the instructions about how an application should be deployed including: details about each of the roles, what their fault and upgrade domains are, TCP ports to open (for worker roles), what local storage should be available, VM size to use, level of trust, and more. After upload, the service definition is shipped off to thefabric controller who will parse it and work out what to do with your cloud package.
We’ll focus on one more thing you will find in the service definition file – information about configuration items. Essentially the service definition states what configuration values will be available in the service configuration file, for each role. It looks something like this:
1: <WorkerRole name="ImageSearch.Cloud.Overlord">
2: <ConfigurationSettings>
3: <Setting name="ImageSearchSettings" />
4: <Setting name="ImageSearchDBC" />
5: <Setting name="SearchMultiplier" />
6: <Setting name="MatchTolerance" />
7: </ConfigurationSettings>
8: </WorkerRole>
If a configuration setting name is not specified in the service definition, it can not be used in the service configuration file to configure your app. Think of it as an instruction to the fabric controller: “My app can be configured with these 4 values”. Also, once you’ve uploaded your application, you can’t add or remove settings, since the service definition file is not editable; you can only change the configuration values. I’ll show you how later on.
In the service configuration file, our entry would look like this:
1: <Role name="ImageSearch.Cloud.Overlord">
2: <Instances count="1" />
3: <ConfigurationSettings>
4: <Setting name="ImageSearchSettings" value="UseDevelopmentStorage=true" />
5: <Setting name="ImageSearchDBC" value="Data Source=..." />
6: <Setting name="SearchMultiplier" value="3" />
7: <Setting name="MatchTolerance" value="50" />
8: </ConfigurationSettings>
9: </Role>
Its pretty similar to the <appSettings> element you are probably familiar with. There is an element for every role in your cloud project, and the <ConfigurationSettings> child element contains all the settings of your application as “name/value” pairs.
Setting Configuration Values
When setting values in the service configuration and definition files directly, you will get complete intellisense, making it very easy to work out what the appropriate values are. It is also possible to set configuration values via the tooling.
In your main cloud project (which contains the links to all your roles) you can bring up the properties window for a role. Under the ‘Settings’ tab you can add new configuration values.
When adding a new setting, the IDE will insert the relevant placeholder in the service definition, and insert the value in the service configuration. This makes the Visual Studio IDE approach a bit of a time saver and helps ensure your definition and configuration files are in sync. In the above screen shot you can see we have two configuration items: the first is a cloud storage connection string, while the second is a database connection string. Essentially, all configuration items are strings, but the IDE gives you some shortcuts when creating configuration values for storage accounts via this connection string type. Clicking the ellipses […] delivers a new modal window where you can specify the details of your storage account.
In the end this just creates another string configuration value that can be used by the app.
<Setting
name="ImageSearchSettings"
value="DefaultEndpointsProtocol=https;AccountName=ImageSearch;AccountKey=3ob...UY=="
/>
Changing Configuration Values At Runtime In Azure
Simple Handling Of Configuration Values In Code
The simplest way to leverage configuration items in your code is to use the API that comes with the Cloud tools. This provides a bunch of useful assemblies that give you strongly typed access to all the things you would want to do with your application. In the Microsoft.WindowsAzure.ServiceRuntimeassembly (and namespace) we have a sealed class called RoleEnvironment which affords us a static method for accessing configuration values at runtime:
var tolerance = RoleEnvironment.GetConfigurationSettingValue("MatchTolerance”);
Handling Storage Connection Strings In Code
1: public class StorageAccountFactory
2: {
3: public static CloudStorageAccount Create()
4: {
5: return CloudStorageAccount.FromConfigurationSetting("ImageSearchSettings");
6: }
7: }
The Catch With Using Configuration Methods In The Storage API
SetConfigurationSettingPublisher needs to be called before FromConfigurationSetting can be used
What this is trying to tell you is that you need to instruct the CloudStorageAccount to use the standard configuration definition file when loading configuration settings. That might seem a little silly at first.. where else could your configuration settings be coming from? Haven’t you just wasted half an hour reading about the Azure configuration files?
Well when running your app in Azure, your configuration will certainly come from the Azure service configuration file. But the tooling guys atMicrosoft wanted you to create apps that could still be easily switched back to running on private infrastructure without having to remove all the Azure related integration points; and unfortunately the service configuration file is an Azure only integration point. We need to be able to factor that out into abstraction and make our apps transparent to the source of configuration settings.
Let me explain further with an example. Consider this scenario: you have a web role that puts items into a queue, and a worker role that grabs items out of the queue and processes them. You have your web role setup to use CloudStorageAccount.FromConfigurationSetting to load your storage client from the service configuration file. However later on you decide to move your web role on premise, and leave the other bits running in Azure. You detach your web role from the cloud service project; it now stands on its own two feet and can be run on IIS. But that also means you no longer have a service configuration file; you’re stuck with plain old web.config again. Ideally you should still be able to use the same static method to load your storage account from configuration settings, its just that those configuration settings are now in a different place.
The SetConfigurationSettingsPublisher method that the error refers to is another static method on theCloudStorageAccount class that lets us specify where configuration should be loaded from. According to the MSDN documentation:
This method should be called once to set up the environment. The environment could be the Windows Azure runtime, in which case the publisher is a simple wrapper of the configuration reading and change event. The environment could also be a .NET environment, in which case the developer can hook up a custom configuration reader and change notification.
As stated in the documentation, you should only setup the configuration publisher once, so this ideally should happen in your role’s OnStart event. The code to tell CloudStorageAccount to use the configuration definition uses a delegate which is stored and called every time the configuration is requested:
1: CloudStorageAccount.SetConfigurationSettingPublisher(
2: (configName, configSetter) =>
3: configSetter(RoleEnvironment.GetConfigurationSettingValue(configName))
4: );
In essence, a configuration setting publisher is just an Action – a delegate that is called when attempting to get the value of a configuration setting name. In the code above we are telling the storage account client that whenever it needs to get a configuration item (configName) then call the standardRoleEnvironment.GetConfigurationSettingValue static method with that name to find and return the value.
How Can I Make My Application Utilise This Abstraction
Great question! Lets say we actually wanted to make our code more flexible and be able to switch between the configuration definition when running in Azure, over to web.config appSettings when running in plain old IIS on our own server. We would like our app to detect that it is no longer running in the world of Azure,and there is a property we can use that does just that: RoleEnvironment.IsAvailable. We can use it to customise who our setting publisher is. Consider the following static method on a factory class that I have created called StorageAccountFactory:
1: public static Action<string, Func<string,bool>> GetConfigurationSettingPublisher()
2: {
3: if (RoleEnvironment.IsAvailable)
4: return (configName, configSetter)
5: => configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
6:
7: return (configName, configSetter)
8: => configSetter(ConfigurationManager.AppSettings[configName]);
9: }
You would then call the new method like this:
1: CloudStorageAccount.SetConfigurationSettingPublisher(
2: StorageAccountFactory.GetConfigurationSettingPublisher()
3: );
Walla! Our app is now aware of when it is and is not running in Azure and can switch its settings provider as needed, while still giving us the benefit of using the CloudStorageAccount API to load our storage account from configuration.
Handling Configuration Changes At Runtime
As I mentioned earlier, you can change configuration values at runtime while your app is already strolling along happily in production. The reasons for needing to make a change can vary; perhaps you want to tweak a performance setting or change the format of log file output.
Most importantly, you don’t want your app to always stop and restart on a configuration change. The default behaviour of Azure roles is to restart on any configuration change so if you want to prevent this behaviour, read on!
You can detect changes to the role environment by handling the 2 following static evenst, available on the RoleEnvironment class:
RoleEnvironment.Changing += RoleEnvironmentChanging;
RoleEnvironment.Changed += RoleEnvironmentChanged;
When you create a new web or worker role, the first event is automatically inserted for you, along with the event handler code:
1: private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
2: {
3: if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
4: {
5: e.Cancel = true;
6: }
7: }
The default behaviour of this code is to ‘cancel’ the event on any configuration change. Cancelling the event is a bit misleading;what this actually means is that the role will be recycled, configuration changes will be applied, and the role will start up again. So “e.Cancel” actually means “e.Reboot”.
Naturally we need to make changes to this default code. Its up to you to decide which changes require the role to restart and which ones don’t. Personally, I like to make a static array of names of configuration items that I don’t want to cause a restart, like so:
private static readonly string[] ExemptConfigurationItems = new[] { "MatchTolerance", "SearchMultiplier" };
Then in the RoleEnvironmentChanging event handler we can decide whether or not to reboot, and if we don’t need to reboot, apply the new configuration changes in the RoleEnvironmentChanged event:
1: private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
2: {
3: Func<RoleEnvironmentConfigurationSettingChange, bool> changeIsExempt =
4: x => !ExemptConfigurationItems.Contains(x.ConfigurationSettingName);
5:
6: var environmentChanges = e.Changes
7: .OfType<RoleEnvironmentConfigurationSettingChange>();
8: e.Cancel = environmentChanges.Any(changeIsExempt);
9:
10: if (!e.Cancel)
11: {
12: var oldMultiplier = RoleEnvironment
13: .GetConfigurationSettingValue("SearchMultiplier");
14: }
15: }
The RoleEnvironmentChangingEventArgs supplies a Changes property which is a list of all changes that caused this event to fire.Typically these will be a change of the number of instances that the role is running, or a change to configuration items. We request all the changes that are of typeRoleEnvironmentConfigurationSettingChange which represents just setting changes. We then compare the changed items to our static list of configuration names, and if any of the changes aren’t in the list, we’ll do a reboot. If we don’t do a reboot (which means all changes belonged to our exempt list) we will apply those new changes as necessary.
Summary
And that’s all there is to know about configuration at this point in time. Here’s a couple of points summarising what we’ve learnt:
- Configuration values can be changed while your app is still running
- Default behaviour in such cases is to reboot the role
- Configuration is just XML but the Visual Studio IDE gives nice design time experience
- Connection strings are a special kind of configuration string that store details for a Windows Azure Storage account
- Using the API we can abstract our settings publisher to create flexibility of usage in Azure and non-Azure applications
- Runtime configuration changes can be checked and instance recycling can be avoided if necessary
Please keep in mind that this was valid at the time of writing and that the Azure platform is continually evolving, so there might already be a better technique for what you want to do.
Additional Links
- Overview of Service Architecture
- Changing The Windows Azure Service Configuration when running on the DevFabric
- Windows Azure Services – Exercise 2: Configuration, Logging, and Debugging
- Preparing for Application and Service Deployment - Windows Azure Development Deep Dive: Working Wi
- Preparing for Application and Service Deployment-Application Life Cycle Management for Windows Azure
- Preparing for Application and Service Deployment-Debugging and Troubleshooting Windows Azure Applic
- Preparing for Application and Service Deployment-Adding an HTTPS Endpoint to a Windows Azure Cloud
- Preparing for Application and Service Deployment - Introducing the Windows Azure Content Delivery Ne
- Preparing for Application and Service Deployment-Azure Lessons from the Trenches
- Preparing for Application and Service Deployment-Differences Between the Storage Emulator and Window
- Use Azure Service Application and Service Principal
- Preparing for the Sample Application
- Windows Azure Mobile Service - Logs for diagnostics
- Preparing Yourself for Modern JavaScript Development
- Windows Azure Service Bus - Bridge of Azure And Private Cloud
- How to set up ADB for remote machine development and local device deployment
- Key Hashes for Facebook Apps - Android application development in Windows
- Beginning Jailbroken iOS Development - Building And Deployment
- API Security: Deep Dive into OAuth and OpenID Connect
- Using the default SQL Server instance for Windows Azure development storage
- VMware Virtualization Application and Development
- 移动平台还有哪些创业机会
- 沉痛悼念张孝祥老师-记我与张孝祥老师的事。
- 今天看了一点LDAP和JNDI的资料
- 申請Google Map API Key
- JAVA中List应用简介
- Preparing for Application and Service Deployment - Windows Azure Development Deep Dive: Working Wi
- Preparing for Application and Service Deployment-Adding an HTTPS Endpoint to a Windows Azure Cloud
- JAVA Set与List集合区别
- vim删除重复行 (走过弯路的人血泪总结)
- JAVA中Map集合的使用举例
- Flex增加和删除Tree节点
- JAVA this关键字用在构造方法中
- Preparing for Application and Service Deployment-Application Life Cycle Management for Windows Azure
- 写一篇游戏主程都需要干什么的文章计划