DCSIMG
January 2009 - Posts - Alex Golesh's Blog About Silverlight Development

January 2009 - Posts

Silverlight in the Mesh and the “Cloud” – Silverlight Mesh Enabled Web Application and Azure Services (Part 4)

Hello,

In previous parts (Part 1, Part 2, Part 3) we have seen how to create Azure Hosted Service, How to Access Azure Data Services Blob data, how to create SMEWA-like application which uses those services.

While creating Silverlight application I’ve faced some problems – I couldn’t use Live Framework along with WebServices which returns non primitive types. Then I solved it by creating and hosting standard (non SMEWA) Silverlight application in the Mesh. This time I want to build “Cloud Store” client application which will use data stored in blob by Management application (created here) and provide UI to browse blob contents, “purchase” blob content and save it in Mesh Live Desktop folder. Once this Live Desktop folder will be synchronized with real folder at clients machine (with Live Mesh client installed on user machine) the purchases will arrive to the client’s machine.

This time I will not be able to use the “cheat” I’ve used in previous part – this time I really need Live Framework services to have an access to Live Desktop folders, to be able to interact with items there. From the other side I still want to use my Azure hosted services. So, let’s start…

My UI will look like this:

image

Well, build this UI is pretty easy if not take to account the fact, that I cannot receive the List<ContentEntry> I used in Part 2. I decided to do the following trick: serialize the web method result (with SOAP serializer) by myself and will use LINQ to XML to read it at the second side (close to what any web service call and automatically generated proxy does). The my function which returns me the files list turned to be like follows:

[WebMethod]
public string GetFiles()
{
  // Get the configuration from the cscfg file
  StorageAccountInfo accountInfo = StorageAccountInfo.GetDefaultBlobStorageAccountFromConfiguration();
 
  // Container names have the same restrictions as DNS names
  BlobStorage blobStorage = BlobStorage.Create(accountInfo);
  BlobContainer _Container = blobStorage.GetBlobContainer(RoleManager.GetConfigurationSetting("ContainerName"));
 
  IEnumerable<object> blobs = _Container.ListBlobs(string.Empty, false);
  List<ContentEntry> filesList = new List<ContentEntry>();
 
  foreach (object o in blobs)
  {
    BlobProperties bp = o as BlobProperties;
    if (bp != null)
    {
      BlobProperties p = _Container.GetBlobProperties(bp.Name);
      NameValueCollection fileEntryProperties = p.Metadata;
      filesList.Add(new ContentEntry() { BlobName = p.Name, FileUri = bp.Uri.ToString(), FileName = fileEntryProperties["FileName"], Submitter = "ALEX" });
    }
  }
 
  //WORKAROUND - SEEMS THERE IS NO WAY TO USE LIVE MESH ALONG WITH COLLECTIONS (?)
  ContentEntry[] files = filesList.ToArray<ContentEntry>();
  XmlSerializer serializer = new XmlSerializer(filesList.GetType());
  MemoryStream stream = new MemoryStream();
  serializer.Serialize(stream, filesList);
  string sRes = "";
 
  using (StreamReader reader = new StreamReader(stream))
  {
    stream.Position = 0;
    sRes = reader.ReadToEnd();
  }
 
  stream.Close();
  stream.Dispose();
 
  return sRes;
}

And in client UI SMEWA i created corresponding ContentEntry class and used LINQ to XML to process the response as follows:

private void LoadMeshItems()
{
  storeBL.ContentHandlerSoapClient client = new ContentDownloaderSilverlight.storeBL.ContentHandlerSoapClient();
  client.GetFilesCompleted += (s, e) =>
    {
      if (null == e.Error)
      {
        //Get the string result
        string res = e.Result;
 
        //Load in and use LINQ to XML to create the list of ConentEntry items
        XDocument xmlTopics = XDocument.Parse(res);
        var files = from file in xmlTopics.Descendants("ContentEntry")
                    select new ContentEntry
                    {
                      BlobName = (string)file.Element("BlobName"),
                      FileName = (string)file.Element("FileName"),
                      FileUri = (string)file.Element("FileUri"),
                      Submitter = (string)file.Element("Submitter")
                    };
 
        lst.ItemsSource = files;
      }
      else
      {
        //Take care of exception received from server
      }
    };
 
  client.GetFilesAsync();
}

Now I had the list of files being displayed.

Then I created the function, which iterates over Live Mesh Folders (I didn’t create some recursive mechanism, because I wanted to use only a single level folder hierarchy in this simple application) and adds them as a nodes in my TreeView control. The I’ve also added the items in folder as a leaves of this TreeView Node(s).

//Get Mesh application and the environment
MeshApplicationService meshApp = Application.Current.GetMeshApplicationService();
MeshObjectsCollection = meshApp.LiveOperatingEnvironment.Mesh;
 
//Get all root level live mesh folders, which this application could "see"
var folders = from a in MeshObjectsCollection.MeshObjects.Entries
              where a.Resource.Type == MeshConstants.LIVE_MESH_FOLDER
              select a;
 
foreach (var folder in folders)
{
  //Add them to the tree
  TreeViewNode node = new TreeViewNode();
  node.EnableCheckboxes = true;
  node.Text = folder.Resource.Title;
  node.ID = folder.Resource.Id;
  node.Icon = "images/Folder-Closed-16x16.png";
  node.IconExpanded = "images/Folder-Open-16x16.png";
  node.Tag = folder.Resource.Type;
  treeFolders.TreeViewNodes.Add(node);
 
  //Get root level folder data feeds
  var fileFeed = from a in folder.DataFeeds.Entries
                 where a.Resource.Type == MeshConstants.LIVE_MESH_FILES
                 select a;
    
  //Iterate oved files in the DataFeed
  var files = from a in fileFeed.First().DataEntries.Entries
              where a.Resource.Type == MeshConstants.File
              select a;
 
  foreach (var file in files)
  {
    //Add files to the current folder as a child
    TreeViewNode filenode = new TreeViewNode();
    filenode.EnableCheckboxes = false;
    filenode.Text = file.Resource.Title;
    filenode.ID = file.Resource.Id;
    filenode.Icon = "images/Document-16x16.png";
    filenode.Tag = file.Resource.Type;
    node.TreeViewNodes.Add(filenode);
  }
}

Now when I have the list of files I’d like to download one and save it in selected Live Desktop folder. First of all to save data in live desktop we need to do the following steps:

1. Create MeshObject (if still not exists). The type of this object should be “LiveMeshFolder”. This will be the Root folder, which will have all the downloaded files:

//Get current active Mesh Application Services
MeshApplicationService meshApp = Application.Current.GetMeshApplicationService();
 
//Get the Mesh object from Live Environment
Mesh mesh = meshApp.LiveOperatingEnvironment.Mesh;
 
// Create folder object. title is a name of new folder.
MeshObject meshObject = new MeshObject(title);
 
// It is a mesh folder
meshObject.Resource.Type = MeshConstants.LIVE_MESH_FOLDER;
 
// Add folder to collection of mesh objects. mesh is from Mesh type.
mesh.MeshObjects.Add(ref meshObject);

2.Create DataFeed which will accept our data (files). In my case Type of the DataFeed will be “LiveMeshFiles”, and Handler “FileSystem”:

// Create feed for files (required)
DataFeed fileDataFeed = new DataFeed(MeshConstants.LIVE_MESH_FILES);
 
// Set type and handler type (required)
fileDataFeed.Resource.Type = MeshConstants.LIVE_MESH_FILES;
fileDataFeed.Resource.HandlerType = MeshConstants.FILE_HANDLER_TYPE;
 
// Add new data feeds to collection
meshObject.DataFeeds.Add(ref fileDataFeed);

3. Now I can add data to my DataFeed.

//Instantiate a new DataEntry and set it's values
fileDataFeed.DataEntries.Add(...);

This time I had to stop to evaluate my options. DataEntries.Add() has couple overloads methods. All of them have only 3 different ways to get data – another parameters are metadata of the DataEntry.

First and not relevant for my case is accepts another DataEntry. Second (and most obvious option) to use in my case was overload which receives URI object. This is something I had in my hands, from ContentEntry.FileUri of selected List Item. When trying to use it I’ve got exception:

"Access is denied"

It was strange, because the very same FileUri was used as a source for preview Image on the page:

ImageSource source = new BitmapImage(new Uri((lst.SelectedItem as ContentDownloaderSilverlight.ContentEntry).FileUri));
imgPreview.Source = source;

Then I tried to use third type of overloads, which get stream. I tried to get it  via WebClient.OpenReadAsync(FileUri). This time  I’ve got SecurityException because I have no clientaccesspolicy.xml at http://devcorner.cloudapp.net and I cannot put it there because it is actually generated domain to provide endpoint to my Azure Data Services… But how ImageSource gets data from there?

Well, after “playing” a little bit with tools like Fiddler 2 and Silverlight Spy I had to conclude, that ImageSource, BitmapImage, probably MultiScaleImage and others seems to make an actual call through the browser's Javascript network stack using XMLHttpRequest. Not fair, but that’s what it is… :(

So how I solved my problem?

I created ASP.NET generic handler (*.ashx) and add it to my Azure Hosted Services. This solved me the problem with security exception and also gave me a way to return byte[] of my blob file stream:

[WebService(Namespace = "http://devcorner.cloudapp.net/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Images : IHttpHandler
{
  public void ProcessRequest(HttpContext context)
  {
    string FileName;
 
    FileName = HttpContext.Current.Request.QueryString["fileName"];
 
    // Get the configuration from the cscfg file
    StorageAccountInfo accountInfo = StorageAccountInfo.GetDefaultBlobStorageAccountFromConfiguration();
 
    // Container names have the same restrictions as DNS names
    BlobStorage blobStorage = BlobStorage.Create(accountInfo);
    BlobContainer _Container = blobStorage.GetBlobContainer(RoleManager.GetConfigurationSetting("ContainerName"));
 
    if (_Container.DoesBlobExist(FileName))
    {
      //Get Blob data to memory stream
      MemoryStream stream = new MemoryStream();
      BlobContents contents = new BlobContents(stream);
      BlobProperties props = _Container.GetBlob(FileName, contents, false);
 
      if (null != contents)
      {
        if (stream.Length > 0)
        {
          //write stream bytes back to output stream and mark content typa as JPEG image
          context.Response.ContentType = "image/jpeg";
          context.Response.OutputStream.Write(stream.ToArray(), 0, (int)stream.Length);
        }
 
        stream.Close();
        stream.Dispose();
      }
    }
  }
 
  public bool IsReusable
  {
    get
    {
      return false;
    }
  }
}

At the UI SMEWA side i used the WebClient to access generic handler and save the stream to Live Desktop when it will arrive:

string fileUri = "http://????????????.cloudapp.net/Images.ashx?fileName=" + (lst.SelectedItem as ContentEntry).BlobName;
WebClient downloader = new WebClient();
downloader.OpenReadCompleted += (s, args) =>
{
  if (null == args.Error)
  {
    Stream str = args.Result;
 
    //If got stream from fileHandler save it to the mesh folder
    if (null != str)
    {
      //Save logic here....           
    }
  }
};
downloader.OpenReadAsync(new Uri(fileUri, UriKind.Absolute));

That’s it – mission accomplished! File arrives from the Blob (via Hosted Services) and could be stored in  Mesh Live Desktop Folder!

With the SMEWA from Part 3 and Hosted Services from Part 2 it makes the complete cycle I promised in Part 1:

Local file from any client machine uploaded to the Cloud Storage with SMEWA by user with access to Management UI SMEWA, then at different machine it was downloaded from the Cloud Storage (Blob) with different SMEWA and saved in Live Desktop of user with access to this Client SMEWA. If Live Desktop folder is synchronized with real folder on client machine (via Live Mesh Client installed there) it will be synchronized like any other Live Mesh conetent.

Client SMEWA application execution video is here:

Cloud Store Clinet SMEWA - Demo

 

Enjoy,

Alex

Silverlight in the Mesh and the “Cloud” – Silverlight Mesh Enabled Web Application (Part 3)

Today I’ll talk about SMEWA (Silverlight Mesh Enabled Web Application) creation.

To create one (as for today) you need to be a member of Live Framework CTP. Invite to this CTP could be received through Microsoft Connect site.

After receiving the invitation key and redeeming it you will be able to download Live Framework SDK and Tools for Visual Studio and at Azure Services Developer Portal create new project – Live Framework CTP

image

After installing the Live Framework Tools for Visual Studio you will receive new project type (Live Framework) and will be able to create MEWA or SMWEA

image

I’ll create SMEWA. This creates 2 projects: one is actual Mesh Application, and another one is Silverlight application with references to 3 Live Framework DLL’s

image

Well, from here the things will be pretty easy (so I thought) and started to build my Cloud Store Management UI. I created pretty simple Silverlight application, which allows to see existing Blob objects, upload new file and delete exiting file. My UI final UI is looks like follows:

image

Giving the fact, that I created and tested all supporting web services already (in Part 2) the task was to create UI and connect it to those web services.

Well, I had the first “surprise” when tried to add reference to my “FileHandler” WebService (used web services description is here).

AddRef1

I’ve got proxy generation error:

AddRef2

Hmm… What is it… Why it failed?!?!? The test Silverlight app had no problem with it… I tried to learn from documentation, but frankly didn’t find any clear answer what is wrong. Here clearly stated, that “The Live Framework resource model is completely agnostic of any communication protocol or representation and no behavior is associated with the model. Live Framework resources, including FeedSync metadata, can be rendered to any wire format, such as POX, ATOM, RSS, or JSON.” So why not SOAP?

Well, I wanted to use existing services, so I had to find some solution… And I actually did – I removed 2 (out of 3) references to Live Framework and it worked:

AddRef4 AddRef5 AddRef6

Then I successfully added reference to my Cloud-based web service.

Basically, when I changed my WebMethods return parameters and input parameters to be simple .NET types (int, string, bool, etc. and not arrays, List<T>, etc.) I added the reference and called the WebService successfully.

Well – this was a small cheat, but what I will do in second SMEWA, when I will have to get the contents from the blob I just putted there and save it to Live Mesh Folder? Hmm… Stay tuned to the next part…

One small tip here – pay attention to web Service address being added to “ServiceReferences.ClientConfig”. You have to remove port (20000) before usage:

AddRef3

By removing the references to Live Framework I also lost an ability to use Live Services in my SMEWA. In next part I’ll deal with it also.

Actually, after all this trails with the management application I just removed created Silverlight application and added new standard Silverlight application. If you doing is you have to change references at Mesh Application also. When trying to debug this applications at the first time, you getting the dialog screen, which helps you to connect local application with Mesh Project:

image

The most important part there is Application Self-Link (it could be also added in Mesh Application project properties). After filling in the link Visual Studio upload the application to the Developer Mesh and opens it.

After my Silverlight application is loaded I’m executing asynchronous call to Web Service to get data:

//Create WebService SOAP Client
CloudStoreBL.FileHandlerSoapClient uploader = new ContentUploaderSilverlight.CloudStoreBL.FileHandlerSoapClient();
//Subscribe to completed events and handle returned data
uploader.GetFilesCompleted += (s, args) =>
{
    if (null != args.Error)
    {
      txtDebug.Text = "Error occured (" + args.Error.Message.ToString() + ")";
      txtDebug.Foreground = new SolidColorBrush(Colors.Red);
    }
    else
    {
      //assign returned results to list box
      lst.ItemsSource = args.Result;
      txtDebug.Text = "Ready";
      txtDebug.Foreground = new SolidColorBrush(Colors.Blue);
    }
};
//Perform the call
uploader.GetFilesAsync();

Here I got next problem – cross domain call exception. Well, it is pretty clear why I’m getting it – I’m running from https://developer.mesh-ctp.com/ and accessing web service at http://devcorner.cloudapp.net/.

All I have to do is to add clientaccesspolicy.xml to my Hosted Service:

image

After testing and debugging my SMEWA I was ready to upload it to the Mesh. I’ve uploaded the package and published the application:

image

All metadata about the application comes from Manifest.xml which is a part of package (and the Mesh Application project:

<?xml version="1.0" encoding="utf-8" ?>
<!-- 
The properties in the Manifest are applied when the application is uploaded through the Azure Services Developer Portal. 
They are not applied when debugging or running the application from Visual Studio. 
The following fields cannot be changed once the application is created:
      MultiInstance
      InstallReturnLink
      UnInstallReturnLink
      CallbackHomeLink
      RequireDelegation
If these fields are modified after the initial upload of the application, subsequent uploads will be rejected.
To successfully change these fields a new application must be created through the Developer Portal and 
the new Application Self-Link must be copied into the application’s project properties in Visual Studio.
-->
<Manifest xmlns="http://schemas.mesh.com/application/manifest/2008">
  <Name>Cloud Store Content Manager</Name>
  <Description>Cloud Store Content Management Application</Description>
  <PublisherName>DevCorner</PublisherName>
  <DisplayVersion>0.5</DisplayVersion>
  <MultiInstance>true</MultiInstance>
  <PrivacyPolicyLink>http://blogs.microsoft.co.il/blogs/alex_golesh</PrivacyPolicyLink>
  <SupportLink>http://blogs.microsoft.co.il/blogs/alex_golesh</SupportLink>
  <VendorLink>http://blogs.microsoft.co.il/blogs/alex_golesh</VendorLink>
  <RequireDelegation>false</RequireDelegation>
</Manifest>

Now I had to “install” this application to my Live Framework Mesh Desktop. I used “Install URL” from project properties page:

image

After giving myself permissions to use my application I created a new instance of it and gave it a name:

image

And now I had it on my Live Dsktop’:

image

Here the video of application execution:

Cloud Store Management SMEWA In Action

Well, this time I cheated a little bit – I created Silverlight application working in the Live Desktop  instead of real SMEWA with Live Services access… Next time I will have no choice but to deal with the problem I had today.

Stay tuned to the next part – I will create the real SMEWA with my Live Mesh folders access – my downloader UI will save the contents from Blob to the “Cloud Store Content” folder at my Live Desktop.

 

Enjoy,

Alex

Silverlight 3 Sessions at MIX09 announced

MIX09Logo[1]

 

New sessions related to Silverlight 3 just announced at MIX09!

 

The sessions are:

  • What’s New in Silverlight 3.  Learn about the new experience-oriented Silverlight 3 features, and see how to build Silverlight 3 applications using Expression Blend and Visual Studio.
  • What's New in Silverlight 3 Media.  Learn about the latest media features available with Silverlight 3.
  • Deep Dive into Silverlight Graphics.  Hear about the Silverlight 3 rendering pipeline, and learn how to enhance your application experience with the latest additions to the Silverlight graphics APIs.

Also, latest update to MIX09 sessions, including more new sessions on Silverlight, Live Mesh/Live Framework and RIA.

Registration is still open here.

 

See you at MIX09,

Alex

Silverlight in the Mesh and the “Cloud” – Hosted Service and Blob Storage (Part 2)

Hello. As I promised here I’m starting to describe my experiences in creating Silverlight Mesh Enabled Web Application (MEWA or SMEWA) with Cloud Hosted Services and Cloud Storage.

Today I’ll talk about creating the storage and supported hosted services.

First of all I needed to be a part of Windows Azure CTP and have at least 1 Storage account (to have persistent and non-persistent storage in Windows Azure) and at least 1 Hosted Services account (environment that provides the hosting and management service for cloud based applications).

To get such account(s) one should apply for them via Microsoft Connect site.

After getting invitation to this program from Microsoft Connect you could go to Azure Services Developer Portal, claim received tokens, download and install Windows Azure SDK and Windows Azure Tools Visual Studio and start creating cloud based applications. One small note here – those tools doesn’t support Windows 7 Beta right now, so it will not work there.

Once all setup done, we could go to Azure Services Developer Portal and create a new project:

image

I created 1 for Storage

image

(Endpoints are gateways that I could use from anywhere when accessing my storage account, and pair of key access is to secure my connection.)

Another project was created for Hosted Services

You could have 2 projects simultaneously running at the cloud – one for testing/debugging online and one as a real production service. The URL for the service in Staging will change every time you will re-deploy the new version of the service, thus you have to reconfigure your applications which will work with those services externally.

 image

Now back to my “Cloud Store”. I decided to provide access to my cloud storage via Web Services and those web services will be in my Host Services Project.

After installing Windows Azure Tools for Visual Studio you will get new project templates:

image

For my purposes I’ve created Web Cloud Service. In my service I’ve added 2 new web services – one which will be used by Content Management UI SMEWA, and one by Content Consumer UI SMEWA. I wish I had more Hosted Services projects allocated to use different projects for each application, but I haven’t. Also, I could use the same service for both applications but I wanted the whole thing to me close to the real world architecture.

When you creating such a project Visual Studio will create 2 projects in the solution – ASP.NET Web Application and the Web Cloud Service Project:

image

In my case I’ve also added 2 exiting projects from Windows Azure SDK Samples (Common and Storage Client) which will handle for me all communications with the blob.

Now to the interesting part. Lets see how to work with the blob storage. Most of the “real mesh code” was taken from PCD demos and samples from Windows Azure SDK so if you need more info you know where to find it.

Let’s see  the FileUpload WebMethod as an example:

[WebMethod]
public bool UploadFile(string fileName, string contentType ,byte[] f)
{
  //Assume success - its good to be optmistic :)
  bool bRes = true;
  try
  {
    // Get the configuration from the cscfg(cloud service configuration) file
    StorageAccountInfo accountInfo = StorageAccountInfo.GetDefaultBlobStorageAccountFromConfiguration();
 
    // Container names have the same restrictions as DNS names
    BlobStorage blobStorage = BlobStorage.Create(accountInfo);
    _Container = blobStorage.GetBlobContainer(RoleManager.GetConfigurationSetting("ContainerName"));
 
    // returns false if the container already exists, ignore for now
    // Make the container public so that we can hit the URLs from the web
    _Container.CreateContainer(new NameValueCollection(), ContainerAccessControl.Public);
 
    BlobProperties properties = new BlobProperties(Guid.NewGuid().ToString());
 
    // Create metadata to be associated with the blob
    NameValueCollection metadata = new NameValueCollection();
    metadata["FileName"] = fileName;
 
    properties.Metadata = metadata;
    properties.ContentType = contentType;
 
    // Create the blob
    BlobContents fileBlob = new BlobContents(f);
    _Container.CreateBlob(properties, fileBlob, true);
  }
  catch (WebException webExcept)
  {
    bRes = false;
    if (webExcept.Status == WebExceptionStatus.ConnectFailure)
      System.Diagnostics.Debug.WriteLine("Failed to connect to the Blob Storage Service, make sure it is running: " + webExcept.Message);
    else
      System.Diagnostics.Debug.WriteLine("Error creating container: " + webExcept.Message);
  }
  catch (Exception ex)
  {
    bRes = false;
    System.Diagnostics.Debug.WriteLine(ex.Message);
  }
 
  return bRes;
}

The code itself is pretty easy – create or get blob container, fill new blob properties and metadata and the create new blob to the container.

Same goes for DeleteFile WebMethod

[WebMethod]
public bool DeleteFile(string fileName)
{
  bool bRes = true;
 
  // Get the configuration from the cscfg file
  StorageAccountInfo accountInfo = StorageAccountInfo.GetDefaultBlobStorageAccountFromConfiguration();
 
  // Container names have the same restrictions as DNS names
  BlobStorage blobStorage = BlobStorage.Create(accountInfo);
  _Container = blobStorage.GetBlobContainer(RoleManager.GetConfigurationSetting("ContainerName"));
 
  //Check if desired blob exists, and if it does - delete it
  if (_Container.DoesBlobExist(fileName))
    bRes = _Container.DeleteBlob(fileName);
 
  return bRes;
}

Last, but not least is I want to able to show blob contents in my management SMEWA, so I created GetFiles WebMethod

[WebMethod]
public List<ContentEntry> GetFiles()
{
  // Get the configuration from the cscfg file
  StorageAccountInfo accountInfo = StorageAccountInfo.GetDefaultBlobStorageAccountFromConfiguration();
 
  // Container names have the same restrictions as DNS names
  BlobStorage blobStorage = BlobStorage.Create(accountInfo);
  _Container = blobStorage.GetBlobContainer(RoleManager.GetConfigurationSetting("ContainerName"));
 
  //Get blobs in my account
  IEnumerable<object> blobs = _Container.ListBlobs(string.Empty, false);
  List<ContentEntry> filesList = new List<ContentEntry>();
 
  foreach (object o in blobs)
  {
    BlobProperties bp = o as BlobProperties;
    if (bp != null)
    {
      //Get current blob properties
      BlobProperties p = _Container.GetBlobProperties(bp.Name);
      NameValueCollection fileEntryProperties = p.Metadata;
      //Create data container which will return relevan information to the client
      filesList.Add(new ContentEntry() { BlobName = p.Name, FileUri = bp.Uri.ToString(), FileName = fileEntryProperties["FileName"], Submitter = "ALEX" });
    }
  }
 
  return filesList;
}

The ContentEntry class itself is pretty simple also:

 

public class ContentEntry
{
  public ContentEntry()
  {
  }
 
  public ContentEntry(string blobName, string fileAddress, string name, string user)
  {
      BlobName = blobName;
      FileUri = fileAddress;
      FileName = name;
      Submitter = user;
  }
 
  public string FileUri { get; set; }
 
  public string BlobName { get; set; }
 
  public string FileName { get; set; }
 
  public string Submitter { get; set; }
}

After doing all that, I had to configure my service to work with local development storage. Configuration settings for cloud services defined in file named “ServiceDefinition.csdef”. In my case it is like follows:

<ServiceDefinition name="StoreBusinessTier" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WebRole name="WebRole">
    <InputEndpoints>
      <!-- Must use port 80 for http and port 443 for https when running in the cloud -->
      <InputEndpoint name="HttpIn" protocol="http" port="80" />
    </InputEndpoints>
    <ConfigurationSettings>
      <Setting name="AccountName"/>
      <Setting name="AccountSharedKey"/>
      <Setting name="BlobStorageEndpoint"/>
      <Setting name="ContainerName"/>
    </ConfigurationSettings>
  </WebRole>
</ServiceDefinition>

And the actual values for those configuration settings are in “ServiceConfiguration.cscfg” file:

<ServiceConfiguration serviceName="StoreBusinessTier" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration">
  <Role name="WebRole">
    <Instances count="1"/>
    <ConfigurationSettings>
      <!--Local Develoment Storage Account Settings-->
      <Setting name="AccountName" value="devstoreaccount1"/>
      <Setting name="AccountSharedKey" value="Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="/>
      <Setting name="BlobStorageEndpoint" value="http://127.0.0.1:10000/"/>
      
      <!--Real Cloud Storage Settings-->
      <!--<Setting name="AccountName" value="STORAGE_PROJECT_NAME"/>
      <Setting name="AccountSharedKey" value="PRIMARY_ACCESS_KEY"/>
      <Setting name="BlobStorageEndpoint" value="https://blob.core.windows.net"/>-->
 
      <Setting name="ContainerName" value="files"/>
    </ConfigurationSettings>
  </Role>
</ServiceConfiguration>

Compiling an executing the application will bring Developer Storage

image 

and the Development Fabric

 image

and finally IE with standard ASP.NET Web Application debugging experience. In my case the WebService was a start-up file, so I’ve got this:

image

My second web service has pretty simple functionality – Listing the exiting files and getting the specific file content:

image

GetFile WebMethod should return me the list of files (like FileHandler web service) – I thought I could even use the one from FileHandler… I thought so, but it will not work – will see why in last part.

GetFile WebMethod should return me the contents of the selected file (byes[] or Stream or something) – pretty easy task… Hm… This one was actually not trivial as it turns out – will see why also in last part.

 

Last thing I did after checking this service locally with some tester application I’ve deployed this service to the cloud and started to work on my SMEWA:

image

 

Stay tuned for the next part.

This part will connect the two worlds which are very close, but somehow not connected until now -  I will show how to create management SMEWA and use Azure Storage (blob) and Azure Hosted Services (I just created here) to save the data from Live Mesh Application to the Windows Azure Storage.

 

 

Enjoy,

Alex

Silverlight 2 Developer Day

Come and join me at “Getting Started with Silverlight 2” developer day at Microsoft Israel offices, 04-Feb-2009.

At this event I’ll introduce the technology and the tools for developing with Silverlight 2.

Many cool samples and good time are promised!

 

The registration is open and free of charge.

Register here.

 

See you,

Alex

Silverlight in the Mesh and the “Cloud” – Introduction/Teaser (Part 1)

Hello,

For quite some time I’m investigating the Azure Services and Live Framework. After gaining some experience, I decided to build simple project - Content Store – to share with you how to build the next generation of applications.

My “Cloud Store” project will use Windows Azure Storage Account to persist content at the cloud, will use Windows Azure Hosted Services as business logic provider (submit contents to the store, display the contents and “purchase” it). Also, my project will use Live Framework Mesh Silverlight applications to provide UI for content submitters and content viewers/buyers.

 

Schematically my project looks like follows:

image

The store itself will be pretty simple – not the real store with security restrictions, money transactions, etc. – to keep the project as simple as possible. In my “ideal” world everyone will be able to submit content, and everyone will be able to “purchase” content for free :)

Along with it, it will include the demos about how to work with storage account (blobs and possibly tables), how to create/consume hosted services, how to create Mesh applications and consume hosted services from there. Also it will show how to create mesh objects to store purchased content at users Live desktop (at the mesh).

All parts will be accompanied with sources, but to use the sources you will need to have access to Azure Services Developer Portal and have an ability to create a new projects. At the current stage you have to be a member of CTP to do it.

 

Stay tuned for next parts really soon.

 

Enjoy,

Alex

Windows 7 Beta 1 – Lets the testing begin!

Windows 7 Beta 1 gone public!

Get Windows 7 Beta 1 here.

Yesterday (09 Jan) most of us got “Server too busy” message while trying to download the beta and generate the keys.

Now, (10 Jan, 19:10 CET) everything works!

image image

Just finish installing the build on my home machine and enjoying the speed of this version!

image

Enjoy,

Alex

Posted by Alex Golesh | with no comments

Silverlight Tip: Dynamic animations

Hello,

I was asked about creation of animations dynamically for various elements. Today I’ll show how to create such animations for any (almost) Silverlight element. I’ll create some of popular standard PowerPoint animations.

I know that it is not the full set of animations available in PowerPoint, also the animations itself are probably not perfect but it is a good starting point to those who want to know how to do it.

Generally, to create the animation on-the-fly we need to create a storyboard, add one or more animations to it, add the created storyboard to resources of our container and run it.

For this sample I’ve created function, which will receive Target Element, new storyboard name and some animation definitions. The function will add created storyboard to topmost parent element resources.

private void CreateAnimation(FrameworkElement targetElement,
                             string StoryboardName,
                             AnimationSpeed StoryboardDuration,
                             AnimationType type,
                             AnimationDirection direction)
{
    //...
}

Also, I’ve created a couple Enums to define animation

private enum AnimationType
    {
      FlyIn,
      FlyOut,
      FadeIn,
      FadeOut
    }
private enum AnimationDirection
   {
     Top,
     Bottom,
     Right,
     Left,
     TopLeft,
     TopRight,
     BottomLeft,
     BottomRight,
     None
   }
private enum AnimationSpeed
   {
     ExtremlySlow = 10000,
     VerySlow = 5000,
     Slow = 3000,
     Normal = 1000,
     Fast = 500,
     VeryFast = 250,
     ExtrimlyFast = 100
   }

In my “CreateAnimation” function I did the following:

1. Prepared TransformGroup with all possible Transforms for my desired element

private FrameworkElement prepareTransformGroup(FrameworkElement targetElement, Point transformOrigin)
{
  targetElement.RenderTransform = new TransformGroup();
  (targetElement.RenderTransform as TransformGroup).Children.Add(new ScaleTransform());
  (targetElement.RenderTransform as TransformGroup).Children.Add(new SkewTransform());
  (targetElement.RenderTransform as TransformGroup).Children.Add(new RotateTransform());
  (targetElement.RenderTransform as TransformGroup).Children.Add(new TranslateTransform());
  targetElement.RenderTransformOrigin = transformOrigin;
 
  return targetElement;
}

2. Created new Duration object (based on received parameter) and Storyboard object

Duration duration = new Duration(TimeSpan.FromMilliseconds((double)StoryboardDuration));
Storyboard sb = new Storyboard();
sb.Duration = duration;

3. Then, based on direction, created animations (will see one of them – in my case other will be almost identical)

DoubleAnimation animX = new DoubleAnimation();
animX.Duration = duration;
 
FrameworkElement parent = GetParent(targetElement);
if (type == AnimationType.FlyIn)
  animX.From = parent.ActualWidth * -SCALE_FACTOR;
else
  animX.To = parent.ActualWidth * -SCALE_FACTOR;
animX.SetValue(Storyboard.TargetNameProperty, targetElement.Name);
Storyboard.SetTargetProperty(animX, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"));
sb.Children.Add(animX);
 
DoubleAnimation animY = new DoubleAnimation();
animY.Duration = duration;
if (type == AnimationType.FlyIn)
  animY.From = parent.ActualHeight * -SCALE_FACTOR;
else
  animY.To = parent.ActualHeight * -SCALE_FACTOR;
animY.SetValue(Storyboard.TargetNameProperty, targetElement.Name);
Storyboard.SetTargetProperty(animY, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"));
sb.Children.Add(animY);

4. Added created storyboard to topmost parent

FrameworkElement p = GetParent(targetElement);
p.Resources.Add(StoryboardName, sb);

5.GetParent function recursively traverses the visual tree until it gets topmost FrameworkElement

private FrameworkElement GetParent(FrameworkElement element)
{
  if ((element.Parent as FrameworkElement) == null)
    return element;
  else
    return GetParent((element.Parent as FrameworkElement));
}

Now we can call the “CreateAnimation” and then execute created animation

FrameworkElement elm = someButton;
if (null == ((LayoutRoot.Parent as FrameworkElement).Resources["myDynamicAnimation"] as Storyboard))
    CreateAnimation(elm, "myDynamicAnimation", AnimationSpeed.Fast, AnimationType.FadeIn, AnimationDirection.None);
((LayoutRoot.Parent as FrameworkElement).Resources["myDynamicAnimation"] as Storyboard).Begin();

Here it works…

Dynamic Silverlight Animation

Full sources here.

 

Enjoy,

Alex

Happy New Year!

I wish all of us Happy New Year, peace, love, good health and wealth.

 

Happy Holidays,

Alex

Posted by Alex Golesh | with no comments
תגים: