Understanding Amazon CloudFront and working with Web Distributions

Amazon CloudFront is a network of data centers across the world that provides lower latency for content delivery to end users. Reducing latency is the primary usage of CloudFront. It serves as a proxy to the origin servers (S3, EC2) to deliver users your static or dynamic content. Naturally there are more data centers of Amazon CloudFront than the data hosting Amazon data centers (hosting everything) and access price of content via CloudFront is cheaper than  AWS Origin sources (EC2, S3).

So if your content is accessed frequently and you are not too much worried about caching and expired data then exposing your content via CloudFront is a good choice.



In the diagram above the blue box shows the world wide CloudFront network. The router in the network is just a hypothetical (Software/Hardware) that determines the user’s location and based on that routes the request to the nearest location of CloudFront node. By this the latency is decreased because the nearest CloudFront location delivers the cached copy of the content to the user. For example the user located in Asia requests the content via CloudFront URL on his browser, the request is routed to the nearest location of user (probably in Asia or his country).

If the content is requested for the first time or the cache has expired then it is requested from the origin server and is then cached to host further requests from the region.

So, a lot of question arise at this time like how can I ask CloudFront to get my content? How do I make users route via CloudFront to my data? What about security of my data and how does it work? What if I update my content but the users get the old copy of it? What type of content I can make available via CloudFront?

It is not necessary that the end user requests data via CloudFront network but can retrieve directly from servers like Amazon S3, EC2 instances or your own servers. To route users through CloudFront we have to create web distributions and users have to use the CloudFront URL to access content via CloudFront network. Web distributions can be made from the AWS Management console or calling APIs.

You can go to the AWS Management console and create web distributions. The tasks to create web distributions are simple and are documented here. Once the distribution is created the status ensure that the status of the distribution is changed to deployed and enabled. If you have finished the steps of configuring the CloudFront distribution wait for some time like 15-20 minutes for the status to be changed to Deployed.



After creating the web distribution you will get a weird domain name of your CloudFront, if you wish you can define the domain name you own in CNAME during configuration. You have mapped the Origin of the content to the CloudFront web distribution you created. It means that the content from your Origin will be cached (according to the cache settings) if the content is accessed via the URL of the CloudFront distribution.

File Origin in S3 (located in US West data center)



CloudFront URL and S3 URL patterns

http: // d337qkfydxn3ty.cloudfront.net/images/AccessCloudFrontSample.png.
http: // awss3-samples-abdul-rafay.s3.amazonaws.com/images/AccessCloudFrontSample.png




In my configurations I specified my S3 bucket as my origin. I uploaded a file to the bucket and defined the security as publicly available. Please note that the content accessed via CloudFront in this sample is publicly available. I have made it publicly available from Visual Studio by right click –> Make Publicly Readable. For private content you have to used Signed URLs to access the secure & private content.

So I have tested successfully that my content was available via CloudFront and I was able to access it in the browser.

Instead, the user accessing the content directly from S3 he can do so with CloudFront URL with increased performance.

Next we are going to have some basic code for reading the distribution settings with AWSSDK .NET API.


The above code will print the distribution ID, CloudFront Domain Name and the Origin Domain Name.

The output is shown below from the code.


System.Xml.XmlException : {“The ‘BR’ start tag on line 6 position 30 does not match the end tag of ‘FONT’. Line 7, position 3.”}

I was having a little trouble with proxy settings so I configured the proxy settings with the below code. You can put your domain, user and password to fix the exception if you are getting it due to proxy issues.


Working with Amazon S3 (Simple Storage Service)

Amazon S3 (Simple storage service) is “in the cloud” or internet based storage service. It is managed by Amazon in their data centers world wide and provides highly available, secure and scalable solution for storage. The objects or files stored on this storage can be retrieved & saved via REST interface or APIs provided by Amazon.

The objects stored on S3 can be used in your web/mobile applications, websites, Big data analytics or for backup and archiving. It provides cost effective solution by on demand basis need of storage space and pay according to usage. The prices of storing, archiving, retrieving and transfer can be found here.

According to S3 storage architecture the objects are stored in logical containers called buckets. Buckets are tied to your amazon account and logically infinite number of objects can be stored in the bucket. When objects are stored in the bucket they can be accessed by a unique URL. There are two styles of URLs to access the buckets one is virtual hosted style URL and the other is path styled URL. The difference is in virtual style bucket name is part of the domain name where in path style it is not. You can see the examples below.

virtual host style URL example : http://bucketname.s3.amazonaws.com

path style URL example: http://s3.amazonaws.com/bucketname

Access to buckets and objects are regulated by ACL (Access control list). Each user in AWS account can be given permissions grants to buckets and objects.

In this post we will try to do basic operations with buckets and objects with .NET API. You can do the same with AWS console commands and some with REST Services. The difference between .NET API and REST API is that REST APIs are low level APIs and give us more control over transfer of data. In later posts I will try to work with REST APIs.

Using .NET SDK buckets can be created via simple classes and methods in Amazon.S3 namespace. The namespace is included in the project after referencing AWSSDK assembly. Assemblies and namespaces will be included by default by creating AWS projects from AWS templates.

1- Create a Bucket

In the below code bucket is created in S3 with a few lines of code. The first step is to create amazonS3Client object from AWSClientFactory. It is a generic client object through which any type of S3 request can be submitted.

The client takes the type of request object as a parameter. For creating a bucket PutBucketRequest object is created and the name of the bucket is specified.


After the call following is the output and bucket named “awss3-samples-abdul-rafay” is created.



2- Write an object in the bucket

With a similar pattern the PutObjectRequest type of object is created and passed to the AWSS3Client object.

The parameters (ContentBody, BucketName, Key) as shown below is set for the object of PutObjectRequest type.

Please note that there are several other parameters (like metadata) can be set but depends on the type and nature of object to be stored.


Following is the output after the object named “Test Object Key” is created in the bucket.


You can see the object created in the bucket which can be browsed from AWS Explorer in VS2010.



3- Retrieve object from S3 and write the contents in the file

The GetObjectRequest type of object is passed to the S3Client object and the object which was stored earlier can be retrieved by passing the key and the bucket name. The key should be unique per bucket and if any other object is overwritten with the same key it will be overridden. It is up to the application to ensure uniqueness and object locking when objects are retrieved and written.


Below is the output of the code and the object is read and saved in the file on the desktop with the same name.



4- Listing objects in the bucket

ListObjectRequest type of object is passed to the S3Client object with BucketName as a parameter.


5- Deleting object

DeleteObjectRequest type object is passed to S3 Client with BucketName and Key as a parameter.


The object is deleted from the bucket.


Why cloud computing?

The origin of “cloud computing” term is unknown but the concept of cloud has been there in since internet. I have seen diagrams with cloud depicting the internet or grid of sophisticated computer network. Back in old web development days I used to deploy websites and its database on remote web/database hosting servers available publicly which shared resources between different websites/databases hosted on these servers. The concept of cloud computing is the same but goes beyond websites and database and has a lot to offer.

Today the concept of cloud has evolved to an abstract remote network of computers providing processing, storage and networking capability which can be accessed via internet. Cloud computing refers to the usage of dynamically allocated resources based on demand via remote calls. The concept is an analogous to the SOA (Service oriented architecture) which provides processing, execution and business logic abstraction and reusability accessed remotely. Cloud computing goes beyond this and provides infrastructure capabilities (IaaS), platforms (PaaS) and software (SaaS) as a service which can be reused, shared, dynamically allocated and called remotely.

SOA was a paradigm shift in distributed computing from the conventional peer to peer communication and provides business benefits like lower cost, less time to market the product and technological benefits like reusability of business functions, less connectivity management, less support overhead and less effort in IT change management. I won’t go into the details of how SOA is capable to provide these benefits. You can search more about SOA if you have confusions and questions about it.

Similarly cloud computing is a paradigm shift in the business and technology model. Cloud computing also has private, public and hybrid deployment models. I will focus on public cloud deployment and discuss the factors that benefits business and technology of the organization.

Changing the Business Model:

First let’s take a look how cloud computing fits and changes the business model. By business model I mean the cost, payment, calculation and business focus shifts for an organization. If an organization adapts public cloud computing it will be renting resources than owning the resources. This will effect the balance sheet of the organization shifting CAPEX to OPEX model, meaning that amortization of resources over the years will be replaced by operating expenses which is analogous to rather than owning a car hiring a taxi. In addition, avoiding the cost of owning the resources will enable the organization to use its capital investment in its core business. You can think for e.g. instead of investing your money to buy a car & maintaining it you can use this money in other core activities and keep hiring a taxi. This means you are having pay-as-you-go model instead of paying upfront which will be helpful in increasing the liquidity for the organization.

This also transfers the technology risks like upgrades, downtimes and maintenance issues to the cloud hosting company. This is analogous to our car example that if you hire a taxi you don’t care about its maintenance, breakdowns or accidents. You ensure that whenever you want to travel you can do so without any hiccups.

So this ensures business continuity without owning the risks and mitigation methods.

There is a marketing hype that cloud computing helps organizations to save costs and achieve economies of scale. I would say it can be possible but in reality we have to look at a lot of factors. If our renting cost outweighs the owning cost then we are in a loss from cloud computing and economies of scale is an illusion. So the organization adapting cloud computing has to do its analysis and then justify this point. Normally predicting or formulating the justification of adapting cloud computing vs. owning the resources would be a challenge and would require due diligence, vision and planning. In the upcoming blog post I plan to write about some use cases of cloud computing and genes of applications that might be a good candidate to host in the cloud due to their nature and are widely accepted in the industry to be hosted in the cloud rather on premises.

Changing the Technology model:

Other important factor is elasticity and dynamic allocation of resources based on demand. This is the beauty of cloud computing that you pay for what you use and can scale up/down or de allocate resources for any duration at any point of time. This factor is very important for companies which have significant variation in customer base, business cycles and peak business hours. Lets take an example of a new dynamic website which attracted people and needs scaling up continuously because of the increase in usage and customer base. Moreover it’s used to the maximum in peak hours for 7-8 hours while rest of the time the resources are sitting idle.

In contrast if we use fixed on premises hardware it would be very difficult to scale up the hardware all the time involving downtimes and resulting in unsatisfied customers. It would also waste resources when the business cycle is in a recession or during non peak hours. For e.g. take an example of a web site selling tickets for FIFA world cup. This website is a good candidate to host in the cloud because the maximum customers logged in would be in day time in the region where the world cup has to be hosted and the volume of customers can vary. Also after some time the web site will be depreciated, in this case de allocating resources from the cloud would be easy rather than liquidating a lot of hardware.

Summing it up, the factors mentioned in this article can urge the organization to adapt cloud computing and shift the business and technology paradigm. There are a lot of myths and misconceptions about cloud computing like privacy, data security and re-architecting of applications which hopefully I will write about in the upcoming posts.

Request-Response messaging via Queues, Web services and SOA technologies

The topic is an old debate in the software industry, we have been listening to SOA experts to use modern technologies like web services, SOA middleware products while from an archaic we would listen terms like queues, reliable messaging etc.

This post will try to differentiate between these concepts, their advantages and disadvantages and probably bridge the generation gap of messaging.

Today web services are widely used due to SOAP, WS Messaging and WSS Security protocol standards. They also tend to provide synchronous mode of messaging communication between the client and the server. Almost of the modern technologies and vendors can call and consume web services easily.

Although web services have an advantage of having synchronous communication and easier way to be consumed they lack asynchronous and one way messaging. I am not sure about other technologies but WCF has a one-way asynchronous communication mechanism.

However in online transactions synchronous request-response messaging is essential and usage of web services is inevitable. Due to asynchronous processing nature of queues they should be avoided. Queues do have a request-response pattern as given below but the latency, client implementation of session management and reliability management (handshakes of messages) is an overhead.

In this post we will briefly look at request-response synchronous messaging via Queues and SOA technologies. I hope the conclusion would be interesting.

Reliability, atomicity and retry submit messages in

Web services

Reliability, retrying mechanism and atomicity is not possible in web services since they tend to be synchronous and stateless in nature. Once the request is processed there is no record of the message. This can be fragile and the messages can get lost. For example if the host process is restarted or got crashed and the messages were in-flight and were being processed by the web services. The transaction in the web services will be inconsistent in this case.


There are a lot of vendors for queues (JBOSS A-MQ, active MQ, RabbitMQ, ZeroMQ etc)  but we’ll focus on MSMQ, IBM MQ Series and JMS queues request-response pattern. All of the queue technologies expose APIs where clients can access the queues and put messages in the queues for processing. This requires clients to handle session states, implement reliability mechanism by checking ACK/NAK messages etc. The advantages and disadvantages of queues are same regardless of different vendors and technologies. The queues can be transactional, allows messages to persist and retrying of message processing can be implemented.

The queues can be of two types.

1- Point-to-point: It means that each queue will be connected to only one subscriber/destination.

2- Publish-subscribe: It means that a queue can be connected to multiple subscribers but the publisher has to publish the message by topic and each subscriber gets the copy of message.

IBM MQ Series

IBM MQ Series is a system/Message Oriented middleware (MOM) in which applications can talk to each other via queues. In the scenario below SOAP messages can also be exchanged between the applications and for application A it is a request-response pattern. In the below the same queue can also be used if the applications and queues use the publish-subscribe model.



MQ Series: Request response pattern

WCF- Reliable messaging via MSMQ

WCF offers the capability of reliable messaging via WS-RM protocol. It uses reliable sessions and MSMQ to queue messages. The disadvantage is latency, session state handling from client application and queues communication which is a different implementation from a client application than just calling a SOAP web service. However it will serve the purpose of reliability (messages are persisted) and retrying. The following figure illustrates the structure of a WCF service and client using MSMQ as a transport.


Queued Application Diagram

WCF service and client using MSMQ as a transport

JMS Request-Response messaging via Queues

I will not go deep into JMS architecture and capabilities you can read here for more information. I am focusing on request/response synchronous pattern implementation via Queues.

In the below diagram you can see that the publisher has to put message in the queue. The advantage is reliability but it comes at the cost of latency.

A publisher sends a message to two subscribers via a
topic destination and receives replies via a queue. Figure is explained in

JMS Request-Response pattern with publish/subscribe model

SOA products:

There are a number of SOA products in the market worth to mention is IBM Message broker, Oracle middleware fusion, TIBCO and Microsoft BizTalk Server. This genes of messaging system has a different set of features than the classical queuing systems like Orchestrations, Business Rules Engines, Business Activity Monitoring, Enterprise Service Bus, Dynamic Routing, Transformation and Error Recovery capabilities. They are far more capable than the classical queues.

In this post we are looking at the request-response message pattern between web services, queues and SOA products. We are concerned about how the message flows between these three set of message processing and their reliability, resilience, error recovery, retrying and atomicity. Lets take a look how message flows between SOA products in request-response pattern then we can compare with Queues and Web services. The message flow is same in all the SOA products we’ll look at the message flow in BizTalk server.


BizTalk Server messaging architecture

SOAP Request-Response Message flow along with an extra File message processing

In BizTalk server the client requests a SOAP message which is accepted by the receive location and then published into the Message Box. The subscribers (orchestrations or send ports) picks up the message. If there are multiple subscribers they will get a copy of the message.

If the subscriber is orchestration it will be the processing unit of the message. Orchestrations has persistence points so the state of the transaction will also be persisted to the store. When the orchestration has finished processing it will again publish the message to the database to be picked up by another subscriber. In SOAP request-response pattern it will be routed back to the receive location.

If the subscriber is a send port then the message is probably meant to be sent to another system outside the middleware server. If there is any transmission failure in the message it will be stored in the message box awaiting for actions to be taken (retry submission or suspend).





In all the SOA technologies a persistence data store is present like an Oracle, SQL database or file. This guarantees reliability of the messages and messages never gets lost within the engine since it is persisted to and from memory to data store.

The data store are used as a single queue while the model is the same publish/subscribe where the publisher publishes the message to the data store and relevant subscribers pick the message for processing. In SOA products publishers are receive locations (SOAP, File) and subscribers can be orchestrations (business processing units) or Send Ports (output from the middleware system). It can be a file a destination system or even another orchestration.

Advantages over queues & web services:

The use of publish/subscribe model in analogous to the publish/subscribe model in queues. The advantage is that the clients can just call SOAP messages and the queue and session handling is abstract.


The SOA technologies implement transactions (Long running/Atomic) which leverages persistence capability by which transactions can recover or resume from their last state in case of a server crash, restart or operating system process failure.

Advantages over queues & web services:

The state of the orchestration is persisted in the store and the transaction state can be retrieved and appropriate actions can be taken. Web services & queues lack this feature.

Retrying/Resubmission of messages

SOA technologies can resume the transactions from the last persisted state or even the message can be retried from beginning since it is persisted in the store.

Advantages over queues & web services:

Queues can retry the message since the message when received is stored however the state of the transaction is not stored since the subscriber will be processing the message which is disjoint from the queue. Web services lack retrying and resubmission of messages.

Publishing Windows Azure Solutions from VS2012

I will publish the MVC 4 solution which we created in the previous post to the Windows Azure. You should have a Windows Azure account from http://www.windowsazure.com. Once you have got your account after entering the payment information and selecting your subscription you can see the Windows Azure portal as below.


To deploy our application to Windows Azure we would require the following steps.

1- Create a new Hosted Service.
2- Create a new Storage Storage Account.
3- Create and configuring management Certificates.
4- Pre-publishing steps.
5- Publishing the solution from Visual Studio 2012.
6- Changing runtime configurations after deployment (Not mandatory for publishing)

1- Create a new Hosted Service

To deploy our application containing a Web and a Worker role we would need Storage Service and Hosted Service. First we would create a Hosted Service which is to host our Web and Worker role services. Click on New Hosted Service and the below popup would open. In the dialog you can choose a subscription and enter the name of your Hosted Service. Choose a URL prefix for your service I am naming it HelloWorldAzureAbdul. For the solution I am creating and affinity group which is going to have my Hosted Service in the East Asia Data Center region.

2  3

Choose Do not deploy and click OK. You can see in the Hosted Services we have a Hosted Service called “HelloWorldAzureAbdul” which we created.

4  5

2- Create a new Storage Storage Account

To create a new storage account go to “Storage Accounts” and then on the top click “New Storage Account”. In the dialog give choose a subscription and enter the URL. I will enter the same URL helloworldazureabdul and choose the affinity group which was created in Step 1. Click OK and then you can see that the new Storage Account is created.


3- Create and configuring management Certificates.

To enable Visual Studio deploy the solution to my Windows Azure solutions we need to configure the management certificates so that I can enable my account to accept deployment from my machine which has the SSL certificate. In Visual Studio go to the Server Explorer (CTRL+W, L) where you can see the Windows Azure Compute and Windows Azure Storage Node which is installed by the Windows Azure SDK.

Right Click “Windows Azure Compute” and Click “Add Deployment Environment”.


Since I don’t have any existing deployment environment Click “Manage”. In the Authentication Settings dialog click “New” which would ask you to create a new certificate on your local machine.

7  8

Enter a friendly name of the certificate, I would name it “HelloWorldAzureAbdulCert” and then click OK. You can enter the name of these credentials I would name them “HelloWorldAzureAbdulAccount”. In the second textbox you need to enter your subscription ID which you can get from the portal.

9  15

In the above dialog click “Copy the full path” of the certificate you created. Click OK and you will be able to see the Account with the Solution Environment.


In the management portal go to Management Certificates and select your subscription. Then on the top click “Add Certificate”.


Click Browse to upload the certificate from your local PC. Since we already copied the full path of the certificate created we can just paste it and click Open.


Click Ok and then in the portal you will be able to see the uploaded certificate.

13  14

4- Pre-publishing steps

Before publishing the application to the cloud we need to make sure about the dependencies that are locally present on the machine but they won’t be available in the cloud. We need to check for the referenced assemblies connection strings and application configurations. If there are any third party assemblies or your local project assemblies so set the Copy Local property of the assemblies to True.

If you look at the worker and web role settings in the Windows Azure project it is having connection strings being used by diagnostics so you can uncheck the option to remove these diagnostic connection strings so that there are no dependencies.

5- Publishing from Visual Studio 2012

Now that everything is set up we can publish the solution to the cloud from VS. Right click the Windows Azure project and then click Publish. It will open the Windows Azure publish wizard in the first step Choose the subscription.



Click Next and in the Common Settings tab choose the cloud service solution, choose the staging/production environment. In the Advanced Settings tab label the deployment and select the Storage Account. Click next to finish the publishing steps and go to the summary page.




The deployment will start and the deployment progress can be seen in the Windows Azure Activity log window in Visual Studio.


After sometime you can notice in the Server Explorer that the Web and Worker role VM’s are created in the staging environment of the deployment but will be in the stopped state.


In the Server Explorer after some time it can be noticed that the VM’s are starting.


Once the deployment is completed the status will be updated to completed and the Website URL with a GUID will be created.


You can then go the the website URL generated and see the application. In the portal you can see that the solution is deployed.



6- Changing runtime configurations after deployment.

In the previous post we added a configuration key “Message” so that it can be changed after deployment into the cloud and re-deployment can be avoided. We can change the configuration from the portal, Select the Deployment and then click Configure in the top menu. A dialog having the configuration XML will appear in which the Message value can be changed.


After changing the value click OK as shown below and the changes will take effect in each instance of the web role.



You can refresh the browser where the application in the cloud was opened and see the updated message.


Creating my first Hello World cloud solution

I was very happy with the news that recently Windows Azure was available in my region which I was waiting for. So this would be my first cloud solution which I would deploy in the cloud. To start with I will make a simple MVC 4 application and deploy in the cloud using VS 2012.

The Windows Azure SDK for .NET can be downloaded from here for VS2012/VS2010. After installing the SDK you would get the Windows Azure tools and Emulator to develop and test cloud solutions locally. After installing the SDK you can see the cloud template under C# as shown below. You can see the cloud service by selecting framework 4.0 and then selecting “Windows Azure Cloud Service”.

1   2

In the dialog box below you can select the different roles that are required for the cloud solution. In our scenario since we are making a simple MVC 4 application so a MVC 4 web role would be enough but to do more with the solution in the future I am adding a worker role. A web role is the front end of the azure service which can be assumed that it will be on a web server (IIS) in the cloud whereas a worker role can be assumed as a Windows Service which can be used for background processing.

3   4

The web and worker roles will be renamed from the default and click OK. After that the template for MVC 4 application will appear and we will choose the internet application.


As you can see in the solution there are three more projects along with the MVC 4 project. One is the Unit test project for the MVC. In the MVC project you can see that most of the files are the same but with one more additional file WebRole.cs. If you open this file you can see the entry point. This is the entry point which is going to start everything before the web application starts executing.

If you go to the worker project and open the WorkerRole.cs you can see the Run method and the OnStart method. The Run method will have the implementation of your code in which you can fire some events like call WCF service, monitor for storage etc.

The third Windows Azure project you can see a Web Role and a Worker Role configuration file. If you open the HelloWorldMvcWebRole file you can see the below configurations. In this configuration files we can specify how many web role instances we want in the cloud and the size of the VM. The VM size has different billing cost so we will specify the extra small VM since we don’t need much memory and processing. I will specify two instances for high availability and load balancing the web role.

In the settings tab I will add another configuration called “Message” in which I will specify a string value “Hello Windows Azure”. The advantage of this configuration is after deploying the solution in the cloud we can change the value and it would reflect in the application at runtime. Otherwise without configuration these changes would require redeployment in the cloud. So keeping these kind of settings in the configuration is an important decision while developing Azure solutions.



If you open the ServiceConfiguration.Cloud.csfg file you can see all the settings in the XML format which we specified above in the interface.


Now lets open the HelloWorldWorkerRole file and you will find the same GUI and configurations. Right now we are not doing any background processing so I will keep the instance count 1 and the VM size as Extra Small.


Now lets change some code in the Home Controller in the MVC Web role project as in the below screen and put a break point. We are just reading the “Message” configuration key from the Windows Azure project as shown in the code below. Lets hit F5 and run the project. Make sure that the “Compute Emulator” and the “Storage Emulator” which was installed with the SDK is started and the status is in the Running State in the task bar.


The output can be seen on the browser and note the URL that it is running locally on the PC with the Windows Azure Emulators.


You can open the Windows Azure Compute Emulator from the taskbar and see the deployment. You can see the two instances of the Web Role and one instance of the Worker Role as shown below. The Emulator runs on the local PC emulating the cloud and using the local storage. You can open the local store as shown below in the screen.



BizTalk 2010 Cookbook Released

I am very happy to announce that BizTalk 2010 Cookbook written by a great MVP Steef Jan is released.

He has done a marvelous job writing this book, the contents of the book can be viewed at Packt Website.

The book is mainly for Developers and Administrators who can gain their knowledge in Development, Maintaining, Monitoring & Deployment of BizTalk Solutions. The book has step by step implementations (recipe) of BizTalk Solutions which follows industry best practices & patterns.

I had the honor to be one of the official technical reviewer of the book along with Randal van Splunteren, Sandro Pereira & Rene Brauwers

I have enjoyed reviewing the book specially the recipes related to Monitoring and deployment, of which most of the developers and administrators are unaware.

Congratulations Steef, it has been an outstanding effort from you authoring the book so well.



Get every new post delivered to your Inbox.

Join 161 other followers

%d bloggers like this: