Arkiv för December, 2011

Nuget WindowsAzure.Storage.Contrib v.1.6.0.3 Updated the library quality and usability

I have had a few “how do I use AzureContrib” requests and so I decided to step up my game considerably by going all in by upping both the code quality and the usability of the project. V1.6.0.3 of the product contains all of the goodness. PM> Install-Package WindowsAzure.Storage.Contrib

The Improvements

  • StyleCop: I use StyleCop to make the style of my code live up to standards.
  • Treat warnings as errors – All: No warnings allowed in the released code.
  • XML documentation files: The entirety of the public API is documented. (Treat warnings as errors – All enforces this.) The .xml documentation files are included in the published packages for your convenience.
  • CodeAnalysis: Microsoft All Rules applied and all problems erased including strong name key signing.
  • Separate NuGet for Core functionality: Which I will re-use in the up-coming RunTime and Diagnostics nugets.

And as previously

  • Dependes on WindowsAzure.Storage nuget: Meaning you mind as well get this package to get some added benefit to Microsofts official release.
  • .NET 3.5: The only pre-requisite.

All in all I really feel this package now has pretty great code style and binary quality and that the library has good usability since everything is documented.

Installation

Using NuGet gui inside of VisualStudio type WindowsAzure.Storage and select the WindowsAzure.Storage.Contrib package:

WindowsAzure.Storage.Contrib

Or using the Package Manager Console type:

PM> Install-Package WindowsAzure.Storage.Contrib
Attempting to resolve dependency 'WindowsAzure.Storage (≥ 1.6)'.
Successfully installed 'WindowsAzure.Storage.Contrib 1.6.0.1'.
Successfully added 'WindowsAzure.Storage 1.6' to AzureContrib.WindowsAzure.StorageClient.NuGetTester.
Successfully added 'WindowsAzure.Storage.Contrib 1.6.0.1' to AzureContrib.WindowsAzure.StorageClient.NuGetTester.

Let me know what you think of this release (@noopman). Happy Coding in Windows Azure!

Cheers,

Magnus

Windows Azure Storage Contrib NuGet v1.6

In order to make the Windows Azure Storage enhancements of AzureContrib (Windows Azure contribution project) more available to developers not deploying to Windows Azure I have split out the StorageClient library enhancements to a separate NuGet Package.

Earlier this month Windows Azure Technical Evangelist Wade Wegner published the Windows Azure Storage Services Client Library as a NuGet Package (WindowsAzure.Storage). The rationale is to make Cloud Storage communication more readily available to any developer targeting the Windows Azure Storage Service. Since the Windows Azure Storage Service has a REST based API over HTTP the service may be called from anywhere that your are able to make an outbound HTTP request: Windows Azure Storage Services REST API Reference.

Given this NuGet release I wanted to do the same with the Storage Service enhancements in AzureContrib.

Said and done!

Here is a new NuGet package Windows.Storage.Contrib which gives you code that has the exact same limitations as the Microsoft.WindowsAzure.StorageClient.dll but adds to it some additional enhanced Storage Service Client Library Functionality.

Facts:

  • .NET Framework 3.5 is the only pre-requisite.
  • Depends on the WindowsAzure.Storage NuGet. This means that if you pull down WindowsAzure.Storage.Contrib you will also get WindowsAzure.Storage – the official Microsoft release.
  • Adds better testability to some of the commonly used Storage Service functionality.

Install with:

PM> Install-Package WindowsAzure.Storage.Contrib

(I’ll push the AzureContrib source code soonish. I’m in the middle of refactoring so the state of the code is not all that nice. Also I’m half anticipating a 1.7 version of the Windows Azure SDK and I might hold of on pushing the source code until I’m compatible with that release.)

Merry Christmas! ;~)

Cheers,

Magnus

Windows Azure Deploy video

En video som visar hur man enkelt deployar en vanlig Web Application från Visual Studio till Windows Azure:

http://www.youtube.com/watch?v=kH2ftDwneyY

Hoppas detta inspirerar dig till att komma igång med utveckling för Windows Azure för det är helt gratis att prova på, både utvecklingsverktyg och konto med begränsad användning så att man inte av misstag kan råka dra på sig kostnader.

Trevlig helg!

Magnus Mårtensson – Business Responsible Azure

Microsoft removes Windows Azure developer on-boarding obstacles

As a developer you get Windows Azure for free! This is actually a GREAT piece of news which shows a very strong power play from Microsoft and also that the Windows Azure Softies listen closely to customer feedback! (Continue Azure offering free for Developers is the #2 request on mygreatwindowsazureidea.com). This addresses both the business concern that developing products actually warrants a fee as well as the developer concern “What if I accidentally start up some instances or forgets to take them down). The last issue being that you have to register a credit card for a freebie. This is still the case today since you can opt to continue using Windows Azure passed the capping limits the system has put in place.

Here’s the full deal:

For 90 days you get a quota of monthly usage. After the quota is used up for the month your account will be caped. At this point you can naturally opt to use more Windows Azure to the regular costs. Included in the monthly usage are the following features:

  • Compute: 750 hours of a Small Compute Instance which means you can run one small instance full-time or other sizes at the equi)
  • Storage: 20GB with 50k Storage transactions
  • Data Transfers: 20GB outbound / Unlimited inbound data transfer
  • Relational Database: 1GB Web Edition SQL Azure database
  • Access Control: 100k transactions
  • Service Bus: Free through March 31, 2012
  • Caching: 128MB cache

So now you can just simply get to start showing Windows Azure your love because Windows Azure loves you! ;~)

Cheers,

M.

(Original announcement post: Improved Developer Experience, Interoperability, and Scalability on Windows Azure)

Speed up your jQuery by Replacing .live() with .on()

The live() is really practical since you don’t need to reattach it when adding new objects and since that it’s also widely used. But it’s not very efficient and has a few issues. Two new functions where added to jQuery 1.7 to replace the live() function, they are the on() and the off() functions. As [...]

Using-blocks and asynchronous operations

Just as the community got used to using using...

I think that the using statement in C# is a really nice invention. It’s an excellent syntactic sugar for handling IDisposables in a correct fashion. I get the impression that it took a while for the community to make it part of their daily routine to use it and now, as we are coming there, there is a shift towards asynchronous programming that may render the using block useless (or at least temporarily so, I hope to see C# 5 handling this in conjunction with the await keyword).

Recently I ran into a situation where the asynchronous approach made the using block less ideal. I still like the simplicity of it, so I started thinking about creating a pattern that would only mean a minor shift away from it; an asynchronous using block. This pattern should ideally be close enough to a regular using block so that you could make some sort of (probably regex-based) search replace approach for moving to the asynchronous version.

This blog post is also written in a way so that it follows the thought process that I went through when making the code.

Executive summary

If you don’t want to wade through the whole thought process of creating the asynchronous using approach along with tests, skip ahead to the solution.

Let’s start from the beginning

As a starting point, let’s say that you a class that can save its contents to a Stream, and that you have some code doing that, nicely wrapped in a using block:

using (Stream stream = File.OpenWrite(@”\slowserver\share\file.txt”))
{
    someClass.Save(stream);
}

...and then you figure that "nah, blocking this thread for that save... on that slow server… no thanks", and as it happens there is an asynchronous version of the method returning a Task:

using (Stream stream = File.OpenWrite(@”\slowserver\share\file.txt”))
{
    // Disclaimer: in real code you would want to get hold of that Task, observing
    // any errors on it and handle them. This is omitted from the code samples for
    // the sake of focusing on the topic at hand.
    someClass.SaveAsync(stream);
}

And now you have a bug instead. You create a Stream, pass it to the asynchronous method and then immediately dispose the stream. When the save method comes around to writing to the Stream, it's is quite likely already disposed, and you will have an exception.

I imagined that rewriting the code to work with Task but without using blocks could look like this:

Stream stream = File.OpenWrite(@”\slowserver\share\file.txt”);

someClass.SaveAsync(stream)
    .ContinueWith(task => 
    {
        if (stream != null)
        {
            stream.Dispose();
        }
    });

Simply put, this code consists of three things:

  1. Acquire the IDisposable resource
  2. Perform some action that uses that resource
  3. Dispose the resource

The goal was to encapsulate these steps into a reusable form.

Setting the stage

First I needed to figure out how to test this. The first test I wanted to write was one that used a regular using block, and that waited for the task to finish within the block. The reason was that this is a known and simple scenario where I knew the expected outcome.

[Test]
public void NormalUsingBlock_WaitForTask()
{
    var instance = new Disposable();
    using (instance)
    {
        Task.Factory.StartNew(() =>
        {
            if (instance.IsDisposed)
            {
                throw new ObjectDisposedException("The Disposable is already disposed.");
            }
        }).Wait();
    }
    Assert.IsTrue(instance.IsDisposed);
}

This is the bare minimum that I needed for the test: a class that implements IDisposable that contains a property indicating whether it’s disposed or not, and a task using that resource. If the resource is disposed before the tasks executes, an exception is thrown. Finally I verify that the resource has indeed become disposed.

The implementation of the Disposable class is the simplest possible:

public class Disposable : IDisposable
{
    public void Dispose()
    {
        IsDisposed = true;
    }

    public bool IsDisposed { get; private set; }
}

There, with that in place the first test passed as it should. Time for the next test. Now I wanted to create a scenario where the test consistently would fail if not waiting for the task within the using block; a test that would guarantee that the resource is disposed before the task tries to use it. This could probably be achieved by putting a Thread.Sleep inside the task, before checking the IsDisposed property, but Thread.Sleep is a thin ice to walk on. It can give you a reasonable chance that Dispose is invoked while sleeping, but there is no such guarantee. So I decided to use a wait handle instead, so that I can signal things in a deterministic way. I also decided to use an event to get notified when the object was disposed.

[Test]
public void NormalUsingBlock_AsyncFails()
{
    // arrange
    var instance = new Disposable();
    ManualResetEvent mre = new ManualResetEvent(false);
    EventHandler disposedHandler = (s, e) => mre.Set();
    instance.Disposed += disposedHandler;

    // act
    Task task;
    using (instance)
    {
        task = Task.Factory.StartNew(() =>
        {
            mre.WaitOne();
            if (instance.IsDisposed)
            {
                throw new ObjectDisposedException("The Disposable is already disposed.");
            }
        });
    }

    // assert
    Assert.Throws<AggregateException>(() => task.Wait());

    // clean up
    instance.Disposed -= disposedHandler;
}

For this to work I needed to add the event code to the Disposable class, and raise the event when Dispose was invoked:

public class Disposable : IDisposable
{
    public event EventHandler Disposed;

    protected void OnDisposed(EventArgs e)
    {
        EventHandler handler = Disposed;
        if (handler != null) handler(this, e);
    }

    public void Dispose()
    {
        IsDisposed = true;
        OnDisposed(EventArgs.Empty);
    }

    public bool IsDisposed { get; private set; }
}

Now I was in a position where I could verify that a regular using block would dispose my resource as expected, and also that a regular using block could dispose my resource before the task was finished, if I didn’t wait for the task inside the block. Perfect, now I had the tools to create the asynchronous using functionality.

Making it work

I realized at this point that I would needed to write a few different tests to make sure things work as I wanted them to. I also realized setting up the tests will be quite similar for each test. Since I am not a huge fan of copy/pasting large portions of code that does the same thing, I decided to encapsulate the task creation into a method:

private static Task GetTask(Disposable disposable, WaitHandle waitHandle = null)
{
    return Task.Factory.StartNew(() =>
    {
        if (waitHandle != null)
        {
            // Wait for a signal. This enables us to wait in a deterministic
            // way before checking the disposed state.
            waitHandle.WaitOne();
        }

        if (disposable.IsDisposed)
        {
            throw new ObjectDisposedException("The Disposable is already disposed.");
        }
    });
}

There, now that I had a disposable resource and an asynchronous consumer, I could write a test for an asynchronous approach to using disposable resources.

As mentioned before, there are three steps involved; acquiring the disposable resource, invoking some code that uses the resource and finally disposing the resource. Disposing the resource is done in the exact same way regardless of what resource it is. This is also reflected by the regular using block; you as a developer never supply any code for that part. The other two however must be supplied by the developer.

With that in mind, I thought out the following approach:

[Test]
public void Using_WithTask()
{
    // act
    var task = Async.Using(() => new Disposable(),
        disposable => 
        {
            return GetTask(disposable);
        });
    task.Wait();

    // assert
    Assert.IsFalse(task.IsFaulted);
}

I imagined making an Async class (for functionality facilitating some async headaches), containing a Using method that takes two parameters; a Func that produces a disposable resource, and a Func taking such a resource as input and returning a task. Since I didn’t want to be forced to unnecessary type casting, I decided to make the method generic.

Do you see the similarity of this code construction, compared to the regular using block? First we have a statement that will produce an IDisposable object of some kind, then we have a code block where we can use that object, and in this case we call the variable holding the reference to that object disposable. We use it for whatever it’s needed for, and then we return a Task (so that we can chain ContinueWith calls on it, check the result, observe exceptions and so on).

By refactoring the code sample from above (that showed using a disposable resource with tasks, but without the help of any syntactic sugar or helper methods), I came to this implementation:

public static Task Using<T>(
    Func<T> disposableAcquisition, Func<T, Task> taskFunc)
    where T : IDisposable
{
    T instance = disposableAcquisition();

    return taskFunc(instance)
        .ContinueWith(task =>
        {
            if (!ReferenceEquals(instance, null))
            {
                instance.Dispose();
            }
            return task;
        });
}

…and the test passed! There it was, the first incarnation of the async using method.

My next step would be to create a version of the async using block for when I would want to execute any piece of code inside an asynchronous using block, but that where the code does not necessarily return a Task object. It could be that you just want to push some work off the UI thread to keep the UI responsive, for instance.

As always, test comes first. By now I realized that the structure of the following tests would be quite similar to the first one, in terms of necessary setups and such, so next step was to move some setup and teardown work to separate methods, moving some noise away from the tests:

[TestFixture]
public class AsyncTests
{
    private Disposable disposableInstance;
    private ManualResetEvent manualResetEvent;

    [SetUp]
    public void Setup()
    {
        disposableInstance = new Disposable();
        manualResetEvent = new ManualResetEvent(false);
        disposableInstance.Disposed += DisposedHandler;
    }

    private void DisposedHandler(object s, EventArgs e)
    {
        manualResetEvent.Set();
    }

    // the tests go here (removed for brevity)
}

Now the disposable class instance was created with all necessary wiring set up automatically before each tests was executed, so that code did not need to reside inside each test. I like how that makes the test code more focused on its purpose. So with that in place, I could make a simple test to make sure that I could execute code that does not involve a Task in the same sort of asynchronous manner:

[Test]
public void Using_WithAction()
{
    // act
    var task = Async.Using(() => disposableInstance,
        disposable =>
        {
            // wait for the wait handle to be signaled
            manualResetEvent.WaitOne();

            if (disposable.IsDisposed)
            {
                throw new ObjectDisposedException("The Disposable is already disposed.");
            }
        });

    manualResetEvent.Set();
    task.Wait();

    // assert
    Assert.IsFalse(task.IsFaulted);
}

Same approach as before, only this time without a Task. The code will throw an exception if the disposable object is disposed prior to the wait handle being signaled. The wait handle is signaled after the Async.Using method call returns. Finally the test verifies that the disposable resource is properly disposed, and that the resulting Task does not fail.

"Wait a minute..., didn't you just say that this test scenario did not involve any Task!?"  Yes I did, and I meant it ;-) The code that executes asynchronously within the block does not use or return any Task, but the construct itself, the Async.Using method, wraps the whole thing in a new Task that is returned so that your code can wait for it, chain other operations to follow on it, observe exceptions and so on. Let's looks at the implementation and it will be more clear:

public static Task Using<T>(
    Func<T> disposableAcquisition, Action<T> action)
    where T : IDisposable
{
    T disposable = disposableAcquisition();

    return Task.Factory.StartNew(() => action(disposable))
        .ContinueWith(task =>
        {
            if (!ReferenceEquals(disposable, null))
            {
                disposable.Dispose();
            }
            return task;
        });
}

As you can see, it's very similar to the one we created first, but it creates a new Task that invokes the Action<T> delegate that is passed into the method, and returns that Task object.

At this point, the Async class started to fulfill the needs that I had, so I didn't do much more work on it, but there are of course a lot more that code be done with it.

The final Async class

Here is the the "full" Async class, should you want to use it. I say "full", since it is in no way complete; there are many overloads that you could wish for, supporting Action and Func delegates with various number of type arguments, for instance.

You can also grab a full Visual Studio solution (containing both the class and some tests) from my BitBucket repository.

/*
 * This file is created by Fredrik Mörk, twitter.com/fmork
 *
 * It comes without any warranty of any kind. Use it at your own risk.
 * But feel free to do so.
 */

using System;
using System.Threading.Tasks;

namespace Alcedo.AsyncUsing
{
    /// <summary>
    /// Contains functionality for asynchronous operations.
    /// </summary>
    public static class Async
    {
        /// <summary>
        /// Emulates a using block with asynchronous support.
        /// </summary>
        /// <typeparam name="T">A type that implements <see cref="IDisposable"/></typeparam>
        /// <param name="disposableAcquisition">A <see cref="Func{TResult}"/> that gets
        /// an object that implements <see cref="IDisposable"/>.</param>
        /// <param name="action">The action to perform asynchronously.</param>
        public static Task Using<T>(
            Func<T> disposableAcquisition, Action<T> action)
            where T : IDisposable
        {
            T disposable = disposableAcquisition();

            return Task.Factory.StartNew(() => action(disposable))
                .ContinueWith(task =>
                {
                    if (!ReferenceEquals(disposable, null))
                    {
                        disposable.Dispose();
                    }
                    return task;
                });
        }

        /// <summary>
        /// Emulates a using block with asynchronous support.
        /// </summary>
        /// <typeparam name="T">A type that implements <see cref="IDisposable"/></typeparam>
        /// <param name="disposableAcquisition">A <see cref="Func{TResult}"/> that gets
        /// an object that implements <see cref="IDisposable"/>.</param>
        /// <param name="taskFunc">A <see cref="Func{T,Task}"/> that
        /// uses the <see cref="IDisposable"/> object.</param>
        /// <returns></returns>
        public static Task Using<T>(
            Func<T> disposableAcquisition, Func<T, Task> taskFunc)
            where T : IDisposable
        {
            T instance = disposableAcquisition();

            return taskFunc(instance)
                .ContinueWith(task =>
                {
                    if (!ReferenceEquals(instance, null))
                    {
                        instance.Dispose();
                    }
                    return task;
                });
        }

        /// <summary>
        /// Emulates a using block with asynchronous support for a task that returns a result.
        /// </summary>
        /// <typeparam name="T">A type that implements <see cref="IDisposable"/></typeparam>
        /// <typeparam name="TResult">The type or the result produced by the task.</typeparam>
        /// <param name="disposableAcquisition">A <see cref="Func{TResult}"/> that gets
        /// an object that implements <see cref="IDisposable"/>.</param>
        /// <param name="taskFunc">A <see cref="Func{T,Task}"/> that uses
        /// the <see cref="IDisposable"/> object.</param>
        public static Task<TResult> Using<T, TResult>(
            Func<T> disposableAcquisition, Func<T, Task<TResult>> taskFunc)
            where T : IDisposable
        {
            T instance = disposableAcquisition();

            return taskFunc(instance)
                .ContinueWith(task =>
                {
                    if (!ReferenceEquals(instance, null))
                    {
                        instance.Dispose();
                    }
                    return task.Result;
                });
        }
    }
}

kick it on DotNetKicks.com

Forbidden Words in Windows Azure

Ever sat in code-frustration hacking away at something naming something in a way that perhaps is not so very well thought through? Ever found that naming in your code at an embarrassing time when someone else is watching? Even though it’s humorous it may also be more than a little costly and deterring to partners and colleagues. Naturally the answer is; don’t give in to the temptation and always take the high road. Windows Azure has taken this one step further and forbids certain words.

Microsoft is, of course, a company that takes business very seriously. Windows Azure is very serious Cloud Computing business indeed!

Thusly Microsoft have enforced a naming standard on Windows Azure Cloud resources. This filter prevents you from inventing a name for a Cloud resource, out of frustration, or perhaps out of intent?

therequestednamecontainswordsonthelistofforbiddenwords

Typing “bad words” causes the validation failure “The requested name contains words on the list of forbidden words.”

This is a very good move by Microsoft.

What was I trying to write for a name for my new storage account? We’ll I guess you’ll never know since in Windows Azure you can’t write that! ;~) In all honesty I was not actually typing something bad it was an abbreviation that somehow got caught in the filter. That’s actually why this interests me.

There is a really good point to this post. I hope you’re not missing it? Wouldn’t you like to read the “list of forbidden words”? I foresee a lot of giggles on that list.

Cheers,

Magnus

Find a Cloud you don’t have to pull the virtual cord from

As an IT Operations Manager you want to be able to sleep well at night knowing that your systems are safely running with your outsourcing partner. And should they get a hiccup during the night you want to rest assured that they will bounce right back! What a lot of us should really do is hire the Chaos Monkey and keep him on a retainer for all our systems in operations.

In Sweden there has just been a very major and publicly embarrassing IT-crash in a data center operated by one of the largest IT-Operators in Sweden. A couple of Swedish government agencies, a few schools, the Swedish pharmacy digital recipe distribution service and some other public service institutions have all suffered several day-long outages. The Swedish Car Testing Agency have had to resort to pen and paper, in this day and age – outrageous, and are facing a huge backlog once the systems come online again. This article is as current as ever!

[This is a re-print of my column published in the Swedish Cloud Magazine, #2 2011, here translated into English.]

Security problems in the Cloud revolve around the same old threats – you only need to learn how to handle partly other factors.

I remember at my old job some ten years ago when we got hit by worms and trojans immediately filling all of the email accounts up with spam email. Our IT-Manager resolutely walked over to the email server and pulled the cord. But the Cloud does not have a cord to pull. That’s why you have to understand how to handle the virtual Cloud cord in your Cloud partners data center if needs be.

When I hear people whine and bellyache about security in the Cloud, I sometimes want to ask: “What’s security like in your own systems?” Since you would rarely run all your systems in the Cloud it’s not a bad idea to start your security analysis in the systems you run “at home”. These systems will in the future integrate with Cloud services in different ways. All of “your own” systems have to be secure and all of the possible interactions between the parts also have to be secure.

What you should look for in your future Cloud partner is simplicity in handling your applications in their safe harbor. What services do they offer to install, secure and manages your business critical applications and your data? It is a clear trend that the Cloud is the realization of IT as a utility – calculations, storage and services on demand. Future applications are built on a foundation of Platform as a Service. Pandora's box for developers have opened and we won’t want to shut it again. The supplier of Cloud who prevails in the future is the one who best understands to offer a good nights sleep through stable hosting and simple, powerful services for such things as caching, service busses, security and much more. The most and the best services wins. You want to develop quickly and and securely today. The same rules apply in the Cloud.

Perhaps the best advice to those who are worried about security in the Cloud is – find a Cloud where you don’t have to pull your Cloud cord. But start with the cord in the systems you operate on your own.

Magnus Mårtensson – Business Responsible Cloud at Diversify

P.S.: “Microsoft believes that PaaS provides the best foundation for creating, running and managing custom applications.” Windows Azure White Papers IT as a Service D.S.

Is it worth while to move to the Cloud?

Almost daily I meet customers and developers whom have understood the fact that it will be quite difficult to move to the Cloud. Consequently I get the question if the effort is worth while. Mostly I think that it is. Here are four distinct scenarios where migration to the Cloud gives undisputable advantages.

[This is a re-print of my column recently published in the Swedish Cloud Magazine, #4 2011, here translated into English.]

  • Governance and control. Surprisingly many managements have poor control over I&O (Infrastructure & Operations) actual total cost. In a recent study by the benchmarking agency Compass we find that migration to the Cloud has cut up to 40% of costs for operations. It is most likely that the Cloud will make your operations significantly cheaper. At the same time you will get exact costs for operations so that you will be able to find expensive parts of the operations and follow up on a monthly basis.
  • Simpler and unified management of user accounts. To be able to fully utilize the properties and services in the Cloud you usually need to modify your own applications somewhat. How much work it is to rebuild your current applications depend on how they are built from the start. Most applications run fine in the Cloud. The changes most often revolve around using Cloud-based Services for example for logging in, security and messaging.
  • More rational operations. In addition to governance and control you can also achieve “Multitenancy”. This means that one of your deployments will be able to serve many customers in order to, simply put, rationalize and make your oprations much more effective. The big mail services on the Net – Yahoo Mail, Hotmail and Gmail are good examples of multitenancy. You may need to rebuild your applications to be able to handle multiple customers in one deployment.
  • A new career as a service supplier. When your applications are migrated and adapted to a life in the Cloud and also modified to handle multiple customers it is time to take advantage of perhaps the most lucrative advantage in the Cloud – online marketplaces. You will be able to shop for any type of application for what ever purpose, delivered as SaaS, in any of the marketplaces in the Cloud!

Magnus Mårtensson – Business Responsible Cloud at Diversify

Tillbaka