Migrating TailspinSpyworks Web Forms to Windows Azure | Migration de l’appli Web Forms TailspinSpyworks vers Windows Azure

Windows Azure Web Sites makes it easy to create new Web Sites. A site can be empty, created from a popular framework such as Wordpress or Umbraco, or the result of a migration from an existing app. Les sites Web Windows Azure simplifient la création de nouveaux sites Web. Un tel site peut être vide, créé à partir d’un Framework populaire tel que Wordpress ou Umbraco, ou être le résultat de la migration d’une application existante.
In order to test these features yourself, you can benefit from a 90 day free trial offer, and activate the preview web sites feature. si vous souhaitez tester ces fonctionnalités par vous même, vous pouvez profiter d'une offre d'essai gratuit pendant 90 jours, et activer la fonctionnalité des sites Web actuellement en test.
A lot is being written about ASP.NET MVC which is awesome, but legacy applications may still be written as ASP.NET Web Forms (Note that most of this post can also be applied to other ASP.NET apps like an MVC one!). On écrit beaucoup à propos d’ASP.NET MVC qui est excellent, mais les applications existantes risquent fort d’être de type Web Forms ASP.NET (NB: une bonne partie de ce billet s’applique à ASP.NET en général et donc à MVC!).
Let’s see how to migrate such an ASP.NET Web Forms App. to Windows Azure Web Sites. Voyons comment migrer une telle application ASP.NET Web Forms vers les sites Web Windows Azure.
TailspinSpyworks is one of the available samples on ASP.NET reference web site. It can be found at https://www.asp.net/web-forms/samples which leads to the following download. TailspinSpyworks est un des exemples sur le site de référence d’ASP.NET. On peut le trouver à https://www.asp.net/web-forms/samples qui amène au site de téléchargement suivant.

image

 

The first part of this post is about downloading the sample and make it run locally. Then I’ll show how to migrate it to Windows Azure. La première partie de ce billet est consacrée à la façon de télécharger cet exemple et le faire fonctionner localement avant de le migrer vers Windows Azure.

 

My development machine has Visual Studio 2012, SQL Server 2012, and the latest SQL Server Data Tools (SSDT) that can be donwloaded for Visual Studio 2012. Ma machine de développement a Visual Studio 2012, SQL Server 2012, et les derniers outils SQL Server Data Tools (SSDT) qui peuvent être téléchargés pour Visual Studio 2012.
The solution was written with previous generation tools, but it was already targetting .NET Framework 4.0 and I won’t change that. La solution a été écrite avec la génération précédente des outils, mais elle cible le .NET Framework 4.0 et l’on ne va pas changer cela.
After unblocking the zip file I downloaded from codeplex and unzipping to D:\dev\TailspinSpyworks-v0.9, I get the following: Après avoir débloqué le fichier zip que j’ai téléchargé depuis codeplex et dézippé vers D:\dev\TailspinSpyworks-v0.9, j’obtiens cela:

image

 

I open the solution in Visual Studio 2012. J’ouvre la solution dans Visual Studio 2012.
I have a simple report with just a few warnings that I can ignore. J’'obtiens un rapport avec juste quelques warnings que je peux ignorer

image

The solution uses two different databases. The ASP.NET database and the commerce database. The first one contains data for ASP.NET services like membership and the commerce DB contains the core application data. La solution utilise deux bases de données différentes. La base ASP.NET et la base Commerce. La première contient des services ASP.NET telle que les comptes et la base commerce contient les données de base de l’application.

image

The database connection strings suppose you have SQL Server Express. In my case, I have a SQL Server 2012 developer edition so I just move the files from App_Data in the project to the SQL Server Data folder and attach the files in that SQL Server 2012 developer edition instance. The details are beyond the scope of this post. Les chaines de connexion des bases de données supposent l’utilisation de SQL server Express. Dans mon cas, j’ai SQL Server 2012 developer edition; je déplace donc les fichiers depuis App_Data du projet pour les attacher à cette instance SQL Server 2012 developer edition. Les détails exacts vont au delà de ce billet.

image

image

image

image

image

(…)

image

(…)

I also remove the user that corresponds to the developer as it is not used by the project. There’s an associated schema which is not used either and that can also be removed. J’enlève également l’utilisateur qui correspond au développeur puisqu’il n’est pas utilisé dans ce projet. Il y a également un schéma associé qui n’est pas non plus utilisé et que je supprime également.

image

Then, it is also possible to view those databases from the SSDT; this is a way to get the connection strings, amongst other things. Il est ensuite possible de voir ces mêmes bases de données depuis SSDT, de façon à obtenir les chaînes de connexion, entre autres.

image

image

Then the 2 local connection strings can be updated in the Web.config file. In my case, they change from Puis les 2 chaînes de connexion locale peuvent être mises à jour dans le fichier Web.config. Dans mon cas, on les change de
     <connectionStrings>
    <add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" />
    <add name="CommerceEntities" connectionString="metadata=res://*/Data_Access.EDM_Commerce.csdl|res://*/Data_Access.EDM_Commerce.ssdl|res://*/Data_Access.EDM_Commerce.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Commerce.mdf;Integrated Security=True;User Instance=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
to vers
   <connectionStrings>
    <add name="ApplicationServices" connectionString="Data Source=.;Initial Catalog=ASPNETDB-TAILSPINSPYWORKS.MDF;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False" providerName="System.Data.SqlClient" />
    <add name="CommerceEntities" connectionString="metadata=res://*/Data_Access.EDM_Commerce.csdl|res://*/Data_Access.EDM_Commerce.ssdl|res://*/Data_Access.EDM_Commerce.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.;Initial Catalog=COMMERCE-TAILSPINSPYWORKS.MDF;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>

 

then I start locally the App. puis je peux démarrer l’application.

image

image

I also had to fix a few things in the code like this one in D:\dev\TailspinSpyworks-v0.9\TailspinSpyworks\Error.aspx.cs J’ai aussi dû corriger deux ou trois choses dans le code comme cela dans le fichier D:\dev\TailspinSpyworks-v0.9\TailspinSpyworks\Error.aspx.cs
 …

namespace TailspinSpyworks
{
    public partial class Error : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Label_ErrorFrom.Text = Request["Err"].ToString();
            // there might be no Inner Exception. 
            //Label_ErrorMessage.Text = Request["InnerErr"].ToString();
            // string.Format will apply ToString() only to non null arguments
            Label_ErrorMessage.Text = string.Format("{0}", Request["InnerErr"]);
        }
    }
}

 

as well as recreate an empty event for the ProductDetails.aspx page. The event was not there and generated an exception: ou comme recréer un évenement vide pour la page ProductDetails.aspx. L’événement était absent et générait une exception:

image

         protected void FormView_Product_PageIndexChanging(object sender, FormViewPageEventArgs e)
        {
            // this event was recreated but is not handled
        }

 

so for now, I just made the sample app working on my machine. I didn’t start the migration to Windows Azure yet! So I mark the post with an <hr/> Donc jusqu’à présent j’ai juste fait fonctionner l’application sur ma machine. Je n’ai pas encore commencé la migration vers Windows Azure! Je marque donc le billet d’un <hr/>

OK, let’s start the migration now! OK, démarrons la migration maintenant!
First I create a new Windows Azure Web Site named TailspinSpyworks, with an associated Windows Azure SQL database. In this case, I create a database in an existing Windows Azure SQL database server, but I could also create a new server as well. Pour commencer je crée un nouveau site Web Windows Azure appelé TailspinSpyworks, avec une base de données Windows Azure SQL Database. Ici, je crée une base dans un serveur Windows Azure SQL Database existant, mais j’aurais aussi pu créer un nouveau serveur.
This is done from the Windows Azure portal, at https://manage.windowsazure.com. Cela se fait depuis le portail Windows Azure, à https://manage.windowsazure.com.

image

image

image

image

A few seconds later, I have an empty web site with its associated Windows Azure SQL Database where I’ll be able to host the migrated Web Forms app. Quelques secondes après, j’ai un site Web vide avec une base de données Windows Azure SQL Database associée où je vais pouvoir hébergée l’application migrée.

image

image

image

I will get and download from the portal the publishing profile of the new web site. Je vais récupérer et télécharger depuis le portail le profil de publication du nouveau site Web.

image

image

Now, I can start publishing from Visual Studio 2012. Maintenant, je peux démarrer une publication depuis Visual Studio 2012.

image

image

image

The next screen is the most important one L’écran suivant est le plus important

image

I check the “remove additional files at destination” because I know my local app has the whole content and I can remove the default index page once the App is deployed. Je sélectionne “remive additional files at destination” parce que je sais que mon application locale a tout le contenu dont j’ai besoin et je peux donc supprimer la page d’index par défaut une fois que l’application aura été déployée.

image

 

The first database (ASPNETDB…) can have its schema recreated in Windows Azure SQL Database at runtime instead of being migrated. You can find more information on this in blog post by a Scott Handelman about ASP.NET Universal providers that are compatible with Windows Azure SQL Database. Of course, you can also follow the link provided by the UI. So I click on the biggest button! Le schéma de la première base (ASPNETDB…) peut être recréé au moment de l’exécution dans Windows Azure SQL Database plutôt que de migrer la base. Vous trouverez plus d’information dans ce billet de Scott Handelman à propos des fournisseurs universels ASP.NET qui sont compatibles avec Windows Azure SQL Database. Bien sûr, vous pouvez aussi suivre le lien fourni dans l’interface graphique. Tout cela pour dire que je clique sur le plus gros bouton!

image

and I accept to close the Wizard and install et j’accepte de fermer l’assistant pour installer

image

image

image

The details about this are provided in the link. I will create such a user once the App is in the cloud. So let’s move on by restarting the publishing Wizard. Les détails sont fournis dans le lien. Je vais créer un utilisateur de l’application une fois que cette dernière sera hébergée dans Windows Azure. Avançons et redémarrons l’assistant de migration.

image

image

The “ApplicationServices” connection string has been replaced by the “DefaultConnection” connection string. As I want to use only one database for the ASP.NET Universal Providers and the Commerce DB, I select the same connection string for both cases. It happens to be the Windows Azure SQL Database that was created with the Windows Azure Web Site. La chaîne de connexion “ApplicationServices” a été remplacée par la chaîne de connexion “DefaultConnection”. Comme je veiux utiliser uniquement une base de données pour les fournisseurs universels ASP.NET et la base Commerce, je sélectionne la même chaîne de connexion pour les deux cas. Il s’agit d’ailleurs de la base Windows Azure SQL Database qui avait été créée en même temps que le site Web Windows Azure.

image

For both databases, I leave the Update Database check box cleared because I use other means to migrate the databases. The ASP.NET Universal Providers will create the schema at runtime, and I will migrate the Commerce DB with a tool I like a lot because it si simple and easy to use. Pour les deux bases de données, je laisse la case à cocher “Update Database” vierge puisque j’utilise d’autres méthodes pour migrer les bases. La base des fournisseurs universels ASP.NET créera le schéma au moment de l’exécution, et je vais migrer le base de données Commerce avec un outil que j’aime bien pour sa simplicité d’utilisation.

Next>

image

Publish

image

image

Let’s now migrate the database with the Windows Azure SQL Database migration Wizard that can be found at https://sqlazuremw.codeplex.com. Migrons maintenant la base de données avec l’assistant de migration Widnows Azure SQL Database qui peut être trouvé à https://sqlazuremw.codeplex.com.

image

I just download it, unblock it, and extract it to a folder from where I start SQLAzureMW.exe. Je le télécharge, le débloque, l’extrais dans un dossier où je peux démarrer SQLAzureMW.exe.

image

image

image

Connect

image

Next>

image

Next>

image

Next>

image

image

The result summary gives information about default choices made by the tool. They can also be seen in the SQL Script tab. Here is its content in my case: Le résumé du résultat fournit quelques informations sur les choix par défaut proposés par l’outil. On peut aussi les voir dans l’onglet “SQL Script”. Voici son contenu dans mon cas:
 --~Changing index [dbo].[Orders].PK_Orders to a clustered index.  You may want to pick a different index to cluster on.
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Orders]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[Orders](
    [OrderID] [int] IDENTITY(1,1) NOT NULL,
    [CustomerName] [nvarchar](256) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
    [OrderDate] [datetime] NOT NULL,
    [ShipDate] [datetime] NOT NULL,
 CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED 
(
    [OrderID] ASC
)WITH (STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF)
)
END
GO
IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[DF_Orders_OrderDate]') AND type = 'D')
BEGIN
ALTER TABLE [dbo].[Orders] ADD  CONSTRAINT [DF_Orders_OrderDate]  DEFAULT (getdate()) FOR [OrderDate]
END
GO
IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[DF_Orders_ShipDate]') AND type = 'D')
BEGIN
ALTER TABLE [dbo].[Orders] ADD  CONSTRAINT [DF_Orders_ShipDate]  DEFAULT (getdate()) FOR [ShipDate]
END
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[OrderDetails]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[OrderDetails](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [OrderID] [int] NULL,
    [ProductID] [int] NULL,
    [Quantity] [int] NULL,
    [UnitCost] [money] NULL,
 CONSTRAINT [PK_OrderDetails] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF)
)
END
GO
--~Changing index [dbo].[Categories].PK_Categories to a clustered index.  You may want to pick a different index to cluster on.
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Categories]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[Categories](
    [CategoryID] [int] IDENTITY(1,1) NOT NULL,
    [CategoryName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
 CONSTRAINT [PK_Categories] PRIMARY KEY CLUSTERED 
(
    [CategoryID] ASC
)WITH (STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF)
)
END
GO
--~Changing index [dbo].[Products].PK_Products to a clustered index.  You may want to pick a different index to cluster on.
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Products]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[Products](
    [ProductID] [int] IDENTITY(1,1) NOT NULL,
    [CategoryID] [int] NOT NULL,
    [ModelNumber] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [ModelName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [ProductImage] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [UnitCost] [money] NOT NULL,
    [Description] [nvarchar](3800) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
 CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED 
(
    [ProductID] ASC
)WITH (STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF)
)
END
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[SelectPurchasedWithProducts]') AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE dbo.SelectPurchasedWithProducts
 @ProductID int
AS
    SELECT  TOP 5 
    OrderDetails.ProductID,
    Products.ModelName,
    SUM(OrderDetails.Quantity) as TotalNum

FROM    
    OrderDetails
  INNER JOIN Products ON OrderDetails.ProductID = Products.ProductID

WHERE   OrderID IN 
(
    /* This inner query should retrieve all orders that have contained the productID */
    SELECT DISTINCT OrderID 
    FROM OrderDetails
    WHERE ProductID = @ProductID
)
AND OrderDetails.ProductID != @ProductID 

GROUP BY OrderDetails.ProductID, Products.ModelName 

ORDER BY TotalNum DESC
RETURN

' 
END
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Reviews]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[Reviews](
    [ReviewID] [int] IDENTITY(1,1) NOT NULL,
    [ProductID] [int] NOT NULL,
    [CustomerName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [CustomerEmail] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Rating] [int] NOT NULL,
    [Comments] [nvarchar](3850) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
 CONSTRAINT [PK_Reviews] PRIMARY KEY CLUSTERED 
(
    [ReviewID] ASC
)WITH (STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF)
)
END
GO
--~Changing index [dbo].[ShoppingCart].PK_ShoppingCart to a clustered index.  You may want to pick a different index to cluster on.
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ShoppingCart]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[ShoppingCart](
    [RecordID] [int] IDENTITY(1,1) NOT NULL,
    [CartID] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Quantity] [int] NOT NULL,
    [ProductID] [int] NOT NULL,
    [DateCreated] [datetime] NOT NULL,
 CONSTRAINT [PK_ShoppingCart] PRIMARY KEY CLUSTERED 
(
    [RecordID] ASC
)WITH (STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF)
)
END

IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[ShoppingCart]') AND name = N'IX_ShoppingCart')
CREATE NONCLUSTERED INDEX [IX_ShoppingCart] ON [dbo].[ShoppingCart] 
(
    [CartID] ASC,
    [ProductID] ASC
)WITH (STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF)
GO
IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[DF_ShoppingCart_Quantity]') AND type = 'D')
BEGIN
ALTER TABLE [dbo].[ShoppingCart] ADD  CONSTRAINT [DF_ShoppingCart_Quantity]  DEFAULT ((1)) FOR [Quantity]
END
GO
IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[DF_ShoppingCart_DateCreated]') AND type = 'D')
BEGIN
ALTER TABLE [dbo].[ShoppingCart] ADD  CONSTRAINT [DF_ShoppingCart_DateCreated]  DEFAULT (getdate()) FOR [DateCreated]
END
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[VewOrderDetails]'))
EXEC dbo.sp_executesql @statement = N'CREATE VIEW dbo.VewOrderDetails
AS
SELECT        dbo.Products.ProductID, dbo.Products.ModelNumber, dbo.Products.ModelName, dbo.OrderDetails.Quantity, dbo.OrderDetails.UnitCost, 
                         dbo.OrderDetails.OrderID
FROM            dbo.OrderDetails INNER JOIN
                         dbo.Products ON dbo.OrderDetails.ProductID = dbo.Products.ProductID
' 
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[ViewAlsoPurchased]'))
EXEC dbo.sp_executesql @statement = N'CREATE VIEW dbo.ViewAlsoPurchased
AS
SELECT        TOP (5) dbo.OrderDetails.ProductID, dbo.Products.ModelName, SUM(dbo.OrderDetails.Quantity) AS TotalNumPurchased, dbo.OrderDetails.OrderID, 
                         dbo.Products.ProductID AS Products_ProductID
FROM            dbo.OrderDetails INNER JOIN
                         dbo.Products ON dbo.OrderDetails.ProductID = dbo.Products.ProductID
WHERE        (dbo.OrderDetails.OrderID IN
                             (SELECT DISTINCT OrderID
                               FROM            dbo.OrderDetails AS OrderDetailsSelected))
GROUP BY dbo.OrderDetails.ProductID, dbo.Products.ModelName, dbo.OrderDetails.OrderID, dbo.Products.ProductID
ORDER BY TotalNumPurchased DESC
' 
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[ViewCart]'))
EXEC dbo.sp_executesql @statement = N'CREATE VIEW dbo.ViewCart
AS
SELECT        TOP (100) PERCENT dbo.Products.ProductID, dbo.Products.ModelNumber, dbo.Products.ModelName, dbo.Products.UnitCost, dbo.ShoppingCart.Quantity, 
                         dbo.ShoppingCart.CartID
FROM            dbo.Products INNER JOIN
                         dbo.ShoppingCart ON dbo.Products.ProductID = dbo.ShoppingCart.ProductID AND dbo.Products.ProductID = dbo.ShoppingCart.ProductID
ORDER BY dbo.Products.ModelName, dbo.Products.ModelNumber
' 
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_Order_OrderDetails]') AND parent_object_id = OBJECT_ID(N'[dbo].[OrderDetails]'))
ALTER TABLE [dbo].[OrderDetails]  WITH CHECK ADD  CONSTRAINT [FK_Order_OrderDetails] FOREIGN KEY([OrderID])
REFERENCES [dbo].[Orders] ([OrderID])
GO
IF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_Order_OrderDetails]') AND parent_object_id = OBJECT_ID(N'[dbo].[OrderDetails]'))
ALTER TABLE [dbo].[OrderDetails] CHECK CONSTRAINT [FK_Order_OrderDetails]
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_Products_Categories]') AND parent_object_id = OBJECT_ID(N'[dbo].[Products]'))
ALTER TABLE [dbo].[Products]  WITH CHECK ADD  CONSTRAINT [FK_Products_Categories] FOREIGN KEY([CategoryID])
REFERENCES [dbo].[Categories] ([CategoryID])
GO
IF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_Products_Categories]') AND parent_object_id = OBJECT_ID(N'[dbo].[Products]'))
ALTER TABLE [dbo].[Products] CHECK CONSTRAINT [FK_Products_Categories]
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_Reviews_Products]') AND parent_object_id = OBJECT_ID(N'[dbo].[Reviews]'))
ALTER TABLE [dbo].[Reviews]  WITH NOCHECK ADD  CONSTRAINT [FK_Reviews_Products] FOREIGN KEY([ProductID])
REFERENCES [dbo].[Products] ([ProductID])
NOT FOR REPLICATION 
GO
IF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_Reviews_Products]') AND parent_object_id = OBJECT_ID(N'[dbo].[Reviews]'))
ALTER TABLE [dbo].[Reviews] CHECK CONSTRAINT [FK_Reviews_Products]
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ShoppingCart_Products]') AND parent_object_id = OBJECT_ID(N'[dbo].[ShoppingCart]'))
ALTER TABLE [dbo].[ShoppingCart]  WITH CHECK ADD  CONSTRAINT [FK_ShoppingCart_Products] FOREIGN KEY([ProductID])
REFERENCES [dbo].[Products] ([ProductID])
GO
IF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ShoppingCart_Products]') AND parent_object_id = OBJECT_ID(N'[dbo].[ShoppingCart]'))
ALTER TABLE [dbo].[ShoppingCart] CHECK CONSTRAINT [FK_ShoppingCart_Products]
GO
-- BCPArgs:2:[dbo].[Orders] in "c:\SQLAzureMW\BCPData\dbo.Orders.dat" -E -n -b 10000 -a 16384
GO
-- BCPArgs:13:[dbo].[OrderDetails] in "c:\SQLAzureMW\BCPData\dbo.OrderDetails.dat" -E -n -b 10000 -a 16384
GO
-- BCPArgs:7:[dbo].[Categories] in "c:\SQLAzureMW\BCPData\dbo.Categories.dat" -E -n -b 10000 -a 16384
GO
-- BCPArgs:41:[dbo].[Products] in "c:\SQLAzureMW\BCPData\dbo.Products.dat" -E -n -b 10000 -a 16384
GO
-- BCPArgs:6:[dbo].[ShoppingCart] in "c:\SQLAzureMW\BCPData\dbo.ShoppingCart.dat" -E -n -b 10000 -a 16384
GO
In this case, what the tool did was to make some indexes on primary keys clustered because a Windows Azure SQL Database requires each table to have a cluster index. The tool also removed extended properties(without mentionning) that are used by the entity framework to store designer related data that can be used at design time. Dans ce cas, ce que l’outil a fait est de rendre l’index sur la clef primaire clusterisé parce qu’une base Windows Azure SQL Database a besoin d’un index custerisé. L’outil a également supprimé des propriétés étendues (sans le mentionner) qui sont utilisées par l’entity framework pour stocker des informations du designer qui peuvent être utilisées au moment de la conception.
If you need to have a deep control on how the database is migrated, you can also use the SQL Server Data Tools (SSDT). This blog post explains how this works. Si vous avez besoin d’avoir un contrôle plus précis sur la façon dont la migration de la base se fait, vous pouvez utiliser les SQL Server Data Tools (SSDT). Ce billet explique comment cela marche.
The choices made by the tool are OK for me so I just accept and click Next and I enter the parameters about the Windows Azure SQL Database server Les choix effectués par l’outil me conviennent donc j’accepte, je clique sur Next et j’entre les paramètres à propos du serveur Windows Azure SQL Database

image

image

image

image

 

 18/09/2012 16:18:34 --> Error #: 40514 -- 'NOT FOR REPLICATION' is not supported in this version of SQL Server.
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_Reviews_Products]') AND parent_object_id = OBJECT_ID(N'[dbo].[Reviews]'))
ALTER TABLE [dbo].[Reviews]  WITH NOCHECK ADD  CONSTRAINT [FK_Reviews_Products] FOREIGN KEY([ProductID])
REFERENCES [dbo].[Products] ([ProductID])
NOT FOR REPLICATION 

 

The script had remaining errors. So I change the local database with SSDT before re-executing the Wizard. Le script a encore quelques erreurs. Cela m’amène à changer la base de données locale avec SSDT avant de ré-exécuter l’assistant.

image

image

image

image

 

image

NB: the same could also have been done from SQL Server Management Studio. NB: on peut faire la même chose depuis SQL Server Management Studio.

image

I restart the Windows Azure SQL Database Migration Wizard with the same steps as before until this screen: Je redémarre l’assistant de migration Windows Azure SQL Database avec les mêmes étapes que précédemment jusqu’à cet écran:

image

image

The tables that had already succeeded have primary key violations when trying again, which can be safely ignored. Another option could be to remove objects in the target  database and retry. I choose to skip the errors. Les tables qui avaient jusqu’ici déjà été migrées ont des violations de clef primaire quand l’outil cherche à recharger leurs données; cela peut donc être ignoré. Une autre option aurait été de supprimer les objets dans la base cible et de recommencer. Je choisis d’ignorer les erreurs en question.

image

and I repeat the operation for each tab about any previously succeeding table until the last one puis je répète l’opération pour les différents onglets des différentes tables concernées jusqu’au dernier

image

the result is OK le résultat est OK

image

Exit

I can now test the App in Windows Azure Web Sites: Je peux maintenant tester l’application dans Windows Azure Web Sites:

https://tailspinspyworks.azurewebsites.net/

image

the pictures were not included because they are not part of the project which is a good way to show how easy it is to update the app from  the Visual Studio project: les images n’ont pas été incluses parce qu’elles ne faisaient pas partie du projet ce qui me donne l’occasion de montrer qu’il est simple de republier l’application depuis le projet Visual Studio:

image

image

image

image

image

 

image

After creating the first user, I see that the database contains the table for membership and so on, together with the other commerce tables; having all the tables in the same DB is the option I chose: Après avoir créé le premier utilisateur, je vois que la base de données contient les tables d’utilisateurs entre autres, ainsi que les tables de la base commerce; avoir toutes les tables dans la même base est l’option que j’avais choisie:

image

 

Smile

Benjamin