Export (0) Print
Expand All

Walkthrough: Adding Dynamic Data to an Existing Web Site

Visual Studio 2008

Updated: July 2008

This walkthrough shows how to modify an existing ASP.NET Web site to include Dynamic Data framework features. Additionally, it shows ways in which you can customize a Dynamic Data Web site. At the end of the walkthrough you will have a functional Web site that uses the data model to interact with the database. Also, you will have custom field templates that define how data fields are rendered for display and for editing.

A defining aspect of ASP.NET Dynamic Data is its ability to infer at run time the appearance and behavior of data fields from the data model that represents the database. This information is then used in the data controls, with the support of field templates, to eliminate the need for repetitive code in the presentation layer.

This walkthrough shows how you can do the following with a minimum amount of code:

  • Interact with the data model. Dynamic Data incorporates features to help you create a data-driven application that can perform create, read, update, and delete (CRUD) operations.

  • Customize how users see and edit data fields by creating field templates. Dynamic Data selects the appropriate field templates based on the information that is inferred from the data model.

You will follow these steps:

  • Create a Web site and then modify it to support Dynamic Data. The primary goal of this task is to create the data model that will be used by Dynamic Data to interact with the database.

  • Create field templates. Field templates are user controls that define the UI for how data is displayed and edited.

  • Create a custom page to display a table. This page shows how Dynamic Data interacts with the database, and shows that you need only minimal code for this task.

  • Test Dynamic Data integration. This lets you make sure that Dynamic Data capabilities have been integrated in the Web site. You can interact with the data model and verify that the application works as expected. As part of this process, you will generate and handle errors.

In order to complete the examples in this topic, you need the following:

  • Microsoft Visual Studio 2008 Service Pack 1 or Visual Web Developer 2008 Express Edition Service Pack 1.

  • The AdventureWorksLT sample database. For information about how to download and install the SQL Server sample database, see Microsoft SQL Server Product Samples: Database on the CodePlex site. Make sure that you install the correct version of the sample database for the version of SQL Server that you are running (Microsoft SQL Server 2005 or Microsoft SQL Server 2008).

In this section you will create a Dynamic Data Web site in Visual Studio. You will start with a standard ASP.NET Web site and then transform it into a site that supports Dynamic Data features. To do so, you will do the following:

  • Create an ASP.NET Web site.

  • Connect the site to a database. This database contains the table whose columns (data fields) will be accessed for custom display and editing.

  • Configure the site to use Dynamic Data controls. This enables integration of the Dynamic Data features in the Web site.

You will then create and configure the data model that you will work with. You will do the following:

  • Create data-model classes based on a SQL Server database.

  • Add metadata to the data model to enable custom validation of the user's input, and to later enable a Calendar control to modify data fields.

Preparing a Web Site for Dynamic Data

This section shows how to create an ASP.NET Web site, how to add a database, and how to configure the Web site to integrate Dynamic Data features.

To create an ASP.NET Web site

  1. Start Visual Studio.

  2. In the File menu, click New, and then click Web Site.

    The New Web Site dialog box is displayed.

  3. Under Visual Studio installed templates, select ASP.NET Web Site.

  4. Next to Location, select File System, and in the second box, enter the name of the folder where you want to keep the pages of the Web site. For example, enter the folder name C:\WebSites\DynamicDataWebSite.

  5. In the Language list, select the programming language that you prefer to work in.

  6. Click OK.

    Visual Studio creates the folders and the files for an ASP.NET Web site.

The next step is to add a database to the site. This database contains the table whose columns (data fields) will be accessed for display and editing.

To add the database to the Web site

  1. In Solution Explorer, right-click the App_Data folder, and then click Add Existing Item.

  2. In the Add Existing Item dialog box, enter the location where you installed the AdventureWorksLT database file (AdventureWorksLT.mdf), and then click Add.

    This creates a copy of the database file in the project.

You can now configure the Web site in order to integrate Dynamic Data features.

To configure the Web site

  1. In Solution Explorer, open the Web.config file.

  2. Add the assembly references for the following assemblies:

    • System.Web.Routing

    • System.Web.DynamicData

    • System.ComponentModel.DataAnnotations

    The following example shows how to add the assemblies. Make sure that you use the correct assembly versions.

    <system.web>
      <compilation>
        <assemblies>
        
          <add assembly="System.Web.Routing, Version=3.5.0.0,  
               Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 
          <add assembly="System.Web.DynamicData, Version=3.5.0.0,  
               Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 
          <add assembly="System.ComponentModel.DataAnnotations,  
               Version=3.5.0.0,  
               Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        </assemblies>
      </compilation>
    
  3. Configure the asp tag prefix to reference the System.Web.DynamicData namespace, as shown in the following example:

    <system.web>
      <pages>
        <controls>
        
          <add tagPrefix="asp" namespace="System.Web.DynamicData"  
             assembly="System.Web.DynamicData, Version=3.5.0.0,  
             Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        </controls>
      </pages>
    </system.web>
    
  4. Save and close the Web.config file.

Setting the Data Model

This section shows how to create the data model that is a key component in achieving dynamic behavior for the Web site. In this walkthrough you will use a LINQ-to-SQL data model. However, you could use an ADO.NET Entity Framework data model instead. This section also shows how to add metadata information to the data model.

To create the data model

  1. In Solution Explorer, right-click the project name, click Add ASP.NET Folder, and then click App_Code.

  2. Right-click the App_Code folder and then click Add New Item.

  3. Under Visual Studio installed templates, click LINQ to SQL Classes.

  4. In the Name box, enter the name AdventureWorksLT.dbml for the database model.

  5. Click Add.

    The Object Relational Designer (O/R Designer) is displayed. For more information, see Object Relational Designer (O/R Designer).

  6. In the O/R Designer, click the Server Explorer link.

  7. In Server Explorer, under Data Connections, expand the AdventureWorksLT_Data.mdf node and then expand the Tables node.

  8. Drag the Customer table into the O/R Designer window.

  9. Save and close the AdventureWorksLT.dbml file.

    You have created the data model that represents the AdventureWorksLT database.

The next procedure shows how to add custom validation of user input. It also shows how to use a Calendar control to render the UI for the display and editing of DateTime data fields

To add custom validation and metadata to the data model

  1. In Solution Explorer, right-click the App_Code folder, and then click Add New Item.

  2. Under Visual Studio installed templates, click Class.

  3. In the Name box, enter the name of the database table (as defined in the data model) that contains the data for the custom field template to display. For this walkthrough, you will be working with the Customer class. Therefore, create a class file that is named Customer.cs or Customer.vb. This file will also contain an associated class that you will create later to apply attributes to data fields.

  4. Add the Partial keyword in Visual Basic or the partial keyword in Visual C# to the Customer class definition to make it a partial class.

  5. If you are creating the class in Visual C#, delete the default constructor.

    The following example shows the updated class declaration.

    public partial class Customer {
        
    }
    

    Partial Public Class Customer
        
    End Class
    
  6. Add references to the System.Web.DynamicData and System.ComponentModel.DataAnnotations namespaces by using the Imports keyword in Visual Basic or the using keyword in Visual C#, as shown in the following example:

    using System.Web.DynamicData;
    using System.ComponentModel.DataAnnotations;
    

    Imports System.Web.DynamicData
    Imports System.ComponentModel.DataAnnotations 
    
  7. In the same file, create another partial class that will act as the associated metadata class. You can use any name for the class. For this walkthrough, name the class CustomerMetadata, as shown in the following example:

    public partial class CustomerMetadata
    {
    
    }
    

    Partial Public Class CustomerMetadata
        
    End Class 
    
  8. Apply the MetadataTypeAttribute attribute to the Customer partial class. For the attribute's parameter, specify CustomerMetadata, which is the name of the associated metadata class that you created in the previous step

    The following example shows the Customer partial class with the attribute applied.

    [MetadataType(typeof(CustomerMetadata))]
    public partial class Customer {
        
    }
    

    <MetadataType(GetType(CustomerMetadata))> _
    Partial Public Class Customer
        
    End Class
    
  9. In the metadata class, create a public field named ModifiedDate that is typed as Object.

    In the metadata class, you create a field for each data field whose display and edit behavior you want to customize. For the field name in the metadata class, you use the same name as the name of the data field that you want to modify.

  10. Apply the UIHintAttribute attribute to the ModifiedDate field. For the parameter, specify "DateCalendar". This is the name of a field template that you will create later.

    NoteNote:

    The Object is used as a marker in the metadata type to represent the data field. Dynamic Data infers the actual type from the data model.

    The following example shows the UIHintAttribute attribute applied.

    public partial class CustomerMetadata
    {
        [UIHint("DateCalendar")]
        public object ModifiedDate;
    }
    

    Partial Public Class CustomerMetadata
        <UIHint("DateCalendar")> _
        Public ModifiedDate As Object
    End Class 
    
  11. In the metadata class, create public fields for the FirstName and LastName properties.

  12. Apply the RegularExpressionAttribute attribute to the data fields FirstName and LastName. Specify a regular expression pattern that allows only alphabetical characters, spaces, and hyphens, and that limits the name to 40 characters. Include a custom error message to display if the validation fails

    The following example shows the FirstName and LastName fields with the attribute applied.

    [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$",  
        ErrorMessage="Entered characters are not allowed.")]
    public object FirstName;
    
    [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$", 
        ErrorMessage = "Entered characters are not allowed.")]
    public object LastName; 
    

    <RegularExpression("^[a-zA-Z''-'\s]{1,40}$", _ 
        ErrorMessage:="Entered characters are not allowed.")> _
    Public FirstName As Object
    
    <RegularExpression("^[a-zA-Z''-'\s]{1,40}$", _ 
        ErrorMessage:="Entered characters are not allowed.")> _
    Public LastName As Object
    

    Notice that the data fields match Customer table columns that are defined in the data model. You use them only to add metadata information that Dynamic Data uses when it renders these data fields.

    The regular expression pattern allows up to 40 uppercase and lowercase characters as well as several special characters that are common to names in English.

  13. Save and close the class file.

You can now register the data-model context so that Dynamic Data can access metadata information.

To register the data model context

  1. In Solution Explorer, right-click the project name, and then click Add New Item.

  2. Under Visual Studio installed templates, select Global Application Class and then click Add.

    This adds a Global.asax file to the site.

  3. Add an @ Import directive with a Namespace attribute that references the System.Web.DynamicData namespace, as shown in the following example:

    <%@ Import Namespace="System.Web.DynamicData" %>
    
  4. In the Application_Start method, register the data context with the scaffolding option disabled, as shown in the following example.

    This registration tells Dynamic Data what data model to use. It also tells Dynamic Data not to enable tables to be visible for scaffolding. This last step is not required, but it is used here to emphasize that the Web site does not use scaffolding.

    MetaModel model = new MetaModel();
    model.RegisterContext(typeof(AdventureWorksLTDataContext), 
    new ContextConfiguration() {ScaffoldAllTables = false });
    

    Dim model As MetaModel = New MetaModel()
    model.RegisterContext(GetType( _
        AdventureWorksLTDataContext), _
        New ContextConfiguration() With { _
        .ScaffoldAllTables = False})
    
  5. Save and close the Global.asax file.

Field templates are user controls that Dynamic Data uses to render UI for displaying and editing data fields. Dynamic Data requires field templates to exist for each data field type that is represented in the data context. (If no field template exists for a specific data field type and no field template can be found using fallback rules, Dynamic Data throws an exception.)

If you create a Dynamic Data Web site, the site includes a set of field templates that represent typical database data types. These are created together with page templates, a master page, and cascading style sheet files. However, in this walkthrough, you are learning how to add Dynamic Data capabilities to an existing site. Therefore, it is assumed that you do not have access to default field templates.

The field templates that you create in this walkthrough will resemble the default templates in a Dynamic Data Web site. For more information, see ASP.NET Dynamic Data Field Templates Overview. You can see the default field templates that are generated when you create a Web site that uses scaffolding. For more information, see Walkthrough: Creating a New ASP.NET Dynamic Data Web Site Using Scaffolding.

This section shows how to create the following templates:

  • Field templates that render UI for displaying and editing String type data fields.

  • Field templates that render UI for displaying and editing DateTime type data fields.

Creating Field Templates for String Data

This section shows how to create field templates to render UI for displaying and editing String data fields.

To create field templates to display and edit String data fields

  1. In Solution Explorer, right-click the project name, and then click New Folder.

  2. Rename the new folder DynamicData.

    NoteNote:

    You must use the folder names that are described in this procedure, because the names have special meaning in Dynamic Data.

  3. In Solution Explorer, right-click the DynamicData folder, and then click New Folder.

  4. Rename the new folder FieldTemplates.

  5. In Solution Explorer, right-click the FieldTemplates folder, and then click Add New Item.

  6. Under Visual Studio installed templates, click Dynamic Data Field.

  7. In the Name box, enter Text.ascx. Make sure that you select Place the code in separate file.

  8. Click Add.

    Two field templates named Text.ascx and Text_Edit.ascx are created. The first control renders the UI for displaying String data fields. The second control renders the UI for editing String data fields.

  9. Open the Text_Edit.ascx file and in the @ Control directive, set the AutoEventWireup attribute to true.

  10. Save and close the user control files.

    You have now created the field templates that render UI for displaying and editing String data fields.

Creating DateTime Field Templates

This section shows how to create field templates to render UI for displaying and editing DateTime data fields. The display field template uses a short date representation that excludes the time. The editing field template uses the Calendar control to enable the user to enter a new value.

To create a field template to display and edit DateTime data fields

  1. In Solution Explorer, right-click the DynamicData\FieldTemplates folder, and then click Add New Item.

  2. Under Visual Studio installed templates, click Dynamic Data Field.

  3. In the Name box, enter DateCalendar.ascx. Make sure that you select Place the code in separate file.

  4. Click Add.

    Two field templates named DateCalendar.ascx and DateCalendar_Edit.ascx are created. The first control renders the UI for displaying DateTime data fields. The second control renders the UI for editing DateTime data fields.

  5. Open the DateCalendar.ascx file.

  6. In the Literal control, delete the FieldValueString assignment to the Text attribute, as shown in the following example.

    <asp:Literal ID="Literal1" runat="server"/>
    
  7. Save and close user control file.

  8. Open the DateCalendar.ascx.vb or DateCalendar.ascx.cs field template code-behind file.

  9. Override the user control OnDataBinding method to format the DateTime value for display by excluding the time, as shown in the following example. The value of the field is available in FieldValue.

    protected override void OnDataBinding(EventArgs e)
    {
      base.OnDataBinding(e);
      string shortDate = string.Empty;
      if (FieldValue != null)
      {
        DateTime dt = (DateTime)FieldValue;
        shortDate = dt.ToShortDateString();
      }
      Literal1.Text = shortDate;
    }
    

    Protected Overloads Overrides Sub OnDataBinding( _
        ByVal e As EventArgs)
        MyBase.OnDataBinding(e)
        Dim shortDate As String = String.Empty
        If FieldValue IsNot Nothing Then
          Dim dt As DateTime = Format(CType(FieldValue, DateTime), "d")
          shortDate = dt.ToShortDateString()
        End If
        Literal1.Text = shortDate
    End Sub  
    
  10. Save and close the code-behind file.

  11. Open the DateCalendar_Edit.ascx file.

  12. In the @ Control directive, set the AutoEventWireup attribute to true.

  13. In the TextBox control, replace the FieldValueString expression in the Text attribute with the custom GetDateString() method, as shown in the following example.

    <asp:TextBox ID="TextBox1" runat="server" 
      Text='<%# GetDateString() %>' >
    </asp:TextBox>
    
  14. Add the following markup to the file to define the Calendar control that renders UI to enable an alternative way of editing dates.

    <asp:Calendar ID="Calendar1" runat="server" 
      VisibleDate=
        '<%# (FieldValue != null) ? FieldValue : DateTime.Now %>'
      SelectedDate=
        '<%# (FieldValue != null) ? FieldValue : DateTime.Now %>'
      OnSelectionChanged="Calendar1_SelectionChanged" />
    

    <asp:Calendar ID="Calendar1" runat="server" 
      VisibleDate=
      '<%# If(FieldValue,DateTime.Now)%>'
      SelectedDate=
      '<%# If(FieldValue,DateTime.Now) %>'
      OnSelectionChanged="Calendar1_SelectionChanged" /> 
    
  15. Save and close the field template file.

  16. Open the DateCalendar_Edit.ascx.vb or DateCalendar_Edit.ascx.cs code-behind file.

  17. Add a GetDateString method. In the method, process the user's input as entered through the TextBox control. The method formats the date by using a short date format that excludes the time.

    The following example shows how to do this.

    protected string GetDateString()
    {
      if (FieldValue != null)
      {
        DateTime dt = (DateTime)FieldValue;
        return dt.ToShortDateString();
      }
      else
        return string.Empty;
    }
    

    Protected Function GetDateString() As String
      If FieldValue <> Nothing Then
        Dim dt As DateTime = Format(CType(FieldValue, DateTime), "d")
          Return dt.ToShortDateString()
      Else
        Return String.Empty
      End If
    End Function
    
  18. Add a handler for the Calendar control's SelectionChanged event.

  19. In the handler, set the Text property of the TextBox control to a formatted version of the selected date from the calendar. This displays the user's current selection in the text box.

    The following example shows the handler.

    protected void Calendar1_SelectionChanged(
      object sender, EventArgs e)
    {
      // Display value using the short date format.
      TextBox1.Text = 
      Calendar1.SelectedDate.ToString("d");
    }
    

    Protected Sub Calendar1_SelectionChanged( _
        ByVal sender As Object, ByVal e As EventArgs)
        ' Display value using the short date format.
        TextBox1.Text = Calendar1.SelectedDate.ToString("d")
    End Sub
    
  20. Save and close the field template files.

    You have now created the field templates that render the UI for displaying and editing DateTime data field types. The field templates instruct Dynamic Data to apply appropriate formatting and validation. If validation fails, the field templates also generate appropriate error messages.

This section shows how to create a custom page that displays the Customer table by using a GridView control with dynamic behavior.

The control's dynamic behavior is established by doing the following:

The database table contains String and DateTime data field types. Therefore, when you use the GridView control with dynamic behavior to display the table data, Dynamic Data will use the custom field templates that you have created.

To create a custom page to display the Customers table

  1. In Solution Explorer, right-click the project name, and then select Add New Item.

  2. Under Visual Studio installed templates, select Web Form.

    In the Name box, enter Customers.aspx. Make sure that you select Place code in separate file.

  3. In the @ Page directive, set the AutoEventWireup attribute to true.

  4. In Source view, add a DynamicDataManager control to the body of the page, as shown in the following example:

    <body>
        
        <asp:DynamicDataManager ID="DynamicDataManager1" 
          runat="server"/>
        
    </body>
    

    The DynamicDataManager control instructs Dynamic Data to handle the data controls in the page as dynamic controls.

  5. From the Data tab of the Toolbox, add a LinqDataSource control to the page.

  6. Set the EnableUpdate property of the LinqDataSource control to true.

    This enables update operations for the data control.

  7. Set the LinqDataSource control's TableName property to the table that you want to use (Customers).

  8. Set the ContextTypeName property to the data context class (AdventureWorksLTDataContext), as shown in the following example:

    <asp:LinqDataSource ID="LinqDataSource1" runat="server" 
      TableName="Customers" 
      ContextTypeName="AdventureWorksLTDataContext" 
      EnableUpdate="true">
    </asp:LinqDataSource>
    
  9. From the Data tab of the Toolbox, add a GridView control to the page.

    This control will be used to display and modify the data fields.

  10. Set the GridView control's DataSourceID property to the ID of the LinqDataSource control, as shown in the following example:

    <form ID="Form1" runat="server" >
    
        <asp:GridView ID="GridView1"  runat="server" 
          DataSourceID="LinqDataSource1" >
        </asp:GridView>
    </form>
    
  11. Set the GridView control's AutoGenerateColumns property to false and set the AutoGenerateEditButton property to true, as shown in the following example:

    <asp:GridView ID="GridView1"  runat="server" 
      AutoGenerateEditButton="true" 
      AutoGenerateColumns="false" >
    </asp:GridView>
    

    This enables the edit operation and disables the automatic generation of columns that are based on the database table. You will instead use a DynamicField controls to populate the GridView control.

  12. Set the GridView control's AllowPaging and AllowSorting properties to true, as shown in the following example:

    <asp:GridView ID="GridView1"  runat="server" 
        
      AllowPaging="true" 
      AllowSorting="true" >
    </asp:GridView>
    
  13. Add three DynamicField controls to the Columns property and set their DataField properties to "FirstName", "LastName", and "ModifiedDate".

    DynamicField controls use ASP.NET Dynamic Data to read data from the data model and to format it by using the appropriate field template. Notice that you do not have to include any information in the DynamicField controls about how to read or format the data. These tasks are handled automatically by Dynamic Data.

    The following example shows the markup for the GridView control after you add the DynamicField controls.

    <asp:GridView ID="GridView1"
     runat="server">
        
      <Columns> 
        <asp:DynamicField DataField="FirstName" /> 
        <asp:DynamicField DataField="LastName" /> 
        <asp:DynamicField DataField="ModifiedDate" /> 
      </Columns>
    </asp:GridView>
    
    NoteNote:

    The DynamicField control is not in the Toolbox. Therefore, you must add it as markup in Source view.

  14. Save and close the Customers.aspx file.

    You have now created the custom page to access the Customers table.

  15. Open the Customers.aspx.cs or Customers.aspx.vb code-behind file.

  16. Add a reference to the System.Web.DynamicData namespace by using the Imports keyword in Visual Basic or the using keyword in Visual C#, as shown in the following example:

    using System.Web.DynamicData;
    

    Imports System.Web.DynamicData
    
  17. Create a Page_Init method, as shown in the following example:

    protected void Page_Init(object sender, 
    EventArgs e)
    {    }
    

    Protected Sub Page_Init(ByVal sender As Object, _
    ByVal e As EventArgs)
        
    End Sub
    
  18. In the Page_Init method, register the GridView control with the DynamicDataManager to enable dynamic behavior.

    The following example shows how to do this.

    protected void Page_Init(object sender, 
    EventArgs e)
    {
        DynamicDataManager1.RegisterControl(GridView1);
    }
    

    Protected Sub Page_Init(ByVal sender As Object, _
        ByVal e As EventArgs)
        DynamicDataManager1.RegisterControl(GridView1)
    End Sub
    
  19. Close the code-behind file.

This section shows how to make sure that Dynamic Data capabilities have been integrated in the Web site. You can interact with the database through the data model and verify that the integration works. You will see that when you modify data, if you provide invalid values, error messages are generated by Dynamic Data based on the information that it infers from the database.

To test that Dynamic Data capabilities have been integrated

  1. In Solution Explorer, right-click the Customers.aspx page and select View in Browser.

    The browser shows a page that displays the Customers table with the selected columns.

  2. On any row, click Edit and clear the first name.

  3. On the same row, click Update.

    Dynamic Data displays an error message that warns you that an empty string is not allowed for the FirstName data field.

  4. On the same row, click Cancel.

  5. On any row, click Edit and then change the last name.

  6. On the same row, click Update.

    Dynamic Data updates the database. Because you entered a valid value for the last name, the data passes the validation control that is part of the field template that you built earlier.

  7. On any row, click Edit and enter non-alphabetical characters for the first or last name.

  8. On the same row, click Update.

    Dynamic Data displays the custom error message that you specified with the regular expression, which warns you that you have entered characters that are not allowed.

  9. On the same row, click Cancel.

  10. On any row, click Edit and, clear the date.

  11. On the same row, click Update.

    Dynamic Data displays an error message that warns you that an empty string is not allowed for the ModifiedDate data field.

  12. On the same row, click Cancel.

  13. On any row, click Edit and then change the date using the Calendar control.

  14. On the same row, click Update.

    Dynamic Data updates the database. Because you entered an allowed value for the date, the data passes the validation control that is part of the field template that you built earlier.

This walkthrough has illustrated the basic principles of ASP.NET Dynamic Data, and how to add Dynamic Data features to an existing ASP.NET Web site. When you integrate Dynamic Data features into an existing ASP.NET Web site, you can do the following:

  • Interact with the underlying database. Dynamic Data incorporates key features for a data-driven application such as create, read, update, and delete (CRUD) operations.

  • Display and edit data fields, because Dynamic Data selects the appropriate field template based on the information that is inferred from the database.

You might want to experiment with additional features. Suggestions for additional exploration include the following:

For general information, you might want to do the following:

Date

History

Reason

July 2008

Added topic.

SP1 feature change.

Community Additions

ADD
Show:
© 2014 Microsoft