Shahar Gvirtz's Weblog

Generating SQL Backup Script for Tables & Data from any .NET Application using SMO

What is SMO?

SMO, SQL Server Management Object, is a collection of objects that includes all you need to manage SQL Server from .NET applications. With SMO you can manage pretty much everything – from databases, tables, stored procedures, jobs – you name it.

Actually, SMO is “.NET Version” of COM object known as SQL-DMO (SQL Distributed Management Objects).

SMO Assemblies (dll’s) can usually be found at: C:\Program Files\Microsoft SQL Server\100\SDK\Assemblies\ (for SQL Server 2008).

What We’re Going To Do?

In this post I’ll show an easy way to write a method that generates SQL File that include backup of both the schema and the data of specific tables (CREATE statements for each table and INSERT statements for all the data). Same as if you right-click on DB name at SQL Server Management Studio and choose “Generate Scripts”

The Method

First, we’ll have to add references to the following assemblies:

  1. Microsoft.SqlServer.ConnectionInfo
  2. Microsoft.SqlServer.Management.Sdk.Sfc
  3. Microsoft.SqlServer.Smo

[All of them can be found in the directory I mentioned before, with the same name as in the list just with “.dll” in the end]

In the following example, we want to backup specific tables (we know the tables names) that are in a specific DB. This is how our method will look:

   1: public static void Backup(string FileName, string[] Tables)
   2: {
   3:     StringBuilder sb = new StringBuilder();
   4:     Server srv = new Server(new Microsoft.SqlServer.Management.Common.ServerConnection("<db name>", "<user name>", "<password>"));
   5:     Database dbs = srv.Databases["<db name>"];
   6:     ScriptingOptions options = new ScriptingOptions();
   7:     options.ScriptData = true;
   8:     options.ScriptDrops = false;
   9:     options.FileName = FileName;
  10:     options.EnforceScriptingOptions = true;
  11:     options.ScriptSchema = true;
  12:     options.IncludeHeaders = true;
  13:     options.AppendToFile = true;
  14:     options.Indexes = true;
  15:     options.WithDependencies = true;
  16:     foreach (var tbl in Tables)
  17:     {
  18:         dbs.Tables[tbl].EnumScript(options);
  19:     }
  20: }

Our method get two parameters. The first one is the Full path to the file we want to export, and the second is an array with name of the tables we want to generate SQL backup script for.

In line 4 you can see that there is a new instance of “Server” object that represents the SQL Server itself.

In line 5 choose the DB that we want (Pay attention to add Exception handling if you going to use this code).

Then, from line 6 to 15 we set some properties in the ScriptingOptions object that includes our settings for the script generation. In this example, i backup both data and schema so ScriptData and ScriptSchema are both true.

I also backup the Indexes. And, in this example, i set WithDependencies property as true which means that the generated script will include CREATE statements for tables that are somehow related to the tables we actually backup. For example, if table A has FK to table B and I’ll backup table A with this method, it’ll also generates the SQL Statements to backup table B.
You can find the full documentation of all the available settings here.

In lines 15-18 we iterate the array we get as a parameter to the method and for each table call Table.EnumScript method thet get ScriptiongOptions instance as parameter (which includes all the settings). This method also returns a collection of strings (IEnumerable<string>) that includes the generated SQL.

In this example i Ignore the returned value because i set the property ScriptiongOptions.FileName to a path for a file where the SQL will be saved, so i don’t need the collection in the code (know that because i call EnumScript several times, for each table, it’s important to set ScriptingOptions.AppendToFile as true or we’ll override the file each time).

The Difference Between EnumScript and Script

If you’ll take a look in the documentation you’ll see that there is also method called Script that we can use with Table object. So why don’t I use it?

The reason (which i couldn’t find in the official documentation) is that if we set in the ScriptingOptions object we pass to the method ScriptiongOptions.ScriptData = true we must use EnumScript because Script will give us the following Exception:

“This method does not support scripting data”.

Summary

In order to work with SQL Server from .NET Applications we have SMO components.
We can generate SQL statements that can be used to backup table (create table and insert data) with Table.EnumScript method, and we can give the settings we want with ScriptingOptions object.

Shahar.

DTOGenerator: Easily Generate Data Transfer Objects from ADO.NET Entity Framework or LINQ to SQL Data Classes

In my previous post I wrote about a small utility that automatically generates Data Transfer Objects from LINQ to SQL Data Classes. Few days ago I had the time to add an important feature – the application can now generate DTO’s from ADO.NET Entity Framework Model as well. I also renamed the application to DTOGenerator and published it in CodePlex.

Data Transfer Objects in 2 Diagrams

There are really a lot of explanations about Data Transfer Objects in the web. You can read about them in the MSDN Magazine. But, Here is a 2 diagrams that show the concept of DTO’s in 2 most common scenarios:

Getting Information: DAL=>BLL=>GUI (click to enlarge)

image

Insert Information: GUI=>BLL=>DAL (click to enlarge)

image

How to Use DTOGenerator

Creating Data Transfer Objects is really easy while using DTOGenerator.

  1. First, you have to download the latest version. You can choose if you want to download executable files only or the full source code.
  2. After the download completed, extract the application. in the following examples i’ll assume that the application files (/bin/release in the full source code, or the files in the root of the “Executable Files Only” ZIP) located in c:\DTOGenerator.
  3. In order to use the application, you must have a .NET assembly that include ADO.NET Entity Framework model or LINQ to SQL Data Classes (or both…). Then, you have to use the following command from cmd:
    c:\DTOGenerator\DTOGenerator.exe “param1”  “param2”
    (between parameter1 and parameter2 there is a single space).
    param1 is the path for you .net assembly
    param2 is the path to a directory where the generated files (.cs files – DTO classes) will be created.
  4. After the files created, add them to your project. The DTO’s are in different namespace called DTO (you can change it manually).

The following code is an example for the file that DTOGenerator will create for the “Product” entity in the Northwind database:

   1: //ADO.NET EF Example
   2:  
   3: using System;
   4: using System.Data.Linq;
   5: using System.Linq;
   6: using System.Collections.Generic;
   7: /*
   8: This Data Transfer Object created Automatically by DTOGenerator.
   9: You can download DTOGenerator and get support in the project site: http://dtogenerator.codeplex.com 
  10: DTOGenerator developed by Shahar Gvirtz (http://weblogs.asp.net/shahar)
  11: */
  12:  
  13: namespace DTO
  14: {
  15:     public class ProductDTO
  16:     {
  17:         public static ProductDTO GetDTOFromDALObject(ConsoleApplication3.Product src, bool GetChilds)
  18:         {
  19:             ProductDTO obj = new ProductDTO();
  20:             obj.Discontinued = src.Discontinued;
  21:             obj.ProductID = src.ProductID;
  22:             obj.ProductName = src.ProductName;
  23:             obj.QuantityPerUnit = src.QuantityPerUnit;
  24:             obj.ReorderLevel = src.ReorderLevel;
  25:             obj.UnitPrice = src.UnitPrice;
  26:             obj.UnitsInStock = src.UnitsInStock;
  27:             obj.UnitsOnOrder = src.UnitsOnOrder;
  28:             if(src.Category != null && GetChilds)
  29:                 obj.Category = CategoryDTO.GetDTOFromDALObject(src.Category,false);
  30:             if(src.Order_Details != null && GetChilds)            {
  31:                 List<Order_DetailDTO> Order_DetailDTOlst = new List<Order_DetailDTO>();
  32:                 src.Order_Details.ToList().ForEach(p=>Order_DetailDTOlst.Add(Order_DetailDTO.GetDTOFromDALObject(p,false)));
  33:                 obj.Order_Details = Order_DetailDTOlst;
  34:             }
  35:  
  36:             if(src.Supplier != null && GetChilds)
  37:                 obj.Supplier = SupplierDTO.GetDTOFromDALObject(src.Supplier,false);
  38:  
  39:             return obj;
  40:         }
  41:         public ConsoleApplication3.Product GetDALObject(bool IncludeChilds)
  42:         {
  43:             ConsoleApplication3.Product obj = new ConsoleApplication3.Product();
  44:             obj.Discontinued = Discontinued;
  45:             obj.ProductID = ProductID;
  46:             obj.ProductName = ProductName;
  47:             obj.QuantityPerUnit = QuantityPerUnit;
  48:             obj.ReorderLevel = ReorderLevel;
  49:             obj.UnitPrice = UnitPrice;
  50:             obj.UnitsInStock = UnitsInStock;
  51:             obj.UnitsOnOrder = UnitsOnOrder;
  52:             if(Category != null && IncludeChilds)
  53:                 obj.Category = Category.GetDALObject(false);
  54:             if(Order_Details != null && IncludeChilds)            {
  55:                 System.Data.Objects.DataClasses.EntityCollection<ConsoleApplication3.Order_Detail> Order_Detailsgetdallst = new System.Data.Objects.DataClasses.EntityCollection<ConsoleApplication3.Order_Detail>();
  56:                 Order_Details.ForEach(p=>Order_Detailsgetdallst.Add(p.GetDALObject(false)));
  57:                 obj.Order_Details = Order_Detailsgetdallst;            }
  58:  
  59:             if(Supplier != null && IncludeChilds)
  60:                 obj.Supplier = Supplier.GetDALObject(false);
  61:  
  62:  
  63:             return obj;
  64:         }
  65:         
  66:         public Boolean Discontinued { get; set; }
  67:         public Int32 ProductID { get; set; }
  68:         public String ProductName { get; set; }
  69:         public String QuantityPerUnit { get; set; }
  70:         public Int16? ReorderLevel { get; set; }
  71:         public Decimal? UnitPrice { get; set; }
  72:         public Int16? UnitsInStock { get; set; }
  73:         public Int16? UnitsOnOrder { get; set; }
  74:         public DTO.CategoryDTO Category { get; set; }
  75:         public List<DTO.Order_DetailDTO> Order_Details { get; set; }
  76:         public DTO.SupplierDTO Supplier { get; set; }
  77:  
  78:  
  79:     }
  80: }

If we work with LINQ to SQL, then the DTO for “Product” will looks like this:

   1: using System;
   2: using System.Data.Linq;
   3: using System.Linq;
   4: using System.Collections.Generic;
   5: /*
   6: This Data Transfer Object created Automatically by DTOGenerator.
   7: You can download DTOGenerator and get support in the project site: http://dtogenerator.codeplex.com 
   8: DTOGenerator developed by Shahar Gvirtz (http://weblogs.asp.net/shahar)
   9: */
  10:  
  11: namespace DTO
  12: {
  13:     public class ProductDTO
  14:     {
  15:         public static ProductDTO GetDTOFromDALObject(ConsoleApplication4.Product src)
  16:         {
  17:             ProductDTO obj = new ProductDTO();
  18:             obj.ProductID = src.ProductID;
  19:             obj.ProductName = src.ProductName;
  20:             obj.SupplierID = src.SupplierID;
  21:             obj.CategoryID = src.CategoryID;
  22:             obj.QuantityPerUnit = src.QuantityPerUnit;
  23:             obj.UnitPrice = src.UnitPrice;
  24:             obj.UnitsInStock = src.UnitsInStock;
  25:             obj.UnitsOnOrder = src.UnitsOnOrder;
  26:             obj.ReorderLevel = src.ReorderLevel;
  27:             obj.Discontinued = src.Discontinued;
  28:  
  29:             return obj;
  30:         }
  31:         public ConsoleApplication4.Product GetDALObject()
  32:         {
  33:             ConsoleApplication4.Product obj = new ConsoleApplication4.Product();
  34:             obj.ProductID = ProductID;
  35:             obj.ProductName = ProductName;
  36:             obj.SupplierID = SupplierID;
  37:             obj.CategoryID = CategoryID;
  38:             obj.QuantityPerUnit = QuantityPerUnit;
  39:             obj.UnitPrice = UnitPrice;
  40:             obj.UnitsInStock = UnitsInStock;
  41:             obj.UnitsOnOrder = UnitsOnOrder;
  42:             obj.ReorderLevel = ReorderLevel;
  43:             obj.Discontinued = Discontinued;
  44:  
  45:  
  46:             return obj;
  47:         }
  48:         
  49:         public Int32 ProductID { get; set; }
  50:         public String ProductName { get; set; }
  51:         public Int32? SupplierID { get; set; }
  52:         public Int32? CategoryID { get; set; }
  53:         public String QuantityPerUnit { get; set; }
  54:         public Decimal? UnitPrice { get; set; }
  55:         public Int16? UnitsInStock { get; set; }
  56:         public Int16? UnitsOnOrder { get; set; }
  57:         public Int16? ReorderLevel { get; set; }
  58:         public Boolean Discontinued { get; set; }
  59:  
  60:  
  61:     }
  62: }

 

Using the Data Transfer Objects

The main difference in the way DTOGenerator works with ADO.NET EF and the way it works with LINQ to SQL, is that while working with LINQ to SQL no object association will be created. You can compare line 74 in the first example to line 52 in the second example and see the difference.

As you can see, each DTO include two important method: static method called GetDTOFromDALObject that get as parameter an instance of the ADO.NET EF entity object and return DTO that already has all the data stored in the entity instance.
The second method is GetDALObject that return an instance of the entity object that includes all the data stored in the Data Transfer Object.

If you don’t want to load data into the associated objects (for lazy-loading or for some other reasons) GetDTOFromDALObject and GetDALObject has both Boolean parameter that indicates if you want to fill the associated objects with data (the Boolean parameter is only when the DTO’s was generated from ADO.NET EF Model).

For example, if we work with LINQ to SQL then this how selecting data will looks like:

using (var data = new NorthwindDataContext())
{
List<DTO.ProductDTO> products = (from p in data.Products
select DTO.ProductDTO.GetDTOFromDALObject(p)).ToList();
}

Selecting data with ADO.NET Entity Framework will looks like this:

   1: using (var data = new NORTHWNDEntities())
   2: {
   3:     var product = data.Products.First(p => p.Category.CategoryName == "Beverages");
   4:     product.Category = data.Categories.First(p => p.CategoryID == 1);
   5:     var product2 = ProductDTO.GetDTOFromDALObject(product, true);
   6:     Console.WriteLine(product2.Category.Description); 
   7:     Console.Read();
   8: }

as you can see, in line 5 we say that we want to get DTO with associated objects that filled with data. if we called DetDTOFromDALObject with “false” then line 6 will throw an exception, because product2.category would be null.

Adding rows to the table will looks like this (LINQ to SQL Example):

   1: //Create a new Product in GUI - use DTO
   2: DTO.ProductDTO newProduct = new DTO.ProductDTO();
   3: newProduct.CategoryID = 1;
   4: newProduct.Discontinued = true;
   5: newProduct.ProductName = "check";
   6: newProduct.QuantityPerUnit = "10";
   7: newProduct.UnitPrice = 90;
   8: newProduct.UnitsInStock = 10;
   9:  
  10: //In the DAL, the Insert method get DTO.ProductDTO as parameter,
  11: //but it has to use the LINQ to SQL object to insert it - that's why we have GetDALObject()
  12: using (var data = new NorthwindDataContext())
  13: {
  14:     data.Products.InsertOnSubmit(newProduct.GetDALObject());
  15:     data.SubmitChanges();
  16: }

First, we get DTO object from another layer in our application (GUI, for example), then, when we add the data (to LINQ to SQL in this example) we use the “GetDALObject” method to give InsertOnSubmit the correct type as parameter, with all the data that stored in the DTO inside.

Summary

DTOGenerator is a small code generator the automatically create Data Transfer Objects from given .NET assembly with LINQ to SQL Data Classes or ADO.NET Entity Framework.

It’s really easy to use the application.

It’s beta version, so please report aboug bugs that you found or features you want.

Project Site
Download v0.5

Shahar.

an Open Source Utility that Automatically Create Data Transfer Objects based on LINQ to SQL Data Classes

Few weeks ago I posted in my Hebrew blog a post about using Data Transfer Objects to work with LINQ to SQL and ADO.NET Entity Framework (that currently both of them doesn’t support working with POCO).
One of the comments I got was that using DTO’s takes twice the time than not using them. That’s because you have to write DTO class for each entity and you also have to write  method in the DTO class that return the DAL object (the object created by the ORM and mapped to a table in the DB) from the DTO and vice-versa.

Although I don’t think it’s too much work, and i think that the advantages are significant enough to make the effort worth, I wrote during my job a small code generator that create DTO’s for each entity in the LINQ to SQL DataClasses that exists in the application.

LINQ2SQLDTOCreator

The application I wrote called LINQ2SQLDTOCreator get a path to an assembly (let’s say – the application DLL) and a path to a folder where the application will save the generated files. The application looks in the assembly to find classes that has the attribute System.Data.Linq.Mapping.TableAttribute . Classes with this attributes are actually classes that are part of LINQ to SQL model.
In the classes with this attribute, the application looks for properties with System.Data.Linq.Mapping.ColumnAttribute attribute. These properties, are properties that mapped to a specific column in a table.

Finally, for each object in the LINQ to SQL Data Classes, the application creates a new class (.cs file) in the path the user gave as parameter to the application.
The generated class include definition for the properties that are in the original object created by LINQ to SQL.
In addition to the properties, the generated classes contains two important methods: a static method that get an instance of the object created by LINQ to SQL (the data class) and return an instance of the DTO and a method that return an instance of the LINQ to SQL object with all of the values that stored in the DTO.
That means that if you put the generated DTO’s in a separate project you have to make sure that this project have reference to the assembly that include your LINQ to SQL Data Classes (so the method that work with this data classes will compile).

For example, here is a DTO class created by the Application:

   1: using System;
   2: /*
   3: ------------------------DTO OBjECT-----------------------------
   4: --------------Generated By LINQ2SQLDTOCreator------------------
   5: ----------------Developed by Shahar Gvirtz---------------------
   6: ---------http://blogs.microsoft.co.il/blogs/shahar-------------
   7: ---------------http://weblogs.asp.net/shahar-------------------
   8: */
   9:  
  10: namespace DTO
  11: {
  12:     public class VideoDTO
  13:     {
  14:         public static VideoDTO GetDTOFromDALObject( DAL.Video src )
  15:         {
  16:             VideoDTO obj = new VideoDTO ();
  17:             obj.ID = src.ID;
  18:             obj.Title = src.Title;
  19:             obj.DateAdded = src.DateAdded;
  20:             obj.Code = src.Code;
  21:             obj.ForumLink = src.ForumLink;
  22:             obj.CategoryID = src.CategoryID;
  23:             obj.ThumbnailURL = src.ThumbnailURL;
  24:             obj.Description = src.Description;
  25:  
  26:             return obj;
  27:         }
  28:         public DAL.Video GetDALObject()
  29:         {
  30:             DAL.Video obj = new DAL.Video ();
  31:             obj.ID = ID;
  32:             obj.Title = Title;
  33:             obj.DateAdded = DateAdded;
  34:             obj.Code = Code;
  35:             obj.ForumLink = ForumLink;
  36:             obj.CategoryID = CategoryID;
  37:             obj.ThumbnailURL = ThumbnailURL;
  38:             obj.Description = Description;
  39:  
  40:  
  41:             return obj;
  42:         }
  43:         
  44:         public Int32 ID { get; set; }
  45:         public String Title { get; set; }
  46:         public DateTime DateAdded { get; set; }
  47:         public String Code { get; set; }
  48:         public String ForumLink { get; set; }
  49:         public Int32 CategoryID { get; set; }
  50:         public String ThumbnailURL { get; set; }
  51:         public String Description { get; set; }
  52:  
  53:  
  54:     }
  55: }

How To Use The DTO Generator?

  1. Download the application
  2. The file you downloaded contains the full source. inside the project directory in \bin\Release you’ll find the executable file. extract all of them to another directory.
  3. This is a Console Application. This application get two command line parameters separated by blank space. The first parameter is the path of the assembly that contain your LINQ to SQL Data Classes. The second parameter is the path to a directory where all of the .cs files generated by the application will stored. For example:
     
  4.    1: c:\myApp\LINQ2SQLDTOCreator.exe "c:\Dev\App\bin\debug\logic.dll" "c:\outputfromapp"
       2:  

    (make sure the parameters are separated by a single blank space)
  5. Now, the application will run and in the folder you entered in the second parameter you will find the DTO classes. Now, you can migrate this files into your project, compile and use.
  6. Remember to re-run the application every time you change the LINQ to SQL model in order to get an updated DTO’s.

Known Problems

  • The application doesn’t support any relationships between objects. If there are relationships in the database, the DTO will contain a property for the FK but no object association will be created.
  • The application can’t work with .NET 4.0 assemblies for a simple reason. If you want to work with .NET 4.0 assemblies you have to modify the project settings and set the Target Framework to .NET 4.0, rebuild and enjoy.
  • The application doesn’t put the created files automatically in your project.

If you get any other problems, let me know and I’ll try to fix.

Summary

LINQ2SQLDTOCreator is a really simple application that use Reflection in order to create Data Transfer Objects based on given assembly that include LINQ to SQL model. The application can be really useful if you use LINQ to SQL and want to create DTO’s without write at all :-)

You can download the application, for free, here.

Shahar.

IPSWeb – Web Client for Windows PowerShell

Yesterday, I published small application I developed called IPSWeb. This application is actually web client for Windows PowerShell.
It’s very simple, to install this application you create new IIS website, copy the files to the website directory and then, you have web access to the Windows PowerShell on the server.

In addition to execute commands and get the output, you can use all the great features of Windows PowerShell. There is also a built-in script editor (that will be better next versions) that gives the Server Administrator the option to create, edit and execute scripts on the server from the web client (IPSWeb), also when the ExecutionPolicy in the server doesn’t allow script execution.
IPSWeb supports more than one user in the same time, each user get his PowerShell instance. It’s also possible to create startupscript (in addition to the profile file) that will run in the beginning of each session.

The installation is very simple (full instructions available here) and take no more than two minutes.

This version (0.1) supports PowerShell v1.0 and the CTP’s of v2.0, although there aren’t any features that use the new features of PowerShell v2.0. Next versions will use the new features of v2.0, including managing of background jobs and more from the web interface.

 

This is an open-source project and v0.1 is ready. v0.1 is an alpha version so you might find some bugs. if you find any bug, please tell me about.

Download IPSWeb v0.1

 

Shahar.

How To: Prevent running ASP / ASP.NET code in specific folder

Sometimes, you may want to prevent running ASP or ASP.NET code in specific folder, for security reasons for example.
In this case, you have to follow these instructions (Windows Server 2003, IIS6):

  1. run inetmgr, the IIS management consoleimage
  2. Right-Click on the folder you want to disable ASP/ASP.NET inside
  3. Open the properties window.
  4. image In the "Directory" tab, in the "Execute Premissions list, choose "None". Now, It's impossible to execute ASP files or CGI scripts in this folder.
  5. Make an application for this folder, by clicking "Create" button.
  6. Click on the "Configuration" button.





  7. image In the "Wildcard application maps" section, choose the aspnet_isapi.dll item, and click Removee.

That's it!
Now, it's impossible to execute ASP or ASP.NET code on this folder.

Shahar.

Posted: Mar 16 2008, 02:54 PM by shahargs | with 691 comment(s)
Filed under:
PowerShell Script to backup SharePoint Site Collection

I wrote a small script that backup selected Windows SharePoint Services Site Collection and I publish it here. This is PowerShell script, that can be run manually or from scheduled task.

This is the script (you can download it, in the end of this post, if you can't see the full line):

   1:  #Backup Site Collection in Windows SharePoint Services Site Collection to file
   2:  #Author: Shahar Gvirtz
   3:  #Weblog: http://weblogs.asp.net/shahar
   4:   
   5:  param(
   6:  [string]$SiteCollectionUrl = $(throw "Please enter the URL of the Site Collection you want to backup"),
   7:  [string]$Path =$(throw "Please enter the folder you want to backup to")
   8:  )
   9:  if(test-path $path)
  10:  {
  11:      $guid = "\" + [Guid]::NewGuid().ToString()
  12:      & "$env:programfiles\Common Files\Microsoft Shared\web server extensions\12\BIN\stsadm.exe" `
  13:   -o backup -url $SiteCollectionUrl -filename $Path$guid.backup -overwrite > $null
  14:      [DateTime]::Now.ToString() +  ": Backup Done! File name is $path$guid.backup" >> "$path\log.txt"
  15:  }
  16:  else
  17:  {
  18:      write-error "The Path doesn't exists"
  19:  }
  20:   

This script get two parameters: the first one is the Site Collection url, and the second onw is the path to the folder where you want to save the backups.
If everything works fine, this script backup your site collection using stsadm.exe command line tool (line 13 is the continue of 12. there is a Back Tick operator in the end of line 12 which means that you only break the line).
After creating the backup, the script add new line to log file, with the current time and the name of the backup file.

Here is the syntax for using this script:

c:\backup.ps1 -SiteCollectionUrl "http://web:2020" -Path c:\backups

You must give an existing folder for the path parameter!
If you use it from the task scheduler, use this syntax (change the path and the site collection url):

powershell.exe c:\script\backup.ps1 -SiteCollectionUrl "http://web:2020" -Path c:\backups

You can download the full script, as txt file from here (change the file extension from txt to ps1 before using).

Shahar Gvirtz

How-To: Use ClickOnce to deploy your Applications

Part 1 - What is ClickOnce?

CickeOnce, is a technology for deploying smart-client applications. When we talk about smart-client application that deployed with ClickOnce, we want that the application will:

  • Provide automatic installation in one click.
  • Install updated automatically
  • Can be installed from local file, or from the WEB.

ClickeOnce, give us this options out of the box, and all we need to do is to write two XML manifest files (one for the application, and one for the ClickOnce engine). If you use Visual Studio, you have a wizzard for this.
In this post, I'll show how to work with ClickOnce from Visual Studio, and from your code too.

Part 2 - How to use ClickOnce in your application?

First of all, ClickOnce supports deployment of Windows Applications from all types (Console image Applications, Windows Forms Applications, WPF Applications).
So, in this example I created a new empty Windows Forms Application. to edit the ClickOnce settings, you should go to the project properties page (by right click on the project name in the solution explorer, see pic. #1).

In the Property page go the the "Publish" tab. In this tab, you can change the ClickOnce settings for this Project. First of all, in the first textbox, you have to enter where VS will create the installation files. It can be in the local file system, web site imageand FTP.

If you'll click on the Application Files button, you can edit the files that will include in your  project.
You can add new files that are currently in your solution, and choose if they will be in the package.

 

 

image

 

In the Prerequisites screen, you can choose package that muse be installed in the computer before your project will deploy.

For example, the .NET version you use, SQL Server etc.

 

image

 

It's recommended to click on the Update button, and turn on the update feature.
By default, it's turned off. This feature give you the option to create new versions and the clients will automatically update.

By default, the updates should be in the same directory like the publish directory.
But, you can specify a special directory for the updates, if you want so. Note that the updater will check if there is a newer version in the server. the version defuned in the main screen, in the Publish tab in the Project properties. If the V in "Automatically increment revision with each publish" checked, then any publish will increase the version.

image

After you configure the Updates, click on the Options button in the main screen and configure the general details.

 

After you finish, go close this Dialog and click on the Publish button:

image

Now, Visual Studio will build your project and will publish it. After anything will done, a new IE window will open (by default, unless you change it in the Options screen.) with the product auto-generated page.image

The page that automatically generated, include the prerequisites, and if everything is already installed you can click in the "launch" link. After clicking, if you are verified publisher, the application will start automatically, and later can be started from the Start Menu shortcut.

 

 

 

Part 3 - How the updater works?

The current project includes only an empty form. Now, let's say it's version 1.0.0.1.
Now, I changed the back color of the form , and I want it to be version 2.0.0.0.

image image

I'll go to the Publish tab in the project properties and edit the version:

image

Now, I'll click the publish now button. It will publish the new version to the location I chose (in the web).
Next time I'll launch the application, as I set in the Update properties, the application will update and show this message:

image

If you click OK, then the new version will download and run.

Part 4 - ClickOnce with code

Until now, we worked with wizards and GUI to manage the ClickOnce deployment, but we can do it from our code too. First of all, we should add using statement to System.Deployment.Application:

using System.Deployment.Application;

Now, we can use the ApplicationDeployment class to manage our application deployment information. This code, for example, check for updates and shows a MessageBox with the version of the newest version for the current deployment. Note, that this code can replace the built-in message of new versions. you can cancel in the Update screen in the Publish tab the auto-check for updates, and do it manually from your code:

   1:  ApplicationDeployment deploy =   ApplicationDeployment.CurrentDeployment;
   2:  UpdateCheckInfo update = deploy.CheckForDetailedUpdate();
   3:  MessageBox.Show("You can update to version: " + update.AvailableVersion.ToString());

image

Note that this code will cause an exception if no update available, because then update.AvailableVersion.ToString() will be null. So, if you want to use this code, make sure that it's in if...else statement that show the message only if update doesn't equal to null.

We can fix this code a little, so the application will update after the message show:

ApplicationDeployment deploy = ApplicationDeployment.CurrentDeployment;
UpdateCheckInfo update = deploy.CheckForDetailedUpdate();
 if (deploy.CheckForUpdate())
{
     MessageBox.Show("You can update to version: " + update.AvailableVersion.ToString());
     deploy.Update();
     Application.Restart();
}

This code will work always. If an update is available, it will inform the user, download the update synchronously and restart the application. Otherwise, this code do nothing.

Put this code in the form load event, and then when you release a new version, the user will informed about and the application will update. you can use this code instead the built-in message, to make this progress more friendly.

Shahar Gvirtz.

Dynamic Data Web Application - Part 1

ASP.NET 3.5 Extensions is a package of new controls and tools that improve the existing ASP.NET 3.5.
One of the interesting (and time-saving) features, is the Dynamic Data Controls. Dynamic Data Controls can be used to build easily, almost without writing any line of code a complete data-driven Web Application.
The controls cover the common things that developers use when build a web application which work with DB -  view information, delete, update, view detailed information, add new data etc.

For example, let's say we need to build a management panel for DB. First, we (or the DBA) build the DB, and then, we create a web forms for managing this DB. Let see how can I do it simply with Dynamic Data Web Application in 5 minutes.

In this article, you won't see any line of code!
The site we build is actually based on the Dynamic Data controls built-in template, and doesn't include any custom logic.
In the real world, we may want to add our logic, and in the next part of the article you'll see how to do this.

Step 1 - Create a new Dynamic Data Web Applicationimage

After you downloaded and installed the ASP.NET 3.5 Extensions, you open your VS 2008, and create new Dynamic Data application. Note that you must use .NET 3.5 for this (if you use .NET 2.0, maybe you want to check ASP.NET Futures July CTP which works in .NET 2.0)

 

 

Step 2 - Add you database to the App_Data folder

In this example, I use the Northwind database.

Step 3 - Add LINQ to SQL Classes Fileimage

Add new item to your project, I called in "db". The Dynamic Data Controls based on LINQ to SQL Object Mapper, and use it to get and work with your DB. Drag from the Server Explorer the items you want that Dynamic Data will work with. I added all the tables in Northwind DB.

 

 

Step 4 - Edit your web.config file

If you don't want to customize the Dynamic Data site, and you want to create fully data driven application without writing even one line of code (great for demos), just go to web.config to line 130 and set enableTemplates property as "true" and set the dataContextType to the name of our LINQ to SQL classes name:

<dynamicData dataContextType="db" enableTemplates="true">

In this line we set Dynamic Data to work with the default templates (you can find them in App_Shared folder).

Step 5 - Run the Application

image

What we get by default?
The default template of the Dynamic Data site stored in the App_Shared folder. The web forms use the new controls - DynamicGridView (which render on client side like a standard GridView), DynamicFormView etc.

In the main page we can se list of all our tables that are in the LINQ to SQL. The LINQ to SQL include the full database schema, which means that all the relationships can be used it the Dynamic Data Site.
For example, take a look in the Products page. you see a list of all the items in GridView, you imagecan select and see details in the DetailsView in the bottom of  the page, you can sort, edit and delete.
But, you can also see that the last 3 columns, are a links to another pages that include the categories, the order dentils and the supplier information. In the database schema, this columns include only the ID of the category, the ID of the Supplier. The DynamicData Controls, show instead the ID, a link to page with the category details or the supplier details.  imageThis feature based on the LINQ to SQL that create objects from the tables, with association that make it possible for DynamicData Controls to link the relevant page instead show numeric ID.

Summary

In this part, you see how to create a simple data driven web application without write code.
In the next part, we'll see how we can customize the application. change the style, remove and add columns from the view, and add logic.

 

Shahar Gvirtz.

How to run PowerShell script from command-let

Sometimes, we want to run PowerShell script from command-let that derives from PSCmdlet (If you derived from Cmdlet, you can't use this way).
To do so, we just have to use this code:

   1:  using System.Management.Automation;
   2:  using System.Collections.ObjectModel;
   3:   
   4:  ......
   5:   
   6:  Collection<PSObject> results = InvokeCommand.InvokeScript("dir" /*replace it with your script */);
   7:  foreach (PSObject var in results)
   8:  {
   9:         WriteObject(var.ToString(),false);
  10:  }

I included in this code the important using statements, and the code itself. Few things about this code:

  1. I use PSObject as the type for the collection, which means that I can access any property and method of the returning object, include Extended methods (ETS).
  2. Always use WriteObject method in Command-lets NEVER use System.Console.
    That's because WriteObject write stream of object, not text, which is one of the biggest advantages in PowerShell - we can work with object instead text.
    When you use WriteObject you can be sure that any PowerShell host will be able to use the command-let and the output easily.

Shahar.

[Tip] Option Explicit in PowerShell

Someone asked me how we can set Windows PowerShell to work like in VB when you specify Option Explicit.
How to disable using of variables that didn't defined in the code. In this way, you know for sure that you aren't use undefined variable and get unexpected results.

to do "Option Explicit" in PowerShell, simply run this command:

set-psdebug -strict

and to disable the Option Explicit:

set-psdebug -off

Shahar.

More Posts Next page »