[T-1]PDCを楽しむなら最新Azure SDKとVisualStudio2010即ゲット!
成田空港にて出発前にブログの投稿予約。日本でこのエントリーがアップされている頃には
僭越ながら私が団長?をつとめるPDC視察ツアーご一行は無事ロサンゼルスに到着していることと思う。
そう、今週はいよいよ待ちに待ったPDC!
日本からオンラインで参戦される方々は、PDC09のホームページを随時チェックしていただき、
キーノートはやはりライブでご覧いただきたいところである。17日、18日ともにPSTで8:30から。
ちょっと夜更かしすれば見られない時間ではない。あらかじめ翌日朝いちの打ち合わせは
可能な限り排除しておいた方がよいだろう。
(日本時間では17日、18日の25:30から、という表現がわかりやすいだろうか)
twitterのアカウントはpdc09、ハッシュタグは #pdc09 が一般的になるだろう。マイクロソフトや
他のコミュニティが主催するサイドイベントなどもいくつかあってそれぞれにハッシュタグが
つくこともあると思われる。(例:The Underground@PDC09)
PDCはマイクロソフトの将来のテクノロジーの方向性を世界中のプロフェッショナルな開発者に
伝える場である。マイクロソフトではコードは書かないけどIT全般に詳しい方々をITproと呼んでいる。
マイクロソフト主催の同じような大規模技術カンファレンスであるTech・EdではITpro向けの
インフラ系やオフィス系などのセッションも行われるが、PDCは純粋に開発者のためのカンファレンス
なのである。したがって「ノンテク」な方には、正直少々絡みづらいと思われるところもあるだろう。
キーノートでカリスマエンジニアがコードをうちながら、数千人集まった会場から歓声が上がる
状況は、日本では残念ながらあまりお目にかかれない。Attendeeパーティーの名称がGeekFestと
なっていることからも分かるとおり、PDCはギークのためのお祭りなのである。
そんなPDCをひとりのエンジニアに立ち戻って心底楽しみたいところではあるのだが、
Windows Azureを中心にさまざまな発表が行われる予定になっているため、マイクロソフトの
中の人としてはそうそう遊んでいるわけにもいかないのがつらいところでもある。
さて、今回の発表の目玉になるのが Windows Azure。昨年、Ray Ozzieがマイクロソフトの
クラウドコンピューティング戦略を語りつつ、はじめて Windows Azure を披露したのもこのPDC。
昨年から1年にわたりCTPとよばれる技術評価期間を展開してきたが、そのフィードバックや、
競合各社の動きに対応した技術や施策を発表することができると思われる。注目は17日の
RayOzzieキーノート。続くBob MugliaのパートでもWindows Azureにふれる機会があるだろう。
キーノートがライブ配信されるPDCをより深く楽しむために必要な事前タスクを2つご紹介したい。
まず1つめは、先週末日本語版の一般公開も開始された VisualStudio 2010 beta2 の入手と
インストールである。PDCでは言語やフレームワークに関する多くのセッションが予定されており、
実際に手元で試してみたくなることもあるだろう。今回のPDCでは、よほどの問題がない限り、
デモはVisualStudio2010ベースになることが予想される。あらかじめ同じ環境を用意しておこう。
以前、バルマー来日イベントMDFの際にも似たようなアナウンスをしていたはずだと記憶されている
方もいるかもしれないが、MDFではMSDN購読者限定となっていた。今回は誰でもOK、太っ腹な弊社
開発製品部の気が変わらないうちに、入手、検証、評価を済ませてしまったほうがよい。
2つめは、待ちに待ったAzure ToolsのNov 2009版である。PDCで発表される多くのfeatureに
対応したAzure SDKの最新版。これまで使用してきたAzure SDKと大きく異なるので、
これは差し替えておいた方がよい。Visual Studio2010 beta2にも対応しているので、
上記の評価版と併せて新しい開発環境を構築してみてはいかがだろうか。
なお、すでにCTPに参加してAzure開発を進められてきた皆様には、追ってマイグレーションの手順を
お伝えしなければならないと認識はしているのだが、とりいそぎ下記を共有しておきたい。
(JulyCTP以前のAzureコードをNovリリースに対応させる手順をまとめたメモ←現段階ではまだ用検証)
具体的にどこが変わったかは、入手して現物をご確認いただきたい。
Assemblies
1. New assemblies and references – the assemblies are found in the ref directory in the SDK install
· Microsoft.Samples.ServiceHosting.StorageClient > Microsoft.WindowsAzure.StorageClient
· Microsoft.ServiceHosting.ServiceRuntime > Microsoft.WindowsAzure.ServiceRuntime
Configuration
2. Storage service configuration has a new connection string format.
Where you would previously have config like:
<ConfigurationSettings>
<Setting name="BlobStorageEndpoint" value="http://127.0.0.1:10000"/>
<Setting name="TableStorageEndpoint" value="http://127.0.0.1:10002/" />
<Setting name="AccountName" value="devstoreaccount1"/>
<Setting name="AccountSharedKey" value=" "/>
</ConfigurationSettings>
The endpoints are no longer configured and you have a single connection string config entry:
<Setting name="DataConnectionString" value="DefaultEndpointsProtocol=https;AccountName=YourAccountName;AccountKey=YourAccountKey" />
Table Storage
3. Consuming the storage connection string is handled through a new CloudStorageAccount class.
Where you previously had something using StorageAccountInfo:
StorageAccountInfo account = StorageAccountInfo.GetDefaultQueueStorageAccountFromConfiguration();
string queueStorageEndpoint = account.BaseUri.ToString();
string accountName = account.AccountName;
string accountKey = account.Base64Key;
The connection string can instead be consumed using the new CloudStorageAccount class:
string connectionString = RoleEnvironment.GetConfigurationSettingValue(connectionStringName);
CloudStorageAccount account = CloudStorageAccount.Parse(connectionString);
One thing I ran into here is that the key itself is no longer exposed as a property through the CloudStorageAccount class. I had a child process that needed to connect to storage, so the idea is to pass the full connection string to the child process and have it use the StorageClient. If you need access to the raw key for whatever reason – you would need to parse the connection string yourself. This change was done to avoid leakage of storage keys in log entries, etc…
4. Storage Table creation through CreateTablesFromModel now happens using a CloudTableClient and works in the dev fabric (no need to generate tables before running the project)
Where you previously might have created the table using the static TableStorage class with your StorageAccountInfo:
StorageAccountInfo tableStorageAccountInfo = new StorageAccountInfo(new Uri(Configuration.TableStorageEndpoint), null, Configuration.AccountName, Configuration.AccountKey);
TableStorage.CreateTablesFromModel(typeof(ControlMessageContext), tableStorageAccountInfo);
TableStorage.CreateTablesFromModel(typeof(ResponseMessageContext), tableStorageAccountInfo);
You do the same now using a CloudTableClient with the CloudStorageAccount
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
CloudTableClient.CreateTablesFromModel(typeof(ControlMessageContext), Convert.ToString(storageAccount.TableEndpoint), storageAccount.Credentials);
CloudTableClient.CreateTablesFromModel(typeof(ResponseMessageContext), Convert.ToString(storageAccount.TableEndpoint), storageAccount.Credentials);
5. Table storage entity and context class names have changed as well as the base class definition for the service context
TableStorageEntity à TableServiceEntity
TableStorageDataServiceContext à TableServiceContext
The TableStorageDataServiceContext base class previously took your StorageAccountInfo as the base class constructor:
public class ControlMessageContext : TableStorageDataServiceContext
{
public ControlMessageContext(StorageAccountInfo info)
: base(info)
{
Instead, now a TableServiceContext is used which has a base class that takes the service Uri and storage credentials which are both properties of the new CloudStorageAccount that is setup using your connection string:
public class ControlMessageContext : TableServiceContext
{
public ControlMessageContext(string baseAddress, StorageCredentials credentials)
: base(baseAddress,credentials)
{
6. TableStorageHelpers.EvaluateException() was removed
In order to get detailed storage exception information TableStorageHelpers.EvaluateException() was previously used to extract storage details:
catch (Exception e)
{
HttpStatusCode status;
StorageExtendedErrorInformation errorInfo;
TableStorageHelpers.EvaluateException(e, out status, out errorInfo);
if (errorInfo != null)
{
Log.WriteEvent(Severity.Error, String.Format("Failed to send control message. Error: {0} : {1}",
errorInfo.ErrorCode, errorInfo.ErrorMessage));
Instead, you can now specifically catch StorageException which contains a StorageExtendedErrorInformation property containing this information:
catch (StorageException e)
{
StorageExtendedErrorInformation errorInfo = e.ExtendedErrorInformation;
if (errorInfo != null)
{
Log.WriteEvent(Severity.Error, String.Format("Failed to send control message. Error: {0} : {1}",
errorInfo.ErrorCode, errorInfo.ErrorMessage));
7. TableStorageConstants no longer exists.
I was using this to initialize my DateTime objects since you can’t use DateTime.MinValue:
http://dotnetbyexample.blogspot.com/2009/08/azure-tables-and-datetime-some.html
This may be an oversight in the new SDK. The values for TableStorageConstants can be used directly if still needed though (from Reflector):
static TableStorageConstants(){ MaxStringPropertySizeInBytes = 0x10000; MaxStringPropertySizeInChars = MaxStringPropertySizeInBytes / 2; MinSupportedDateTime = DateTime.FromFileTime(0L).ToUniversalTime().AddYears(200);} Local Storage
8. The ILocalResource interface no longer exists – instead replaced by the LocalResource class
This is a simple change – what was:
ILocalResource dumpPath;
dumpPath = RoleManager.GetLocalResource("AzureDbg");
string dumpStoreLocation = dumpPath.RootPath;
Is now: LocalResource dumpPath;
dumpPath = RoleEnvironment.GetLocalResource(AzureDbgLocalStorageName);
string dumpStoreLocation = dumpPath.RootPath; Also, the layout of the local resource configuration in the service definition changed slightly and now accepts multiple entries: <LocalResources>
<LocalStorage name="LocalStorageConfigName" />
</LocalResources>
Blob Storage
9. BlobStorage and BlobContainer objects have also changed into CloudBlob objects that use references to refer to each other
Here’s an example of code I migrated to upload a file into blob storage:
Get a BlobStorage object using the StorageAccountInfo:
BlobStorage storage = BlobStorage.Create(account);
Get my container or create it if it doesn’t exist:
BlobContainer container = storage.GetBlobContainer("containername");
if (!container.DoesContainerExist())
{
container.CreateContainer();
}
Create a new BlobContents, fill it with a FileStream:
BlobProperties properties = new BlobProperties(ZipFileName);
using (FileStream fs = new FileStream(DumpLocation + ZipFileName, FileMode.Open))
{
BlobContents blob = new BlobContents(fs);
Create a the blob in the container:
container.CreateBlob(properties, blob, true);
}
With the new StorageClient:
Setup a new CloudBlobClient using my CloudStorageAccount to talk to blob storage:
CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString);
CloudBlobClient blobClient = new CloudBlobClient(account.BlobEndpoint, account.Credentials);
Using the CloudBlobClient get the container reference for my container and create it if it doesn’t exist:
CloudBlobContainer container = blobClient.GetContainerReference("containername");
container.CreateIfNotExist();
Get the blob reference for my container and create a CloudBlob with it:
CloudBlob blob = container.GetBlobReference("myfilename");
Upload the file into the blob:
blob.UploadFile(FilePath + "myfilename");
Logging & Misc
10. RoleManager.WriteToLog is gone
Instead of using RoleManager.WriteToLog use the standard Trace.WriteLine() classes which can be picked up and pushed into table storage using the new Diagnostics API
11. RoleManager.IsRoleManagerRunning is replaced with RoleEnvironment.IsAvailable