Click here to Skip to main content
Click here to Skip to main content

HealthReunion - A Windows Azure based healthcare product

, 26 Jun 2013 BSD
Rate this:
Please Sign up or sign in to vote.
HealthReunion is a complete solution for medium , large scale healthcare providers and patients. It's a Azure based hosted solution

Please note

This article is an entry in our Windows Azure Developer Challenge. Articles in this sub-section are not required to be full articles so care should be taken when voting. Create your free Azure Trial Account to Enter the Challenge.

 

 

Download Source Code - Service Bus Message 

 

Download Source Code - Service Bus Message With Topics 

Download Source Code - EMR Provider Portal  

Download Source Code - DACPAC-BACPAC-Exporter Utility  

 

Download Source Code - HealthReunion Federation Database Script  

Download Source Code - SQL Azure Federation Utility  

Download Source Code - SQL Azure REST Based Management Utility  

Download Source Code - Pascal Pyramid Experiment  

 

Download Source Code - HealthReunion Service Bus, WPF Client-Server App  

Download Source Code - Azure Session Management Worker Project  

Download Scripts for Azure Session Management   

 

Download Source Code - HealthReunionDataService   

Download Source Code - Patient Portal Web Solution(Responsive Based Design)   

Download Source Code - HealthTopics Windows Phone App    

Download Source Code - HealthTopics Web API    

Download Source Code - HealthAnalyser    

Download Source Code - HealthReunion Provider Portal (Responsive Based Design)    

Download User Manual (HealthReunion Provider and Patient Portal)    

Download Sample CCR/CCD Document    


Disclaimer           

This article is published for CodeProject-Windows Azure Challenge  http://www.codeproject.com/Competitions/637/Windows-Azure-Developer-Contest.aspx. No part of the product , source code etc belongs to the organization that I work / worked for. The source code which is being uploaded as a part of his article is a work in-progress of the actual system to be implemented as a part of the contest.    

Website URL    

 

 


HealthReunion Provider Portal  

 

 

 

http://healthreunionproviders.azurewebsites.net/   

Username - demo  

Password - demo123  

 


 

HealthReunion Patient Portal  

http://healthreunionpatients.azurewebsites.net/     

UserName - demo  

Password - demo123  


HealthAnalyser  

http://healthanalyser.azurewebsites.net/      


Pascal Pyramid Experiment  

 

http://pascalpyramidexperiment.azurewebsites.net/  

 


 

 

 

Web API for HealthTopics   

 

http://myhealthtopics.azurewebsites.net/api/healthtopics/asthma



Windows Azure Challenge        

Challenge 1   -  First Challenge: Getting Started. April 15 - May 3

Challenge 2   -  Build a website. April 29 - May 12. 

Challenge 3  -   Using SQL on Azure. May 13 - May 26                         

                         Lessons Learnt

                         Pascal Pyramid Experiment

                         SQL Azure Management 

                         SQL Azure Database Connection

                         Migrating from SQL Server to SQL Azure 

                         SQL Azure Backup and Restore  

                         SQL Azure Federation with Entity Framework 

                         SQL Azure REST API  

Challenge 4  -  Virtual Machines. May 27 - Jun 9 

Creating a new virtual machine (VM)

Manage endpoints

Managing Virtual machines

Hosting Web application (HealthReunion) in virtual machine 

How to run intensive task in .NET on a Windows Azure virtual machine 

  Load balancing in Azure VM 

Managing sessions in a load balancing environment

Deploying the Worker Role as a Cloud Service for cleaning up of expired sessions. 

Command line tools for Managing Azure VM 

Setting up HTTP based file server in Azure Virtual Machine

          Setting up SQL Server in Azure VM 

Creating and consuming WCF Data Service

Design , Implement and Host Patient Portal MVC4 based web solution for patients 

Conclusion  

  Challenge 5  -  Mobile access June 10 - June 24

          HealthTopics , A Windows Phone Mobile App 

HealthAnalyser , A mobile optimized responsive design based website 

HealthReunion Providers Portal - A Mobile optimized , Responsive design based website 

The Trick of Responsive Design  

Conclusion 

 

 




 

Introduction       

In this article we will discuss the design and implementation of a healthcare product "HealthReunion" which makes use of Windows Azure and takes advantage of the suite. This product is planned to keeping Interoperability in mind.

There is a huge investment on healthcare products. Healthcare products are much more complex, involves lot of work in terms of sharing the patient health information, supporting different formats of data exchange , securing the patient health information and make it easy for one to export and import the patient health information. HealthReunion is a one such product which is designed to collaborate and exchange patient healthcare information between heterogeneous systems. This product can be used by medium and large hospitals or private practices. 

This products is designed to make use of the following Windows Azure features and take benefit from it. The reason being azure is , it provides a single suite and a complete solution for any organizations to build and host products, small organizations have less burden and will not have to worry about managing the servers, licensing, securing the data, making sure the service , website, SQL Server to be available up and running and for clients.

1. Websites 

As Windows azure provides a scalable websites , we can make use of this feature and deploy a web based solution for providers and patients. Also it's very easy for one to deploy our solution directly to windows azure. 

Implement ASP.NET Web API and deploy them in Windows Azure as websites so that the mobile or desktop clients can easily consume data.   

2. Cloud Service  

The greatest advantage of using cloud service and hosting our HealthReunion sites is allows flexible scaling.  We can have multiple web roles and/or working roles each with its own application files and configurations. As a part of azure service level agreement ,  we must be having at least two instances of web roles . As the cloud service deployment gives us an option to deploy our site in staging environment , there we can test and make sure everything works fine. Later we can promote easily to production environment. 

In Summary the  advantage of using cloud service is , it can be easily scaled by increasing the number of web role instances i.e the virtual machine. Also we can scale the SQL Database instance, by changing the SQL Database edition and the maximum database size.   

3. SQL Azure

The reason is to rapidly create, scale and extend applications into the cloud. We have no overhead of maintaining and securing the patient health information. Also for a small healthcare organization , there are lots of benefits of making use of SQL Azure as they need not be worried about the licensing , administering and making sure that it is always available. With SQL Azure providing 99.9% of availability , we can easily go with it.  

4. Service Bus on Azure

As of now , this product is planned to make use of Service bus queues because it is reliable and provides a
persistent messaging between applications. Also the biggest advantage is the queues can be processed by any clients who has access to the storage account. We will also take advantage of Service bus and assess queues via standalone or REST services developed using .NET or Java. Also it helps a easy way to develop our HealthReunion components to asynchronously communicate and process messages from Queues.

5. Software as a Service (SaaS)

With Software as a service , the HealthReunion is made available to customer so that they can pay and use our services. Using the web based interface they can register their hospital , configure their hospital specific information and can take part in import and export of patient health information which is a part of HIE (Health Information Exchange) System.

With SaaS , the customers have no worries about how it works internally. They can opt in and opt out of the services anytime. This is one of the greatest advantage, one can give a try with our product and see how it goes. In Summary the customer need not buy our entire product suite  In turn they will have to pay for the services that we are providing them.  

Also there are other kinds of services that I have planned to provide in future , say processing the patients health information coming in different formats like CCR, CCD, HL7 messages etc , provide a way for customers to use selected components.

6. Infrastructure and Platform as a Service (IaaS & PaaS)

HealthReunion is designed to be deployed and make use of Azure Platform as a service, With this we are not going to buy either the hardware/software and other related services for managing our product. We just need to focus on our business logic related to HealthReunion , the rest is taken care by Azure platform as a service. In summary we have no worries in managing the hardware or software , licensing issues etc. 

7. Azure Mobile Service

Mobile services is an option I have kept in mind, so that the clients can receive push notifications, SMS and email. 

8. Virtual machines

Have a plan , however as of now I never played around with it. Planning to come up with a Java based client for HealthReunion , and run the same in VM.    

We will make use of the windows azure endpoints to access the storage. Also the other biggest advantage of using this approach is we can use REST or HTTP based services to access the storage accounts. There may be different clients desktop/mobile who can consume the data, in such cases it's easy to go with this approach. If we wish to have some additional disk-space , we just need to create new storage accounts and make use of it. That's the beauty of azure hiding or abstracting the details so that neither as a developer nor as a customer have to worry about how the data is stored what disks or RAID drives are used etc. 

We will be using Azure Brokered messages, where the producers are HealthReunion clients send messages so that we can process , validate and maintain them in Azure SQL Server.  We will be taking advantage of the messaging infrastructure which stores all the messages reliably so that we don't miss-out any messages. The main reason behind using the brokered messages is for better load balancing where the producers can send multiple messages at a time, behind the scene we will process the messages.  

The below picture shows the how the patient health information is being centralized and accessed by various hospitals , labs etc.

 

 

Below flowchart shows hows the high level understanding of "HealthReunion" 
 

The below picture shows the mobile client accessing patient health information. 

Features of HealthReunion   

1. Healthcare providers should be able to share patient healthcare information.

2. Patients should be able to access their healthcare information securely from cloud storage. 

3. Healthcare providers should be able to import or export patient health information supporting different format of data exchange like Continuity Of Care Record (CCR), Continuity Of Care Document etc.

4.  A Mobile portal for Patients and Providers to access the patient health information. 

 

Security

 

We will be using SSL for securing the data exchange between the client and the cloud service. HealthReunion makes use of Cloud Services , the client application will be configured to use certificates and an HTTPS endpoint will be added to the WebRole. 

 

All services which are deployed to Windows Azure will make use of Service Certificates wherein all the certificate is stored in the hosted service. 

Below is the command for creating a self signed certificate for testing

makecert -sky exchange -r -n "CN=RanjanAzure" -pe -a sha1 -len 2048 -ss My "RanjanAzure.cer"  

The certificate will be created in Personal folder and can be managed using certmgr - Certificate manager.

 

Uploading the certificate (*.CER) to Azure. 

We will have to export the the *.CER certificate file using Certificate Export Wizard. We will be using this file and upload the same to our HeathReunion Cloud Service.  

 

Challenge 2 

Building Website 

We will see the real meat of building HealthReunion Provider Portal here. Feel free to have a feel about the hosted azure providers portal at http://healthreunion.azurewebsites.net/ , with the defaut username :  demo and password : demo. You can also download the latest source code for provider portal. 

Provider portal is designed in such a way that hospital admins can log in to the portal and create new providers. In turn providers can log in and create one or more users so that they can create new patients and upload patients medical documents, view clinical document, view patient information.

Let us see the Log in for Provider Portal. Below is the login screen , which will be shown first so that providers can log in with the username and password or create new provider and key in provider specific information. 

Below is the code block of UserRepository. You can notice the data access is build with Entity Framework approach and we have repository for every entities which does CRUD operation specific to the entity. 

public class UserRepository
{
	public UserRepository()
	{
		//
		// TODO: Add constructor logic here
		//
	}

    public void AddUser(User user)
    {
        using (var dataContext = new healthreunionEntities())
        {
            // Add user entity
            dataContext.Users.Add(user);
            // Save changes so that it will insert records into database.
            dataContext.SaveChanges();           
        }
    }
}

 

Let us see how we can create new providers. Below is the screenshot of the actual implementation for creating new providers. 

Below is the code snippet for ProviderRepository. We have methods for getting all providers , validating the user based on the provider, Add new provider with default user etc. 

public class ProviderRepository
{
	public ProviderRepository()
	{
		//
		// TODO: Add constructor logic here
		//
	}

    public List<provider> GetAllProviders()
    {
        using (var dataContext = new healthreunionEntities())
        {
            return dataContext.Providers.ToList();
        }
    }

    public bool ValidateUser(string userName, string passWord, int providerID)
    {
        using (var dataContext = new healthreunionEntities())
        {
            return dataContext.Users.Where(u => u.UserName == userName && u.Password == passWord && u.ProviderId == providerID).FirstOrDefault() != null;
        }
    }
    
    public void AddProviderWithDefaultUser(Provider provider, User user)
    {        
        using (TransactionScope scope = new TransactionScope())
        {
            using (var dataContext = new healthreunionEntities())
            {
                // Add provider enity
                dataContext.Providers.Add(provider);

                // Save changes so that it will insert records into database.
                dataContext.SaveChanges();

                user.ProviderId = provider.ProviderId;

                // Add user entity
                dataContext.Users.Add(user);

                dataContext.SaveChanges();

                // Complete the transaction if everything goes well.
                scope.Complete();
            }
        }
    }
}

Let us see how we can add new patient information. Below is the screenshot shows the create new patient screen for adding a new patient. The whole idea is providers can create their patient and manage their clinical documents. Under patient portal , the patients can login and check their health information. 

Below is the code snippet for PatientRepository

public class PatientRepository
{
	public PatientRepository()
	{
		//
		// TODO: Add constructor logic here
		//
	}

    public Patient GetPatientById(int patientID)
    {
        using (var dataContext = new healthreunionEntities())
        {
            return dataContext.Patients.Where(p => p.PatientId == patientID).FirstOrDefault();
        }
    }

    public List<patient> GetAllPatients(int providerId)
    {
        using (var dataContext = new healthreunionEntities())
        {
            return dataContext.Patients.Where(p => p.ProviderId == providerId).ToList();
        }
    }

    public void AddPatient(Patient patient)
    {
        using (var dataContext = new healthreunionEntities())
        {
            dataContext.Patients.Add(patient);
            dataContext.SaveChanges();
        }
    }
}

 

Let us now see how the providers can view their patient information. Below is the screenshot shows patient information in a Gridview and allows Providers to see additional or detailed information

 


 

 

Below is the code snippet for the PatientRepository. Notice the implementation for getting all patients by provider Id, get patients by Id and adding new patient. 

public class PatientRepository
{
	public PatientRepository()
	{
		//
		// TODO: Add constructor logic here
		//
	}

    public Patient GetPatientById(int patientID)
    {
        using (var dataContext = new healthreunionEntities())
        {
            return dataContext.Patients.Where(p => p.PatientId == patientID).FirstOrDefault();
        }
    }

    public List<patient> GetAllPatients(int providerId)
    {
        using (var dataContext = new healthreunionEntities())
        {
            return dataContext.Patients.Where(p => p.ProviderId == providerId).ToList();
        }
    }

    public void AddPatient(Patient patient)
    {
        using (var dataContext = new healthreunionEntities())
        {
            dataContext.Patients.Add(patient);
            dataContext.SaveChanges();
        }
    }
}

We will see how the provider manages the patient clinical documents. The providers can upload CCD/CCR documents for patient. Below is the screenshot for the same

Below is the code snippet for DocumentRepository. It deals with Adding new clinical documents, Getting documents etc

public class DocumentRepository
{
	public DocumentRepository()
	{
		//
		// TODO: Add constructor logic here
		//
	}

    public void AddDocuments(Document document)
    {
        using (var dataContext = new HealthReunionEntities())
        {
            // Add document entity
            dataContext.Documents.Add(document);
            // Save changes so that it will insert records into database.
            dataContext.SaveChanges();
        }
    }

    public Document GetDocumentById(int documentId, string documentType)
    {
        using (var dataContext = new HealthReunionEntities())
        {
            return dataContext.Documents.Where(d => d.DocumentId == documentId && d.DocumentType.Equals(documentType)).First();
        }
    }

    public List<patientdocumentsmodel> GetDocuments(int patientId)
    {
        var patientDocumentsList = new List<patientdocumentsmodel>();
        using (var dataContext = new HealthReunionEntities())
        {
            var patientDocuments = (from doc in dataContext.Documents
                                    join patient in dataContext.Patients
                                    on doc.PatientId equals patient.PatientId
                                    where doc.PatientId == patientId 
                                    select new { Patients = patient , Documents = doc}).ToList();

            foreach (var item in patientDocuments)
            {
                patientDocumentsList.Add(new PatientDocumentsModel
                {
                    FirstName = item.Patients.FirstName,
                    LastName = item.Patients.LastName,
                    MiddleName = item.Patients.MiddleName,
                    DocumentId = item.Documents.DocumentId,
                    DocumentType = item.Documents.DocumentType,
                    PatientId = item.Documents.PatientId,
                    ProviderId = item.Documents.ProviderId,
                    CreationTime = item.Documents.CreationTime,
                    DocumentText = System.Text.Encoding.UTF8.GetString(item.Documents.Document1)
                });
            }

            return patientDocumentsList;
        }
    }
}
</patientdocumentsmodel></patientdocumentsmodel>

The password encryption is does as follows. For now it is very simple method, Things will be improved further.

I'm reusing the encryption and decryption mechanism provided by codeproject user -"kadu.sumit" http://www.codeproject.com/Tips/306620/Encryption-Decryption-Function-in-Net-using-MD5Cry. Thanks for the code snippet and a simple article. 

We are just making use of Encrypt method , also I have made a small change to get the password phrase to get the password phrase by reading the certificate and returning the Raw certificate data as password phrase.

Here's how It's done, coming next we will have to read the certificate file from the certificate store.

 public static string ReadCert()
    {
        // The path to the certificate. 
        string Certificate = HttpContext.Current.Server.MapPath("HealthReunionHealthVaultIntegration.cer");

        // Load the certificate into an X509Certificate object.
        X509Certificate cert = X509Certificate.CreateFromCertFile(Certificate);

        // return certificate raw data string
        return cert.GetRawCertDataString();
    }

Database Design for Providers Portal (HealthReunion) 

Below is the entity framework design that I have exported. We only have few main tables as a part of this portal.



1. Provider table - It's used for manage the providers (doctors) information. 

CREATE TABLE [dbo].[Providers](
	[ProviderId] [int] IDENTITY(1,1) NOT NULL,
	[ProviderName] [varchar](100) NOT NULL,
	[ProviderLogo] [varbinary](max) NOT NULL,
	[ProviderDescription] [varchar](500) NULL,
	[PrivacyStatement] [varchar](max) NULL,
	[AuthorizationReason] [varchar](500) NULL,
	[TermsOfUse] [varchar](500) NULL,
 CONSTRAINT [PrimaryKey_df6c62bf-be25-45c7-8ef4-4f06e143c353] PRIMARY KEY CLUSTERED 
(
	[ProviderId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
Providers can create multiple users , there is one to many relationship between Providers and Users.

2. Users - It's used for managing the users. 
CREATE TABLE [dbo].[Users](
	[UserId] [int] IDENTITY(1,1) NOT NULL,
	[UserName] [varchar](50) NULL,
	[Password] [varchar](50) NULL,
	[ProviderId] [int] NOT NULL,
 CONSTRAINT [PrimaryKey_d9426c40-1ba4-43f5-8feb-940856412067] PRIMARY KEY CLUSTERED 
(
	[ProviderId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

3. Patient table - Every providers can have multiple or many patients. So it's 1 to many relationship between the providers and patients. 
 
CREATE TABLE [dbo].[Patients](
	[PatientId] [int] IDENTITY(1,1) NOT NULL,
	[ProviderId] [int] NOT NULL,
	[MedicalRecordNumber] [uniqueidentifier] NOT NULL,
	[DOB] [date] NOT NULL,
	[Sex] [bit] NOT NULL,
	[Address] [varchar](500) NULL,
	[Phone] [varchar](15) NULL,
	[Email] [varchar](20) NULL,
	[LastName] [varchar](50) NOT NULL,
	[FirstName] [varchar](50) NOT NULL,
	[MiddleName] [varchar](50) NULL,
	[City] [varchar](50) NULL,
	[State] [varchar](50) NULL,
	[Country] [varchar](50) NULL,
	[IsActive] [bit] NOT NULL,
	[RegisteredWithHealthVault] [bit] NOT NULL,
 CONSTRAINT [PrimaryKey_d9426c40-1ba4-43f5-8feb-940856412069] PRIMARY KEY CLUSTERED 
(
	[PatientId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

4. Documents - It's used to manage patients documents like CCD, CCR. These documents will be exported from an Enterprise health record or Enterprise medical record, the providers will make use of HealthReunion portal for uploading the patients documents. Every provider can have one or more patients and every patients can have one or more documents. Its again one to many relationship.
 
CREATE TABLE [dbo].[Documents](
	[DocumentId] [int] IDENTITY(1,1) NOT NULL,
	[PatientId] [int] NOT NULL,
	[ProviderId] [int] NOT NULL,
	[CreationTime] [datetime] NOT NULL,
	[Document] [varbinary](max) NULL,
	[DocumentType] [varchar](50) NOT NULL,
 CONSTRAINT [PrimaryKey_d9426c40-1ba4-43f5-8feb-940856412070] PRIMARY KEY CLUSTERED 
(
	[DocumentId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Easter egg challenge  

 

We will see how we hide our easter eggs in HealthReunion web application. Below is the screenshot shows up when you are find the easter egg.

All we have to do to enable or see the hidden easter egg "One needs to click on the HealthReunion Logo".Below is what it happens when you click on the logo. 

1. The easter egg logo gets replaced with the HealthReunion logo. 
2. Animation text with the Welcome to CodeProject-Windows Azure Contest gets displayed, It moves down and up and with and repeats the same. 
3. A Song will be played at the background. We are using HTML5 Audio element. 
4. The bob logo starts vibrating. 

The above everything is done with the help of jquery animation, HTML5 and some CSS.

 

Here is the details about the easter logo. Please note the we are reusing the bob log provided in the challenge and created a nice easter logo with bob init. I have used Adobe PhotoShop for this.

How do we replace the HealthReunion Logo and display animated text?


If you see the source code for master page , the Logo is placed inside the div named 'Logo' , we just need to handle the click event and replace the image with our bob logo. 
 

$('#logo').click(function () {

            $('#easterEggAnimation').show();

            $('#logo').html('<img src="images/EasterEgg-CodeProjectBob.png" alt="CodeProject bob" />');  

            jQuery('#logo').vibrate();

            var stage_left = (($('body').width() - 866) / 2);
            var stage_top = 30;

            $('#easterEggAnimation').sprite({ fps: 8, no_of_frames: 14 })
                .spRandom({
                    top: 40,
                    left: stage_left + 20,
                    right: 400,
                    bottom: 140,
                    speed: 3500,
                    pause: 1000
                });

            var audio = document.getElementById("easterEggAudio");
            audio.play();
        });

How are we playing the audio ?

With the help of HTML5 Audio element , it was very easy to include the audio tag and play the same. Please refer the above code for getting the audio element by getElementById and play the same.

How are we making the Bob to vibrate ? 


Below is the jquery code block , I have included from this site - http://andreaslagerkvist.com/jquery/vibrate/#jquery-plugin-example-code which does the work for us.

 jQuery.fn.vibrate = function (conf) {
            var config = jQuery.extend({
                speed: 30,
                duration: 2000,
                frequency: 5000,
                spread: 3
            }, conf);

            return this.each(function () {
                var t = jQuery(this);

                var vibrate = function () {
                    var topPos = Math.floor(Math.random() * config.spread) - ((config.spread - 1) / 2);
                    var leftPos = Math.floor(Math.random() * config.spread) - ((config.spread - 1) / 2);
                    var rotate = Math.floor(Math.random() * config.spread) - ((config.spread - 1) / 2);

                    t.css({
                        position: 'relative',
                        left: leftPos + 'px',
                        top: topPos + 'px',
                        WebkitTransform: 'rotate(' + rotate + 'deg)'  // cheers to erik@birdy.nu for the rotation-idea
                    });
                };

                var doVibration = function () {
                    var vibrationInterval = setInterval(vibrate, config.speed);

                    var stopVibration = function () {
                        clearInterval(vibrationInterval);
                        t.css({
                            position: 'static',
                            WebkitTransform: 'rotate(0deg)'
                        });
                    };

                    setTimeout(stopVibration, config.duration);
                };

                setInterval(doVibration, config.frequency);
            });
        };


Responsive Design

 

 

 

 

Every day number of devices keeps adding , the browsers that needs to work on that device gets increases. So here comes the Responsive design of web sites. 

Responsive Web design is all about the application being responding to the environment in which it's running. Responsive design allows our websites to adjust to different layouts for a variety of different devices.

Goal
-----
Develop a responsive website which elegantly scales down to downsized browser windows, tablets and mobile phones.

One Site for Small + Medium + Large screens.

Basic Elements of a Responsive Design
--------------------------------------------
Fluid grids, Flexible media and CSS media queries. In addition to these we will also need to consider performance, device support, device optimization and future-friendly designs.

Mixed Approach
-------------------

Fixed width for large and medium.
Fluid width for small.

Frameworks
-------------

There are handful for frameworks available. We need to pick one and implement. 

1. Bootstrap, from Twitter - It's a Simple and flexible HTML, CSS and Javascript based framework.

2. The Goldilocks Approach - It gives us a boilerplate CSS and HTML files based on the current best practices. It's a good starting point for design that takes device resolution out of the equation. The Goldilocks Approach uses a combination of Ems, Max-Width, Media Queries and Pattern Translations.

3. Foundation - It's an easy to use , very powerful and flexible framework for building prototypes and production code on any kind of device.

4. Skeleton - It's a minimal responsive framework. It can be used for designing a beautiful responsive , mobile friendly sites.

Media Queries
----------------

We will be using media queries in CSS3 and this is an extremely powerful tool for creating responsive designs. It allows us to apply changes to our site’s design based on the viewing size and capability of the device on which your content is displayed. A separate stylesheet for desktop and browsers will be created so that the styles are applied based on the device width.

Below is an example of styles applies for the max device width of 480px.

@media only screen and (max-device-width: 480px) {
div#wrapper {
width: 400px;
}
div#header {
background-image: url(media-queries-phone.jpg);
height: 93px;
position: relative;
}
div#header h1 {
font-size: 140%;
}
float: none;
width: 100%;
}
float:none;
width: auto;
}
}

How to handle device orientation
---------------------------------
We will be applying styles based on the device orientation. Media queries are used to detect the screen orientation.

<link rel="stylesheet" media="all and (orientation:portrait)" href="portrait.css"> 
<link rel="stylesheet" media="all and (orientation:landscape)" href="landscape.css"> 

Packaging for simple deployment of Websites

 

We will see how to package our HealthReunion Website for azure deployment. Note, there are different techniques or ways of deployment. We will see all types , you may select the best ones. 

Deploy using Publishing Profile  

1. Log on to Azure portal , then create a website. You can use Quick start to create one.

2. In order to publish our application , we need to download the publishing profile. Please refer the below picture for the same. 

 

  

 

3. Make sure the Website is building successfully , Then right click on WebSite -> Select Publish Web Site option.
It will show up a windows as below.


 

4. Click on Import button to import the downloaded publishing profile file from Step 2. Then click on 'Next' button, it will take you to the Connection information. 

You can see the publishing method is - Web Deploy. Also notice the Server where you want to publish the site , username and password to connect to that server for deployment. 

If everything succeeds , you should be able to browse site as mentioned in the Destination Url. 

Note: I had clicked on Validate Connection button, just to make sure everything is correct.


 


5. Just follow the wizard steps, Below is the Preview window shown. You should be able to refresh the window and see all the DLL's that's required as a part of the website deployment. 


   


6. This should be the last step, Just click on Publish button so that the website publishing begins.  When the publishing completes successfully , you should be able to see the website running in windows azure.  

Deploy using FTP (File Transfer Protocol) 

In order to deploy using FTP mechanism, the basics things required is 

1. FTP Host Name
2. FTP User Name
3. FTP Password  

We will get all the information regarding deployment from the publishing profile. One has to just open the publishing profile file , in our case it's HealthReunion.azurewebsites.net file.  

Below is what it looks like , Just take a look into the publishing method - FTP and make a note on the above mentioned details , we are getting ready for the FTP based deployment. 

<publishData>
<publishProfile profileName="HealthReunion - Web Deploy" publishMethod="MSDeploy" publishUrl="waws-prod-ch1-001.publish.azurewebsites.windows.net:443" msdeploySite="HealthReunion" userName="$HealthReunion" userPWD="zJYihFdyejcwuHtsDlxLdhtFfkppTixwCvn4vu64f8r9AdaojEktAf0Zvr51" destinationAppUrl="http://healthreunion.azurewebsites.net" SQLServerDBConnectionString="" mySQLDBConnectionString="" hostingProviderForumLink="" controlPanelLink="http://windows.azure.com">
  <databases/>
</publishProfile>
<publishProfile profileName="HealthReunion - FTP" publishMethod="FTP" publishUrl="ftp://waws-prod-ch1-001.ftp.azurewebsites.windows.net/site/wwwroot" ftpPassiveMode="True" userName="HealthReunion\$HealthReunion" userPWD="zJYihFdyejcwuHtsDlxLdhtFfkppTixwCvn4vu64f8r9AdaojEktAf0Zvr51" destinationAppUrl="http://healthreunion.azurewebsites.net" SQLServerDBConnectionString="" mySQLDBConnectionString="" hostingProviderForumLink="" controlPanelLink="http://windows.azure.com">
  <databases/>
</publishProfile>
</publishData> 

 


Open windows file explorer and copy-paste the FTP Host Name, it will ask you to key in the credentials to connect to the FTP Host. Provide all the details , we are good to go for the deployment. 

Below is the picture shows the files which are already exists as we have deployed the website using publishing profile Web based mechanism. Don't worry about the *.cs files, we could have avoided copy these files by selecting only the pre-compiled files in "Publishing Web" Settings window. 

All you have to do is copy paste the DLL's , bin folder and associated compiled files into the FTP directory.

 
 

Deploy using TFS

This can be done once we set up the TFS deployment for the website in Windows Azure. Just log on to windows azure and navigate to Websites -> Deployements

We will have to an account for TFS Visual Studio , i.e in my case it's https://ranjancse.visualstudio.com. Once you have done with this , you should be able to see something like below. You website has to link with this account
for deployment.

 

Now we will have to setup the source control with the source code for automatic deployment , every time when we check in our code changes. 

From Visual Studio -> Team menu click on "Connect to Source Control" option so that it allows us to add the TFS server. Once you are connected to source control , we can map setup the source code and check-in our code to the newly created TFS server. 

Below picture shows the Server Explorer , You can notice the TSF server as "ranjancse.visualstudio.com"

 

Apart from deployment, anytime you can log into your TFS server and managing your project , Bugs tasks etc using https://tfs.visualstudio.com/

Below picture shows the TFS online. 

 

What about the other 9 free sites you can set up under your free Azure account ?

 


There are lots of things I have in my mind to do with the other free websites. I would host the free websites like Wordpress, CMS websites, develop a mobile based websites and host the same. There are few free websites that I can see listed in the Azure Gallery , I would try using them and take advantage of whatever available as a part of the subscription. 

How will your web app tie into the next challenge ?


Coming next, It's still more exciting with SQL Azure, I have already planned and working on implementation of SQL Service Bus, we will do a lot more than just saving the data in SQL Azure. 


Play with VM,  build a cloud  and host our site. We will see how to manage the applications , Install required softwares in VM to run our application. 

Building a mobile based solution , use Mobile services and implement a fully functional responsive based web application so that we can access one common portal everywhere all devices.  

In addition to these , planned to use SendGrid to send emails. When the provider registers a new patient, an email can be triggered to patient with the credentials so that patients can log in to the patient portal and see their clinical information.

Below is the screenshot of SendGrid I have installed as App Services in Azure. 

 


Little insight to HealthVault integration

As I already planned to integrate HealthReunion with HealthVault, here's some work which is in progress. You must be wondering how does the this integration done, for that we are using HealthVault SDK , it involves some basic configuration changes and some code snippet to authorize the user for HealthVault Application. 

Note: One has to create HealthVault application for the same. Below is the application configuration screen that you can see. 

HealthVault SDK provides us HealthVault Application Manager , a winform based application for creating an web based application, it creates certification and we can have the sample web application provided by this tool so that we can use it for our integration. Below is the screenshot of HealthVault Application Manager, you can also see that we are exporting the certificate private key for future use.

Below is the screenshot of the web application, Create patient. When the Healthreunion provider creates a patient, the following are the basic information that he has to provide so that the application registers and submits this information to HealthVault.

Below is the screenshot of the Acknowledgement screen if everything goes well. The patient has to make use of the below mentioned identity key so that he authorizing himself to HealthReunion application to export clinical information. 

 

 

Challenge 3 

Lessons Learnt  

Below are the things I learnt from the contest. I have highlighted the main points which I have practically learnt from this contest.   

1. How to manage , connect and access data from SQL Azure. 
2. How to export and import data base from SQL Azure. 
3. How to backup and restore SQL Azure database. 
4. How to export database from on-premises database to SQL Azure. It includes exporting scripts , exporting data to SQL Azure.
5. How to scale out with SQL Azure federations. 
6. How to make use of SQL Azure REST API for managing the servers, ex: Getting the firewall rules, Creating servers, Getting the list of servers for our subscription, Dropping server.    


Pascal Pyramid Experiment  

Part of the challenge was to Create a stored procedure that outputs the nth level of Pascal’s Pyramid. Here's the screen shot which shows the main page where you can key in the nth level number and see the results , time taken to execute the stored procedure for 10 iterations. Here's the site where you can test the same http://pascalpyramid.azurewebsites.net/  

 

Behind the scene we will see the stored procedure logic which is responsible for producing this output.  

 

CREATE PROCEDURE GetNthPascalPyramid
@N as Int,
@ReturnValue varchar(max) OUT
AS

DECLARE @InnerLoopCount NUMERIC(38,0)
SET @InnerLoopCount = 0

DECLARE @Result NUMERIC(38,0)
SET @Result = 1

DECLARE @FinalResult as varchar(max)
SET @FinalResult = ''

WHILE (@InnerLoopCount <= @N)
  BEGIN
     SET @FinalResult = @FinalResult + ' ' + CAST(@Result as varchar)
	 SET @Result = @Result * (@N - @InnerLoopCount) / (@InnerLoopCount + 1) 
     SET @InnerLoopCount = @InnerLoopCount + 1
END
SET @ReturnValue = @FinalResult
     
GO

Below is the website code which makes a call to the stored procedure

 

  protected void btnSubmit_Click(object sender, EventArgs e)
        {
            try
            {
                lblResponse.ForeColor = System.Drawing.Color.Black;
                var stringBuilder = new StringBuilder();
                string connectionString = "Server=tcp:s4w58fcilt.database.windows.net,1433;Database=healthreunion;User ID=ranjan@s4w58fcilt;Password=sql2012#;Trusted_Connection=False;Encrypt=True;Connection Timeout=120;";
                using (var sqlConn = new SqlConnection(connectionString))
                {                    
                    sqlConn.Open();
                    for (int i = 1; i <= 10; i++)
                    {
                        DateTime then = DateTime.Now;
                        using (SqlCommand cmd = new SqlCommand("GetNthPascalPyramid ", sqlConn))
                        {
                            cmd.CommandType = CommandType.StoredProcedure;
                            cmd.CommandType = CommandType.StoredProcedure;
                            cmd.Parameters.Add("@N ", SqlDbType.Int).Value = txtNthNumber.Text.Trim();
                            cmd.Parameters.Add("@ReturnValue", SqlDbType.VarChar, 4000).Direction = ParameterDirection.Output;
                            cmd.ExecuteNonQuery();
                            lblResponse.Text = cmd.Parameters["@ReturnValue"].Value.ToString();

                            DateTime now = DateTime.Now;
                            var value = (now.Millisecond - then.Millisecond).ToString();
                            stringBuilder.AppendFormat("Iteration: {0} : {1} milliseconds", i , value );
                            stringBuilder.AppendLine("
");
                        }
                    }
                    lblResponseTime.Text = stringBuilder.ToString();
                }
            }
            catch (Exception ex)
            {
                lblResponse.ForeColor = System.Drawing.Color.Red;

                if (ex.Message.Contains("Arithmetic overflow error converting expression to data type numeric"))
                    lblResponse.Text = "This number is too high for calculation. Please try a smaller number.";
                else
                    lblResponse.Text = ex.Message;
            }
        }


SQL Azure Management

We will see how we can manage SQL Azure database with the help of web based Windows Azure SQL Management or by using SQL Server Management Studio (You will have to install SQL 2008 R2 or higher). Managing SQL Azure database from SQL Server Management studio is no difference , you will have to specify the server name and credentials to connect to Azure database. We will concentrate on how we can manage SQL Azure DB through web based management portal. 
 


Step 1 : Log on to Windows Azure Management portal - https://manage.windowsazure.com/ 

then click on Database Icon on the left panel , You should see a list of database if you have already created one. Else don't worry we can create new one.  

Please follow this step if you are creating a brand new SQL Azure Database.   

Log on to management portal as mentioned in Step 1, then click on 'New' and navigate to SQL Database -> Quick Create as shown in the below screenshot.

 

Below is the main screen , shows when you click on the existing SQL Azure database.  

 

You can notice the server name, port number etc. The first recommended things to do is setting up of windows azure firewall rules. SQL Azure by default blocks all access from any incoming IP Address for managing databases. One has to set the firewall rules for adding the IP Address of the machine so that one can manage the database from Web based or SQL Management studio.

Click on 'Set up Windows Azure firewall rules for this IP Address' link ,You should be able to see the notification message something like below.  

 

 

 

 


Step 2: The next step is managing SQL Azure database. In the above screen-shots you can an option named 'Manage' , We will have to click on that to manage SQL Azure database. Below is the Log on screen you will see first, Use your credentials to connect to SQL Azure database.  

 


Once you log on , you should be able to see the below main screen where you can have an option execute any kind of DDL or DML queries by selecting 'New Query' option. You could also open existing queries and run the same using 'Open' option. The refresh option is available say if you want to refresh the table results etc.  


Now we will see querying results for Patients table in HealthReunion database. Note – We are just executing the below mentioned select query to fetch all the patients data. Please see below the screen-shot for the same.    

 

SQL Azure Database Connection

We will see the connection string and application code for connecting SQL Azure.   

 

<connectionStrings>
  <add name="SQLAzureConnection" connectionString="Data Source=<ProvideServerName>.database.windows.net;Initial Catalog=TestDb;User ID=<ProvideUserName>;Password=<ProvidePassword>;Encrypt=true;Trusted_Connection=false;"
    providerName="System.Data.SqlClient" />
</connectionStrings> 

The data layer consists of Entity framework , we are using Model first. Below is the DbContext class ,we will be using this in our data access repository classes. 

public partial class healthreunionEntities : DbContext
{
    public healthreunionEntities()
        : base("name=healthreunionEntities")
    {
    }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }
    public DbSet<Document> Documents { get; set; }
    public DbSet<Patient> Patients { get; set; }
    public DbSet<Provider> Providers { get; set; }
    public DbSet<User> Users { get; set; }
} 

The detailed data access things using repository pattern is discussed in Challenge -2 Building website section. So we will not repeat the same data access logic here. 

 

Migrating from SQL Server to SQL Azure 

 


We will see how we can migrate our data from an on-premises Microsoft SQL Server data store to SQL Azure.  It's very important to understand this step if you have an existing database with data needs to be moved to SQL Azure.

 


Step 1: We will connect to our local database and SQL Azure database.  Below see the below screen for the same. 

 

 

Step 2: Create a new empty SQL Azure database. We will be using that in the later stage for migrating the data.

Step 3: Using Generate script wizard, We will export the schema of our local database. For that we need to select our HealthReunion database , Right click -> All tasks , then select Generate and Publish scripts option. then we will be selecting all tables , click next and select Advanced option and choose SQL Azure Database option for 'Script for database engine type'. Please refer the below mentioned snapshot. 

 

 

 

 

   

 

  

Step 4: Run the exported script in SQL Azure database so that it creates all the necessary tables.


Step 5: Now we will see how to export data from local database to SQL Azure. We need to select the local database i.e our HealthReunion database , Right click and select 'Export Data' option, It will show up a wizard. Click Next so that you will see the below mentioned screen. Select SQL Authentication / Windows Authentication and click next. 

 

 

 

Step 6:  We will now have to specify the destination server name , username and password for SQL Server Authentication , then select the database which you wish to import data.


 

Step 7:  In this step, we will have to select the default option for copying all the tables from source database. Then select the tables for which you want to export the data.


 

 

Step 8: Now we have two options , either we can save the SSIS package and execute the same by creating a new Business intelligence project or we an execute directly from the wizard. Below is the screen shot for both of them.

 

 

Step 9: If you have choose Run , on clicking next button you will see the below mentioned summary screen.

 

 

 

 

SQL Azure Backup and Restore   

 

We will see how we can backup and restore the database with the help of Data-Tier Application Framework (DACFx) client tool - sqlpackage.exe 

We will be using DAC (Data tier application) tools for exporting and deploying the database.

DAC is a self-contained unit of SQL Server database deployment that enables data-tier developers and database administrators to package SQL Server objects into a portable artifact called a DAC package, also known as a DACPAC. 

The main advantages of using DAC is it simplifies the database deployment and management.

When we are extracting the DAC package , it contains the definition of the database like tables, views, instance objects and logins – associated with a user’s database.  There are different ways one can go with exporting and importing , either programmatically or by using  tool.  We will see the most simpler approach of using a tool to perform the same. 

Here's the command line option for exporting. Please make sure you are running the command prompt in administrator mode.

"C:\Program Files (x86)\Microsoft SQL Server\110\DAC\bin\sqlpackage.exe" /a:Export /ssn:yourserver.database.windows.net /sdn:"your database to export" /su:"yourdbuser" /sp:"your password" /tf:"bacpac file to create on local disk" 

For importing, one need to use the below command

"C:\Program Files (x86)\Microsoft SQL Server\110\DAC\bin\sqlpackage.exe" /a:Import /tdn:"your database to create" /tp:"your password here" /tsn:"yourserver.database.windows.net" /tu:"yourdbuser" /sf:"bacpac on local disk" 

Here's various options of sqlpackage.exe  

Extract: Creates a database snapshot (.dacpac) file from a live SQL Server or Windows Azure SQL Database.

Export: Exports a live database - including database schema and user data - from SQL Server or Windows Azure SQL Database to a BACPAC package (.bacpac file).

Import: Imports the schema and table data from a BACPAC package into a new user database in an instance of SQL Server or Windows Azure SQL Database.

Publish: Incrementally updates a database schema to match the schema of a source .dacpac file. If the database does not exist on the server, the publish operation will create it. Otherwise, an existing database will be updated.

DeployReport: Creates an XML report of the changes that would be made by a publish action.

DriftReport: Creates an XML report of the changes that have been made to a registered database since it was last registered.

Script: Creates a Transact-SQL incremental update script that updates the schema of a target to match the schema of a source. 

Below is the snapshot of the usage of sqlpackage.exe

 

Here's a windows form application , It's a small little utility tool that I have created for exporting and importing or deploying the SQL Azure database. Now you can see there are two different things DACPAC and BACPAC. Let us first understand what are they ?

Below is the screenshot of the utility

Here's the description from MSDN , I felt it's more meaningful and easily understandable.


A DACPAC is focused on capturing and deploying schema, including upgrading an existing database. The primary use case for a DACPAC is to deploy a tightly defined schema to development, test, and then production environments, and the reverse: capturing production’s schema and applying it to back to test and development environments.  

 

A BACPAC, on the other hand, is focused on capturing schema and data. A BACPAC is the logical equivalent of a database backup and cannot be used to upgrade existing databases. The primary use case for a BACPAC is to move a database from one server to another or from a local server to the cloud - and archiving an existing database in an open format. 

Using the little utility you can do a lot, we can extract the DACPAC and deploy the same to SQL Azure.   

Below is the usage of this utility 

1. “Target connection string” - we need to specify the windows azure SQL Azure connection string , In our case it's

Server=tcp:s4w58fcilt.database.windows.net,1433;Database=healthreunion;User ID=ranjan@s4w58fcilt;Password={your_password_here};Trusted_Connection=False;Encrypt=True;Connection Timeout=30;

2. Source database – we need to specify the SQL Azure database as our source database , in our case it's healthreunion.

3. Target database – It's required in case of deploying the DACPAC/BACPAC database exported files to SQL Azure or local database. We just need to specify the target database. A new database will be deployed based on the target connection string what we specified 

4. Operation – We need to select suitable operations , If you are interested in exporting then select the export options available. 

5. Target BACPAC/DACPAC file path – Here we need to specify the full path where we want to save our exported files.  

Here's some interesting thing we will see about from the exported DACPAC file. Just try to unpack the file and see the extracted folder. It has the below mentioned files. 

1. DacMetadata – It's an XML file , has the name, version and description in it.

<?xml version="1.0" encoding="utf-8"?>

<DacType xmlns="http://schemas.microsoft.com/sqlserver/dac/Serialization/2012/02">

  <Name>Sample DACPAC</Name>

  <Version>1.0.0</Version>

  <Description>Sample Extract</Description>

</DacType>

2. Model (SQL File) – This file contains our database schema, scripts for creating the entire database model.

3. Model (XML file) – It's an XML file , contains table and relationship mapping information, it's more or like the Entity framework XML mapping.

4. Origin (XML file) – This file has meta data information , contains packaging properties, server information etc.

Below is the screenshot of the unpacked package.

 

 

 

We will see the implementation of DAC utility. The first thing we need to do is , create a DacServices instance. You should be specifying a valid database connection string for the same.  

DacServices svc;
svc = new DacServices(txtTargetConnectionString.Text);

 

Below is the code snippet for extracting the database as DACPAC. Note the extract options can be specified while exporting. 

void Extract(DacServices svc, string SourceDatabaseName, string Path)
        {
            Console.WriteLine("\n\rPerforming Extract of {0} to {1} at {2}", SourceDatabaseName, Path, System.DateTime.Now.ToLongTimeString());
            
            DacExtractOptions dacExtractOptions = new DacExtractOptions
            {
                ExtractApplicationScopedObjectsOnly = true,
                ExtractReferencedServerScopedElements = false,
                VerifyExtraction = true,
                Storage = DacSchemaModelStorageType.Memory
            };

            svc.Extract(Path, SourceDatabaseName, "Sample DACPAC", new Version(1, 0, 0), "Sample Extract", null, dacExtractOptions);
        }

Below is the code snippet for deploying the DACPAC package to database. We need to specify the file path from which the DACPAC file will be loaded for deployment. Once the package gets loaded into DacPackage, we will be deploying the same to the specified target database.

 void Deploy(DacServices svc, string TargetDatabaseName, string Path)
        {
            Console.WriteLine("\n\rPerforming Deploy of {0} to {1} at {2}", Path, TargetDatabaseName, System.DateTime.Now.ToLongTimeString());

            using (DacPackage dacpac = DacPackage.Load(Path))
            {
                svc.Deploy(dacpac, TargetDatabaseName, true); // set it to True for - Upgrade existing database.
            }
        }

Code snippet for exporting BACPAC package

  void Export(DacServices svc, string SourceDatabaseName, string Path)
        {
            Console.WriteLine("\n\rPerforming Export of {0} to {1} at {2}", SourceDatabaseName, Path, System.DateTime.Now.ToLongTimeString());

            svc.ExportBacpac(Path, SourceDatabaseName);
        }

Code snippet for importing BACPAC package , we will have to load the BACPAC file and make a call to ImportBacpac with the package and the target database name.

 void Import(DacServices svc, string TargetDatabaseName, string Path)
        {
            Console.WriteLine("\n\rPerforming Import of {0} to {1} at {2}", Path, TargetDatabaseName, System.DateTime.Now.ToLongTimeString());

            using (BacPackage bacpac = BacPackage.Load(Path))
            {
                svc.ImportBacpac(bacpac, TargetDatabaseName);
            }
        }

Once you have the DACPAC package, you can also deploy the package from SQL Server Management Studio

Below is the screen shot shows how we can do



 


SQL Azure Federation with Entity Framework 

 

 

SQL Database Federations is a technology for building scale-out database solutions. They are objects like tables , stored procedures etc however federations provide a way to partition the data and allow applications to scale out parts or all of their data.

Sharding is the other word for federating, is the process of breaking a large database into many smaller databases and distributing these databases across different hardware devices to take advantage of greater physical resources. 

Note: Below we assume the entire process of federating is done freshly in SQL Azure , However many times this isn't the case say when you are migrating database. You will have to think off the below ones , also an application changes is required to work with federated database. 

1. Cross-database joins are not supported in SQL Azure. The federated database members all live as anonymous and they do not have a referential integrity between them.

2. On what basis we are going to shard the data depends on the type of shard we have choose to do. We have four possible data types: int, bigint, uniqueidentifier and varbinary. 

3. If our existing database table has a primary key which is identity column. It cannot be used for federation because SQL Azure does not support identity key column for federations.  The reason being there are no uniqueness and sequential guarantees across multiple databases. 


Creating federations 

The federation root database is a SQL Azure database that contains metadata about the federations. Below is the script which creates the federation root. In the below example , the text marked in bold is optional. 

 

CREATE DATABASE TestHealthReunion (MAXSIZE = 100 GB, EDITION = 'business') 

 

The federation is where you define the data type (e.g., ProviderId, PatientId) you’ll shard on. Note , the CREATE FEDERATION process creates a new database with the name as system-GUID , it's not the same as the physical database. 

-- Create Federation Root, named TestHealthReunionFederation 

CREATE FEDERATION TestHealthReunionFederation(Id BIGINT RANGE)
GO

-- Create Federated tables based on the below mentioned distribution constraint

USE FEDERATION TestHealthReunionFederation(Id = 100) WITH RESET, FILTERING=OFF
GO

Create tables with federations 

 

CREATE TABLE [dbo].[Patients] (
    [PatientId]                 BIGINT              NOT NULL,
    [ProviderId]                INT              NOT NULL,
    [MedicalRecordNumber]       UNIQUEIDENTIFIER NOT NULL,
    [DOB]                       DATE             NOT NULL,
    [Sex]                       BIT              DEFAULT ((1)) NOT NULL,
    [Address]                   VARCHAR (500)    NULL,
    [Phone]                     VARCHAR (15)     NULL,
    [Email]                     VARCHAR (20)     NULL,
    [LastName]                  VARCHAR (50)     NOT NULL,
    [FirstName]                 VARCHAR (50)     NOT NULL,
    [MiddleName]                VARCHAR (50)     NULL,
    [City]                      VARCHAR (50)     NULL,
    [State]                     VARCHAR (50)     NULL,
    [Country]                   VARCHAR (50)     NULL,
    [IsActive]                  BIT              DEFAULT ((1)) NOT NULL,
    [RegisteredWithHealthVault] BIT              DEFAULT ((0)) NOT NULL,
    FOREIGN KEY ([ProviderId]) REFERENCES [dbo].[Providers] ([ProviderId]),
CONSTRAINT [PK_Patient] PRIMARY KEY CLUSTERED 
(
	[PatientId] ASC
) 
)FEDERATED ON (Id = PatientId);
GO

CREATE TABLE [dbo].[Documents] (
    [DocumentId]   BIGINT          NOT NULL,
    [PatientId]    BIGINT             NOT NULL,
    [ProviderId]   INT             NOT NULL,
    [CreationTime] DATETIME        NOT NULL,
    [Document]     VARBINARY (MAX) NULL,
    [DocumentType] VARCHAR (50)    NOT NULL,
    FOREIGN KEY ([ProviderId]) REFERENCES [dbo].[Providers] ([ProviderId]),
CONSTRAINT [PK_Document] PRIMARY KEY CLUSTERED 
(
	[DocumentId] ASC,
	[PatientId] ASC,
	[ProviderId] ASC
) 
)FEDERATED ON (Id = DocumentId);


Verifying the federation metadata

You can run the below mentioned SQL script in the management studio and understand more about the federation.   

-- Route connection to federation root
USE FEDERATION ROOT WITH RESET
GO
-- View the Federation Root metadata
SELECT db_name() [db_name]
SELECT * FROM sys.federations
SELECT * FROM sys.federation_distributions
SELECT * FROM sys.federation_member_distributions ORDER BY federation_id, range_low;
GO  

Below is the screenshot of the federation metadata



Now we shall deep dive into federations management. Federations can be managed using SQL Azure web management , we can create new federation , split , re-size, create new tables for federations etc.

1. We need to login to SQL Azure Management portal.  and run the below mentioned query for creating a new federation in TestHealthReunion database. 

CREATE FEDERATION TestHealthReunionFederation(Id BIGINT RANGE)
GO 
USE FEDERATION TestHealthReunionFederation(Id = 100) WITH RESET, FILTERING=OFF
GO 

2. You will see the below mentioned screen if the Step 1 is successful. Now we will see how we can manage federations. 

3. For managing federations and members , one has to just click on the above highlighted federation - TestHealthReunion , Below is the screenshot you should be able to see the below mentioned screen of federation members.



You could notice now we can do create , split , re-size , drop federation options.

4. Creating new distribution -  From the above picture we can see an option a 'New' button for creating a new federation distribution. Below is the screenshot for the same


 

Now we will see the real meat of underlying federations management with the help of a WPF based utility that I have created specially for managing federations for HealthReunion. The source code for the same can be downloaded , please navigate to the downloads link mentioned at top.  

We shall assume below things. 

1. Created a database with name : TestHealthReunion  

2. After creating federation for TestHealthReunion , it creates a system database for managing federations. 

for managing the federations from the utility , we will have to change the connection strings to point to the right federations database.  

Now we shall see how to manage federations.  

 

1. Create federation - See below the screen shot attached for the same , we will create a new federation for TestHealthReunion database. Notice the sql query in used to create federation. 

 

Below is the code snippet for the same 

 StringBuilder sbResults = new StringBuilder();

            if (txtFederationName.Text == "")
            {
                MessageBox.Show("Please enter federation name");
                txtFederationName.Focus();
                return;
            }

            CONST_FEDERATION_NAME = txtFederationName.Text.Trim();               

            try
            {
                SqlConnectionStringBuilder stringBuilder = new SqlConnectionStringBuilder(
                 ConfigurationManager.ConnectionStrings["testHealthReunionConnectionString"].ConnectionString);

                //Drop federation root and federation members
                string strInitialCatalog = stringBuilder.InitialCatalog;

                //Connect to the master database
                using (SqlConnection connection = new SqlConnection(stringBuilder.ToString()))
                {
                    connection.Open();
                    sbResults.AppendFormat("-- Open {0}\r\n\r\n", stringBuilder.ToString());

                    using (SqlCommand command = connection.CreateCommand())
                    {
                        command.CommandText = String.Format("CREATE FEDERATION {0}(Id BIGINT RANGE)", CONST_FEDERATION_NAME);
                        command.ExecuteNonQuery();
                        sbResults.AppendFormat("{0}\r\nGO\r\n\r\n", command.CommandText);
                    }
                }

                MessageBox.Show("Created successfully, Please change the connection string to point to federation system database");

                txtResult.Text = String.Format("----- {0} : ----- Creating federation  -----\r\n{1}\r\n",
                    DateTime.Now.ToString(), sbResults.ToString()) + txtResult.Text;
            }
            catch (Exception ex)
            {
                txtResult.Text = String.Format("-- Error Creating:\r\n{0}\r\n{1}\r\n{2}",
                    ex.Source, ex.Message, ex.StackTrace) + txtResult.Text;
                txtResult.Text = String.Format("----- {0} : ----- Creating federation  -----\r\n{1}\r\n",
                    DateTime.Now.ToString(), sbResults.ToString()) + txtResult.Text;
            }

2. Get Root Metadata - Once the federation is created , we can see the root metadata. Below is the attached screenshot for the same. You can notice here the federation was already split with Id = 100. 

 

Below is the code snippet for the same

  if (txtFederationName.Text == "")
            {
                MessageBox.Show("Please enter federation name");
                txtFederationName.Focus();
                return;
            }

            CONST_FEDERATION_NAME = txtFederationName.Text.Trim();

            StringBuilder sbResults = new StringBuilder();
            DataSet data = null;
         
            string strSQL = @"SELECT f.name, fmc.federation_id, fmc.member_id, fmc.range_low, fmc.range_high " +
                                                                "FROM sys.federations f " +
                                                                "JOIN sys.federation_member_distributions fmc " +
                                                                "ON f.federation_id=fmc.federation_id " +
                                                                "ORDER BY fmc.federation_id, fmc.range_low, fmc.range_high";
            string strTableName = "federation_member_distributions";

            try
            {
                using (SqlConnection connection = new SqlConnection(connectionStringBuilder.ToString()))
                {
                    connection.Open();
                    sbResults.AppendFormat("-- Open {0}\r\n\r\n", connectionStringBuilder.ToString());

                    data = new DataSet();
                    data.Locale = System.Globalization.CultureInfo.InvariantCulture;

                    using (SqlCommand command = connection.CreateCommand())
                    {
                        // Connect to federation root or federation member
                        command.CommandText = "USE FEDERATION ROOT WITH RESET";
                        command.ExecuteNonQuery();
                        sbResults.AppendFormat("{0}\r\nGO\r\n", command.CommandText);
                    }

                    SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(strSQL, connection);
                    sqlDataAdapter.Fill(data, strTableName);
                    sbResults.AppendFormat("{0}\r\nGO\r\n", strSQL);

                    DisplayDataGrid(data);                                      
                }
            
                txtResult.Text = String.Format("----- {0} : ----- Federation root metadata-----\r\n{1}\r\n",
                    DateTime.Now.ToString(), sbResults.ToString()) + txtResult.Text;
              }
            catch (Exception ex)
            {
                txtResult.Text = String.Format("----- {0} : ----- Federation root metadata -----\r\n{1}\r\n",
                    DateTime.Now.ToString(), sbResults.ToString()) + txtResult.Text;
                txtResult.Text = String.Format("----- {0} : ----- Federation root metadata -----\r\n{1}\r\n",
                    DateTime.Now.ToString(),
                    String.Format("-- Error:\r\n{0}\r\n{1}\r\n{2}", ex.Source, ex.Message, ex.StackTrace)) + txtResult.Text;
            }

 3. Split - We need to specify the federation key for split. Below is the screenshot for split operation. Note , for demonstrating the split operation , I did a split for Id - 200.  

 

Below is the code snippet for the same

if (txtFederationKey.Text == "")
            {
                MessageBox.Show("Please enter federation key");
                txtFederationKey.Focus();
                return;
            }

            if (txtFederationName.Text == "")
            {
                MessageBox.Show("Please enter federation name");
                txtFederationName.Focus();
                return;
            }

            CONST_FEDERATION_NAME = txtFederationName.Text.Trim();

            StringBuilder sbResults = new StringBuilder();
            try
            {
                using (SqlConnection connection = new SqlConnection(connectionStringBuilder.ToString()))
                {
                    connection.Open();
                    sbResults.AppendFormat("-- Open {0}\r\n\r\n", connectionStringBuilder.ToString());

                    using (SqlCommand command = connection.CreateCommand())
                    {
                        // Connect to federation root
                        command.CommandText = "USE FEDERATION ROOT WITH RESET";
                        command.ExecuteNonQuery();
                        sbResults.AppendFormat("{0}\r\nGO\r\n\r\n", command.CommandText);

                        // Perform the split operation
                        command.CommandText = String.Format("ALTER FEDERATION {0} SPLIT AT ({1}={2})",
                                CONST_FEDERATION_NAME,
                                CONST_DISTRIBUTION_NAME,
                                txtFederationKey.Text);
                        command.CommandTimeout = 60 * 4;
                        command.ExecuteNonQuery();
                        sbResults.AppendFormat("{0}\r\nGO\r\n\r\n", command.CommandText);
                    }
                }

                txtResult.Text = String.Format("----- {0} : ----- Split  -----\r\n{1}\r\n",
                    DateTime.Now.ToString(), sbResults.ToString()) + txtResult.Text;
            }
            catch (Exception ex)
            {
                txtResult.Text = String.Format("----- {0} : ----- Split -----\r\n{1}\r\n",
                    DateTime.Now.ToString(), sbResults.ToString()) + txtResult.Text;
                txtResult.Text = String.Format("----- {0} : ----- Split -----\r\n{1}\r\n",
                    DateTime.Now.ToString(),
                    String.Format("-- Error:\r\n{0}\r\n{1}\r\n{2}", ex.Source, ex.Message, ex.StackTrace)) + txtResult.Text;
            }       

4. Add Demo Patients - Here's some interesting dummy data we are inserting into the federated database so that it can help us in fetching the data for patients. Below is the code snippet , it adds 100 dummy records for patients, Note - we have a provider Id key in patients table. The below code also creates new provider if not exist. 

            try
            {
                using(var scope = new TransactionScope())
                {
                    using (var healthReunionEntities = new healthreunionEntities())
                    {
                        AddProviderIfNotExists(healthReunionEntities);
                        AddPatients(healthReunionEntities);
                    }
                    scope.Complete();
                }
                MessageBox.Show("Demo patients added successfully!");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        private void AddPatients(healthreunionEntities entities)
        {
             for (int index = 1; index <= 99; index++){
                var patient = new Patient
                {
                    PatientId = index,
                    MedicalRecordNumber = Guid.NewGuid(),
                    ProviderId = 1,
                    Sex = true,
                    State = "Illinios",
                    RegisteredWithHealthVault = false,
                    Phone = "1111111111",
                    LastName = "Last Name" + index.ToString(),
                    FirstName = "First Name" + index.ToString(),
                    Email = "test@gmail.com",
                    DOB = DateTime.Parse("01/01/1983"),
                    Country = "USA",
                    City = "Waukegan",
                    Address = "Test Address"
                };
                entities.Patients.Add(patient);
            }
             entities.SaveChanges();       
        }

        private void AddProviderIfNotExists(healthreunionEntities entities)
        {
            var providersCount = entities.Providers.Count();
            var logo = File.ReadAllBytes("Provider.png");
            
            if (providersCount == 0)
            {
                var newProvider = new Provider
                {
                    ProviderName = "Ranjan",
                    ProviderDescription = "Test Provider",
                    AuthorizationReason = "Test Authorization",
                    PrivacyStatement ="Test Privacy Statement",
                    ProviderLogo = logo
                };
                entities.Providers.Add(newProvider);
                entities.SaveChanges();
            }
        }

 

5. Query - We will see how we can query the federated database tables with and without filtering. With filtering we will be getting the records only for the specified federated key value. Below is the screen shot for the filtered query. 

Below is the code snippet for the same

 if (txtFederationKey.Text == "")
            {
                MessageBox.Show("Please enter federation key");
                txtFederationKey.Focus();
                return;
            }

            if (txtFederationName.Text == "")
            {
                MessageBox.Show("Please enter federation name");
                txtFederationName.Focus();
                return;
            }

            CONST_FEDERATION_NAME = txtFederationName.Text.Trim();

            bool isChecked = false;
            if (chkFilter.IsChecked != null && chkFilter.IsChecked == true)
                isChecked = true;
            
            long federationKey = Convert.ToInt64(txtFederationKey.Text.Trim());

            StringBuilder sbResults = new StringBuilder();
            string strCmd = String.Format("USE FEDERATION {0}({1}={2}) WITH RESET, FILTERING={3}",
                                             CONST_FEDERATION_NAME,
                                             CONST_DISTRIBUTION_NAME,
                                             txtFederationKey.Text,
                                             (isChecked ? "ON" : "OFF"));
            try
            {
                using (var dc = new healthreunionEntities())
                {
                    sbResults.AppendFormat("-- EF Open {0}\r\n\r\n", dc.Database.Connection.ToString());
                    dc.Database.ExecuteSqlCommand(strCmd);
                    sbResults.AppendFormat("-- EF ExecuteSqlCommand {0}\r\n", strCmd);
                    switch (cboTableNames.SelectedValue.ToString())
                    {
                        case HealthReunionConstants.Patients:
                            ((IObjectContextAdapter)dc).ObjectContext.Connection.Open();
                            dc.Database.ExecuteSqlCommand(strCmd);

                            IList<patient> patients = (from x in dc.Patients
                                                       select x).ToList<patient>();
                            dataGrid.ItemsSource = patients;
                            break;
                        case HealthReunionConstants.Documents:
                             ((IObjectContextAdapter)dc).ObjectContext.Connection.Open();
                            dc.Database.ExecuteSqlCommand(strCmd);

                            IList<document> documents = (from x in dc.Documents
                                                       select x).ToList<document>();
                            dataGrid.ItemsSource = documents;
                            break;
                    }
                }
                txtResult.Text = String.Format("----- {0} : ----- Query federation member data -----\r\n{1}\r\n",
                    DateTime.Now.ToString(), sbResults.ToString()) + txtResult.Text;
            }
            catch (Exception ex)
            {
                txtResult.Text = String.Format("----- {0} : ----- Query federation member data -----\r\n{1}\r\n",
                    DateTime.Now.ToString(), sbResults.ToString()) + txtResult.Text;
                txtResult.Text = String.Format("----- {0} : ----- Query federation member data -----\r\n{1}\r\n",
                    DateTime.Now.ToString(),
                    String.Format("-- Error:\r\n{0}\r\n{1}\r\n{2}", ex.Source, ex.Message, ex.StackTrace)) + txtResult.Text;
            }

Below is the screenshot when you are performing a fetch operation for patients without filtering option. The only difference you can see is , we are getting all records for the federation. 

5. Drop Federation - Now we will see how we can drop the federation , Note - we will have to connect to TestHealthReunion database and execute query to drop federation. Below is the screen shot for the same

 

Below is the code snippet for the same

if (txtFederationName.Text == "")
            {
                MessageBox.Show("Please enter federation name");
                txtFederationName.Focus();
                return;
            }

            CONST_FEDERATION_NAME = txtFederationName.Text.Trim();

            StringBuilder sbResults = new StringBuilder();
   
            try
            {
                SqlConnectionStringBuilder stringBuilder = new SqlConnectionStringBuilder(
                   ConfigurationManager.ConnectionStrings["testHealthReunionConnectionString"].ConnectionString);

                //Drop federation root and federation members
                string strInitialCatalog = stringBuilder.InitialCatalog;

                //Connect to the master database
                using (SqlConnection connection = new SqlConnection(stringBuilder.ToString()))
                {
                    connection.Open();
                    sbResults.AppendFormat("-- Open {0}\r\n\r\n", stringBuilder.ToString());

                    using (SqlCommand command = connection.CreateCommand())
                    {
                        // Drop the federation
                        command.CommandText = String.Format("DROP FEDERATION [{0}]", CONST_FEDERATION_NAME);
                        command.ExecuteNonQuery();
                        sbResults.AppendFormat("{0}\r\nGO\r\n\r\n", command.CommandText);
                    }
                }

                txtResult.Text = String.Format("----- {0} : ----- Drop federation  -----\r\n{1}\r\n",
                    DateTime.Now.ToString(), sbResults.ToString()) + txtResult.Text;
            }
            catch (Exception ex)
            {
                txtResult.Text = String.Format("-- Error DropDB:\r\n{0}\r\n{1}\r\n{2}",
                    ex.Source, ex.Message, ex.StackTrace) + txtResult.Text;
                txtResult.Text = String.Format("----- {0} : ----- Drop federation  -----\r\n{1}\r\n",
                    DateTime.Now.ToString(), sbResults.ToString()) + txtResult.Text;
            }

SQL Azure REST API 

 

Let us see how we can make use of SQL Azure REST API for managing the SQL Azure. In Brief  we will see how we can create new server, drop server, get the list of servers available for our subscription, get firewall settings.
 
SQL Azure Management REST API requires that a specific HTTP request be made against the service management endpoint. The request must be authenticated using an X.509 certificate that has previously been uploaded to the Windows Azure Portal. This can be a self-signed certificate. 

 

First let us see how to create a self signed certificate, and make use of the same for managing the SQL Azure through our SQL Azure REST based utility.  

We will now see how to create a self signed certificate so that we can make use of the same in our SQL Azure REST based utility.  

1. Create a Management Certificate for Windows Azure, start your Visual Studio 2012 Developer Command Prompt or Visual Studio 2010 Command Prompt as a administrator and run the command below by updating <CertificateName>. You’ll have your X.509 v3 certificate with a 2048 bits key length.

makecert -sky exchange -r -n "CN=<CertificateName>" -pe 

-a sha1 -len 2048 -ss My "<CertificateName>.cer"

2. Login to your Windows Azure Management Portal and upload this certificate to Settings > Management Certificates section.

Then you need to export this certificate in PFX format to attach in your calls

3. Run certmgr.msc in your computer

4. In the Microsoft Management Console, in the console tree, expand Certificates, and then expandPersonal.

5. In the details pane, click the certificate you want to manage.

6. On the Action menu, point to All Tasks, and then click Export. The Certificate Export Wizard appears. Click Next.

7. On the Export Private Key page, click Yes, export the private key. Click Next.

8. On the Export File Format page, select Personal Information Exchange – PKCS #12 (.PFX). Click Next.

9.On the Password page, type and confirm the password that is used to encrypt the private key.  

 

Uploading certificate to Azure  

 


We will have to upload the certificate *.cer file to Azure. The cer file contains information about certificate owner and public and private certificate keys. 

1. Run certmgr.msc by Ctrl -> Run

2. Go to Personal Store , then click on the certificate , right click and select All tasks and then select Export , We will not choose  , we will use the default options which are pre selected. At last you will see a radio button checked for exporting *.CER file.  Click next and specify the location where you want to export the file.

3. Now we will have to upload the same to Azure. For that Log on to Windows Azure , In the menu options we can see 'Settings' , Just click on that so that on the right panel you will see a screen , at the bottom of the page there is an option for Uploading/Deleting the certificate.  Just click on Upload options , then select the *.CER file to upload. Below is the screenshot you should be able to see. 

 

 

We will see the how we can make use of the SQL Azure REST API's in our utility. Below is the screenshot of getting the firewall settings. 

 

 

 

Below is the code snippet for getting the firewall settings.  Note that we are making a HttpWebRequest with the formatted Url to manage SQL Azure firewall. 

 

public static string GetFireWallSettings(string certFilename, string certPassword, string subscriptionId, string serverName)
        {
            StringBuilder stringBuilder = new StringBuilder();

            string RESTAPI = "https://management.database.windows.net:8443";
            string url = string.Format(
             "{0}/{1}/servers/{2}/firewallrules",
             RESTAPI, subscriptionId, serverName
            );

            HttpWebRequest webRequest = HttpWebRequest.Create(url) as HttpWebRequest;
            webRequest.ClientCertificates.Add(
             new X509Certificate2(certFilename, certPassword)
            );
            webRequest.Headers["x-ms-version"] = "1.0";
            webRequest.Method = "GET";

            HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
            StreamReader reader = new StreamReader(webResponse.GetResponseStream());
            string str = reader.ReadLine();

            while (str != null)
            {
                Console.WriteLine(str);
                str = reader.ReadLine();
                stringBuilder.AppendLine(str);
            }
            return stringBuilder.ToString();
        }

We will see how to create a new server for the specified location. Below is the screenshot for the same

Below is the code snippet for the same for creating a new server. We will have to make a POST Http Request , set the request properties like Certificate , Header etc. The Http Response contains a newly created Server Name.  

        private void CreateServer_Click(object sender, RoutedEventArgs e)
        {
            var createServer = new CreateServer();
            createServer.CreateServerEvent += createServer_CreateServerEvent;
            createServer.ShowDialog();            
        }

        void createServer_CreateServerEvent(string response)
        {
            txtResult.Text = response;
        }

        public static string CreateServer(string certFilename, string certPassword,
             string subscriptionId, string Admin, string AdminPwd, string Location)
        {
            StringBuilder stringBuilder = new StringBuilder();

            stringBuilder.AppendLine("\n============================");
            stringBuilder.AppendLine("=== CreateServer Request ===");
            stringBuilder.AppendLine("============================\n");
            stringBuilder.AppendFormat("Subscription : {0} \n", subscriptionId);

            try
            {
                string url = string.Format("https://management.database.windows.net:8443/{0}/servers", subscriptionId);
                HttpWebRequest webRequest = HttpWebRequest.Create(url) as HttpWebRequest;

                webRequest.ClientCertificates.Add(new X509Certificate2(certFilename, certPassword));
                webRequest.Headers["x-ms-version"] = "1.0";
                webRequest.Method = "POST";

                //=== Add the Request Payload ===//

                string xmlBody = "\n" +
                                  "<server xmlns="\"http://schemas.microsoft.com/sqlazure/2010/12/\"">\n" +
                                  "  <administratorlogin>" + Admin.ToString() + "</administratorlogin>\n" +
                                  "  <administratorloginpassword>" + AdminPwd.ToString() + "</administratorloginpassword>\n" +
                                  "  <location>" + Location.ToString() + "</location>\n" +
                                  "</server>";

                stringBuilder.AppendLine("Request Body for the CreateServer Request : ...\n");
                stringBuilder.AppendLine(xmlBody);

                byte[] bytes = Encoding.UTF8.GetBytes(xmlBody);
                webRequest.ContentLength = bytes.Length;
                webRequest.ContentType = "application/xml;charset=utf-8";
                using (Stream requestStream = webRequest.GetRequestStream())
                {
                    requestStream.Write(bytes, 0, bytes.Length);
                }

                //=== Send the request and wait on the response ===//
                using (WebResponse webResponse = webRequest.GetResponse())
                {
                    //=== x-ms-request-id is useful for troubleshooting request failures with Microsoft ===//
                    stringBuilder.AppendFormat("\nResponse x-ms-request-id : {0}", webResponse.Headers["x-ms-request-id"]);

                    stringBuilder.AppendFormat("HttpStatusCode = {0}\n", (int)((HttpWebResponse)webResponse).StatusCode);

                    using (Stream stream = webResponse.GetResponseStream())
                    {
                        using (XmlTextReader xmlReader = new XmlTextReader(stream))
                        {
                            while (xmlReader.Read())
                            {
                                switch (xmlReader.NodeType)
                                {
                                    case XmlNodeType.Element:
                                        if (xmlReader.Name == "ServerName")
                                        {
                                            if (xmlReader.Read() && (xmlReader.NodeType == XmlNodeType.Text))
                                            {
                                                stringBuilder.AppendFormat("NewServerName : {0}\n", xmlReader.Value.ToString());
                                            }
                                        }
                                        break;
                                }
                            }
                        }
                    }
                }
            }

            //====================================================================================//
            //=== Catch WebExceptions. The SQL Database Management Service will          ===//
            //=== provide detailed error information in the response stream for WebExceptions. ===//
            //====================================================================================//

            catch (WebException webEx)
            {
                stringBuilder.AppendLine("WebException : \n\n" + webEx.ToString());

                try
                {
                    HttpWebResponse errorResponse = (HttpWebResponse)webEx.Response;
                    stringBuilder.AppendFormat(string.Format("HttpStatusCode = {0}", (int)errorResponse.StatusCode));

                    using (Stream errorResponseStream = errorResponse.GetResponseStream())
                    {
                        using (StreamReader sr = new StreamReader(errorResponseStream))
                        {
                            stringBuilder.AppendFormat(sr.ReadToEnd());
                        }
                    }
                }
                catch (Exception innerEx)
                {
                    stringBuilder.AppendLine(innerEx.ToString());
                    stringBuilder.AppendLine(innerEx.StackTrace.ToString());
                }
            }
            catch (Exception ex)
            {
                stringBuilder.AppendLine(ex.ToString() + "\n");
                stringBuilder.AppendLine(ex.StackTrace.ToString() + "\n");
                if (ex.InnerException != null)
                {
                    stringBuilder.AppendLine(ex.InnerException.ToString() + "\n");
                    stringBuilder.AppendLine(ex.InnerException.StackTrace.ToString() + "\n");
                }
            }

            return stringBuilder.ToString();
        }

List Servers - We will see how to list or display all the SQL Azure servers that we have created for our subscription. Below is the screenshot of the utility. 

Below is the code snippet for the same.

        private void ListServer_Click(object sender, RoutedEventArgs e)
        {
            var response = SQLAzureServerManagement.GetServers(certFilename, certPassword, subscriptionId);
            txtResult.Text = response;
        }

        public static string GetServers(string certFilename, string certPassword, 
                                        string subscriptionId)
        {
            StringBuilder stringBuilder = new StringBuilder();

            stringBuilder.AppendLine("\n================================");
            stringBuilder.AppendLine("====== GetServers Request ======");
            stringBuilder.AppendLine("================================\n");
            stringBuilder.AppendFormat("Subscription : {0} \n", subscriptionId);

            try
            {
                string url = string.Format("https://management.database.windows.net:8443/{0}/servers", subscriptionId);
                HttpWebRequest webRequest = HttpWebRequest.Create(url) as HttpWebRequest;


                webRequest.ClientCertificates.Add(new X509Certificate2(certFilename, certPassword));
                webRequest.Headers["x-ms-version"] = "1.0";
                webRequest.Method = "GET";

                //=== No Request Payload needed to return server list ===//

                using (WebResponse webResponse = webRequest.GetResponse())
                {
                    //=== x-ms-request-id is useful for troubleshooting request failures with Microsoft ===//
                    Console.WriteLine("Response x-ms-request-id : {0}", webResponse.Headers["x-ms-request-id"]);
                    Console.WriteLine("HttpStatusCode = {0}\n", (int)((HttpWebResponse)webResponse).StatusCode);

                    using (Stream stream = webResponse.GetResponseStream())
                    {
                        using (StreamReader sr = new StreamReader(stream))
                        {
                            stringBuilder.AppendLine(sr.ReadToEnd());
                        }
                    }
                }
            }


            //====================================================================================//
            //=== Catch WebExceptions. The SQL Database Management Service will          ===//
            //=== provide detailed error information in the response stream for WebExceptions. ===//
            //====================================================================================//

            catch (WebException webEx)
            {
                HttpWebResponse errorResponse = (HttpWebResponse)webEx.Response;
                Console.WriteLine(string.Format("HttpStatusCode = {0}", (int)errorResponse.StatusCode));

                try
                {
                    using (Stream errorResponseStream = errorResponse.GetResponseStream())
                    {
                        using (StreamReader sr = new StreamReader(errorResponseStream))
                        {
                            stringBuilder.AppendLine(sr.ReadToEnd());
                        }
                    }
                }
                catch (Exception innerEx)
                {
                    stringBuilder.AppendLine(innerEx.ToString());
                }
            }
            catch (Exception ex)
            {
                stringBuilder.AppendLine(ex.ToString() + "\n");
            }

            return stringBuilder.ToString();
        }

We will see how to Drop Server for our subscription. Below is the screenshot which shows how we can do the same. We will have to specify the server name.  

Below is the code snippet for the same.

        private void DropServer_Click(object sender, RoutedEventArgs e)
        {
            var dropServer = new DropServer();
            dropServer.DropServerEvent += dropServer_DropServerEvent;
            dropServer.ShowDialog();           
        }
 
        public static string DropServer(string certFilename, string certPassword,
                                        string subscriptionId, string Server)
        {
            StringBuilder stringBuilder = new StringBuilder();

            stringBuilder.AppendLine("\n===========================");
            stringBuilder.AppendLine("=== Drop Server Request ===");
            stringBuilder.AppendLine("===========================\n");
            stringBuilder.AppendFormat("Subscription : {0}", subscriptionId);
            stringBuilder.AppendFormat("Server : {0}\n", Server);

            try
            {
                string url = string.Format("https://management.database.windows.net:8443/{0}/servers/{1}", subscriptionId, Server);
                HttpWebRequest webRequest = HttpWebRequest.Create(url) as HttpWebRequest;

                webRequest.ClientCertificates.Add(new X509Certificate2(certFilename, certPassword));
                webRequest.Headers["x-ms-version"] = "1.0";
                webRequest.Method = "DELETE";

                //=== No Request Payload needed to return drop the server ===//

                using (WebResponse webResponse = webRequest.GetResponse())
                {
                    //=== x-ms-request-id is useful for troubleshooting request failures with Microsoft ===//
                    Console.WriteLine("Response x-ms-request-id : {0}", webResponse.Headers["x-ms-request-id"]);
                    Console.WriteLine("HttpStatusCode = {0}\n", (int)((HttpWebResponse)webResponse).StatusCode);

                    using (Stream stream = webResponse.GetResponseStream())
                    {
                        using (StreamReader sr = new StreamReader(stream))
                        {
                            stringBuilder.AppendLine(sr.ReadToEnd());
                        }
                    }
                }
            }
            //====================================================================================//
            //=== Catch WebExceptions. The SQL Database Management Service will          ===//
            //=== provide detailed error information in the response stream for WebExceptions. ===//
            //====================================================================================//

            catch (WebException webEx)
            {
                HttpWebResponse errorResponse = (HttpWebResponse)webEx.Response;
                stringBuilder.AppendLine(string.Format("HttpStatusCode = {0}", (int)errorResponse.StatusCode));

                try
                {
                    using (Stream errorResponseStream = errorResponse.GetResponseStream())
                    {
                        using (StreamReader sr = new StreamReader(errorResponseStream))
                        {
                            stringBuilder.AppendLine(sr.ReadToEnd());
                        }
                    }
                }
                catch (Exception innerEx)
                {
                    stringBuilder.AppendLine(innerEx.ToString());
                }
            }
            catch (Exception ex)
            {
                stringBuilder.AppendLine(ex.ToString() + "\n");
            }

            return stringBuilder.ToString();
        }

 

Challenge 4 

In this challenge we will see how to create , manage VM, host website etc.

Creating a new virtual machine (VM)

1. Log on to windows azure account. 
2. Click on New and then navigate to quickly create a new VM. Below is the screenshot for creating a new VM. 



3. You need to select the virtual machine you want to create. Below is the screenshot for selecting the virtual machine operating system.


 

 

 

4. The next step is the virtual machine configuration, you need to specify the name , username and password etc. Below is the screenshot for reference 


 

5.  The next step is the virtual machine mode. We need to specify the DNS name, storage account (If not exist we can create one) , the storage account where the virtual machine hard disk (VHD) is maintained. There is an option for "Connect to an existing virtual machine" , we need to select this one for load balancing. That means we will have multiple VM's. 

  

6. The next step is the Virtual machine option', we need to select/create one if we are working on multiple VM's. If you are working in a single VM, then you need not do anything.  When multiple virtual machines are connected together in a cloud service, an availability set can be used to ensure that the machines are located in different fault domains. More information on managing the availability set option can be found at http://www.windowsazure.com/en-us/manage/windows/common-tasks/manage-vm-availability/

Click on the right check mark, that's all you are done with creating a new virtual machine.  

 

Manage endpoints 

 

 


The next thing is we will see how we can manage the virtual machine endpoints , By default as per the above default option for enable powershell remoting,  the end points for RDP and for powershell gets created while you are creating a new VM.

We will have to add an endpoint for port 80, so that the VM can serve HTTP web requests. Below is the screenshot for the same. Click on the virtual machine and then select the 'Endpoints' item. You can see below we have an option for adding , editing and deleting the endpoints.

 

 

Managing Virtual machines 


Now we will see how we can manage existing virtual machines for our subscription. Below is the screenshot shows the same. We will have to navigate to Virtual Machines and then select the virtual machine instance so that we can connect , restart, shutdown etc. Also there is an option for adding additional disks if required. 


 

Hosting Web application (HealthReunion) in virtual machine. 


We will see how to host our Providers Portal web application in virtual machine. Below are the steps one has to follow.

1. We need to remote log-in to our virtual machine. When we click on 'Connect' option in managing virtual machine (Refer above image). It will download *.rdp file used to connect to VM. Below is the screenshot shows up when you click on the RDP file. You need to specify the valid username and password to connect to VM.

   

2. There are several things we need to do when we log-in for the first time. I have setup a Windows 2008 R2 virtual machine. It shows up the initial configurations tasks window by default. Under customize server -> Add roles , we need to install web server etc. You can choose as many services you want as per your needs and then install the same. The virtual machine might require several re-boots if required.

3. The next thing is , installing .NET Framework 4.0 / 4.5 framework. Note - By default the virtual machine has nothing in it except few basic things. We will have to install .NET framework so that we can host our web application in VM.

4. Now we will see how we can host the web application. First thing we need to do is download the source code for Providers Portal. Then we need to extract the zipped folder and add IIS_USER, NETWORK_SERVICES user with full control permission as show below. 



5. The next thing is , Run command Inetmgr to open IIS , create a new virtual directory with the path to the web application you wish to deploy. Once you have done with this, we need to set the application pool for Asp.NET 4.0 , Please refer the below screenshot for the same. We need to right click on the virtual directory , then select Manage Application -> Advanced Settings.

 

6. That's all , you are done with hosting web application in VM. In this demonstration, we have hosted Providers Portal , you can access the same through the below mentioned URL. 

http://ranjancp.cloudapp.net/ProviderPortal/Login.aspx 


How to run intensive task in .NET on a Windows Azure virtual machine. How to run intensive task in .NET on a Windows Azure virtual machine. 


We will see one of the most exciting part of making of use of virtual machines to run a heavy task. For this to show in action we have a service bus client and server application. Below is the real time senario which happens in hospitals and clinics. 

Use-case : Providers uploading clinical documents for their patients.

Providers or doctors from hospital are making use of Service Bus Client , it's a WPF based desktop application. They will log in with their credentials , select patients and upload clinical documents for the patients. Using service bus what we can do is,  when ever a provider try's to upload the patient document , we are not going to upload at one shot. We will be creating a service bus message and it will be placed inside service bus queue. 


You might ask what's it ? or why are we doing such things. The doctors who is using our application can do bulk upload of patient documents. In such scenarios, a lot of things happen. The clinical document needs to be validated,  check for duplicate document etc. With service bus, the client application can send a serialized Brokered message to the service broker queue and the server application running in VM can process the messages and upload the clinical document for the patient.

Now we will see in action.. There will be more learning , fun and exiting , keep reading and try to understand the concepts. It's highly interesting. Don't forget to download the full source code , it's at the top of the article. 


Getting Started  


Please have a look into this article for creating a service bus queue - http://www.windowsazure.com/en-us/develop/net/tutorials/compute-intensive-task-on-a-virtual-machine/ , if you are using the attached source code for testing, please create a service bus queue with name as 'healthcarehl7'.

We will see the Service Bus Client Application. Some of the configuration changes that are required for client and server applications are as below. Don't worry , when you are trying to add a reference to Service Bus library through nugget package manager, it will add all the required configuration details for us.

 <appSettings>
    <!-- Service Bus specific app setings for messaging connections -->
    <add key="Microsoft.ServiceBus.ConnectionString" value="Endpoint=sb://healthcarehl7.servicebus.windows.net/;SharedSecretIssuer=owner;SharedSecretValue=dGCsSu5OkvJwIqqlHbSY8tbsE2BQ+Bp2H6wP9fJOVOM=" />
   </appSettings>
  <system.serviceModel>
    <extensions>
      <!-- In this extension section we are introducing all known service bus extensions. User can remove the ones they don't need. -->
      <behaviorExtensions>
        <add name="connectionStatusBehavior" type="Microsoft.ServiceBus.Configuration.ConnectionStatusElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="transportClientEndpointBehavior" type="Microsoft.ServiceBus.Configuration.TransportClientEndpointBehaviorElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="serviceRegistrySettings" type="Microsoft.ServiceBus.Configuration.ServiceRegistrySettingsElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </behaviorExtensions>
      <bindingElementExtensions>
        <add name="netMessagingTransport" type="Microsoft.ServiceBus.Messaging.Configuration.NetMessagingTransportExtensionElement, Microsoft.ServiceBus,  Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="tcpRelayTransport" type="Microsoft.ServiceBus.Configuration.TcpRelayTransportElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="httpRelayTransport" type="Microsoft.ServiceBus.Configuration.HttpRelayTransportElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="httpsRelayTransport" type="Microsoft.ServiceBus.Configuration.HttpsRelayTransportElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="onewayRelayTransport" type="Microsoft.ServiceBus.Configuration.RelayedOnewayTransportElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </bindingElementExtensions>
      <bindingExtensions>
        <add name="basicHttpRelayBinding" type="Microsoft.ServiceBus.Configuration.BasicHttpRelayBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="webHttpRelayBinding" type="Microsoft.ServiceBus.Configuration.WebHttpRelayBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="ws2007HttpRelayBinding" type="Microsoft.ServiceBus.Configuration.WS2007HttpRelayBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="netTcpRelayBinding" type="Microsoft.ServiceBus.Configuration.NetTcpRelayBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="netOnewayRelayBinding" type="Microsoft.ServiceBus.Configuration.NetOnewayRelayBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="netEventRelayBinding" type="Microsoft.ServiceBus.Configuration.NetEventRelayBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add name="netMessagingBinding" type="Microsoft.ServiceBus.Messaging.Configuration.NetMessagingBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </bindingExtensions>
    </extensions>
  </system.serviceModel> 


Service Bus Client Application

Below is the log-on screen which pops up when you run the client app. You can make use of the demo logon, with username - demo and password as demo.

With logon , we need to provide a valid username and password. We will be validating the credentials against HealthVault users and we will be getting the provider Id, which will be used later for fetching all the patients associated for the log in provider. Below is the code snippet for validating the user credentials , upon validation it will show up a main window.

private void btnLogOnClick(object sender, RoutedEventArgs e)
{
     var user = new UserRepository().GetProviderId(txtUserName.Text.Trim(), txtPassword.Password);
     if (user != null)
     {
          var mainWindow = new MainWindow();
          mainWindow.ProviderID = user.ProviderId;
          this.Hide();
          mainWindow.ShowDialog();
     }
} 

Below is the Main window screenshot, We are loading all the patients for the log in provider so that provider (doctors) can select and upload patients clinical documents. 

 

Here's what happens , the provider will select a patient for whom he wish to upload some of the clinical documents. Please note that , I have shared with you a sample clinical document , it's inside a folder named SampleDocuments with in the source code. 

Providers can browse , select one or more clinical documents and add it to the list. They need to select either of the options CCR/CCR as a document type. By default CCR option will be selected, When the provider clicks on 'Submit messages' , we are creating a service bus message and putting it to the queue. Below is the code snippet which does that.

You can notice one thing, we are iterating through the listbox and construct the message, which is a serialized entity of type PatientDocumentDataContract. Then we will be sending the same message to service broker queue with the help of a service broker helper that I have coded specially for this application. 

 private void UploadButton_Click(object sender, RoutedEventArgs e)
 {
            try
            {
                ServiceBrokerHelper.CreateQueue(queueName);
                foreach (var message in GetServiceBrokeredMessages())
                {
                   var response =  ServiceBrokerHelper.SendMessages(queueName, message);
                   listBoxBrokeredMessages.Items.Add(response);
                }
                MessageBox.Show("Messages submitted successfully");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
  }
  
  private List<BrokeredMessage> GetServiceBrokeredMessages()
  {
            var brokeredMessages = new List<BrokeredMessage>();
            foreach (var item in listBox.Items)
            {
                var splittedString = item.ToString().Split(':');
                var document = System.IO.File.OpenRead(splittedString[2].Trim());
                var dataContract = new PatientDocumentDataContract();
                dataContract.PatientId = int.Parse(dbcPatient.SelectedValue.ToString());
                dataContract.ProviderId = ProviderID;
                dataContract.Document = GetBytesFromStream(document);
                dataContract.DocumentType = splittedString[0].Trim();
                var message = new BrokeredMessage(dataContract, new DataContractSerializer(typeof(Patient				  	  	  DocumentDataContract)));
                message.MessageId = (messageId++).ToString();
                brokeredMessages.Add(message);
            }
            return brokeredMessages;
        }   
        private byte[] GetBytesFromStream(Stream input)
        {
            byte[] buffer = new byte[16 * 1024];
            using (MemoryStream ms = new MemoryStream())
            {
                int read;
                while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ms.Write(buffer, 0, read);
                }
                return ms.ToArray();
            }
        } 


Below is the code snippet for Service Broker Helper.

 public class ServiceBrokerHelper
 {
        private static QueueClient queueClient = null;
       
        public static void CreateQueue(string queueName)
        {
            NamespaceManager namespaceManager = NamespaceManager.Create();
            if (!namespaceManager.QueueExists(queueName))
            {
                namespaceManager.CreateQueue(queueName);
            }
        }
        public static string SendMessages(string queueName, BrokeredMessage message)
        {
            if (queueClient == null)
                queueClient = QueueClient.Create(queueName);
            try
            {
                queueClient.Send(message);
            }
            catch (MessagingException e)
            {
                if (!e.IsTransient)
                {
                    Console.WriteLine(e.Message);
                    throw;
                }
             }
            return string.Format("Message Id = {0} , sent successfully.", message.MessageId);
        }  
 } 


Service Bus Server Application  

In service bus server application , we will read messages from service bus queue and upload the clinical document to Healthreunion.Documents table. Below is the screenshot of the server application.

I'm running the server application in Azure VM. If you are trying out, download and copy the source code to Azure VM. Please note while connecting to Azure VM, make sure that the copy clipboard option is selected so that you can copy paste the source code / executable to VM.



 

You will notice a Start and Stop button in the above screenshot. We will see what happens when we click on the start button. On Start , we will run the background worker so that it will execute a method responsible for reading the service broker messages from the queue. On Stop , we will cancel the background worker so that the application will not receive any messages. Below is the code snippet for the same. 

 

 

 private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            backgroundWorker.DoWork += _backgroundWorker_DoWork;
        }
        
        void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            ReceiveMessages();
        }

        void ReceiveMessages()
        {
            var serviceBusMessageStringBuilder = new StringBuilder();
            if (queueClient == null)
            {
                queueClient = QueueClient.Create(QueueName);
            }

            serviceBusMessageStringBuilder.AppendLine("\nReceiving message from Queue...");
            BrokeredMessage message = null;
            while (!backgroundWorker.CancellationPending)
            {
                try
                {
                    //receive messages from Queue
                    message = queueClient.Receive(TimeSpan.FromSeconds(5));
                    if (message != null)
                    {
                        var document = message.GetBody<patientdocumentdatacontract>(new DataContractSerializer(typeof(PatientDocumentDataContract)));
                        serviceBusMessageStringBuilder.AppendLine(string.Format("\nMessage received: Id = {0}, Patient ID = {1} , Document Type: {2}", 
                                                                  message.MessageId, document.PatientId, document.DocumentType));
                        message.Complete();

                        try
                        {
                            using (var dataContext = new healthreunionEntities())
                            {
                                dataContext.Documents.Add(new HealthReunionServiceBusClient.Data.Document
                                {
                                    CreationTime = DateTime.Now,
                                    DocumentType = document.DocumentType,
                                    PatientId = document.PatientId,
                                    ProviderId = document.ProviderId,
                                    Document1 = document.Document
                                });
                                dataContext.SaveChanges();
                            }
                        }
                        catch (Exception ex)
                        {
                            serviceBusMessageStringBuilder.AppendLine(string.Format("Problem in parsing messages for Patient ID = {0} , Document Type: {1}, Detailed Error: {2}",document.PatientId, document.DocumentType, ex.Message));
                        }

                        //Update TextBox
                        this.Dispatcher.Invoke((Action)(() =>
                        {
                            txtServiceBusMessages.Text += serviceBusMessageStringBuilder;
                        }));
                    }
                 }
                catch (MessagingException e)
                {
                    serviceBusMessageStringBuilder.AppendLine(e.Message);                  
                }             
            }
        }

        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            backgroundWorker.RunWorkerAsync();
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            backgroundWorker.CancelAsync();
        }

Once we receive the message , we will deserialize the message body to get the PatientDocumentDataContract  and insert the same to Healthreunion.Documents table. 


Load balancing in Azure VM

 

 

We will see how to load balance and run our web application in multiple VM's. Before we start off with the load balancing , we will fist understand how the communication happens with the virtual machine.

We will see how to load balance and run our web application in multiple VM's. Before we start off with the load balancing , we will fist understand how the communication happens with the virtual machine.

Note, all external communication to virtual machines happens to dedicated ports. We need to add endpoints for our virtual machine. Multiple endpoints are used for different purposes , say if you want to remote desktop the VM , run power shell command , access website from VM for all such things we will have to add an endpoint. This can be easily done through windows azure management portal. Each set of endpoints that we are defining will have public and private ports. The private port is defined for setting up communication rules on the virtual machine where as the public port is used by Windows Azure to communicate with the virtual machine from external resources.

Load balancing the virtual machines can be done by creating multiple VM's contained in a cloud service. Note – It is specific to the TCP/UDP endpoints that's defined for the VM. When you are creating a virtual machine , a cloud service will be automatically gets created for us. For load balancing we will be creating multiple virtual machines using the same cloud service which makes use of same endpoints for communication. With load balancing we can ensure a high availability of our web applications running in VM.

Below are the steps taken to achieve Load balancing in virtual machine.

  1. Create first virtual machine – Below is the screen shot for the same, we will be creating a brand new virtual machine for our subscription. We can easily create on from the gallery, for this demonstration, I have created a Window 2008 R2 virtual machine.   

 

 


We will have to select the virtual machine operating system from the ones which are listed below so that we can create a new VM. 


 

The next thing we need to do is specify the virtual machine name, select the required size and key in the user name and password to log-in to the virtual machine. 

 

The next thing is , just leave the option for 'Stand alone virtual machine' , key in the DNS Name and select the storage account or you use an automatically generated storage account. A storage is where our VM's *.vhd the virtual hard disk is maintained.

 


 

 

The next step is create a new availability set , if required. Note – It's optional. When a virtual machine is created with an availability set option, it is deployed to different fault domains than other virtual machines in the set. Multiple virtual machines in an availability set will ensure that our application is available during network failures, local disk hardware failures, and any planned downtime. 

 

 


Now that we are done with creating a single virtual machine. We will treat this virtual machine as a master VM. I will let you know why I'm calling it as a master virtual machine. The reason is we will be using this virtual machine as a template for creating multiple virtual machines for load balancing. For this to happen we will have to capture an image of the VM so that we can easily create a customized VM's.

We shall see how to capture a VM. The first is , you need to log in to virtual machine and run the below sysprep command in command prompt. The system preparation tool dialog gets opened , You need to

select the options shown in the screen-shot. Note – When you are running a sysprep command , it makes to operating system to take as an image, this is the important step that one need to follow. 

 

 

 


Once the command runs successfully and the virtual machines gets shutdown , you are ready for capturing the image of the VM. Below is the screen-shot shown , you can see the VM got shutdown and now the option for Capture is enabled. Just click on capture , a dialog opens up to key in the virtual machine image name. 


 

In the below screen-shot you will have to key in the name of the virtual machine image and then select an option for 'I have run the Sysprep on virtual machine' , this should take couple of minutes for taking the image of the virtual machine.
 

Warning – After taking an image , the VM gets deleted. Don't get frightened !

Note – When you are capturing an image of the VM , the machine gets deleted. One needs to create a virtual machine from the gallery where you can see the image of the virtual machine that we have taken in the previous step. If you have deployed your application in VM and configured it with necessary software to run our application and have captured the image, You need not reconfigure the same every time when you are creating a new VM from the captured image.

The first VM can be created as usual from the gallery , however for the subsequent ones there is a slight change in the steps , for load balancing we will have to connect to the existing VM. 


 

Now we are getting started for creating multiple VM's and load balancing.

The first thing is to create an endpoint that will be shared among all the VM's. We will be creating a dedicated endpoint say port 80 for load balancing. You need to create this endpoint in first VM so that in the subsequent VM's , you will have to select the existing load balancing endpoint so that the endpoint is shared among multiple virtual machines.

Below is the screen-shot were in we are selecting an existing endpoint for load balancing. This can be done only if you have an endpoint created in first machine and multiple VM's are created by connecting to the existing VM which is as shown in the below snapshot. 

 


Below is the screen-shot you can see the second VM's endpoint is created by selecting the endpoint from the drop-down for option “Load balance traffic on an existing endpoint” 

 

 

How are we dealing or managing the sessions when a website is hosted in a load balancing environment ?


By default if we are not altering the web.config for sessionState , the session information will be maintained in InProc mode. This works very well if we are hosting our web application in single VM or hosting the entire sites under 10 free azure websites. However this will not work in a load balancing scenario where the website will be hosted on multiple VM's which are connected by the same endpoints. 

We will have to move out the storage of session information from InProc to OutProc. One way is to maintain the session information in SQL Azure.

Below is the website web.config changes that we need to do for storing the session state in SQL Azure. 

For managing the session information we will be setting up a database named “ASPState” , run the scripts for creating tables and stored procedure. The script which are using is the modified version of th e actual script “InstallSqlState.sql” that ships with the .NET framework , unfortunately we cannot use the same script because of Transact-SQL differences. You can dowload the scripts from the download section at the top of this article.

Below is what you can see the session information is being save in SQL Azure.

 

 

 

Now we will see how to clean-up the expired sessions. We will be creating a Worker role based project and deploy the same as a cloud service.

We will override the Run() method of worker role and perform cleanup of expired sessions. Below is the code snippet for the same.

What it does is , has a infinite loop , with in it sleep for some time and then connect to SQL Azure Database, open a connection and execute “DeleteExpiredSessions” stored procedure , which will take care of cleaning up of expired sessions. 
 

 void ReceiveMessages()
        {
            var serviceBusMessageStringBuilder = new StringBuilder();
            if (queueClient == null)
            {
                queueClient = QueueClient.Create(QueueName);
            }
            serviceBusMessageStringBuilder.AppendLine("\nReceiving message from Queue...");
            BrokeredMessage message = null;
            while (!backgroundWorker.CancellationPending)
            {
                try
                {
                    //receive messages from Queue
                    message = queueClient.Receive(TimeSpan.FromSeconds(5));
                    if (message != null)
                    {
                        var document = message.GetBody<PatientDocumentDataContract>(new DataContractSerializer(typeof(PatientDocumentDataContract)));
                        serviceBusMessageStringBuilder.AppendLine(string.Format("\nMessage received: Id = {0}, Patient ID = {1} , Document Type: {2}", 
                                                                  message.MessageId, document.PatientId, document.DocumentType));
                        message.Complete();
                        try
                        {
                            using (var dataContext = new healthreunionEntities())
                            {
                                dataContext.Documents.Add(new HealthReunionServiceBusClient.Data.Document
                                {
                                    CreationTime = DateTime.Now,
                                    DocumentType = document.DocumentType,
                                    PatientId = document.PatientId,
                                    ProviderId = document.ProviderId,
                                    Document1 = document.Document
                                });
                                dataContext.SaveChanges();
                            }
                        }
                        catch (Exception ex)
                        {
                            serviceBusMessageStringBuilder.AppendLine(string.Format("Problem in parsing messages for Patient ID = {0} , Document Type: {1}, Detailed Error: {2}",document.PatientId, document.DocumentType, ex.Message));
                        }
                        //Update TextBox
                        this.Dispatcher.Invoke((Action)(() =>
                        {
                            txtServiceBusMessages.Text += serviceBusMessageStringBuilder;
                        }));
                    }
                 }
                catch (MessagingException e)
                {
                    serviceBusMessageStringBuilder.AppendLine(e.Message);                  
                }             
            }
        } 

 

There is also one more thing we are doing here. If any exceptions , we will send an email to the pre defined list of recipients. Note , we are using SendGrid , a thrid party azure service to send emails. Here we are using the free 25K email option for sending mails using SendGrid. I found it useful and easy to use.

We will see some of the helper method and techniques of sending mails through SendGrid. Below is the simple helper method I have created for sending emails in plain text. Note – We are using SendGrid nugget package , which allows us to get the transport instance (based on the credentials) to send email.
 

public class SMTPApi
    {
        private String _username = "<sendgrid-smtp-server-username>";
        private String _password = "<sendgrid-smtp-server-password>";
        private String _from;
        private IEnumerable<String> _to;
        public SMTPApi(String from, IEnumerable<String> recipients)
        {
            _from = from;
            _to = recipients;
        }
    
        public void SimplePlaintextEmail(string errorMessage)
        {
            //create a new message object
            var message = SendGrid.GetInstance();
            //set the message recipients
            foreach (string recipient in _to)
            {
                message.AddTo(recipient);
            }
            //set the sender
            message.From = new MailAddress(_from);
            //set the message body
            message.Text = errorMessage;
            //set the message subject
            message.Subject = "AzureSessionManagementWorker Failed";
            //create an instance of the SMTP transport mechanism
            var transportInstance = SMTP.GetInstance(new NetworkCredential(_username, _password));
            //send the mail
            transportInstance.Deliver(message);
        }
    }  


How are we deploying the Worker Role as a Cloud Service ? 

 

One can either directly deploy through Visual Studio or create a package from VS and then manually deploy the same by log in to azure portal. 

It would be nice to create a brand new cloud service which is dedicated to Session management. The following things are required if you are trying to deploy your Worker Role.

  1. You need to package the worker role , this can be done easily from Visual Studio worker role project. Once the packaging is done successfully , you should be able to see the service package file and cloud service configuration file.

     

  2. You need to have a valid certificate with private key for deployment.  

One can either create a cloud service , then manually upload the above mentioned packages. Below is the screen-shot shows the same.  

 

 

 

 

You could also create a cloud service , specify the package to deploy , upload certificate etc and do everything at one shot. Or one can directly deploy the package through visual studio.    

Below is the screen-shot you can see where we have deployed the Worker Role with two instances. They are all running and working on cleaning up of expired sessions.  

 

 

 

Command line tools for Managing Azure VM 

 

 


We will see how to manage azure VM through command line. Below is what we need to install and that's all is required for managing the VM through command line.

  1. Nodejs

  2. Azure Module.

Please run the below mentioned command to install the same. What you can do is , navigate to nodejs directory and run the below one in command prompt.

npm install azure-cli -g

We assume you already have an azure account , at the least trial one. 

The first thing one has to do is import the azure publish settings. The below commad does the work of downloading your azure publish settings.

azure account download

When you are running the above command, it will open up the browser and prompts you to enter the azure account credential. After signing in , you will be able to see the publish settings getting downloaded to your local machine.

The next thing, we need to import the publish settings. Please run the below command so that it imports the settings.

 

azure account import {path to .publishsettings file}  

 

 

Ones imported , we can start playing around in managing the Azure VM. We will see next how to create a new VM for our subscription etc. 

The Azure VM's are created based on the *.vhd , the virtual machine files. In order to see the list of Azure VM images from the gallery , one has to run the below mentioned command. 

azure vm image list

 

 



We can provision and start a virtual machine from the available list of VM images. Below is the command one has to run in-order to create a new VM. Note the root username and password for the virtual machine is myusername and Mypassw0rd.

azure vm create myVM OpenLogic__OpenLogic-CentOS-62-20120509-en-us-30GB.vhd myusername --location "North Central US"

Note – The location specifies the data center in which the virtual machine is stored. If you omit the location option in the above command , it will ask us you specify the location.

 

We will now see how to create an endpoint. The follow command creates and endpoint for port 80. Note – We have specified two ports, one is the external and the other is the internal port for VM.

azure vm endpoint create <myVMName> 80 80

If you want to see the detailed information about your VM , run the following command to display the DNS name, IP Address, Endpoint information etc.

Note – the “myVMName” is the name of your virtual machine for which you are interested in getting the information.

azure vm show <myVMName> 

In order to shutdown, restart, delete VM. Please run the below command.

azure vm shutdown <myVMName>
azure vm start <myVMName>
azure vm restart <myVMName>
azure vm delete <myVMName> 

 

Setting Up HTTP based file server in Azure Virtual Machine    

 

 

We will see how to build an HTTP based file server with the help of HFS (HTTP File Server) , You can download the from http://www.rejetto.com/hfs/

What is HFS ?

... it's file sharing 

... it's webserver 

... it's open source 

... it's free

... it's guaranteed to contain no malware

Log on to Azure VM and then download HFS. By default the program runs in port – 8080. We need add inbound rule for 8080 in firewall , add an endpoint for the same in Azure VM endpoint configuration. That's all the configuration changes required.

Now we will see how to add folders for sharing , Right click on the home folder and add files/ folders which ever you wish to share. 

 


 

Now you should be able to access the HTTP based file server through URL http://ranjancp.cloudapp.net:8080/ 


 

 


Setting up of SQL Server in Azure VM

 

Here we are setting up a new instance of SQL Server within Azure VM. Below refer the below link to download the *.iso image and install the same. http://www.microsoft.com/betaexperience/pd/SQL2012EvalCTA/enus/default.aspx

There is nothing special about this installation , However I have to mention about this setup in VM. The only reason for that is , I personally found this useful. There is nothing impossible with Azure VM, we are just treating the VM as another machine. By setting up of SQL Server instance , what we can leverage is our website can connect to this instance instead of SQL Azure.

The only change that we have to make in the website configuration is the connection string changes to point to the SQL Server instance in VM.

There are some advantages of doing such things, with no difficulty one can easily move the on premise SQL Server to Cloud. 

After the installation , one can directly connect to SQL Azure database , export the database as Extract Data Tier option , we need to specify the path to extract the same so that one can easily import the same to local SQL Server database. Below is the snapshot shown where I have connected to local and SQL Azure database through SQL Server Management Studio. 

 

 

 

 

You can also recall the Trial Azure database limit , i.e only 1 GB of SQL Azure database can be used for free. So with this approach by setting up SQL Server with in Azure VM , we can sure store a large amount of data. Of-course there is a limit of the disk space with in VM. 

 

 

 

Creating and consuming WCF Data Service 

 

 
We need this service so that our desktop and mobile clients can access the patient data easily with no trouble.  

Please refer this article for creating a new WCF Data Service http://msdn.microsoft.com/en-us/library/vstudio/cc668184.aspx

We will be creating one, with the data being fetched from SQL Server which is installed in Azure VM and host the service in Azure VM. The advantage of creating such service is the easier consumption of data by mobile / desktop clients. Below is the code snippet for our data service , Note we are exposing only a limited set of tables.  

 

public class HealthReunionDataService : DataService<HealthReunionContainer>
    {
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
            config.SetEntitySetAccessRule("Providers", EntitySetRights.AllRead);
            config.SetEntitySetAccessRule("Documents", EntitySetRights.AllRead);
            config.SetEntitySetAccessRule("Patients", EntitySetRights.AllRead);
        }
    } 

OData exposes data as resources which are accessible by URI's. The data service makes use of entity framework for fetching the data and OData uses the entity-relationship conventions of the Entity Data Model to expose resources as sets of entities that are related by associations. 

Below is the screen-shot of the data service being accessed from browser. 

 

 

Design, Implement and Host Patient Portal MVC4 based web solution for patients 


We will see the entire design and development of Patient Portal. Before getting into the understand of the implementation part , we will see the following. 

Patient Portal was developed for patients to access their clinical contents online. Here's what it happens, A patients gets admitted to a hospital , where he will be taken care by a provider either specialty provider or a general provider. We assume providers will be using Enterprise Health Record (EHR) or Enterprise Medical Record (EMR) software for managing the patient health information. By which they will be creating and maintaining the patients clinical content. The patient medical records can be maintained and they can be imported or exported from EMR/EHR. 

The providers will be using these documents , log in to the providers portal, select patient or if not exist create a new one and then they will be uploading the clinical documents for the patient.

Following are the main features of Patient Portal 

1. View Clinical Documents - Patients can view their clinical documents which are uploaded by the providers. There are mainly two types of document one is CCR - Continuity of Care Record and the other one is CCD - Continuity of Care Document. 


The CCR's can have the following 6 sections.

- Header 

- Patient Identifying Information

- Patient Financial and Insurance Information

- Health Status of the Patient

- Care Documentation 

- Care Plan Recommendation   

2. Health Topics - Patients can search for a diseases and they will get to know more about the diseases , symptom etc.

3. Search for doctors or providers - It's a very useful option , where the patients can make use of this one and can search for providers by insurances , location, region etc. We are using a third party API for getting all these provider information. i.e http://www.factual.com/data-apis/places/healthcare. Factual has a Database of over 1.8 million doctor, dentist, and healthcare provider.    


For hosting the MVC based application in VM all we need to do is , first install the MVC4  tool kit. One can easily download and install from http://www.asp.net/mvc/mvc4


Then we need to have the compiled version of Patient Portal Web application. Copy the project files and create a virtual directory pointing it to Patient Portal project folder, set the application pool etc. Hosting the application is as easy and simple as we do in our normal machines. 

Below is the Patient Portal web URL you can browse and have a feel. It's hosted in Azure VM. 
http://ranjancp.cloudapp.net/PatientPortal , Please use the valid credentials that you have created from Providers Portal. If you want to use the demo one.. Just log on with UserName - demo and Password - demo. 

Notice a change has be made in Providers Portal while creating a patient, we need to key in the username. When the provider saves the patient information , a new patient record will be created and an entry in the Users table will also be created. By default , the newly created patient will have a password as - Password1. 

The other thing to notice in the Providers Portal , when the provider creates a patient successfully , an email is sent to patient with the credential to log in to the Patient Portal. We are using SendGrid for sending emails and this is a good opportunity to make use of the service provided by SendGrid, we can send emails up-to 25,000 for free.


Now we will see the implementation part of Patient Portal. Below is the work flow 

When the provider creates a new patient , an email will be triggered to patients with the credentials to log in to the Patient Portal. 

Patients will be accessing our HealthReunion Patient Portal Site and they will log in with the default password i.e Password1. If they log in for the first time, the website will take them to Change password option where they have to change the password with a new password. If everything goes well , they will be redirected to view their clinical documents. 

The patients can also use some of the other options like "Health Topics" to know more about some of the diseases etc. Also they can search for doctors etc. Note - for viewing the clinical documents , a patient require to log in to the system. Other options , they can easily access without log in.

Below is the screenshot of the Patient Portal Main screen. Please note that the screenshots were taken for the patients portal hosted as Websites.  One can also navigate to have a feel about the site hosted in Azure VM http://ranjancp.cloudapp.net/PatientPortal , use UserName - demo and Password - demo  


Here's the Controller code snippet for the Patient Log in.. Notice that we are checking for the default password. I will be coming up with a logic to have auto generate default password for patients. Till then here's the logic. 

If it's the default password then , we are redirecting the user for changing the password. Else we will be redirecting the user to view clinical documents.  

 

public ActionResult Login() 
        {
            ViewBag.TitleMessage = "Welcome to HealthReunion Patient Portal";
            return View();
        }

        //
        // POST: /Account/Login

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Login(LoginModel model, string returnUrl)
        {
            try
            {
                if (ModelState.IsValid && ValidateUser(model.UserName, model.Password))
                {
                    if (model.Password.Equals("Password1"))
                    {
                        return RedirectToAction("ChangePassword");
                    }
                    else
                        return RedirectToLocal();
                }
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("", ex.Message);
                return View(model);
            }

            ModelState.AddModelError("", "The user name or password provided is incorrect.");
            return View(model);
        }

Below is the code snippet for the User Repository , Note - We are implementing the repository pattern here for the HealthReunion data access. The repository deals with CRUD operations.
 

 

public class UserRepository
{    
    public User GetUserById(int patientId)
    {
        using (var dataContext = new HealthReunionEntities())
        {
            var user = (from u in dataContext.Users
                        where u.PatientId == patientId
                        select u).FirstOrDefault();
            return user;
        }
    }

    public void AddUser(User user)
    {
        using (var dataContext = new HealthReunionEntities())
        {
            user.Password = EncryptDecrypt.EncryptData(user.Password, EncryptDecrypt.ReadCert());
            // Add user entity
            dataContext.Users.Add(user);
            // Save changes so that it will insert records into database.
            dataContext.SaveChanges();           
        }
    }

    public void UpdatePassword(User user)
    {
        using (var dataContext = new HealthReunionEntities())
        {
            var original = dataContext.Users.Find(user.UserId);
            if (original != null)
            {
                original.Password = EncryptDecrypt.EncryptData(user.Password, EncryptDecrypt.ReadCert());
            }
            dataContext.SaveChanges();
        }
    }
}

 

 


Now we will see how the patients can access their clinical documents. Below is the screenshot for the same.

You can notice the screenshot shows the CCR document which is being uploaded by a doctor. A grid will be displayed with the columns for Document Type , Date and View, when the patient clicks on the "View Document" link , if it's a CCR document , we will be using CCR.xsl , transform the XML document with the XSLT and render the same. The same holds good for CCD document, we are using CCD.XSL 

The clinical document provides the details information so that the patients can keep track about their health.

 

 

 


Below is the Controller logic. You can see below we are using Document Repository for fetching all the clinical documents for patients. Also we are transforming the clinical documents based upon the type of the document and setting them back to the model which will be returned to the view. 

 

 

 public ActionResult Index()
        {
            if (Session["PatientId"] == null || Session["PatientId"].ToString() == "")
            {
                return RedirectToAction("Login", "Account");
            }

            var documentRepository = new DocumentRepository();
            var documentModel = new List<patientdocumentsmodel>();
            documentModel = documentRepository.GetDocuments(int.Parse(Session["PatientId"].ToString()));

            var ccrXslPath = Server.MapPath("~/ccr.xsl");
            var ccdXslPath = Server.MapPath("~/ccd.xsl");
            foreach (var doc in documentModel)
            {
                if(doc.DocumentText.Contains("ContinuityOfCareRecord"))
                    doc.DocumentText = HtmlHelperExtensions.RenderXslt(ccrXslPath, doc.DocumentText).ToHtmlString();
                else if(doc.DocumentText.Contains("ClinicalDocument"))
                    doc.DocumentText = HtmlHelperExtensions.RenderXslt(ccdXslPath, doc.DocumentText).ToHtmlString();
            }

            ViewBag.TitleMessage = "Welcome to HealthReunion Patient Portal";
            return View(documentModel);
        }

 

 


Below is the code snippet for Docuemnt Repository. It has methods for getting the clinical documents for a patient. Also it has a method for fetching a document by ID.
 

public class DocumentRepository
{
    public Document GetDocumentById(int documentId, string documentType)
    {
        using (var dataContext = new HealthReunionEntities())
        {
            return dataContext.Documents.Where(d => d.DocumentId == documentId && d.DocumentType.Equals(documentType)).First();
        }
    }

    public List<patientdocumentsmodel> GetDocuments(int patientId)
    {
        var patientDocumentsList = new List<patientdocumentsmodel>();
        using (var dataContext = new HealthReunionEntities())
        {
            var patientDocuments = (from doc in dataContext.Documents
                                    join patient in dataContext.Patients
                                    on doc.PatientId equals patient.PatientId
                                    where doc.PatientId == patientId 
                                    select new { Patients = patient , Documents = doc}).ToList();

            foreach (var item in patientDocuments)
            {
                patientDocumentsList.Add(new PatientDocumentsModel
                {
                    FirstName = item.Patients.FirstName,
                    LastName = item.Patients.LastName,
                    MiddleName = item.Patients.MiddleName,
                    DocumentId = item.Documents.DocumentId,
                    DocumentType = item.Documents.DocumentType,
                    PatientId = item.Documents.PatientId,
                    ProviderId = item.Documents.ProviderId,
                    CreationTime = item.Documents.CreationTime,
                    DocumentText = System.Text.Encoding.UTF8.GetString(item.Documents.Document1)
                });
            }

            return patientDocumentsList;
        }
    }
}

 

 

 

 

 

 

 

 

Below things are very exciting and I always love and try to implement something new. Now we will see some more interesting topics , i.e the Health Topics. 

Here's the screenshot for the same. Let us discuss one this, here is the typical scenario where the patient thinks about getting some information about some of the most commonly used medical terminologies or to know more about the diseases, that's were the Health Topics comes into picture, the patients can make use of this , search for health topic and get the detailed information. 


We will see the underlying implementation or behind the scene how we are getting the health topic information.

Below is the Controller logic. You can notice one thing that we are making a web request for getting the health topic information. There are two kinds of responses that we can get, either the spelling correction thing or detailed information about the health topics. Thanks to the service provided by MedlinePlus http://www.nlm.nih.gov/medlineplus/webservices.html , without which we won't be getting this information.

 

 public ActionResult HealthTopics()
        {
            ViewBag.TitleMessage = "Welcome to HealthReunion Patient Portal";
            return View();
        }

        [HttpPost]
        public ActionResult HealthTopics(FormCollection formCollection)
        {
            ViewBag.TitleMessage = "Welcome to HealthReunion Patient Portal";
            string webUrl = string.Empty;
            string healthTopicName = "";

            if (formCollection["txtHealthTopicName"] != "")
            {
                healthTopicName = formCollection["txtHealthTopicName"].ToString();
                if (healthTopicName == "")
                {
                    ViewBag.Result = "Please enter health topic name";
                    return View();
                }
                webUrl = "http://wsearch.nlm.nih.gov/ws/query?db=healthTopics&term=" + healthTopicName;
                ViewBag.HealthTopicName = healthTopicName;
            }

            var response = MakeRequest(webUrl);

            if (response != null)
            {
                if (response.ToString().Contains("spellingCorrection"))
                    ViewBag.Result = string.Format("Spelling Correction: {0}", ProcessSpellingCorrection(response));
                else
                    ViewBag.Result = ProcessResponse(response);
            }

            return View();
        }

Now we will see the next most exciting thing about "Search Provider" Option. Below is the screenshot for th same. 

Here's what it helps a patient to know about the doctors. They can simply search for a doctor based on the location or other information such as Region , Insurance , NPI etc. 

Also there is an option provided to view the map by just clicking on the search grid row , so that it will helps the patients in knowing the route to meet the provider. I feel it's a very good feature and a necessary one too.



Below is the Controller Code Snippet. We are using the services provided by Factual , also notice that we have used a library which we can make a request for getting the providers based on our search criteria.
  

 

 [HttpGet]
        public ActionResult Index(int? page)
        {
            ViewBag.TitleMessage = "Welcome to HealthReunion Patient Portal";
            var filter = new PatientPortal.Models.Filter();
            return View(filter);
        }

        private List<provider> GetProviders(PatientPortal.Models.Filter filter)
        {
            var repository = new HealthCareProviderRepository();           
            var providers = new List<provider>();

            var data = repository.GetHealthCareProviderData(filter);
            JObject json = JObject.Parse(data);
            var jss = new JavaScriptSerializer();
            dynamic dynamicData = jss.Deserialize<dynamic>(json["response"]["data"].ToString());

            for (int i = 0; i < dynamicData.Length; i++)
            {
                var item = (dynamicData[i] as System.Collections.Generic.Dictionary<string,>);
                var provider = new Provider();
                if (item.ContainsKey("name"))
                {
                    provider.Name = item["name"].ToString();
                }
                if (item.ContainsKey("locality"))
                {
                    provider.Locality = item["locality"].ToString();
                }
                if (item.ContainsKey("latitude"))
                {
                    provider.Latitude = item["latitude"].ToString();
                }
                if (item.ContainsKey("longitude"))
                {
                    provider.Longitude = item["longitude"].ToString();
                }
                if (item.ContainsKey("npi_id"))
                {
                    provider.Npi = item["npi_id"].ToString();
                }
                if (item.ContainsKey("address"))
                {
                    provider.Address = item["address"].ToString();
                }
                if (item.ContainsKey("region"))
                {
                    provider.Region = item["region"].ToString();
                }
                providers.Add(provider);
            }

            return providers;
        }
        
        [HttpPost]
        public ActionResult Index(PatientPortal.Models.Filter filter)
        {
            ViewBag.TitleMessage = "Welcome to HealthReunion Patient Portal";
            var providers = GetProviders(filter);
            return PartialView("ProvidersWebGrid", providers); 
        }


Here's the Java script code snippet which does the magic of initiating an Ajax request for getting the Doctors information. You can also see the logic used to show the google map. Please note , we also need to reference some of the scripts for it to happen. Note - for fetching the geo location , we are using the HTML5 Geo location code.   

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
<link href="http://www.google.com/uds/css/gsearch.css" rel="stylesheet" type="text/css"/> 
<script src="~/Scripts/yqlgeo.js"></script> 
<script>       
     $(document).ready(function () {
         $('#map').hide();
     });
  
     function Search() {
            $.ajax({
                url: "/Provider/Index",
                type: "post",
                data: $("#JqAjaxForm").serialize(),
                success: function(response){
                    $("#result").html(response);
                },
                error: function (data) {
                    $("#result").html(data.responseText);
                }   
            }); 
     }

     function initiate_geolocation() {
         if (navigator.geolocation) {
             navigator.geolocation.getCurrentPosition(handle_geolocation_query, handle_errors);
         }
         else {
             yqlgeo.get('visitor', normalize_yql_response);
         }
     }

     function handle_errors(error) {
         switch (error.code) {
             case error.PERMISSION_DENIED: alert("user did not share geolocation data");
                 break;
             case error.POSITION_UNAVAILABLE: alert("could not detect current position");
                 break;
             case error.TIMEOUT: alert("retrieving position timedout");
                 break;
             default: alert("unknown error");
                 break;
         }
     }

     function normalize_yql_response(response) {
         if (response.error) {
             var error = { code: 0 };
             handle_error(error);
             return;
         }
         var position = {
             coords:
             {
                 latitude: response.place.centroid.latitude,
                 longitude: response.place.centroid.longitude
             },
             address:
             {
                 city: response.place.locality2.content,
                 region: response.place.admin1.content,
                 country: response.place.country.content
             }
         };
         handle_geolocation_query(position);
     }
   
     function handle_geolocation_query(position) {
         $('#Longitude').val(position.coords.latitude);
         $('#Latitude').val(position.coords.longitude);
     }

     // Our global state
     var gMap;

     function displayMap(latitude, longitude) {
         gMap = new google.maps.Map(document.getElementById("map"), {
             center: new google.maps.LatLng(latitude, longitude),
             zoom: 15,
             mapTypeId: 'roadmap'
         });

        var myLatlng = new google.maps.LatLng(latitude, longitude);
        var marker = new google.maps.Marker({
            position: myLatlng,
            map: gMap,
            title: "You are here!"
        });
    }


Below are some of the other screenshots for About website and Contacts



Conclusion

 


Now it's the time for concluding things , my experience , the exiting things I did and liked while i was working specially for Azure VM challenge. 

Initially I had no idea on what to do with Azure VM. However , after setting up Windows 2008 Server R2 VM and playing with it , I got lot to of ideas starting from developing , implementing , hosting the website, setting up HTTP based file server, so that we can share some of the files which can be made available to public. Initially I had no idea of setting up SQL Server instance with in VM, later it got struck in my mind and though why not to have an instance , configure it so that our web application can directly connect to it than SQL Azure. Also I though it should be a greatest advantage for peoples who wish to move their on-premise database to cloud , they can directly host their websites and deploy their database in SQL Server instance with in VM.

There are certain useful and required things that I learnt from this challenge , that's the Azure Load balancing. with multiple VM's connected with the common endpoint and are created based of the virtual machine image. There were certain architectural changes required say when we are managing the sessions, we can't have an InProc based session, one has to move out the session storage to out of the process so that's one reason I have spent the most to successfully implement and present with you about session management , with the worker role running behind the scene cleans up expired sessions. 

The next big thing which I did was implementing Service Bus based client server application. The reason why we required is say providers or doctors can directly do bulk upload of patients documents in no time. When ever they are trying to upload using the client application , we will creating a Brokered message and place it in a Service Bus Queue so that our server application running in Azure VM can processes all the messages and dump the clinical documents for the patients. I thought it's really required and a lot can be done while processing a message, say if we can validate the document coming in, or we can build some components and provide a service to clients in processing their messages. 

Here's the typical scenario which happens in all most all the hospital systems running in labs. The lab software generates a HL7 based messages or files that will be send across to a system which can handle the messages , process it and maintain. Or say if the hospitals wish to share their lab results they will be sending across these messages to designated TCP Port or upload the lab results to FTP folder.

I'm happy to introduce you with Patient Portal , MVC4 based web application which is a hosted Azure VM/ Website solution. You might remember as well about the provider's portal , all doctors connected to our system can manage and view their patients clinical documents. Until I published Patient Portal there's no way the patients can see their clinical information. There's lot of effort required in building such system , and I was happy to build sub set of the system so that patients can now view their clinical documents which are of CCD or CCR documents. Also they can have a get to know more information about the diseases with the help of a newly introduced thing in patient portal named  "Health topics". Also there is a provision made for patients to search for providers or doctors. 

Some other interesting things which are done as a part of this challenge is managing Azure VM by using command line tools. I did some research and it worked out well , installed NodeJs and Azure module for managing the Azure VM thought command line. 

 

Challenge 5 


In this challenge we will see couple of things which can improve patients and providers mobile experience in using our HealthReunion application. This time I have aimed and fully concentrated on the responsive design. You will see below a complete redesign of HealthReunion Providers Portal with responsive design. Now I'm proud to say you that the portals cane be browsed in Mobile, Tablets or Desktops. I have a strong feeling that it's very much required for patients and providers.  

 

 

HealthTopics , A Windows Phone Mobile App  


Part of this challenge , while working on Health topics , I got an idea to build a small Windows phone app, thought it might help some of the Windows Phone customers. They can install this app and get benefit of Health topics.

Below is the screenshot of the live HealthTopics In action.

 
 

One might wonder a little, the code behind of this app is just 46 lines in total. For demonstration purpose this app makes a request for Azure hosted HealthTopic website. We will see the phone development and the Web API Implementation.

Below is the code snippet for Win Phone App. You can notice below when the user keys in the Health Topic name and hits Search button , we are making an WebRequest with the Service URL as the hosted azure based solution. Ones the WebRequest download gets completed successfully , we will navigate the Web browser control with the response we obtained from the web request.

 

 

public partial class MainPage : PhoneApplicationPage
    {
        private string ServiceUrl = "http://myhealthtopics.azurewebsites.net/api/HealthTopics/";
        public MainPage()
        {
            InitializeComponent();
            Background = new SolidColorBrush(Colors.White);
        }
        private void btnSearch_Click(object sender, RoutedEventArgs e)
        {
            SearchHealthTopics(txtHealthTopicName.Text.Trim());
        }
        private void SearchHealthTopics(string healthTopics)
        {
            if (healthTopics == string.Empty)
            {
                MessageBox.Show("Please enter health topic name.");
                txtHealthTopicName.Focus();
                return;
            }
            WebClient proxy = new WebClient();
            proxy.DownloadStringCompleted += new DownloadStringCompletedEventHandler(proxy_DownloadStringCompleted);
            ServiceUrl += string.Format("{0}{1}", "/", healthTopics);
            proxy.DownloadStringAsync(new Uri(ServiceUrl));
        }
        void proxy_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e != null && e.Result != null)
            {             
                webBrowser.NavigateToString(e.Result);
            }
        }
    } 

 

 

 

 

We will now see the WebAPI implementation of the HealthTopics. Below is the code snippet for the ApiController.

The Get method is what which will be called when we are making a web request (HTTP GET by default) with health topic as parameter. 

The Get method , internally makes a call to a method "MakeRequest" with the Web URL so that in-turn makes a HTTP Request , once we get a response from this request, we are ready to process the same. The response can be a spelling correction or detailed information about the health topic. When I mean spelling correction , it gives us the right key word to be searched. It's a kind of a suggestion so that helps the users to key in the right keyword and search for the health topic. 

 

 

public class HealthTopicsController : ApiController
    {
        /// <summary>
        /// Returns the Health Topic Information. 
        /// </summary>
        /// <param name="healthTopicName"></param>
        /// <returns></returns>
        public string Get(string id)
        {
            string webUrl = string.Empty;
            webUrl = "http://wsearch.nlm.nih.gov/ws/query?db=healthTopics&term=" + id;
            var response = MakeRequest(webUrl);
            if (response != null)
            {
                if (response.ToString().Contains("spellingCorrection"))
                    return string.Format("Spelling Correction: {0}", ProcessSpellingCorrection(response));
                else
                    return ProcessResponse(response);
            }
            return string.Empty;
        }

        private string ProcessSpellingCorrection(XDocument healthTopicsResponse)
        {
            return healthTopicsResponse.Descendants("spellingCorrection").First().Value;
        }

        private string ProcessResponse(XDocument healthTopicsResponse)
        {
            if (healthTopicsResponse == null) return string.Empty;
            string formattedResponse = "";
            var fullSummaryNodes = (from node in healthTopicsResponse.Descendants("content")
                                    where node.Attribute("name").Value == "FullSummary"
                                    select node);
            foreach (var node in fullSummaryNodes)
            {
                formattedResponse += node.Value;
                formattedResponse += "<br/>";
            }
            return formattedResponse;
        }

        private static XDocument MakeRequest(string requestUrl)
        {
            try
            {
                HttpWebRequest request = WebRequest.Create(requestUrl) as HttpWebRequest;
                HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                var xmlDoc = XDocument.Load(response.GetResponseStream());
                return (xmlDoc);
            }
            catch (Exception e)
            {
                return null;
            }
        }
    } 

 

 

 

HealthAnalyser , A Mobile optimized Responsive design based website 

 

 

 

 


HealthAnalyser is a healthcare based product for analyzing the person or patients health data. 

HealthAnalytics is something interesting and challenging. Most people keep track of their health related things like weight , blood pressure etc. This product is all about understanding the health data by making use of Chart.JS.  Chart.JS being simple and easy to use, we are taking the real advantage of it. 

The technology used for this application is MVC4 , Entity Framework, HTML5 based Web application hosted in Azure. The website is designed in consideration of Responsive based design so that one can browse this site various devices like Desktops , Mobile or Tablets.   

The reason behind implementing this solution is we are letting the patients to not only keep track and view their health information but also we give them an option to analyse their health in terms of charts or graphs.  Now we will see the real implementation of HealthAnalyser Product. Please feel free to download the source code , it's at the top of this page.

The project structure is as follows

1. Controllers - Implementing Action methods for Sleep , Exercise , Blood Pressure, Weight etc

2. Helpers - We have helper classes for each of the above mentioned actions. These helper classes has a method to return the ViewModel.

3. Models - It has the collection of ViewModels which are required for this Product. One each for the above Actions.

4. Views - We have one view for each of the above actions , Displays the UI and necessary form elements required for the particular actions , takes input from the user and submits the requests to Controller action. Also it's responsible for rendering the ViewModel data.

5.  HealthAnalyserDataAccess - This product is implemented with Repository pattern , we have one each repository for the various actions. The Repository takes care of CRUD operation in general. However most likely we are concentrating on fetching the data that's required for the analysis.  

Below is the Sleep data analysis , I have used Opera Emulator to have a real feel of the usage of this product in mobile.  

Below is the Sleep Data View model. It has composed entities for displaying the information required for Chart and Grid. 

    public class SleepDataViewModel
    {
        public SleepDataViewModel()
        {
            this.SleepDataEntity = new List<sleepdataviewentity>();
            this.SleepDataChart = new SleepDataViewForChart();
        }
        public List<sleepdataviewentity> SleepDataEntity { get; set; }
        public SleepDataViewForChart SleepDataChart { get; set; }
    }

    public class SleepDataViewEntity
    {
        public string SleepingDateTime { get; set; }
        public int SleepMinutes { get; set; }
        public int SettlingMinutes { get; set; }
        public int Walk { get; set; }
    }

    public class SleepDataViewForChart
    {
        public string Labels { get; set; }
        public string SleepMinituesData { get; set; }
        public string SettlingMinituesData { get; set; }
    }
</sleepdataviewentity></sleepdataviewentity>

Below is the Sleep data helper class implementation. The GetViewModel method internally makes use of the SleepDataRepository for getting all the sleep related information. 
We are doing two things here , gather all the data and construct the entities one for the grid display and the other for the chart display.  Here we are building the chart data to show the sleeping and setting minutes for a person or patient. 

public class SleepDataHelper
    {
        SleepDataViewModel sleepDataViewModel;
        public SleepDataHelper()
        {
            sleepDataViewModel = new SleepDataViewModel();           
        }

        private static string PutIntoQuotes(string value)
        {
            return "\"" + value + "\"";
        }

        public SleepDataViewModel GetViewModel()
        {
            var sleepDataRepository = new SleepDataRepository();
            var sleepDataList = sleepDataRepository.GetAllSleepData();
            foreach (var item in sleepDataList)
            {
                sleepDataViewModel.SleepDataEntity.Add(new SleepDataViewEntity
                {
                    SettlingMinutes = item.SettlingMinutes,
                    SleepingDateTime = item.SleepingDateTime.Date.ToShortDateString(),
                    SleepMinutes = item.SleepMinutes,
                    Walk = item.Walk
                });
            }

            // Get Labels
            string lables = "[";
            foreach (var item in sleepDataList)
            {
                lables = lables + PutIntoQuotes(item.SleepingDateTime.Date.ToShortDateString()) + ",";
            }
            lables = lables.Substring(0, lables.Length - 1) + "]";

            sleepDataViewModel.SleepDataChart.Labels = lables.Replace(@"\", " ");

            // Sleeping Minutes Data
            string sleepData = "[";
            foreach (var item in sleepDataList)
            {
                sleepData = sleepData + item.SleepMinutes.ToString() + ",";
            }
            sleepData = sleepData.Substring(0, sleepData.Length - 1) + "]";
            sleepDataViewModel.SleepDataChart.SleepMinituesData = sleepData;

            // Settling Minitues Data
            string settlingMinituresData = "[";
            foreach (var item in sleepDataList)
            {
                settlingMinituresData = settlingMinituresData + item.SettlingMinutes.ToString() + ",";
            }
            settlingMinituresData = settlingMinituresData.Substring(0, settlingMinituresData.Length - 1) + "]";
            sleepDataViewModel.SleepDataChart.SettlingMinituesData = settlingMinituresData;
            return sleepDataViewModel;
        }
    }

 

Below is the Sleep data repository. Note , as of now we are only dealing with the fetch operation. It makes use of Entity Framework 5.0 , we are using the DbContext for fetching the data for the entities. 

   public class SleepDataRepository
    {
        public List<sleepdata> GetAllSleepData()
        {
            using (var dataContext = new HealthAnalyserEntities())
            {
                return dataContext.SleepData.OrderBy(s => s.SleepingDateTime).ToList();
            }
        }
    }
</sleepdata>

 

 


Exercise data analysis 


Below is the screenshot for the same. We are keeping track of the activity , date , description , duration and time of exercise. Based on these data , we will be plotting a chart.  

The exercise data helper deals will building all the data that's required for showing the grid and chart. Note - We are considering the distance and duration values for charting. 


Below is the code snippet for exercise view model and data  helper.  You can notice the data helper grabs in the Exercise data from DB and builds the entities required for displaying the grid and chart.  

    public class ExerciseDataViewEntity
    {
        public string Activity { get; set; }
        public string Date { get; set; }
        public System.TimeSpan Time { get; set; }
        public string Description { get; set; }
        public int Duration { get; set; }
        public int Distance { get; set; }
    }

    public class ExerciseDataViewModel
    {
        public ExerciseDataViewModel()
        {
            this.ExerciseDataEntity = new List<exercisedataviewentity>();
            this.ExerciseDataChart = new ExerciseDataViewForChart();
        }
        public List<exercisedataviewentity> ExerciseDataEntity { get; set; }
        public ExerciseDataViewForChart ExerciseDataChart { get; set; }
    }

    public class ExerciseDataViewForChart
    {
        public string Labels { get; set; }
        public string DurationData { get; set; }
        public string DistanceData { get; set; }
    }

    public class ExerciseDataHelper
    {
        ExerciseDataViewModel exerciseDataViewModel;
        public ExerciseDataHelper()
        {
            exerciseDataViewModel = new ExerciseDataViewModel();           
        }

        private static string PutIntoQuotes(string value)
        {
            return "\"" + value + "\"";
        }

        public ExerciseDataViewModel GetViewModel()
        {
            var exerciseDataRepository = new ExerciseDataRepository();
            var exerciseDataList = exerciseDataRepository.GetAllExerciseData();
            foreach (var item in exerciseDataList)
            {
                exerciseDataViewModel.ExerciseDataEntity.Add(new ExerciseDataViewEntity
                {
                    Activity = item.Activity,
                    Date = item.Date.ToShortDateString(),
                    Description = item.Description,
                    Distance = item.Distance,
                    Duration = item.Duration,
                    Time = item.Time
                });
            }

            // Get Labels
            string lables = "[";
            foreach (var item in exerciseDataList)
            {
                lables = lables + PutIntoQuotes(item.Date.ToShortDateString()) + ",";
            }
            lables = lables.Substring(0, lables.Length - 1) + "]";

            exerciseDataViewModel.ExerciseDataChart.Labels = lables.Replace(@"\", " ");

            // Duration Data
            string durationData = "[";
            foreach (var item in exerciseDataList)
            {
                durationData = durationData + item.Duration.ToString() + ",";
            }
            durationData = durationData.Substring(0, durationData.Length - 1) + "]";
            exerciseDataViewModel.ExerciseDataChart.DurationData = durationData;

            // Distance Data
            string distanceData = "[";
            foreach (var item in exerciseDataList)
            {
                distanceData = distanceData + item.Distance.ToString() + ",";
            }
            distanceData = distanceData.Substring(0, distanceData.Length - 1) + "]";
            exerciseDataViewModel.ExerciseDataChart.DistanceData = distanceData;
            return exerciseDataViewModel;
        }
    }
</exercisedataviewentity></exercisedataviewentity>


Blood Pressure data analysis 


With the Blood pressure data analysis , we are concentrating more on Systolic and Diastolic and pulse readings. For more information on blood pressure related domain knowledge , read my article http://www.codeproject.com/Articles/566878/Blood-Pressure-Tracker-Win-8-Phone-Based-HealthVau 

Below is the snapshot for the same.  

Below is the code snippet for the Blood Pressure View model entity for rendering the grid and chart.  You can notice , we have properties for each of the Blood pressure related things to render. 

 
 public class BloodPressureDataViewEntity
    {
        public string Date { get; set; }
        public int Systolic { get; set; }
        public int Diastolic { get; set; }
        public int Pulse { get; set; }
    }

    public class BloodPressureDataViewModel
    {
        public BloodPressureDataViewModel()
        {
            this.BloodPressureDataEntity = new List<bloodpressuredataviewentity>();
            this.BloodPressureDataChart = new BloodPressureDataViewForChart();
        }
        public List<bloodpressuredataviewentity> BloodPressureDataEntity { get; set; }
        public BloodPressureDataViewForChart BloodPressureDataChart { get; set; }
    }

    public class BloodPressureDataViewForChart
    {
        public string Labels { get; set; }
        public string SystolicData { get; set; }
        public string DiastolicData { get; set; }
        public string PulseData { get; set; }
    }
</bloodpressuredataviewentity></bloodpressuredataviewentity>

Below is the code snippet for Blood Pressure data helper.  

public class BloodPressureDataHelper
    {
        BloodPressureDataViewModel bloodPressureDataViewModel;
        public BloodPressureDataHelper()
        {
            bloodPressureDataViewModel = new BloodPressureDataViewModel();           
        }

        private static string PutIntoQuotes(string value)
        {
            return "\"" + value + "\"";
        }

        public BloodPressureDataViewModel GetViewModel()
        {
            var bloodPressureDataRepository = new BloodPressureDataRepository();
            var bloodPressureDataList = bloodPressureDataRepository.GetAllBloodPressureData();
            foreach (var item in bloodPressureDataList)
            {
                bloodPressureDataViewModel.BloodPressureDataEntity.Add(new BloodPressureDataViewEntity
                {
                    Date = item.Date.ToShortDateString(),
                    Diastolic = item.Diastolic,
                    Systolic = item.Systolic,
                    Pulse = item.Pulse 
                });
            }

            // Get Labels
            string lables = "[";
            foreach (var item in bloodPressureDataList)
            {
                lables = lables + PutIntoQuotes(item.Date.ToShortDateString()) + ",";
            }
            lables = lables.Substring(0, lables.Length - 1) + "]";

            bloodPressureDataViewModel.BloodPressureDataChart.Labels = lables.Replace(@"\", " ");

            // Systolic Data
            string systolicData = "[";
            foreach (var item in bloodPressureDataList)
            {
                systolicData = systolicData + item.Systolic.ToString() + ",";
            }
            systolicData = systolicData.Substring(0, systolicData.Length - 1) + "]";
            bloodPressureDataViewModel.BloodPressureDataChart.SystolicData = systolicData;

            // Diastolic Data
            string diastolicData = "[";
            foreach (var item in bloodPressureDataList)
            {
                diastolicData = diastolicData + item.Diastolic.ToString() + ",";
            }
            diastolicData = diastolicData.Substring(0, diastolicData.Length - 1) + "]";
            bloodPressureDataViewModel.BloodPressureDataChart.DiastolicData = diastolicData;

            // Pulse Data
            string pulseData = "[";
            foreach (var item in bloodPressureDataList)
            {
                pulseData = pulseData + item.Pulse.ToString() + ",";
            }
            pulseData = pulseData.Substring(0, pulseData.Length - 1) + "]";
            bloodPressureDataViewModel.BloodPressureDataChart.PulseData = pulseData;
            return bloodPressureDataViewModel;
        }
    }


Weight data & Weight goal analysis 


We have two things here in weight data analysis, one is to keep track of the weight. We could either see the weight difference between the date or else the other one is the Weight Goal.

Here's what the weight goal is, One can set the initial readings , the minimum and maximum weight for a particular date. By this way we are setting ourselves with the max and min weight for a given period of time. We are keeping track of all these information , based on this data we will show the grid data and the chart display consisting of Initial weight , Minimum and Maximum weight. 

Below is the snapshot for the weight data analysis

 

Here's the code snippet for the weight data analysis, it's almost the same for weight goal data analysis except for additional properties for managing the information.  

public class WeightDataViewEntity
    {
        public string Date { get; set; }
        public int Weight { get; set; }
    }

    public class WeightDataViewModel
    {
        public WeightDataViewModel()
        {
            this.WeightDataEntity = new List<weightdataviewentity>();
            this.WeightDataChart = new WeightDataViewForChart();
        }
        public List<weightdataviewentity> WeightDataEntity { get; set; }
        public WeightDataViewForChart WeightDataChart { get; set; }
    }

    public class WeightDataViewForChart
    {
        public string Labels { get; set; }
        public string WeightData { get; set; }
    }
</weightdataviewentity></weightdataviewentity>

Below is the code snippet for Weight Data Helper. You can notice here, like all other helpers we are doing the same here, but in this helper we are interested in gathering weight data. 

 public class WeightDataHelper
    {
        WeightDataViewModel weightDataViewModel;
        public WeightDataHelper()
        {
            weightDataViewModel = new WeightDataViewModel();           
        }

        private static string PutIntoQuotes(string value)
        {
            return "\"" + value + "\"";
        }

        public WeightDataViewModel GetViewModel()
        {
            var weightDataRepository = new WeightDataRepository();
            var weightDataList = weightDataRepository.GetAllWeightData();
            foreach (var item in weightDataList)
            {
                weightDataViewModel.WeightDataEntity.Add(new WeightDataViewEntity
                {
                    Date = item.Date.ToShortDateString(),
                    Weight = item.WeightValue 
                });
            }

            // Get Labels
            string lables = "[";
            foreach (var item in weightDataList)
            {
                lables = lables + PutIntoQuotes(item.Date.ToShortDateString()) + ",";
            }
            lables = lables.Substring(0, lables.Length - 1) + "]";

            weightDataViewModel.WeightDataChart.Labels = lables.Replace(@"\", " ");

            // Weight Data
            string weightData = "[";
            foreach (var item in weightDataList)
            {
                weightData = weightData + item.WeightValue.ToString() + ",";
            }
            weightData = weightData.Substring(0, weightData.Length - 1) + "]";
            weightDataViewModel.WeightDataChart.WeightData = weightData;

            return weightDataViewModel;
        }

Mood data analysis 


With mood data analysis , we are keeping track of the persons mood related information through external service provider. i.e we are using mood panda for the same.

Mood data analysis is very interesting and exciting , we will see in detail about this one and I loved integrating this feature which perfectly fits into our analytic's product.  Before we dive into moodpanda please do register in http://moodpanda.com/ may be with external log in such as Facebook would also work and it's easy to do so. 

The interesting thing about mood panada is it provides an API , we need to register the key to make use of it. With this API we can fetch all the mood related data for a given date range and User ID. This is where the data as a service is helpful for us in analysis our mood related things over the time frame.

Below is the screenshot for the same. Note , we are getting the real time data from moodpanda using their API.

 

Below is the code snippet for the Mood data view model.  

    public class MoodViewModelEntity
    {
        [Required]
        [Display(Name = "User ID")]
        public int UserId { get; set; }

        public string Reason { get; set; }
        
        [Required]
        [DataType(DataType.Date)]
        [Display(Name = "From Date")]        
        public DateTime FromDate { get; set; }
       
        [Required]
        [DataType(DataType.Date)]
        [Display(Name = "To Date")]
        public DateTime ToDate { get; set; }

        public int Rating { get; set; }

        [UIHint("Hidden")]
        public string Time { get; set; }
    }

    public class MoodDataViewModel
    {
        public MoodDataViewModel()
        {
            this.MoodViewModelEntity = new List<moodviewmodelentity>();
            this.MoodDataViewForChart = new MoodDataViewForChart();
            this.MoodDataEntity = new MoodViewModelEntity();
        }

        public MoodViewModelEntity MoodDataEntity { get; set; }
        public List<moodviewmodelentity> MoodViewModelEntity { get; set; }
        public MoodDataViewForChart MoodDataViewForChart { get; set; }
    }

    public class MoodDataViewForChart
    {
        public string Labels { get; set; }
        public string RatingData { get; set; }       
    }
</moodviewmodelentity></moodviewmodelentity>

Below is the code snippet for mood data helper. Here's what we do , we are reading the mood related information for the specified user and date range the from and to date in a Dataset.  Ones we get the data, it's all about constructing the entities for rendering the grid and chart. 

We are only interested in the Rating, Reason and Time of mood when we are displaying the information in a grid.  However with chart display , we are rendering the graph based on Rating. 

 public class MoodDataHelper
    {
        MoodViewModelEntity viewModel;
        public MoodDataHelper(MoodViewModelEntity viewModel)
        {
            this.viewModel = viewModel;
        }

        private static string PutIntoQuotes(string value)
        {
            return "\"" + value + "\"";
        }

        public MoodDataViewModel GetViewModel()
        {
            DataSet ds = new DataSet();
            var moodDataViewModel = new MoodDataViewModel();
            moodDataViewModel.MoodDataEntity = viewModel; 

            ds.ReadXml(string.Format("http://moodpanda.com/api/user/feed/data.ashx?userid={0}&from={1}&to={2}&format=xml&DateOrder=ASC&key=5fe9dd40-1f55-4483-abb0-5540d7bf1b93", viewModel.UserId, viewModel.FromDate.Date.ToString("yyyy-MM-dd"), viewModel.ToDate.Date.ToString("yyyy-MM-dd")));
            if (ds.Tables.Count == 1)
            {
                string lables = "[";
                string ratingData = "[";
                foreach (DataRow item in ds.Tables[0].Rows)
                {
                    var splittedDate = item["Date"].ToString().Split('T');
                   
                    moodDataViewModel.MoodViewModelEntity.Add(new MoodViewModelEntity
                    {
                         Rating = int.Parse(item["Rating"].ToString()),
                         Reason = item["Reason"].ToString(),
                         Time = splittedDate[1].ToString()
                    });

                     lables = lables + PutIntoQuotes(splittedDate[0]) + ",";

                    ratingData = ratingData + item["Rating"].ToString() + ",";
                }

                lables = lables.Substring(0, lables.Length - 1) + "]";
                ratingData = ratingData.Substring(0, ratingData.Length - 1) + "]";

                moodDataViewModel.MoodDataViewForChart.Labels = lables.Replace(@"\", " ");
                moodDataViewModel.MoodDataViewForChart.RatingData = ratingData;
            }
            return moodDataViewModel;
        }
    }


HealthReunion Providers Portal - A Mobile optimized , Responsive design based website 

Before we dig into the Responsive based Providers Portal.

Recap -- Just rewinding a bit. 

Let us recall the existing HealthReunion Providers Portal developed using ASP.NET Web Forms. It was working fine and there were no issues in desktop. Please note that it was developed for Challenge 2 Website challenge. To be frank , I was little aware of responsive design at the initial development phase. I thought to rapidly build website so that I can show off some working functionality, I had several things in my mind and with the 2 weeks limit for the challenge , at that time I thought to complete the website first. However one thing which you might have noticed , the website wasn't that responsive , I can say it was working well with desktops and tablets. How about in mobile? and we have various mobile devices. I did tested to an extent and realized this doesn't work as expected. Just in the middle and after finishing challenge 2, I thought let me back off and redesign stuffs and make things responsive.

Here comes the Responsive design.

A complete redesign of HealthReunion Providers Portal developed with MVC4, bootstrap framework for responsive design. With MVC4 , I had better control on the things I wished to implement and render the way I wanted to make things responsive. 

We will see now the real implementation of HealthReunion Providers Portal. Below screenshots are taken by browsing through the live website in Opera Mobile Emulator. 

Below is the snapshot of the Log on Screen. 

Let us see the code snippet for the Controller. We will see only the required things one at the time. We have HttpGet and HttpPost implementations. In Get method, you can see that we are getting all the providers, that's required as the provider will be selecting his/her name and try to log in with his/her credentials. 

In the POST implementation, we are trying to validate the user based on the credentials , if there's a match then we will be redirect to Main screen where there are options for providers for creating patients, new providers , new users, viewing appointments (Its specific to the logged in provider) , Manage clinical documents etc. 

        public ActionResult Login()
        {
            var providers = new ProviderRepository().GetAllProviders();
            var loginViewModel = new LoginModel();
            loginViewModel.Providers = new Models.DrodownItemsViewModel();
            loginViewModel.Providers.Items = GetProviders();
            return View(loginViewModel);
        }
  //
        // POST: /Account/Login
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Login(LoginModel model, string returnUrl)
        {
            try
            {
                if (ModelState.IsValid && ValidateUser(model.UserName, model.Password, model.SelectedProvider))
                {
                    return RedirectToLocal();
                }
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("", ex.Message);
            }
            model.Providers = new Models.DrodownItemsViewModel();
            model.Providers.Items = GetProviders();
            return View(model);
        }

        private bool ValidateUser(string userName, string passWord, int selectedProvider)
        {
            try
            {
                var providers = new ProviderRepository().GetAllProviders();
                if (providers.Count > 0)
                {
                    var providerRepository = new ProviderRepository();
                    if (providerRepository.ValidateUser(userName, passWord, selectedProvider))
                    {
                        Session["UserName"] = userName;
                        Session["ProviderId"] = selectedProvider;
                        return true;
                     }
                    else
                    {
                       throw new Exception("Invalid username or password");
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return false;
       }  

Below is the screenshot of Main Screen. You can notice the vertical view of the options, it should be easy for one to use. The same will be rendered horizontally in tablets / desktops. 




Below is the screenshot for adding a new provider. One can create new provider , here we are registering the provider with credentials required for provider to log into the portal , create new patients and manage their clinical documents. 




Below is the code snippet for adding a new provider. In HttpGet implementation , we are just returning the view with an instance of ProviderViewModel. In case of HttpPost, you can see below , we are creating a new Provider a data access entity, setting in all the properties from the provider view model. Also simultaneously creating a user which is an associated entity an then using Provider Repository we are saving the newly created provider.  

        public ActionResult ProviderRegistration()
        {
             return View(new ProviderViewModel());
        }

        [HttpPost]
        public ActionResult ProviderRegistration(ProviderViewModel providerViewModel)
        {
            if (!ModelState.IsValid)
            {
                return View(providerViewModel);
            }
            try
            {
                HealthReunionDataAccess.HealthReunionEntities dataContext = 
			new HealthReunionDataAccess.HealthReunionEntities();
                ProviderRepository providerRepository = new ProviderRepository();
                var provider = new Provider
                {
                    ProviderName = providerViewModel.ProviderName,
                    TermsOfUse = providerViewModel.TermsOfUse.Trim(),
                    ProviderDescription = providerViewModel.ProviderDescription.Trim(),
                    PrivacyStatement = providerViewModel.PrivacyStatement.Trim(),
                    AuthorizationReason = providerViewModel.AuthorizationReason.Trim(),
                    Email = providerViewModel.Email.Trim()
                };
                var user = new User
                {
                    UserName = providerViewModel.UserName.Trim(),
                    Password = providerViewModel.Password.Trim(),
                    ProviderId = provider.ProviderId
                };
                providerRepository.AddProviderWithDefaultUser(provider, user);
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("", ex.Message);
                return View(providerViewModel);
            }
            ViewBag.Message = string.Format("Provider '{0}' Created Sucessfully!", 
					    providerViewModel.ProviderName);
            return View(new ProviderViewModel());
        }      

Below is the screenshot for adding a new User. Note - A provider can create multiple users and for now those additional users also has the same privilege as that of provider. We are displaying a Grid with all the users belonging for the logged in provider. There's an option for removing the users if required. 

 

Below is the code snippet for managing new provider users. In HttpGet we are creating a new User view model , setting in the Provider Id, and grid with the list of users for the logged in provider. There's a underlying User Repository which does the actual operation of adding and removing users for a provider. Note - We are creating a new user if the user not exist, also you can see the password is being encrypted and stored in DB. 

        public ActionResult NewUser()
        {
            if (!LogOnHelper.CheckLogOn()) return RedirectToAction("Login", "Account");
            var userViewModel = new UserViewModel();
            userViewModel.UserViewEntity.ProviderId = int.Parse(Session["ProviderId"].ToString());
            userViewModel.UserViewEntityGrid = GetAllUsers();
            return View(userViewModel);
        }

        private List<UserViewEnity> GetAllUsers()
        {
            var userRepository = new UserRepository();
            List<UserViewEnity> usersList = new List<UserViewEnity>();
            var users = userRepository.GetUsersByProviderId(int.Parse(Session["ProviderId"].ToString()));
            foreach (var user in users)
            {
                usersList.Add(new UserViewEnity
                {
                    UserId = user.UserId,
                    UserName = user.UserName                    
                });
            }
            return usersList;
        }

        [HttpPost]
        public ActionResult RemoveUser(int userId)
        {
            var userRepository = new UserRepository();
            userRepository.RemoveUser(userId);
            var userViewModel = new UserViewModel();
            userViewModel.UserViewEntityGrid = GetAllUsers();
            return PartialView("UserGrid", userViewModel);
        }

        [HttpPost]
        public ActionResult NewUser(UserViewModel userViewModel)
        {
            if (!ModelState.IsValid)
            {
                userViewModel.UserViewEntity.ProviderId = int.Parse(Session["ProviderId"].ToString());
                userViewModel.UserViewEntityGrid = GetAllUsers();
                return View(userViewModel);
            }
            try
            {
                var userRepository = new UserRepository();
                userRepository.AddUser(new User
                {
                    UserName = userViewModel.UserViewEntity.UserName,
                    Password = EncryptDecrypt.EncryptData(userViewModel.UserViewEntity.Password, EncryptDecrypt.ReadCert()),
                    ProviderId = userViewModel.UserViewEntity.ProviderId 
                });
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("", ex.Message);
                return View(userViewModel);
            }
            ViewBag.Message = "Created Successfully!";
            return RedirectToAction("NewUser");
        } 

Below is the screenshot for adding a new patient for the logged in provider. Here's what it happens. The provider or doctor can manage or have one or more patients. In order to manage their patients, the provider need to create a new Patient. Also in the below screen , you could see there is a field for username, it's the username patients have to make use to log into HealthReunion Patients Portal. When a new patient is created , a new user is also created for the patient and a random password is generated and an email is sent to patient i.e the patients email address that's mentioned while registering a new patient. Note we are using SendGrid's email service, were in we can send up-to 25,000 emails per month for free.

 

Below is the code snippet for the same. The HttpGet method , returns the view with a Patient view model. Also setting in the grid entity with the list of patients for the logged in provider. The HttpPost implementation has the logic to create new patient or update existing patient. Also notice the usage of SendGrid below , were we are sending an email to patient with the credentials required to log in to patient's portal. 

 

        [HttpGet]
        public ActionResult PatientRegistration()
        {
            if (!LogOnHelper.CheckLogOn()) return RedirectToAction("Login", "Account");

            var patientViewModel = new PatientViewModel();
            patientViewModel.PatientViewModelGrid = GetPatientsForLoggedInProvider();            
            return View(patientViewModel);
        }

        private List<patientviewentity> GetPatientsForLoggedInProvider()
        {
            var patientViewEntityList = new List<patientviewentity>();
            PatientRepository patientRepository = new PatientRepository();
            var patientsList =  patientRepository.GetAllPatients(int.Parse(Session["ProviderId"].ToString()));
            foreach (var patient in patientsList)
            {
                patientViewEntityList.Add(new PatientViewEntity
                {
                    PatientId = patient.PatientId,
                    FirstName = patient.FirstName,
                    MiddleName = patient.MiddleName,
                    LastName = patient.LastName,
                    City = patient.City,
                    State = patient.State,
                    Country = patient.Country,
                    DOB = patient.DOB.ToShortDateString(),
                    Phone = patient.Phone
                });
            }
            return patientViewEntityList;
        }

        [HttpPost]
        public ActionResult PatientRegistration(PatientViewModel patientViewModel)
        {
            if (!LogOnHelper.CheckLogOn()) return RedirectToAction("Login", "Account");

            if (!ModelState.IsValid)
            {
                return View(patientViewModel);
            }
            try
            {
                HealthReunionDataAccess.HealthReunionEntities dataContext = new HealthReunionDataAccess.HealthReunionEntities();
                PatientRepository patientRepository = new PatientRepository();
                
                Patient patient = new Patient();
                patient.PatientId = patientViewModel.PatientViewEntity.PatientId;
                patient.ProviderId = int.Parse(Session["ProviderId"].ToString());
                patient.MedicalRecordNumber = Guid.NewGuid();
                patient.LastName = patientViewModel.PatientViewEntity.LastName.Trim();
                patient.FirstName = patientViewModel.PatientViewEntity.FirstName.Trim();
                patient.MiddleName = patientViewModel.PatientViewEntity.MiddleName.Trim();
                patient.DOB = DateTime.Parse(patientViewModel.PatientViewEntity.DOB).Date;
                patient.Address = patientViewModel.PatientViewEntity.Address.Trim();
                patient.Phone = patientViewModel.PatientViewEntity.Phone.Trim();
                patient.Email = patientViewModel.PatientViewEntity.Email.Trim();
                patient.City = patientViewModel.PatientViewEntity.City.Trim();
                patient.State = patientViewModel.PatientViewEntity.State.Trim();
                patient.Country = patientViewModel.PatientViewEntity.Country;
                patient.IsActive = true;

                if (patientViewModel.PatientViewEntity.Gender.Equals("Male"))
                    patient.Sex = true;
                else
                    patient.Sex = false;
                               
                if (patientViewModel.PatientViewEntity.PatientId == 0)
                {
                    string defaultPassword = RandomPasswordGenerator.Generate(8);
                    defaultPassword = EncryptDecrypt.EncryptData(defaultPassword, EncryptDecrypt.ReadCert());
                    patientRepository.AddPatient(patient, patientViewModel.PatientViewEntity.UserName.Trim(), defaultPassword);
                    var sendMail = new SMTPApi(ConfigurationManager.AppSettings["SmtpFromEmailAddress"].ToString(), new List<string> { patient.Email });
                    var stringBuilder = new StringBuilder();
                    stringBuilder.AppendLine("HealthReunion Patient Portal Log On Information. Below are the credentials
<hr />");
                    stringBuilder.AppendFormat("
User Name: {0}", patientViewModel.PatientViewEntity.UserName.Trim());
                    stringBuilder.AppendFormat("
Password: {0}", defaultPassword);
                    stringBuilder.AppendLine("<hr />Please log on to HealthReunion Patient Portal - http://healthreunionpatients.azurewebsites.net/ to access your clinical information.");
                    sendMail.SimpleHtmlEmail(stringBuilder.ToString());
                }
                else
                {
                    patientRepository.UpdatePatient(patient, 
                }               
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("", ex.Message);
                return View(patientViewModel);
            }
            ViewBag.Message = string.Format("Patient '{0} {1} {2}' Created Sucessfully!. An Email is trigged to {3} with credentials to Log in to HealthReunion Patient Portal.", 
                patientViewModel.PatientViewEntity.FirstName, patientViewModel.PatientViewEntity.MiddleName, patientViewModel.PatientViewEntity.LastName, patientViewModel.PatientViewEntity.Email);

            patientViewModel.PatientViewEntity = new PatientViewEntity();
            patientViewModel.PatientViewModelGrid = GetPatientsForLoggedInProvider();       
            return View(patientViewModel);
        }     
    }
</string></patientviewentity></patientviewentity>

View Appointments (In HealthReunion Providers Portal)  

It's a brand new feature which has been added to HealthReunion Patient Portal , which allows patients to book an appointment (for the selected provider). We will discuss more on the appointment scheduling part of Patient Portal shortly. For Now let us see how the provider will come to know his/her day to day or future booking.

Here's the screenshot which says all about the appointment which was booked as of 6/24/2013. By default the Grid which shows all the appointments made by patients. However the provider can select individual patient and view their appointments too.

 

 

Below is the controller logic for viewing the appointments booked by patients. The HttpGet returns the view with appointment view model. Before we return the view , we are setting the appointment view model properties for Patients and AppointmentViewModelGrid. By default , we will be getting all the appointments as of current date and also for the logged in provider. The HttpPost implementation is used for filtering the appointments for the selected date and patient.  

 

        [HttpGet]
        public ActionResult PatientAppointments()
        {
            if (!LogOnHelper.CheckLogOn()) return RedirectToAction("Login", "Account");

            var appointmentViewModel = new AppointmentViewModel();
            appointmentViewModel.Patients = GetPatients();
            appointmentViewModel.AppointmentViewModelGrid = GetAllAppointmentsForProvider();
            return View(appointmentViewModel);
        }

        private List<appointment> GetAppointmentsForPatient(int patientId)
        {
            var appointmentRepository = new AppointementRepository();
            return appointmentRepository.GetAppointmentsByPatientID(patientId, DateTime.Now.Date.ToString());           
        }

        private List<appointmentviewmodelentity> GetAllAppointmentsForProvider()
        {
            var appointmentRepository = new AppointementRepository();
            var appointmentViewModelList = new List<appointmentviewmodelentity>();
            var appointments = appointmentRepository.GetAllAppointments(int.Parse(Session["ProviderId"].ToString()), DateTime.Now.Date.ToString());
            foreach (var appointment in appointments)
            {
                appointmentViewModelList.Add(new AppointmentViewModelEntity
                {
                    ReasonForVisit = appointment.ReasonForVisit,
                    Status = appointment.Status,
                    Time = appointment.Time 
                });
            }
            return appointmentViewModelList;
        }

        
        [HttpPost]
        public ActionResult GetPatientAppointments(int patientId, string appointmentDate)
        {
            var appointmentRepository = new AppointementRepository();
            var appointmentViewModelList = new List<appointmentviewmodelentity>();
            var appointments = appointmentRepository.GetAppointmentsByPatientID(patientId, appointmentDate);
            foreach (var appointment in appointments)
            {
                appointmentViewModelList.Add(new AppointmentViewModelEntity
                {
                    PatientId = appointment.PatientId,
                    AppointmentId = appointment.AppointmentId,
                    AppointmentDate = appointment.AppointmentDate,
                    ProviderId = appointment.ProviderId,
                    ReasonForVisit = appointment.ReasonForVisit,
                    Status = appointment.Status,
                    Time = appointment.Time
                });
            }
            return PartialView("PatientAppointmentGrid", appointmentViewModelList);
        }
</appointmentviewmodelentity></appointmentviewmodelentity></appointmentviewmodelentity></appointment>

Experience of Patient Portal in Tablet.   

Here are few screenshots of HealthReunion Patient Portal experience in Windows Surface Tablet 64 GB RT which I got from this contest. I'm really thankful for CodeProject for providing this one on time so that I could test my application and have a feel of it before making it public. 

Log On Screen   



View Clinical Documents  



Health Topics 



Search Doctors

 

The Trick of Responsive Design 

Below is the screenshot I took after running through some test to see how the websites renders in tablet and mobile.



The portals both of them HealthReunion Patient and Providers Portal make use of Bootstrap Framework. I took the real advantage of it.  Here we will see some of the We will see in bits and pieces on How we made our website responsive so that the site can be viewed in various devices like Desktops , Tablets , Mobile phones. 

Here's the styles and technique of rendering a responsive menu. We are enclosing the “navbar” section within a content wrapper div. 

  <div class="content-wrapper">
                <section id="navbar">
                  <div class="navbar">
                    <div class="navbar-inner">
                      <div class="container" style="width: auto;">
                        <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
                          <span class="icon-bar"></span>
                          <span class="icon-bar"></span>
                          <span class="icon-bar"></span>
                        </a>
                        <div class="nav-collapse" style="float:right">
                          <ul class="nav">
                            <li>@Html.ActionLink("Home", "Index", "Home")</li>
                            <li>@Html.ActionLink("Logout", "LogOff", "Account")</li>
                          </ul>        
                        </div><!-- /.nav-collapse -->
                      </div>
                    </div><!-- /navbar-inner -->
                  </div><!-- /navbar -->
               </section>
            </div>  

 

 

Here's the bootstrap responsive css for max-width = 979 , note we have different styles for various width , it comes by default with the bootstrap framework. However it's good to know how the responsive things internally works.

Notice the styles applied for div with navbar and nav-collapse. 

@media (max-width: 979px) {
  body {
    padding-top: 0;
  }
  .navbar-fixed-top,
  .navbar-fixed-bottom {
    position: static;
  }
  .navbar-fixed-top {
    margin-bottom: 20px;
  }
  .navbar-fixed-bottom {
    margin-top: 20px;
  }
  .navbar-fixed-top .navbar-inner,
  .navbar-fixed-bottom .navbar-inner {
    padding: 5px;
  }
  .navbar .container {
    width: auto;
    padding: 0;
  }
  .navbar .brand {
    padding-right: 10px;
    padding-left: 10px;
    margin: 0 0 0 -5px;
  }
  .nav-collapse {
    clear: both;
  }
  .nav-collapse .nav {
    float: none;
    margin: 0 0 10px;
  }
  .nav-collapse .nav > li {
    float: none;
  }
  .nav-collapse .nav > li > a {
    margin-bottom: 2px;
  }
  .nav-collapse .nav > .divider-vertical {
    display: none;
  }
  .nav-collapse .nav .nav-header {
    color: #777777;
    text-shadow: none;
  }
  .nav-collapse .nav > li > a,
  .nav-collapse .dropdown-menu a {
    padding: 9px 15px;
    font-weight: bold;
    color: #777777;
    -webkit-border-radius: 3px;
       -moz-border-radius: 3px;
            border-radius: 3px;
  }
  .nav-collapse .btn {
    padding: 4px 10px 4px;
    font-weight: normal;
    -webkit-border-radius: 4px;
       -moz-border-radius: 4px;
            border-radius: 4px;
  }
  .nav-collapse .dropdown-menu li + li a {
    margin-bottom: 2px;
  }
  .nav-collapse .nav > li > a:hover,
  .nav-collapse .nav > li > a:focus,
  .nav-collapse .dropdown-menu a:hover,
  .nav-collapse .dropdown-menu a:focus {
    background-color: #f2f2f2;
  }
  .navbar-inverse .nav-collapse .nav > li > a,
  .navbar-inverse .nav-collapse .dropdown-menu a {
    color: #999999;
  }
  .navbar-inverse .nav-collapse .nav > li > a:hover,
  .navbar-inverse .nav-collapse .nav > li > a:focus,
  .navbar-inverse .nav-collapse .dropdown-menu a:hover,
  .navbar-inverse .nav-collapse .dropdown-menu a:focus {
    background-color: #111111;
  }
  .nav-collapse.in .btn-group {
    padding: 0;
    margin-top: 5px;
  }
  .nav-collapse .dropdown-menu {
    position: static;
    top: auto;
    left: auto;
    display: none;
    float: none;
    max-width: none;
    padding: 0;
    margin: 0 15px;
    background-color: transparent;
    border: none;
    -webkit-border-radius: 0;
       -moz-border-radius: 0;
            border-radius: 0;
    -webkit-box-shadow: none;
       -moz-box-shadow: none;
            box-shadow: none;
  }
  .nav-collapse .open > .dropdown-menu {
    display: block;
  }
  .nav-collapse .dropdown-menu:before,
  .nav-collapse .dropdown-menu:after {
    display: none;
  }
  .nav-collapse .dropdown-menu .divider {
    display: none;
  }
  .nav-collapse .nav > li > .dropdown-menu:before,
  .nav-collapse .nav > li > .dropdown-menu:after {
    display: none;
  }
  .nav-collapse .navbar-form,
  .nav-collapse .navbar-search {
    float: none;
    padding: 10px 15px;
    margin: 10px 0;
    border-top: 1px solid #f2f2f2;
    border-bottom: 1px solid #f2f2f2;
    -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
       -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
            box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
  }
  .navbar-inverse .nav-collapse .navbar-form,
  .navbar-inverse .nav-collapse .navbar-search {
    border-top-color: #111111;
    border-bottom-color: #111111;
  }
  .navbar .nav-collapse .nav.pull-right {
    float: none;
    margin-left: 0;
  }
  .nav-collapse,
  .nav-collapse.collapse {
    height: 0;
    overflow: hidden;
  }
  .navbar .btn-navbar {
    display: block;
  }
  .navbar-static .navbar-inner {
    padding-right: 10px;
    padding-left: 10px;
  }
} 

Below is what we are overriding the styles for responsive menu bar.

 

.navbar-inner 
{
    background-color: cadetblue; /* background color will be black for all browsers */
    background-image: none;
    background-repeat: no-repeat;
    filter: none;
}
.navbar .nav > li > a 
{
    float: none;
    line-height: 19px;
    padding: 9px 10px 11px;
    text-decoration: none;
    text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
    color:  White;
} 

 

Responsive Widgets 

You might have noticed about the light gray widget in HealthReunion Provider Portal. These widgets are created with simple div and with CSS styles.

Here's the usage of the widget 

<div class="widget">
    <div class="widget-head">
        <div class="pull-left">Create New User</div>
        <div class="clearfix"></div>
    </div>
    <div class="widget-content" style="display: block;">
        <div class="padd">
	  
	</div>    
</div>
</div>   

 

Below is the widget styles in high level.  

.widget .table{
	margin: 0px;
	width: 100%;
}

.widget {
  border: 1px solid #c9c9c9;
  border-radius: 3px;
  margin-top: 10px;
  margin-bottom: 20px; 
  background: #fafafa;
}

.widget .widget-head,.modal-header{
  background-color: #f8f8f8;
  background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#f2f2f2));
  background: -webkit-linear-gradient(top, #f8f8f8, #f2f2f2);
  background: -moz-linear-gradient(top, #f8f8f8, #f2f2f2);
  background: -ms-linear-gradient(top, #f8f8f8, #f2f2f2);
  background: -o-linear-gradient(top, #f8f8f8, #f2f2f2);
  background: linear-gradient(top, #f8f8f8, #f2f2f2);	
  border-top-right-radius: 3px;
  border-top-left-radius: 3px;
  text-shadow:0px 1px #fff;
  border-bottom: 1px solid #ccc;
  border-top: 1px solid #fff;
	color: #666;
	font-size: 13px;
	font-weight: bold;
    padding: 8px 15px;
}
.widget.wblack .widget-head{
  background-color: #333;
  background: -webkit-gradient(linear, left top, left bottom, from(#333), to(#111));
  background: -webkit-linear-gradient(top, #333, #111);
  background: -moz-linear-gradient(top, #333, #111);
  background: -ms-linear-gradient(top, #333, #111);
  background: -o-linear-gradient(top, #333, #111);
  background: linear-gradient(top, #333, #111);
  text-shadow:0px 1px #000;
  border-bottom: 1px solid #555;
  border-top: 1px solid #666;
  box-shadow: inset 0px 1px 1px #444;
	color: #ccc;
}   

 

I will let the users to dig into the style sheet for the widget. It's available in the source code – HealthReunion Provider Portal.

Responsive Flexible Grid in Providers Portal 

 

 

Below is one such scenario where in the items within the flexible grid renders according to be device width. In mobile with smaller device width , the items will be rendered vertically allowing the users to navigate easily and quickly with no difficulties. 

In tablet and desktop , the same items within the grid will be rendered horizontally. You can notice one thing , we are making use of a style sheet named FlexibleGrid.css which has styles for various device width. 

<div class="section main">
    <ol>
				<li class="figure">
                 <a href="@Url.Action("PatientRegistration", "Patient")">
                        <img border="0" src="~/Images/patient-icon.png" alt="Add Patient" height="100" width="100" /><br />
                        <span style="text-decoration: underline; color: Black;">Add Patient</span></a>
                </li>
                <li class="figure"> 
                    <a href="@Url.Action("PatientAppointments", "Patient")">
                        <img border="0" src="~/Images/details.JPG" alt="View Patients" height="100" width="100" /><br />
                        <span style="text-decoration: underline; color: Black;">View Appointments</span> </a>
                </li>
                <li class="figure"> 
                     <a href="@Url.Action("AddDocuments", "Patient")">
                        <img border="0" src="~/Images/documents.png" alt="Manage Documents" height="100" width="100" /><br />
                        <span style="text-decoration: underline; color: Black;">Manage Documents</span> </a>        
                </li>   
                <li class="figure">
                        <a href="@Url.Action("NewUser", "Provider")">
                                <img border="0" src="~/Images/User-icon.png" alt="Add User" height="100" width="100" /><br />
                                <span style="text-decoration: underline; color: Black;">Add User</span></a>   
                </li>
                 <li class="figure">
                        <a href="@Url.Action("ProviderRegistration", "Provider")">
                                <img border="0" src="~/Images/Provider.png" alt="Add Provider" height="100" width="100" /><br />
                                <span style="text-decoration: underline; color: Black;">Add Provider</span> </a>
                 </li>
    </ol>
</div>  

Style for flexible grid which is being applied for width – 600 px 

@media (max-width: 600px) {
	/* 600px grid */
	.inner {
		position: relative;
	}
	.mast,
	.intro,
	.main,
	.footer {
		float: none;
		width: auto;
	}
	h1 {
		background: none;
	}
	h1 a {
		padding-top: 70px;
		height: 87px;
	}
	.intro {
		margin-top: 0;
	}
	.intro h2 {
		font-size: 1.4em;
	}
} 


Below are the portion of the flexible grid styles. I have just mentioned the main styles required to make a responsive flexible grid. However I strongly recommend users to have a look into FlexibleGrid.css for the better understanding.

.main<span style="font-size: 9pt;">{</span>
    padding-left:25%;     width: 65.9375%; /* 633px / 960px */ } .main h2 {  background: url("site/ornament.png") no-repeat 0 50%;  font-size: 1.4em;  text-transform: lowercase;  text-align: center;  margin: 0.75em 0 1em; } .main h2 b {  background: url("site/bg.png");  font-weight: normal;  padding: 0 1em; } .figure {  float: left;  font-size: 10px;  line-height: 1.1;  margin: 0 3.317535545023696682% 1.5em 0; /* 21px / 633px */  text-align: center;  width: 31.121642969984202211%; /* 197px / 633px */  text-transform: uppercase;  letter-spacing: 0.05em; } .figure b {  display: block;  font-size: 14px;  font-family: "Book Antiqua", "Palatino Linotype", Georgia, serif;  letter-spacing: 0.1em; } .figure img {  -webkit-border-radius: 4px;  -moz-border-radius: 4px;  border-radius: 4px;  -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);  -moz-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);;  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);;  display: block;  margin: 0 auto 1em; }  

Conclusion 

Finally it's the last conclusion. First of all I would like to thank Windows Azure and CodeProject for giving us an opportunity , making it a successful competition. Today I feel what ever I had in my mind I shared with you all in terms of article content , code snippets , the real source code with user manual. I really hope this should help any beginner to intermediate and expert level developers. I tried to share not only the technical aspects but also the healthcare domain knowledge to an extent that should help peoples to understand more about this product. I think as a senior developer or a person who is designing such systems should understand the domain knowledge apart from being technically strong.  

10 weeks of Azure competition went like anything, all I would like to say is a lot I learnt and tried to share as much as possible with you guys. From the beginning I had a bigger plans to share with you and to be frank it was my dream project. Initially I had very less idea of making the website responsive , If you looked at my earlier version of HealthReunion Providers Portal , one would have understood that it was developed using ASP.NET Web form. At that point of time the only reason I went with web forms was rapid development, I was constantly thinking of good design and making it more responsive but I have to tell you one thing , I could not make it with Web Forms. That's the reason I came up with a brand new MVC4 Based HealthReunion Provider Portal. I had even used bootstrap framework for both Patients and Providers Portal. Now I feel much better a kind of a relief that what ever I thought was able to achieve it. Thanks again for CodeProject is delivering Windows Surface RT tablet in time , that really helped me to test my portals to an extent that I can say the website is responsive and works pretty well not only in desktop but also in Tablet and Mobile. Smile | :)   I would suggest peoples to have a close look into the user manual for HealthReunion Providers and Patient Portal for the better understanding of the product. One should be able to know the features and usage of the portal. 

Please let me know your feedback in terms of comments , so that will help me a lot to improve and share as much information as I have in various forms either as article content or through code.   


Background           

Healthcare domain experience or basics concepts and understanding of Healthcare related topics should be sufficient for one to understand this article.    

Using the code  

Let us see the configuration changes required for the application. Below is the app.config , appSettings changes for managing the service bus queues. <add key="Microsoft.ServiceBus.ConnectionString" value="Endpoint=sb://healthcarehl7.servicebus.windows.net/;SharedSecretIssuer=owner;SharedSecretValue=&lt;YourSecretVaule&gt;"> We will see in brief about how we can create queues , send messages and read from the queue. We will be using Microsoft.ServiceBus library for handling queues related things.  Below is the code snippet for creating a queue.
private static void CreateQueue()
{
      NamespaceManager namespaceManager = NamespaceManager.Create();
      Console.WriteLine("\nCreating Queue '{0}'...", QueueName);
      if (!namespaceManager.QueueExists(QueueName))
      {
          namespaceManager.CreateQueue(QueueName);
      }
}
The above code block check whether the queue already exists , if not we will create a new queue with the name as whatever queue name we have assigned for QueueName. Below is the code block for sending a message to the Service broker queue. 1. Create a new copy of QueueClient so that we can send messages. 2. Create HL7 Messages and add them to the message list. 3. Loop through message list. 4. Initiate call to Send method of QueueClient , we will send the messages to the queue.
private static void SendMessages()
        {
             if( queueClient == null)
               queueClient = QueueClient.Create(QueueName);
            String msg = "MSH|^~\\&|HIS|RIH|EKG|EKG|199904140038||ADT^A01|12345|P|2.2\r"
                + "PID|0001|00009874|00001122|A00977|SMITH^JOHN^M|MOM|19581119|F|NOTREAL^LINDA^M|C|564 SPRING ST^^NEEDHAM^MA^02494^US|0002|(818)565-1551|(425)828-3344|E|S|C|0000444444|252-00-4414||||SA|||SA||||NONE|V1|0001|I|D.ER^50A^M110^01|ER|P00055|11B^M011^02|070615^BATMAN^GEORGE^L|555888^NOTREAL^BOB^K^DR^MD|777889^NOTREAL^SAM^T^DR^MD^PHD|ER|D.WT^1A^M010^01|||ER|AMB|02|070615^NOTREAL^BILL^L|ER|000001916994|D||||||||||||||||GDD|WA|NORM|02|O|02|E.IN^02D^M090^01|E.IN^01D^M080^01|199904072124|199904101200|199904101200||||5555112333|||666097^NOTREAL^MANNY^P\r"
                + "NK1|0222555|NOTREAL^JAMES^R|FA|STREET^OTHER STREET^CITY^ST^55566|(222)111-3333|(888)999-0000|||||||ORGANIZATION\r"
                + "PV1|0001|I|D.ER^1F^M950^01|ER|P000998|11B^M011^02|070615^BATMAN^GEORGE^L|555888^OKNEL^BOB^K^DR^MD|777889^NOTREAL^SAM^T^DR^MD^PHD|ER|D.WT^1A^M010^01|||ER|AMB|02|070615^VOICE^BILL^L|ER|000001916994|D||||||||||||||||GDD|WA|NORM|02|O|02|E.IN^02D^M090^01|E.IN^01D^M080^01|199904072124|199904101200|||||5555112333|||666097^DNOTREAL^MANNY^P\r"
                + "PV2|||0112^TESTING|55555^PATIENT IS NORMAL|NONE|||19990225|19990226|1|1|TESTING|555888^NOTREAL^BOB^K^DR^MD||||||||||PROD^003^099|02|ER||NONE|19990225|19990223|19990316|NONE\r"
                + "AL1||SEV|001^POLLEN\r"
                + "GT1||0222PL|NOTREAL^BOB^B||STREET^OTHER STREET^CITY^ST^77787|(444)999-3333|(222)777-5555||||MO|111-33-5555||||NOTREAL GILL N|STREET^OTHER STREET^CITY^ST^99999|(111)222-3333\r"
                + "IN1||022254P|4558PD|BLUE CROSS|STREET^OTHER STREET^CITY^ST^00990||(333)333-6666||221K|LENIX|||19980515|19990515|||PATIENT01 TEST D||||||||||||||||||02LL|022LP554";
         
            List
 messageList = new List
();
            messageList.Add(CreateHL7Message("1", msg));
           
            Console.WriteLine("\nSending messages to Queue...");
 
            foreach (BrokeredMessage message in messageList)
            {
                while (true)
                {
                    try
                    {
                        queueClient.Send(message);
                    }
                    catch (MessagingException e)
                    {
                        if (!e.IsTransient)
                        {
                            Console.WriteLine(e.Message);
                            throw;
                        }
                        else
                        {
                            HandleErrors(e);
                        }
                    }
                    Console.WriteLine(string.Format("Message sent: Id = {0}, Body = {1}", message.MessageId, message.GetBody<string>()));
                    break;
                }
            }
        }
Below is the code snippet for receiving messages. 1. Create a QueueClient instance if it's null. 2. Loop through and initiate a call to QueueClient's Receive method with some specified time interval. 3. If message is not null , get the message body. 4. We are using an open source parser named NuGenParser for parsing the HL7 V2 messages. 5. Create an instance of NuGenGenericParser and parse the message.
 private static void ReceiveMessages()
        {
            if (queueClient == null)
            {
                queueClient = QueueClient.Create(QueueName);
            }
 
            Console.WriteLine("\nReceiving message from Queue...");
            BrokeredMessage message = null;
            while (true)
            {
                try
                {
                    //receive messages from Queue
                    message = queueClient.Receive(TimeSpan.FromSeconds(5));
                    if (message != null)
                    {
                        string msg = message.GetBody<string>();
                        Console.WriteLine(string.Format("Message received: Id = {0}, Body = {1}", message.MessageId, msg));
                        message.Complete();
 
                        try
                        {
                            NuGenParser p = new NuGenGenericParser();
                            Message adt = p.parse(msg);
 
                            string messageControlId = "MessageControlID: " + ((Genetibase.NuGenHL7.model.v25.message.ADT_A01)(adt)).MSH.MessageControlID;
                            string sendingFacilty = "Sending Facility: " + ((Genetibase.NuGenHL7.model.v22.message.ADT_A01)(adt)).MSH.SendingFacility;
                            string sendingApplication = "Sending Application: " + ((Genetibase.NuGenHL7.model.v22.message.ADT_A01)(adt)).MSH.SendingApplication;
                            string receivingFacility = "Receiving Facility: " + ((Genetibase.NuGenHL7.model.v22.message.ADT_A01)(adt)).MSH.ReceivingFacility;
 
                            Console.WriteLine(messageControlId);
                            Console.WriteLine(sendingApplication);
                            Console.WriteLine(sendingFacilty);
                            Console.WriteLine(receivingFacility);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("Problem in parsing messages: " + ex.Message);
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                catch (MessagingException e)
                {
                    if (!e.IsTransient)
                    {
                        Console.WriteLine(e.Message);
                        throw;
                    }
                    else
                    {
                        HandleErrors(e);
                    }
                }
            }
            queueClient.Close();
        }
Below is the code snippet for creating Topics in Service Bus
private static void CreateTopic()
        {
            NamespaceManager namespaceManager = NamespaceManager.Create();

            Console.WriteLine("\nCreating Topic " + TopicName + "...");
            try
            {
                // Delete if exists
                if (!namespaceManager.TopicExists(TopicName))
                {
                    TopicDescription myTopic = namespaceManager.CreateTopic(TopicName);

                    Console.WriteLine("Creating Subscriptions 'HL7', 'CCR' and 'CCD'...");
                    SubscriptionDescription HL7Subscription = namespaceManager.CreateSubscription(myTopic.Path, "HL7");
                    SubscriptionDescription CCRSubscription = namespaceManager.CreateSubscription(myTopic.Path, "CCR");
                    SubscriptionDescription CCDSubscription = namespaceManager.CreateSubscription(myTopic.Path, "CCD");
                }
                else
                {
                    Console.WriteLine(string.Format("Topic with name : {0} already existed", TopicName));
                }               
            }
            catch (MessagingException e)
            {
                Console.WriteLine(e.Message);
                throw;
            }
        }
Code Snippet for Sending Messages to Topic  1. Create an instance of Topic Client. 2. Read CCR Messages from the file and add the message to 'messageList' 3. Loop through the messageList and make a call to Send method of topic client to send messages to desired topic. 
private static void SendMessagesWithTopic()
        {
            topicClient = TopicClient.Create(TopicName);
            string executablePath = System.IO.Directory.GetCurrentDirectory();
            string ccrPath = executablePath.Substring(0, executablePath.LastIndexOf("\\") -4) + "\\CCR";
            string text = System.IO.File.ReadAllText(ccrPath + "\\SampleCCR.xml");

            List messageList = new List();
            messageList.Add(CreateCCRMessage("1", text));           

            Console.WriteLine("\nSending CCR messages to topic...");

            foreach (BrokeredMessage message in messageList)
            {
                while (true)
                {
                    try
                    {
                        topicClient.Send(message);
                    }
                    catch (MessagingException e)
                    {
                        if (!e.IsTransient)
                        {
                            Console.WriteLine(e.Message);
                            throw;
                        }
                        else
                        {
                            HandleErrors(e);
                        }
                    }
                    Console.WriteLine(string.Format("Message sent: Id = {0}, Body = {1}", message.MessageId, message.GetBody<string>()));
                    break;
                }
            }

            topicClient.Close();
        }
Code Snippet for receiving messages from Topic 1. Create a Subscription agent with the topic and name to read the messages. Please note that we are  receiving messages only from Subscription : CCR  2. Make a call to the Receive method of Subscription agent in order to receive messages. 
private static void ReceiveMessagesFromTopic()
        {
            SubscriptionClient agentSubscriptionClient = SubscriptionClient.Create(TopicName, "CCR");
            BrokeredMessage message = null;
            while (true)
            {
                try
                {
                    message = agentSubscriptionClient.Receive(TimeSpan.FromSeconds(5));
                    if (message != null)
                    {
                        Console.WriteLine("\nReceiving message from CCR...");
                        Console.WriteLine(string.Format("Message received: Id = {0}, Body = {1}", message.MessageId, message.GetBody<string>()));
                        message.Complete();
                    }
                    else
                    {
                        break;
                    }
                }
                catch (MessagingException e)
                {
                    if (!e.IsTransient)
                    {
                        Console.WriteLine(e.Message);
                        throw;
                    }
                    else
                    {
                        HandleErrors(e);
                    }
                }
            }
        }
Below is the console output of the message that we receiving from the Service Bus Topic.  

Points of Interest

It was very interesting to learn some new concepts of Windows Azure and use the same in real time product "HealthReunion". I would say it was a challenging experience in working with products integrating azure services.

Future Plans  

Integrating the HeathReunion product with HealthVault. So patients might opt for sharing their health information in Healthvault. So this is one option to think off.

 

Reference Introduction to Windows Azure -  http://www.windowsazure.com/en-us/develop/net/fundamentals/intro-to-windows-azure/

Certificate  -  http://msdn.microsoft.com/en-us/library/windowsazure/gg981929.aspx  http://windowsazurecat.com/2011/02/leveraging-the-windows-azure-service-management-rest-api-to-create-your-hosted-service-namespace/ 
http://www.windowsazure.com/en-us/develop/net/common-tasks/enable-ssl/ 


History    

Version 1.0 - 04/23/2013 - Initial version of HealthReunion for first challenge.

Version 2.0 - 05/12/2013 - Version 2, HealthReunion Providers Portal , Deployed to Azure for second challenge.
 
Version 3.0 - 05/24/2013 - Updated article for SQL Azure, how to backup and restore , detailed explanation and benefits of using SQL federation, How to make use of SQL Azure REST API's for managing the servers etc. Migrations from SQL Server database to SQL Azure DB. How to connect to SQL Azure Db, the connection information. How to manage SQL Azure database through web based management portal.  

Version 4.0 - 06/09/2013 - Updated article for Azure VM.  Created a brand new site - Patient Portal an MVC4 based web application , hosted the same in Azure VM. Now we have two hosted solutions , one for the provider and the other for patients. Successfully performed load balancing with multiple VM's , managed sessions when the website is hosted and accessed in a load balanced scenario. 

Version 5.0 - 06/24/2013 - Updated article for Mobile challenge. Now we have brand new HealthReunion Providers Portal developed with MVC4 and taken care of responsive design. Also introduced HealthAnalyser , it's a portal developed for analyzing the persons or patients health related things. Updated with User Manual  , Uploaded Sample CCR, CCD documents.  

License

This article, along with any associated source code and files, is licensed under The BSD License

Share

About the Author

Ranjan.D
Web Developer
United States United States
Profile
 
Around 10 years of professional software development experience in analysis, design, development, testing and implementation of enterprise web applications for healthcare domain with good exposure to object-oriented design, software architectures, design patterns, test-driven development and agile practices.
 
In Brief
 
Analyse and create High Level , Detailed Design documents.
Use UML Modelling and create Use Cases , Class Diagram , Component Model , Deployment Diagram, Sequence Diagram in HLD.
 
Area of Working : Dedicated to Microsoft .NET Technologies
Experience with : C# , J2EE , J2ME, Windows Phone 8, Windows Store App
Proficient in: C# , XML , XHTML, XML, HTML5, Javascript, Jquery, CSS, SQL, LINQ, EF
 
Software Development
 
Database: Microsoft SQL Server, FoxPro
Development Frameworks: Microsoft .NET 1.1, 2.0, 3.5, 4.5
UI: Windows Forms, Windows Presentation Foundation, ASP.NET Web Forms and ASP.NET MVC3, MVC4
Coding: WinForm , Web Development, Windows Phone, WinRT Programming, WCF, WebAPI
 
Healthcare Domain Experience
 
CCD, CCR, QRDA, HIE, HL7 V3, Healthcare Interoperability
 
Others:
 
TTD, BDD
 
Education
 
B.E (Computer Science)
 
CodeProject Contest So Far:
 
1. Windows Azure Developer Contest - HealthReunion - A Windows Azure based healthcare product , link - http://www.codeproject.com/Articles/582535/HealthReunion-A-Windows-Azure-based-healthcare-pro
 
2. DnB Developer Contest - DNB Business Lookup and Analytics , link - http://www.codeproject.com/Articles/618344/DNB-Business-Lookup-and-Analytics
 
3. Intel Ultrabook Contest - Journey from development, code signing to publishing my App to Intel AppUp , link - http://www.codeproject.com/Articles/517482/Journey-from-development-code-signing-to-publishin
 
4. Intel App Innovation Contest 2013 - eHealthCare - http://www.codeproject.com/Articles/635815/eHealthCare
 
5. Grand Prize Winner of CodeProject HTML5 &CSS3 Article Contest 2014
 
6. Grand Prize Winner of CodeProject Android Article Contest 2014

Comments and Discussions

 
QuestionMy Vote of 5 Pinmemberrjgadag16-May-13 3:49 
AnswerRe: My Vote of 5 PinprofessionalRanjan.D16-May-13 5:32 
GeneralMy vote of 5 PinmemberAbhishek Nandy13-May-13 20:40 
GeneralRe: My vote of 5 PinprofessionalRanjan.D14-May-13 18:26 
GeneralRe: My vote of 5 PinmemberAbhishek Nandy14-May-13 20:00 
QuestionCongratulations on winning Phase 1! Pinprofessionalroscler6-May-13 6:08 
AnswerRe: Congratulations on winning Phase 1! PinprofessionalRanjan.D6-May-13 7:37 
GeneralMy vote of 5 PinmemberRanjan.D29-Apr-13 8:45 
My vote of 5!!
GeneralMy vote of 5 Pinmemberroscler27-Apr-13 13:39 
GeneralRe: My vote of 5 PinmemberRanjan.D27-Apr-13 16:31 
QuestionHealth Care 2.0/ONC Challenges Pinmemberroscler27-Apr-13 9:27 
AnswerRe: Health Care 2.0/ONC Challenges PinmemberRanjan.D27-Apr-13 17:25 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.1411023.1 | Last Updated 26 Jun 2013
Article Copyright 2013 by Ranjan.D
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid