Yukon Demo: AdventureWorks Contacts
By Jason Stowe
Published: 11/13/2003
Reader Level: Intermediate
Rated: 5.00 by 1 member(s).
Tell a Friend
Rate this Article
Printable Version
Discuss in the Forums

Applies to:
   Yukon Beta 1 Customers

Summary
Prerequisites
Introduction to the Example
Quick Start

Yukon Beta 1 Server Setup Steps:

Step 1 - Creating the Additional T-SQL Stored Procedures Needed for the Example
Step 2 - Creating the .NET Assembly for SQLCLR
Step 3 - Linking C# Classes to Stored Procedures
Step 4 - Reserving the HTTP Namespace
Step 5 - Creating the HTTP ENDPOINT

SOAP Client Applications:

Step 6 - Creating Client Application using HttpWebRequest and HttpWebResponse
Step 7 - Creating Client Application Using Proxy Class Generated by WSDL.EXE

Additional Native HTTP Information



Summary

Starting with Yukon Beta 1, Microsoft SQL Server provides the ability to expose native HTTP methods inside the server. These requests and responses are made within SOAP packets, which are an extension of XML.

Yukon Beta 1 also provides the ability to allow managed code to be run inside the SQL Server context. This gives the developer the opportunity to move business logic inside of the server, instead of using the traditional n-tiered approach. Developing using managed code also provides the means for developers to leverage all the advantages of using a managed code environment.

This document was designed to introduce these new technologies using simple examples on top of the AdventureWorks database. The following examples are shown within this document:

Server Side Technologies

Create classes in C# that use the SqlContext class to run TSQL statements within the SQL Server context, but from a managed code environment.

Setup the classes created in C# as stored procedures.  The SQLCLR framework is setup so that implementation details such as the programming language used to create the stored procedure are hidden from the calling clients.  Stored procedures created in managed code or T-SQL are called by the client in the same way.

Reserve a URL namespace for the HTTP Endpoint to be created on

Create an HTTP ENDPOINT which exposes stored procedures created in both C# and TSQL as well as providing for ad hoc TSQL queries to be passes

 
Client Side Technologies

Create a console application in VS.NET that uses the HttpWebRequest and HttpWebResponse classes to send and receive SOAP packets. This will give the reader the ability to see the SOAP packets that are passed to and from the SQL Server.

Create a Windows application on top of the proxy class generated by WSDL to call the methods exposed by the HTTP ENDPOINT.



Prerequisites

To complete this example, there are two prerequisites:

1.  Yukon Beta 1 Properly Installed on a Windows 2003 Server
2.  Perform this example on the machine with Yukon Beta 1 installed since the CLR Framework is needed to create the application
3.  For the Books Online links within this document to work, Yukon Beta 1 Books Online is required to be installed.

Visual Studio is not needed to complete this example since the .NET compiler shipped with Yukon Beta 1 is used to compile any managed code within this example. There are .BAT files included with this example to assist with the compilation of any C# code.



Introduction to the Example

These samples create additional stored procedures in the AdventureWorks database and create a HTTP ENDPOINT to expose these stored procedures.  The stored procedures that will be used are as follows:

Stored Procedure Code Base Description
GetContact TSQL This stored procedure will return a Contact given a ContactId
GetContactCLR C# This stored procedure is built using C# and provides the same functionality as GetContact using the SqlContext class and a parameterized SELECT statement.
GetContactSPCLR C# This stored procedure is built using C# and calls the GetContact stored procedure, basically acting as a managed code wrapper that could be used to include additional business logic implemented in C#.
InsertContact TSQL This stored procedure will insert a row into Contact and return a scalar value representing the resulting ContactId.
InsertContactCLR C# This stored procedure is built using C# and passes a parameterized SELECT statement using the SqlContext class and returns a scalar value representing the resulting ContactId.
InsertContactSPCLR C# This stored procedure is built using C# and calls the InsertContact stored procedure using the SqlContext class and returns a scalar value representing the resulting ContactId.

The HTTP ENDPOINT will expose the following methods:

ENDPOINT Method Stored Procedure Called Description
GetContact GetContact This method calls the GetContact stored procedure created within this example.
GetContactNoSchema GetContact This method calls the GetContact stored procedure, but does not return the XML Schema back with the dataset.  This option could be used when higher performance is desired and the schema can be sacrificed.
GetContactCLR GetContactCLR This method calls the GetContactCLR stored procedure which is a stored procedure implemented in C#.
GetContactSPCLR GetContactSPCLR This method calls the GetContactSPCLR stored procedure.
InsertContact InsertContact This method calls the InsertContact stored procedure.
InsertContactCLR InsertContactCLR This method calls the InsertContactCLR stored procedure.
InsertContactSPCLR InsertContactSPCLR This method calls the InsertContactSPCLR stored procedure.
SqlBatch   This endpoint will also allow adhoc SQL statements to be executed.

The following picture depicts the layers that are being accessed in this example.



Quick Start

If you would like to compile all of the code and run the client applications without necessary stepping through the entire tutorial, perform the following steps:

Step

Description

1.  If Yukon Beta 1 was not installed to "C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL", edit .\2-CLRSPs\CompileAdventureWorksSQLCLR.bat to change the reference within this batch file.
2.  Execute "ExecuteAll.bat" from the directory which the support files were unzipped. This will compile and run all the code as well as opening up the Windows Application created
3.  To use the console application which outputs the SOAP responses from Yukon Beta 1, navigate to the 6-HttpWebRequestApp directory and execute any or all of the following:

httpwebrequestapp -uri=http://localhost/sql/AdventureWorks -input=SampleXMLInputFiles\BatchStatements.xml
httpwebrequestapp -uri=http://localhost/sql/AdventureWorks -input=SampleXMLInputFiles\GetContact.xml
httpwebrequestapp -uri=http://localhost/sql/AdventureWorks -input=SampleXMLInputFiles\GetContactNoSchema.xml
httpwebrequestapp -uri=http://localhost/sql/AdventureWorks -input=SampleXMLInputFiles\GetContactCLR.xml
httpwebrequestapp -uri=http://localhost/sql/AdventureWorks -input=SampleXMLInputFiles\GetContactSPCLR.xml
httpwebrequestapp -uri=http://localhost/sql/AdventureWorks -input=SampleXMLInputFiles\InsertContact.xml
httpwebrequestapp -uri=http://localhost/sql/AdventureWorks -input=SampleXMLInputFiles\InsertContactCLR.xml
httpwebrequestapp -uri=http://localhost/sql/AdventureWorks -input=SampleXMLInputFiles\InsertContactSPCLR.xml

Step 1 - Creating the Additional T-SQL Stored Procedures Needed for the Example

For this example, two stored procedures implemented in TSQL are added into the AdventureWorks database. The two stored procedures that will be added are GetContact and InsertContact. These stored procedures return a record from the Contact table and inserts a record, respectively.

To complete this step, perform the following tasks:

Step

Description

1.  Open SQL Server Workbench
2.  Execute the following as an administrator on the SQL Server

use AdventureWorks

-- Drop AdventureWorks.InsertContact
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[InsertContact]')
  and OBJECTPROPERTY(id, N'IsProcedure') = 1)
begin
  drop procedure InsertContact
  print 'Dropped Stored Procedure: AdventureWorks.InsertContact'
end
go

-- Create AdventureWorks.InsertContact
create procedure InsertContact(
  @Salutation nvarchar(8),
  @FirstName nvarchar(50),
  @MiddleName nvarchar(50),
  @LastName nvarchar(50),
  @NameStyle bit,
  @Phone nvarchar(25),
  @Suffix nvarchar(10),
  @EmailAddress nvarchar(50),
  @EmailPromotion int
)
AS
  SET NOCOUNT ON
  INSERT  Contact(  
      Salutation,
      FirstName,
      MiddleName,
      LastName,
      NameStyle,
      Phone,
      Suffix,
      EmailAddress,
      EmailPromotion)
  SELECT  @Salutation,
      @FirstName,
      @MiddleName,
      @LastName,
      @NameStyle,
      @Phone,
      @Suffix,
      @EmailAddress,
      @EmailPromotion

  SELECT  @@IDENTITY
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[InsertContact]')
  and OBJECTPROPERTY(id, N'IsProcedure') = 1)
begin
  print 'Created Stored Procedure: AdventureWorks.InsertContact'
end

-- Drop AdventureWorks.GetContact
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[GetContact]')
  and OBJECTPROPERTY(id, N'IsProcedure') = 1)
begin
  drop procedure GetContact
  print 'Dropped Stored Procedure: AdventureWorks.GetContact'
end
go

-- Create AdventureWorks.GetContact
create procedure GetContact(
  @ContactID int
)
AS
  SELECT  ContactID,
      Salutation,
      FirstName,
      MiddleName,
      LastName,
      NameStyle,
      Phone,
      Suffix,
      EmailAddress,
      EmailPromotion,
      ModifiedDate
  FROM  Contact
  WHERE  ContactID = @ContactID
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[GetContact]')
  and OBJECTPROPERTY(id, N'IsProcedure') = 1)
begin
  print 'Created Stored Procedure: AdventureWorks.GetContact'
end
go


Step 2 - Creating the .NET Assembly for SQLCLR

This step will walk you through creating stored procedures in C# that will run within the SQLCLR.  The assembly created in this step contains the code for the following stored procedures that will be linked within Yukon Beta 1: CustOrdersDetailCLR, InsertOrderCLR, and InsertOrderSPCLR.

This step uses the System.Data.SqlServer namespace, which is new to Whidbey, the next version of Visual Studio.  Therefore, this project cannot be opened with previous versions of Visual Studio. 

Therefore, in order to compile this assembly, the .NET Framework shipped with Yukon Beta 1 must be used.

Step

Description

1.  Within the support files that accompany this document, open up the file 2-CLRSPs\SPs.cs to review it.  This file should look like the code listed below this table.
2.  Within the support files, ensure that 2-CLRSPs\CompileAdventureWorksSQLCLR.bat contains the correct path to csc.exe. SqlAccess.dll is used as a reference from the \BINN directory of the Yukon Beta 1 Installation. Please verify that this path is also correct. Once this is done, execute it to compile the .DLL.
3.  Ensure that AdventureWorksSQLCLR.dll has been compiled.

using System;
using System.Data;
using System.Data.SqlServer;
using System.Data.SqlTypes;

namespace AdventureWorksSQLCLR
{
  public class SPs
  {
    private SPs()
    {
      // This ensures that this class will not be instantiated since there is
      // no need to do so.
    }
    public static void GetContact(SqlInt32 ContactID)
    {
      // This function demonstrates how the SQLCLR can execute and display
      // SELECT statements by mimicing the CustOrdersDetail stored procedure.
      // Use System.Data.SqlServer.SqlContext to return a command object
      // within the context of the calling user
      SqlCommand cmd = SqlContext.GetCommand();

      // Create the SQL Statement
      string strSql = "SELECT  ContactID, Salutation, FirstName, MiddleName, LastName,
        NameStyle, Phone, Suffix, EmailAddress,  EmailPromotion, ModifiedDate ";
        
      strSql += " FROM Contact ";
      strSql += " WHERE ContactID = @ContactID";

      // Set the command text 
      cmd.CommandText = strSql;

      // Create one input parameters using the 
      // System.Data.SqlServer.SqlParameter object
      SqlParameter para = cmd.Parameters.Add("@ContactID", SqlDbType.Int);

      para.Value = ContactID;

      // Send this query to the relational engine using GetPipe()
      SqlContext.GetPipe().Execute(cmd);
    }

    public static void GetContactSP(SqlInt32 ContactID)
    {
      // This function demonstrates how the SQLCLR can execute and display
      // SELECT statements by mimicing the CustOrdersDetail stored procedure.
      // Use System.Data.SqlServer.SqlContext to return a command object
      // within the context of the calling user
      SqlCommand cmd = SqlContext.GetCommand();

      // Use the GetContact Stored Procedure
      string strSql = "GetContact";
      cmd.CommandType = CommandType.StoredProcedure;
      cmd.CommandText = strSql;

      // Create one input parameters using the 
      // System.Data.SqlServer.SqlParameter object
      SqlParameter para = cmd.Parameters.Add("@ContactID", SqlDbType.Int);

      para.Value = ContactID;

      // Send this query to the relational engine using GetPipe()
      SqlContext.GetPipe().Execute(cmd);
    }
    
    public static int InsertContact(SqlString Salutation, SqlString FirstName,
      SqlString MiddleName, SqlString LastName, SqlBoolean NameStyle,
      SqlString Phone, SqlString Suffix, SqlString EmailAddress, SqlInt32 EmailPromotion)
    {
      // This function demonstrates how the SQLCLR can execute and display
      // scalar statements by inserting an order.
      // Use System.Data.SqlServer.SqlContext to return a command object
      // within the context of the calling user
      SqlCommand cmd = SqlContext.GetCommand();
      string strSql = @"SET NOCOUNT ON ";
      strSql += " INSERT  Contact(Salutation, FirstName, MiddleName, 
        LastName, NameStyle, Phone, Suffix, EmailAddress, EmailPromotion) ";
        
      strSql += " SELECT  @Salutation, @FirstName, @MiddleName, 
        @LastName, @NameStyle, @Phone, @Suffix, @EmailAddress, @EmailPromotion ";
        
      strSql += " SELECT @@IDENTITY";

      cmd.CommandText = strSql;

      // Use the System.Data.SqlServer.SqlParameter object to create these input parameters
      SqlParameter para = null;
      para = cmd.Parameters.Add("@Salutation", SqlDbType.NVarChar);
      para.Value = Salutation;
      para = cmd.Parameters.Add("@FirstName", SqlDbType.NVarChar);
      para.Value = FirstName;
      para = cmd.Parameters.Add("@MiddleName", SqlDbType.NVarChar);
      para.Value = MiddleName;
      para = cmd.Parameters.Add("@LastName", SqlDbType.NVarChar);
      para.Value = LastName;
      para = cmd.Parameters.Add("@NameStyle", SqlDbType.Bit);
      para.Value = NameStyle;
      para = cmd.Parameters.Add("@Phone", SqlDbType.NVarChar);
      para.Value = Phone;
      para = cmd.Parameters.Add("@Suffix", SqlDbType.NVarChar);
      para.Value = Suffix;
      para = cmd.Parameters.Add("@EmailAddress", SqlDbType.NVarChar);
      para.Value = EmailAddress;
      para = cmd.Parameters.Add("@EmailPromotion", SqlDbType.Int);
      para.Value = EmailPromotion;
      
      // Execute this statement and convert the object returned to an integer
      // and return it.
      int orderID = Convert.ToInt32(cmd.ExecuteScalar());

      // Business Logic on orderID could be programmed here.
      // For example, if orderID > 0, use System.Web.Mail to send
      // email to confirm the order?
      return orderID;
    }

    public static int InsertContactSP(SqlString Salutation, SqlString FirstName,
      SqlString MiddleName, SqlString LastName, SqlBoolean NameStyle,
      SqlString Phone, SqlString Suffix, SqlString EmailAddress, SqlInt32 EmailPromotion)
    {
      // This function demonstrates how the SQLCLR can execute and display
      // scalar statements by inserting an order, using the T-SQL SP created earlier.
      // Use System.Data.SqlServer.SqlContext to return a command object
      // within the context of the calling user
      SqlCommand cmd = SqlContext.GetCommand();

      // Use the InsertOrder Stored Procedure
      string strSql = "InsertContact";

      cmd.CommandType = CommandType.StoredProcedure;
      cmd.CommandText = strSql;

      // Use the System.Data.SqlServer.SqlParameter object to create these input parameters
      SqlParameter para = null;
      para = cmd.Parameters.Add("@Salutation", SqlDbType.NVarChar);
      para.Value = Salutation;
      para = cmd.Parameters.Add("@FirstName", SqlDbType.NVarChar);
      para.Value = FirstName;
      para = cmd.Parameters.Add("@MiddleName", SqlDbType.NVarChar);
      para.Value = MiddleName;
      para = cmd.Parameters.Add("@LastName", SqlDbType.NVarChar);
      para.Value = LastName;
      para = cmd.Parameters.Add("@NameStyle", SqlDbType.Bit);
      para.Value = NameStyle;
      para = cmd.Parameters.Add("@Phone", SqlDbType.NVarChar);
      para.Value = Phone;
      para = cmd.Parameters.Add("@Suffix", SqlDbType.NVarChar);
      para.Value = Suffix;
      para = cmd.Parameters.Add("@EmailAddress", SqlDbType.NVarChar);
      para.Value = EmailAddress;
      para = cmd.Parameters.Add("@EmailPromotion", SqlDbType.Int);
      para.Value = EmailPromotion;

      // Execute this statement and convert the object returned to an integer
      // and return it.
      int orderID = Convert.ToInt32(cmd.ExecuteScalar());

      // Business Logic on orderID could be programmed here.
      // For example, if orderID > 0, use System.Web.Mail to send
      // email to confirm the order?
      return orderID;
    }
  }
}

A Little More About the SqlContext Class

The SqlContext class encapsulates information about the caller's context, which can be used from within a database object defined using the CLR.

This class should be used instead of ADO.NET classes when executing TSQL statements or calling programmability objects within the current server. When it is necessary to communicate with another server, use the ADO.NET framework.

For more information about the SqlContext class, please refer to the following the SqlContext Class article within SQL Books Online. To view the members of the SqlContext class, refer to the "SqlContext Members" article within SQL Books Online.



Step 3 - Linking C# Classes to Stored Procedures

This section will link the C# functions created in the previous step to stored procedure names that be called in the same fashion as a traditional stored procedure implemented in T-SQL. To perform this step, do the following steps:

Step

Description

1.  Open SQL Server Workbench
2.  Execute the following as an administrator on the SQL Server after replacing "{REPLACE WITH PATH TO SUPPORT FILES}" with the directory name where the support files were extracted.

use AdventureWorks

-- Drop all CLR stored procedures before dropping assembly since it cannot be dropped with dependencies
if object_id('GetContactCLR') is not null
begin
  drop procedure GetContactCLR
  print 'Dropped Stored Procedure: GetContactCLR'
end
go
if object_id('GetContactSPCLR') is not null
begin
  drop procedure GetContactSPCLR
  print 'Dropped Stored Procedure: GetContactSPCLR'
end
go
if object_id('InsertContactCLR') is not null
begin
  drop procedure InsertContactCLR
  print 'Dropped Stored Procedure: InsertContactCLR'
end
go
if object_id('InsertContactSPCLR') is not null
begin
  drop procedure InsertContactSPCLR
  print 'Dropped Stored Procedure: InsertContactSPCLR'
end
go

-- Drop the assembly if it already exists
if exists (select * from sys.assemblies where name = 'AdventureWorksSQLCLR')
begin
    drop assembly AdventureWorksSQLCLR
  print 'Dropped Assembly: AdventureWorksSQLCLR'
end  
go

-- Execute CREATE ASSEMBLY which allows stored procedures to link to functions within this DLL
-- Note that the assembly name following CREATE ASSEMBLY matches the name of the .DLL
CREATE ASSEMBLY AdventureWorksSQLCLR
FROM '{REPLACE WITH PATH TO SUPPORT FILES}\2-CLRSPs\AdventureWorksSQLCLR.dll'
if exists (select * from sys.assemblies where name = 'AdventureWorksSQLCLR')
begin
  print 'Created Assembly: AdventureWorksSQLCLR'  
end
go



-- Create Procedure GetContactCLR to map to function in managed code
-- Syntax when using EXTERNAL NAME is (AssemblyName):[(Namespace).(Class)]::(Function)

-- Use EXECUTE AS OWNER to avoid having to give SELECT permissions on 
-- Products, [Order Details] to the calling user
-- Note: This is scheduled to change post Beta 1 to "WITH EXECUTE AS OWNER"
CREATE PROCEDURE GetContactCLR
  @ContactId int
WITH EXECUTE AS USER = dbo
as
EXTERNAL NAME AdventureWorksSQLCLR:[AdventureWorksSQLCLR.SPs]::GetContact
go
if object_id('GetContactCLR') is not null
  print 'Created Stored Procedure: GetContactCLR'
go

-- Create GetContactSPCLR
CREATE PROCEDURE GetContactSPCLR
  @ContactId int
WITH EXECUTE AS USER = dbo
as
EXTERNAL NAME AdventureWorksSQLCLR:[AdventureWorksSQLCLR.SPs]::GetContactSP
go
if object_id('GetContactSPCLR') is not null
  print 'Created Stored Procedure: GetContactSPCLR'
go


-- Create the InsertContactCLR stored procedure
CREATE PROCEDURE InsertContactCLR
  @Salutation nvarchar(8),
  @FirstName nvarchar(50),
  @MiddleName nvarchar(50),
  @LastName nvarchar(50),
  @NameStyle bit,
  @Phone nvarchar(25),
  @Suffix nvarchar(10),
  @EmailAddress nvarchar(50),
  @EmailPromotion int
WITH EXECUTE AS USER = dbo
as
EXTERNAL NAME AdventureWorksSQLCLR:[AdventureWorksSQLCLR.SPs]::InsertContact
go
if object_id('InsertContactCLR') is not null
begin
  print 'Created Stored Procedure: InsertContactCLR'
end
go


-- Create the InsertContactSPCLR stored procedure
CREATE PROCEDURE InsertContactSPCLR
  @Salutation nvarchar(8),
  @FirstName nvarchar(50),
  @MiddleName nvarchar(50),
  @LastName nvarchar(50),
  @NameStyle bit,
  @Phone nvarchar(25),
  @Suffix nvarchar(10),
  @EmailAddress nvarchar(50),
  @EmailPromotion int
WITH EXECUTE AS USER = dbo
as
EXTERNAL NAME AdventureWorksSQLCLR:[AdventureWorksSQLCLR.SPs]::InsertContactSP
go
if object_id('InsertContactSPCLR') is not null
begin
  print 'Created Stored Procedure: InsertContactSPCLR'
end
go

A Little More About WITH EXECUTE AS

When stored procedures are created within the SQLCLR using the SqlContext class, the ownership chain is broken. In other words, SqlContext assumes the security context of the user and needs security rights to perform any SQL statements executed.

A common security practice is to give users access to the stored procedures needed and not access to the particular tables. Without using WITH EXECUTE AS USER = dbo, it would be necessary to grant SELECT/INSERT/DELETE/etc rights to every calling user that uses the stored procedure. Of course there are situations where this may be desired, but developers should research how each SQLCLR stored procedure should be executed.

Please refer to the SQL Books Online article "EXECUTE AS" for more information.



Step 4 - Reserving the HTTP Namespace

Internally within HTTP.SYS, HTTP namespaces are used to determine which process should handle incoming HTTP requests. Therefore, it is needed to reserve an HTTP namespace so that HTTP requests can be passed to the Yukon Beta 1 server.

In order to reserve the namespace, it can be done either implicitly or explicitly. Implicitly reserving a namespace is done by calling CREATE HTTP ENDPOINT without calling sp_reserve_http_namespace beforehand. Explicitly reserving a namespace is done by executing the sp_reserve_http_namespace stored procedure. Although it is not necessary to explicitly reserve a namespace, it is the recommended practice.

Explicitly reserving a namespace is done by calling sp_reserve_http_namespace. This reserves a URL and all potential subtrees within the URL. Subsequent HTTP ENDPOINT DDL statements will only need sysadmin security rights and do not require Windows administrator rights.

If sp_reserve_http_namespace is not called, each HTTP ENDPOINT DDL statement implicitly reserves the namespace on the kernel. The disadvantage to this is that the client may need both sysadmin and Windows administrator rights with every HTTP ENDPOINT DDL statement.

This example will reserve the \sql tree so that any subsequent HTTP ENDPOINTS statements that use a URL anywhere underneath the \sql tree will not require Windows administrator rights.


To reserve an HTTP namespace, perform the following steps:

Step

Description

1.  Ensure that you are running as an administrator within the Windows Server where the SQL Server resides
2.  Open SQL Workbench
3.  Execute the following as an administrator on the SQL Server

exec sp_reserve_http_namespace N'http://*:80/sql'
go

For more information on namespace reservation, please refer to the article " URL NAMESPACE Reservation (Managing HTTP Endpoints)" within SQL Server Books Online.

The Books Online article mentioned above contains a reference to httpcfg.exe. To install httpcfg.exe, perform these steps:

Step

Description

1.  Insert the Windows Server 2003 CD in the CD-ROM or DVD-ROM drive.
2.  When the CD opens, click Perform Additional Tasks.
3.  Click Browse this CD.
4.  Double-click Support.
5.  Double-click Tools.
6.  Double-click SUPTOOLS.MSI.
7.  Click Next, type your information in the Name and Organization boxes, click Next, and then click Next on the following screen.
8.  Click Next again to start the installation.
9.  Click Finish.



Step 5 - Creating the HTTP ENDPOINT

In this step, the stored procedures created in C# and TSQL are exposed on a HTTP ENDPOINT. The ENDPOINT will also allow any ad hoc SQL batch queries to be executed and handled in this example.

To create the endpoint, please follow these steps:

Step

Description

1.  Open SQL Server Workbench
2.  Execute the following as an administrator on the SQL Server

if exists(select * from sys.http_endpoints where name = 'sql_AdventureWorks_endpoint')
begin
  drop http endpoint sql_AdventureWorks_endpoint
  print 'Dropped HTTP ENDPOINT: sql_AdventureWorks_endpoint'
end
go

CREATE HTTP ENDPOINT sql_AdventureWorks_endpoint 
AS
    SITE = '*',  
    PATH = '/sql/AdventureWorks', 
    AUTHENTICATION = (INTEGRATED),
    PORTS = ( CLEAR ),
    CLEAR_PORT = 80,
    STATE = STARTED
FOR SOAP (
  WEBMETHOD 'http://AdventureWorks/'.'GetContact' 
              (name=AdventureWorks.dbo.GetContact, 
               schema=STANDARD ), 
  WEBMETHOD 'http://AdventureWorks/'.'GetContactNoSchema' 
              (name=AdventureWorks.dbo.GetContact, 
               schema=NONE ),
  WEBMETHOD 'http://AdventureWorks/'.'GetContactCLR' 
              (name=AdventureWorks.dbo.GetContactCLR, 
               schema=STANDARD ),
  WEBMETHOD 'http://AdventureWorks/'.'GetContactSPCLR' 
              (name=AdventureWorks.dbo.GetContactSPCLR, 
               schema=STANDARD ),
  WEBMETHOD 'http://AdventureWorks/'.'InsertContact' 
              (name=AdventureWorks.dbo.InsertContact, 
               schema=STANDARD ),
  WEBMETHOD 'http://AdventureWorks/'.'InsertContactCLR' 
              (name=AdventureWorks.dbo.InsertContactCLR, 
               schema=STANDARD ),
  WEBMETHOD 'http://AdventureWorks/'.'InsertContactSPCLR' 
              (name=AdventureWorks.dbo.InsertContactSPCLR, 
               schema=STANDARD )
  WITH
    WSDL = ENABLED,
    BATCHES = ENABLED,
    DATABASE = 'AdventureWorks',
    NAMESPACE = 'http://AdventureWorks/'
  ) 
go
if exists(select * from sys.http_endpoints where name = 'sql_AdventureWorks_endpoint')
begin
  print 'Created HTTP ENDPOINT: sql_AdventureWorks_endpoint'
end  
go

For more information on creating endpoints, please refer to "Create HTTP Endpoint" within SQL Books Online.



Step 6 - Creating Client Application using HttpWebRequest and HttpWebResponse

This section describes how to use the HttpWebRequest and HttpWebResponse classes to communicate with the SQL Server and to see the SOAP packets passed.  This is NOT the recommended way to build applications that communicate with Yukon Beta 1 since there are classes such as the ones auto-generated
by WSDL.exe that should be leveraged when building your applications on top of SOAP.  However, this example allows the user to see the SOAP request
and response packets handled by Yukon Beta 1.

The easiest way to perform this step is to simply run CompileHttpWebRequestApp.bat from the 6-HttpWebRequestApp directory. This batch file creates HttpWebRequestApp.exe which is a console application.

If you are using Visual Studio .NET and would like to create the HttpWebRequestApp project from scratch that way you can execute it within a debugger, perform the following steps:

Step

Description

1.  Open Visual Studio .NET
2.  Click File->New->Project->Visual C# Projects->Console Application
3.  Set the Name to HttpWebRequestApp
4.  Right click on the project HttpWebRequestApp within the Solution Explorer and click on Add Existing Item
5.  Add BOTH Arguments.cs and HttpWebRequestApp.cs from the 6-HttpWebRequestApp directory to the project

The code that is now open within Visual Studio .NET performs the following tasks:

Step

Description

1.  When the application is first loaded, the arguments are parsed and validated using the Arguments class defined in Arguments.cs. The Arguments class parses the command line arguments into a StringDictionary class. This is helpful so that any command line arguments can be accessed by name rather than by position.
2.  Using the FileStream class, the input file specified is read.
3.  If an output file is specified, the output stream is set to write to this file using a StreamWriter class.
4.  Using the WebRequest.Create() function, a new HttpWebRequest is instantiated for the URI specified.
5.  The contents of the input file are written to the request stream of HttpWebRequest.
6.  Using the HttpWebResponse.GetResponse() method, the response is synchronously retrieved from the server.
7.  An instance of XmlDocument is used to properly format the contents of the response retrieved from the server.
8.  XmlDocument.Save() is used to output the response from Yukon Beta 1.

The following table describes the command line arguments used by the application:

Argument Name Required Description
Input X This specifies the input filename which contains the SOAP packet to be sent to the database. There are sample .XML files within the \bin\Debug directory that call all of the methods exposed from the HTTP Endpoint created earlier.
URI X This specifies the URI of the database. If you are using the local system, use http://localhost/sql/AdventureWorks to connect to HTTP Endpoint created.
Output   If specified, this is the output file to use instead of stdout
Timeout   If specified, this specifies the timeout period to wait before canceling the request, overriding the default timeout period.
Unformatted   If specified, this causes the output from Yukon Beta 1 to displayed as is, without any formatting.

To execute this program, either run the executable created by compiling the project, or perform the following tasks to execute the program from within the Visual Studio .NET debugger:

Step

Description

1.  Right click on the HttpWebRequestApp project within the Solution Explorer
2.  Select Properties->Configuration Properties->Debugging
3.  Under Start Options, Set the Command Line Arguments to “-input=..\..\SampleInputXMLFiles\GetContactSPCLR.xml –uri=http://localhost/sql/AdventureWorks”
4.  Hit F5

The following additional XML input files have been included in the support files in the 6-HttpWebRequestApp\SampleXMLInputFiles directory:

Filename WebMethod Called
GetContact.xml GetContact
GetContactNoSchema.xml GetContactNoSchema
GetContactCLR.xml GetContactCLR
GetContactSPCLR.xml GetContactSPCLR
InsertContact.xml InsertContact
InsertContactCLR.xml InsertContactCLR
InsertContactSPCLR.xml InsertContactSPCLR
BatchStatements.xml Arbitrary ad hoc SQL statements

The following is a listing of the code used to create this application:

using System;
using System.Net;
using System.IO;
using System.Xml;


namespace HttpWebRequestApp
{
  /// <summary>
  /// Summary description for Class1.
  /// </summary>
  class HttpWebRequestApp
  {
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    /// 

    static private string mURI;
    static private string mInputFile;
    static private string mOutputFile;
    static private bool mFormatted = true;
    static private int mTimeout = 0;
    static private TextWriter outWriter = Console.Out;

    [STAThread]
    static void Main(string[] args)
    {
      try
      {
        // Parse and Validate Arguments
        ParseArguments(args);

        // Read the contents of mInputFile
        FileStream inputStream = new FileStream(mInputFile, FileMode.Open,
          FileAccess.Read, FileShare.Read);
        int inputLength = (int)inputStream.Length;
        byte[] inputBody = new byte[inputLength];
        inputStream.Read(inputBody, 0, inputLength);
        inputStream.Close();
        
        // Open the output file if specified
        if(null != mOutputFile)
        {
          outWriter = new StreamWriter(new FileStream(mOutputFile,
            FileMode.Create, FileAccess.Write));
        }
          
        // Create WebRequest and set headers
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(mURI);
        req.Credentials = CredentialCache.DefaultCredentials;
        req.Method = "POST";
        req.ProtocolVersion = HttpVersion.Version11;
        req.ContentType = "text/xml";
        req.ContentLength = inputLength;
        if(0 < mTimeout)
          req.Timeout = mTimeout;
        
        // Write the input to the request stream
        Stream reqStream = req.GetRequestStream();
        reqStream.Write(inputBody, 0, inputLength);
        reqStream.Close();
        
        // Synchronously get the response and output it
        OutputWebResponse((HttpWebResponse)req.GetResponse());
      }
      catch(IOException e)
      {
        // IOException thrown when file IO exception on input/output file occurs
        outWriter.WriteLine(e.Message);
      }
      catch(ArgumentException)
      {
        // ArgumentException Throw by ParseArguments when InputFile or URI not specified
        DisplayUsage();
      }
      catch(WebException e)
      {
        // Display any web exceptions that occur when sending request to server
        outWriter.WriteLine("WebException Occurred:");
        outWriter.WriteLine();
        outWriter.WriteLine();
        if(null != e.Response)
        {
          OutputWebResponse((HttpWebResponse)e.Response);
        }
        else
        {
          outWriter.WriteLine(e.Message);
        }
      }
      catch
      {
        // Display any other exceptions
        outWriter.WriteLine("Unexpected Exception Occurred in Main\n\n");
        throw;
      }
      finally
      {
        // If displaying to the Console, ReadLine()
        if(Console.Out == outWriter)
        {
          Console.WriteLine("\n\nPress Enter to Continue");
          Console.ReadLine();
        }
      }
    }

    static private void OutputWebResponse(HttpWebResponse resp)
    {
      try
      {
        // Use the response stream to input into a XmlDocument
        Stream respStream = resp.GetResponseStream();
        StreamReader sr = new StreamReader(respStream);
        
        // Display the Status
        outWriter.WriteLine("Response Received:");
        outWriter.WriteLine();
        outWriter.WriteLine("Status Code       : {0}", (int)resp.StatusCode);
        outWriter.WriteLine("Status Description: {0}", resp.StatusDescription);
        outWriter.WriteLine();

        if(mFormatted)
        {
          // Output a formatted XML document
          // Use XmlDocument so that the returned XML is properly formatted
          XmlDocument xmld = new XmlDocument();
          xmld.LoadXml(sr.ReadToEnd());
          xmld.Save(outWriter);
        }
        else
        {
          // Display output without formatting
          outWriter.WriteLine(sr.ReadToEnd());
        }
        outWriter.Flush();
      }
      catch
      {
        outWriter.WriteLine("An Error Occured While Outputting WebResponse");
        throw;
      }
    }

    static private void ParseArguments(string[] args)
    {
      // Use the Arguments class set the member variables
      Arguments myArgs = new Arguments(args);
      if(null != myArgs["uri"])
        mURI = myArgs["uri"];
      if(null != myArgs["input"])
        mInputFile = myArgs["input"];
      if(null != myArgs["timeout"])
        mTimeout = Convert.ToInt32(myArgs["timeout"]);
      if(null != myArgs["output"])
        mOutputFile = myArgs["output"];
      if(null != myArgs["unformatted"] && "true" == myArgs["unformatted"])
        mFormatted = false;

      if(null != mInputFile && null != mURI)
      {
        // Necessary arguments were passed
        if(!File.Exists(mInputFile))
        {
          throw new IOException("Invalid Filename Specified: " + mInputFile);
        }
      }
      else
      {
        throw new ArgumentException("Invalid Arguments Specified");
      }
    }
    static private void DisplayUsage()
    {
      // Display the usage to the screen
      string help_text = " Usage: ";
      help_text += " -uri=<uri> -input=<filename> 
        [-timeout=<waittime>] [-output=<filename>]
        [-unformatted]\n";
      help_text +=  "'uri' specifies the URI\n";
      help_text +=  "'input' specifies the input file\n";
      help_text +=  "'timeout' specifies the time in milliseconds
        to wait before timing out\n";
      help_text +=  "'output' specifies the output file.  If 
        omitted, stdout will be used\n";
      help_text +=  "'unformatted' causes the output from Yukon
        Beta 1 to be displayed as is, without any formatting\n";
      outWriter.WriteLine(help_text);
    }
  }
}




Step 7 - Creating Client Application Using Proxy Class Generated by WSDL.EXE

This section provides a sample application created on top of the proxy class generated using WSDL.EXE. This is a better example of how to call Yukon's web services from a client application that the previous step.

Unfortunately, aspects of this application are not supported in versions prior to Whidbey, so this applcation cannot be fully created within version of Visual Studio prior to the upcoming next major release of VS. However, the application can be compiled using the .NET Framework installed with Yukon.

There are two .cs files included to create this application, AdventureWorksProxy.cs and Reference.cs. AdventureWorksProxy.cs contains the application code. Reference.cs was created by WSDL.EXE by using Visual Studio to add a web reference to http://localhost/sql/AdventureWorks?wsdl. This process creates a .cs file which contains a class that is a derivation of System.Web.Services.Protocols.SoapHttpClientProtocol. The class is created by analyzing the HTTP ENDPOINT and setting up appropriate methods to call the web methods exposed.

The easiest way to perform this step is to simply run CompileAdventureWorksProxyApp.bat from the 7-AdventureWorksProxyApp directory. This batch file will use the .NET Framework installed with Yukon to create the Windows application and execute it.

Step

Description

1.  Navigate to the 7-AdventureWorksProxyApp directory
2.  Execute CompileRunAdventureWorksProxyApp.bat. The application should also execute from this batch file. This application should appear like the following screen shot.

This application works by calling the methods generated by WSDL.EXE. The following is a code listing of ApplicationWorksProxy.cs.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text;

namespace AdventureWorksProxy
{
  /// <summary>
  /// Summary description for Form1.
  /// </summary>
  ///

  public class frmAdventureWorks : System.Windows.Forms.Form
  {
    private System.Windows.Forms.Label lblSqlBatch;
    private System.Windows.Forms.TextBox txtSqlBatch;
    private System.Windows.Forms.Label lblOutput;
    private System.Windows.Forms.Button btnSqlBatch;
    /// 

    /// Required designer variable.
    /// 
    
    private System.ComponentModel.Container components = null;
    private System.Windows.Forms.TextBox txtOutput;
    private System.Windows.Forms.Button btnGetContact;
    private System.Windows.Forms.Label lblContactId;
    private System.Windows.Forms.TextBox txtGetContactId;
    private System.Windows.Forms.ControlArray cArrayGetContact;
    private System.Windows.Forms.Button btnGetContactCLR;
    private System.Windows.Forms.Button btnGetContactSPCLR;
    private System.Windows.Forms.Button btnInsertContact;
    private System.Windows.Forms.Button btnInsertContactCLR;
    private System.Windows.Forms.ControlArray cArrayInsertContact;
    private System.Windows.Forms.Button btnInsertContactSPCLR;
    private System.Windows.Forms.Label lblSaluation;
    private System.Windows.Forms.Label lblFirstName;
    private System.Windows.Forms.Label lblLastName;
    private System.Windows.Forms.Label lblNameStyle;
    private System.Windows.Forms.Label lblPhone;
    private System.Windows.Forms.Label lblSuffix;
    private System.Windows.Forms.Label lblEmail;
    private System.Windows.Forms.Label lblEmailPromotion;
    private System.Windows.Forms.TextBox txtSaluation;
    private System.Windows.Forms.TextBox txtFirstName;
    private System.Windows.Forms.TextBox txtLastName;
    private System.Windows.Forms.Label lblMiddleName;
    private System.Windows.Forms.TextBox txtMiddleName;
    private System.Windows.Forms.TextBox txtEmailPromotion;
    private System.Windows.Forms.TextBox txtSuffix;
    private System.Windows.Forms.TextBox txtPhone;
    private System.Windows.Forms.TextBox txtEmail;
    private System.Windows.Forms.ComboBox cboNameStyle;

    private prxyAdventureWorks.sql_AdventureWorks_endpoint mProxy;

    public frmAdventureWorks()
    {
      //
      // Required for Windows Form Designer support
      //
      InitializeComponent();

      //
      // TODO: Add any constructor code after InitializeComponent call
      //
    }

    /// 

    /// Clean up any resources being used.
    /// 
    
    protected override void Dispose( bool disposing )
    {
      if( disposing )
      {
        if (components != null) 
        {
          components.Dispose();
        }
      }
      base.Dispose( disposing );
    }

    #region Windows Form Designer generated code
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
      this.lblSqlBatch = new System.Windows.Forms.Label();
      this.txtSqlBatch = new System.Windows.Forms.TextBox();
      this.lblOutput = new System.Windows.Forms.Label();
      this.btnSqlBatch = new System.Windows.Forms.Button();
      this.txtOutput = new System.Windows.Forms.TextBox();
      this.btnGetContact = new System.Windows.Forms.Button();
      this.lblContactId = new System.Windows.Forms.Label();
      this.txtGetContactId = new System.Windows.Forms.TextBox();
      this.btnGetContactCLR = new System.Windows.Forms.Button();
      this.cArrayGetContact = new System.Windows.Forms.ControlArray();
      this.btnGetContactSPCLR = new System.Windows.Forms.Button();
      this.btnInsertContact = new System.Windows.Forms.Button();
      this.btnInsertContactCLR = new System.Windows.Forms.Button();
      this.cArrayInsertContact = new System.Windows.Forms.ControlArray();
      this.btnInsertContactSPCLR = new System.Windows.Forms.Button();
      this.lblSaluation = new System.Windows.Forms.Label();
      this.lblFirstName = new System.Windows.Forms.Label();
      this.lblLastName = new System.Windows.Forms.Label();
      this.lblNameStyle = new System.Windows.Forms.Label();
      this.lblPhone = new System.Windows.Forms.Label();
      this.lblSuffix = new System.Windows.Forms.Label();
      this.lblEmail = new System.Windows.Forms.Label();
      this.lblEmailPromotion = new System.Windows.Forms.Label();
      this.txtSaluation = new System.Windows.Forms.TextBox();
      this.txtFirstName = new System.Windows.Forms.TextBox();
      this.txtLastName = new System.Windows.Forms.TextBox();
      this.txtEmailPromotion = new System.Windows.Forms.TextBox();
      this.txtSuffix = new System.Windows.Forms.TextBox();
      this.txtPhone = new System.Windows.Forms.TextBox();
      this.txtEmail = new System.Windows.Forms.TextBox();
      this.lblMiddleName = new System.Windows.Forms.Label();
      this.txtMiddleName = new System.Windows.Forms.TextBox();
      this.cboNameStyle = new System.Windows.Forms.ComboBox();
      this.SuspendLayout();

      // 
      // lblSqlBatch
      // 
      this.lblSqlBatch.Location = new System.Drawing.Point(520, 10);
      this.lblSqlBatch.Name = "lblSqlBatch";
      this.lblSqlBatch.Size = new System.Drawing.Size(216, 24);
      this.lblSqlBatch.TabIndex = 0;
      this.lblSqlBatch.Text = "SQL Batch Statements:";

      // 
      // txtSqlBatch
      // 
      this.txtSqlBatch.Location = new System.Drawing.Point(231, 34);
      this.txtSqlBatch.Multiline = true;
      this.txtSqlBatch.Name = "txtSqlBatch";
      this.txtSqlBatch.Size = new System.Drawing.Size(786, 115);
      this.txtSqlBatch.TabIndex = 0;
      this.txtSqlBatch.Text = "select top 10 * from address";

      // 
      // lblOutput
      // 
      this.lblOutput.Font = new System.Drawing.Font("Microsoft Sans Serif",
        14.25F, System.Drawing.FontStyle.Bold,
        System.Drawing.GraphicsUnit.Point, ((byte)(0)));
      this.lblOutput.Location = new System.Drawing.Point(448, 421);
      this.lblOutput.Name = "lblOutput";
      this.lblOutput.Size = new System.Drawing.Size(84, 22);
      this.lblOutput.TabIndex = 2;
      this.lblOutput.Text = "Output:";

      // 
      // btnSqlBatch
      // 
      this.btnSqlBatch.Location = new System.Drawing.Point(74, 79);
      this.btnSqlBatch.Name = "btnSqlBatch";
      this.btnSqlBatch.Size = new System.Drawing.Size(136, 32);
      this.btnSqlBatch.TabIndex = 1;
      this.btnSqlBatch.Text = "Execute SQL Batch";
      this.btnSqlBatch.Click += new System.EventHandler(this.btnSqlBatch_Click);

      // 
      // txtOutput
      // 
      this.txtOutput.Location = new System.Drawing.Point(11, 453);
      this.txtOutput.Multiline = true;
      this.txtOutput.Name = "txtOutput";
      this.txtOutput.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
      this.txtOutput.Size = new System.Drawing.Size(1023, 304);
      this.txtOutput.TabIndex = 18;

      // 
      // btnGetContact
      // 
      this.btnGetContact.Location = new System.Drawing.Point(78, 168);
      this.btnGetContact.Name = "btnGetContact";
      this.btnGetContact.Size = new System.Drawing.Size(133, 32);
      this.btnGetContact.TabIndex = 3;
      this.btnGetContact.Text = "GetContact";

      // 
      // lblContactId
      // 
      this.lblContactId.Location = new System.Drawing.Point(236, 176);
      this.lblContactId.Name = "lblContactId";
      this.lblContactId.Size = new System.Drawing.Size(58, 18);
      this.lblContactId.TabIndex = 9;
      this.lblContactId.Text = "ContactId:";

      // 
      // txtGetContactId
      // 
      this.txtGetContactId.Location = new System.Drawing.Point(306, 176);
      this.txtGetContactId.Name = "txtGetContactId";
      this.txtGetContactId.Size = new System.Drawing.Size(136, 19);
      this.txtGetContactId.TabIndex = 2;
      this.txtGetContactId.Text = "1";

      // 
      // btnGetContactCLR
      // 
      this.btnGetContactCLR.Location = new System.Drawing.Point(78, 208);
      this.btnGetContactCLR.Name = "btnGetContactCLR";
      this.btnGetContactCLR.Size = new System.Drawing.Size(133, 32);
      this.btnGetContactCLR.TabIndex = 4;
      this.btnGetContactCLR.Text = "GetContactCLR";

      // 
      // cArrayGetContact
      // 
      this.cArrayGetContact.Name = "cArrayGetContact";
      this.cArrayGetContact.Click += new System.EventHandler(this.cArrayGetContact_Click);
      this.cArrayGetContact.AddRange(new System.Windows.Forms.Control[] {
        this.btnGetContact, this.btnGetContactCLR, this.btnGetContactSPCLR
      });

      // 
      // btnGetContactSPCLR
      // 
      this.btnGetContactSPCLR.Location = new System.Drawing.Point(78, 244);
      this.btnGetContactSPCLR.Name = "btnGetContactSPCLR";
      this.btnGetContactSPCLR.Size = new System.Drawing.Size(133, 32);
      this.btnGetContactSPCLR.TabIndex = 5;
      this.btnGetContactSPCLR.Text = "GetContactSPCLR";

      // 
      // btnInsertContact
      // 
      this.btnInsertContact.Location = new System.Drawing.Point(82, 297);
      this.btnInsertContact.Name = "btnInsertContact";
      this.btnInsertContact.Size = new System.Drawing.Size(128, 32);
      this.btnInsertContact.TabIndex = 15;
      this.btnInsertContact.Text = "InsertContact";

      // 
      // btnInsertContactCLR
      // 
      this.btnInsertContactCLR.Location = new System.Drawing.Point(82, 334);
      this.btnInsertContactCLR.Name = "btnInsertContactCLR";
      this.btnInsertContactCLR.Size = new System.Drawing.Size(128, 32);
      this.btnInsertContactCLR.TabIndex = 16;
      this.btnInsertContactCLR.Text = "InsertContactCLR";

      // 
      // cArrayInsertContact
      // 
      this.cArrayInsertContact.Name = "cArrayInsertContact";
      this.cArrayInsertContact.Click += new System.EventHandler(this.cArrayInsertContact_Click);
      this.cArrayInsertContact.AddRange(new System.Windows.Forms.Control[] {
        this.btnInsertContact, this.btnInsertContactCLR, this.btnInsertContactSPCLR
      });

      // 
      // btnInsertContactSPCLR
      // 
      this.btnInsertContactSPCLR.Location = new System.Drawing.Point(82, 372);
      this.btnInsertContactSPCLR.Name = "btnInsertContactSPCLR";
      this.btnInsertContactSPCLR.Size = new System.Drawing.Size(128, 32);
      this.btnInsertContactSPCLR.TabIndex = 17;
      this.btnInsertContactSPCLR.Text = "InsertContactSPCLR";

      // 
      // lblSaluation
      // 
      this.lblSaluation.Location = new System.Drawing.Point(230, 294);
      this.lblSaluation.Name = "lblSaluation";
      this.lblSaluation.Size = new System.Drawing.Size(72, 16);
      this.lblSaluation.TabIndex = 16;
      this.lblSaluation.Text = "Saluation:";

      // 
      // lblFirstName
      // 
      this.lblFirstName.Location = new System.Drawing.Point(231, 324);
      this.lblFirstName.Name = "lblFirstName";
      this.lblFirstName.Size = new System.Drawing.Size(72, 16);
      this.lblFirstName.TabIndex = 17;
      this.lblFirstName.Text = "First Name:";

      // 
      // lblLastName
      // 
      this.lblLastName.Location = new System.Drawing.Point(228, 376);
      this.lblLastName.Name = "lblLastName";
      this.lblLastName.Size = new System.Drawing.Size(72, 16);
      this.lblLastName.TabIndex = 18;
      this.lblLastName.Text = "Last Name:";

      // 
      // lblNameStyle
      // 
      this.lblNameStyle.Location = new System.Drawing.Point(230, 404);
      this.lblNameStyle.Name = "lblNameStyle";
      this.lblNameStyle.Size = new System.Drawing.Size(72, 16);
      this.lblNameStyle.TabIndex = 19;
      this.lblNameStyle.Text = "NameStyle:";

      // 
      // lblPhone
      // 
      this.lblPhone.Location = new System.Drawing.Point(598, 297);
      this.lblPhone.Name = "lblPhone";
      this.lblPhone.Size = new System.Drawing.Size(64, 16);
      this.lblPhone.TabIndex = 20;
      this.lblPhone.Text = "Phone:";

      // 
      // lblSuffix
      // 
      this.lblSuffix.Location = new System.Drawing.Point(598, 329);
      this.lblSuffix.Name = "lblSuffix";
      this.lblSuffix.Size = new System.Drawing.Size(64, 16);
      this.lblSuffix.TabIndex = 21;
      this.lblSuffix.Text = "Suffix";

      // 
      // lblEmail
      // 
      this.lblEmail.Location = new System.Drawing.Point(598, 353);
      this.lblEmail.Name = "lblEmail";
      this.lblEmail.Size = new System.Drawing.Size(64, 16);
      this.lblEmail.TabIndex = 23;
      this.lblEmail.Text = "Email:";

      // 
      // lblEmailPromotion
      // 
      this.lblEmailPromotion.Location = new System.Drawing.Point(598, 386);
      this.lblEmailPromotion.Name = "lblEmailPromotion";
      this.lblEmailPromotion.Size = new System.Drawing.Size(94, 17);
      this.lblEmailPromotion.TabIndex = 22;
      this.lblEmailPromotion.Text = "Email Promotion:";

      // 
      // txtSaluation
      // 
      this.txtSaluation.Location = new System.Drawing.Point(305, 294);
      this.txtSaluation.MaxLength = 8;
      this.txtSaluation.Name = "txtSaluation";
      this.txtSaluation.Size = new System.Drawing.Size(74, 19);
      this.txtSaluation.TabIndex = 6;
      this.txtSaluation.Text = "Mr.";

      // 
      // txtFirstName
      // 
      this.txtFirstName.Location = new System.Drawing.Point(305, 324);
      this.txtFirstName.MaxLength = 50;
      this.txtFirstName.Name = "txtFirstName";
      this.txtFirstName.Size = new System.Drawing.Size(253, 19);
      this.txtFirstName.TabIndex = 7;
      this.txtFirstName.Text = "Jason";

      // 
      // txtLastName
      // 
      this.txtLastName.Location = new System.Drawing.Point(306, 375);
      this.txtLastName.MaxLength = 50;
      this.txtLastName.Name = "txtLastName";
      this.txtLastName.Size = new System.Drawing.Size(252, 19);
      this.txtLastName.TabIndex = 9;
      this.txtLastName.Text = "Stowe";

      // 
      // txtEmailPromotion
      // 
      this.txtEmailPromotion.Location = new System.Drawing.Point(693, 383);
      this.txtEmailPromotion.MaxLength = 10;
      this.txtEmailPromotion.Name = "txtEmailPromotion";
      this.txtEmailPromotion.Size = new System.Drawing.Size(59, 19);
      this.txtEmailPromotion.TabIndex = 14;
      this.txtEmailPromotion.Text = "1";

      // 
      // txtSuffix
      // 
      this.txtSuffix.Location = new System.Drawing.Point(693, 319);
      this.txtSuffix.MaxLength = 10;
      this.txtSuffix.Name = "txtSuffix";
      this.txtSuffix.Size = new System.Drawing.Size(75, 19);
      this.txtSuffix.TabIndex = 12;
      this.txtSuffix.Text = "I";

      // 
      // txtPhone
      // 
      this.txtPhone.Location = new System.Drawing.Point(693, 292);
      this.txtPhone.MaxLength = 25;
      this.txtPhone.Name = "txtPhone";
      this.txtPhone.Size = new System.Drawing.Size(129, 19);
      this.txtPhone.TabIndex = 11;
      this.txtPhone.Text = "425-555-5555";

      // 
      // txtEmail
      // 
      this.txtEmail.Location = new System.Drawing.Point(693, 348);
      this.txtEmail.MaxLength = 50;
      this.txtEmail.Name = "txtEmail";
      this.txtEmail.Size = new System.Drawing.Size(270, 19);
      this.txtEmail.TabIndex = 13;
      this.txtEmail.Text = "jstowe@microsoft.com";

      // 
      // lblMiddleName
      // 
      this.lblMiddleName.Location = new System.Drawing.Point(227, 350);
      this.lblMiddleName.Name = "lblMiddleName";
      this.lblMiddleName.Size = new System.Drawing.Size(97, 16);
      this.lblMiddleName.TabIndex = 32;
      this.lblMiddleName.Text = "Middle Name:";

      // 
      // txtMiddleName
      // 
      this.txtMiddleName.Location = new System.Drawing.Point(305, 350);
      this.txtMiddleName.MaxLength = 50;
      this.txtMiddleName.Name = "txtMiddleName";
      this.txtMiddleName.Size = new System.Drawing.Size(252, 19);
      this.txtMiddleName.TabIndex = 8;
      this.txtMiddleName.Text = "P";

      // 
      // cboNameStyle
      // 
      this.cboNameStyle.Items.AddRange(new object[] {
        "0", "1"
      });
      this.cboNameStyle.Location = new System.Drawing.Point(306, 404);
      this.cboNameStyle.Name = "cboNameStyle";
      this.cboNameStyle.Size = new System.Drawing.Size(37, 21);
      this.cboNameStyle.TabIndex = 10;
      this.cboNameStyle.Text = "0";

      // 
      // frmAdventureWorks
      // 
      this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
      this.ClientSize = new System.Drawing.Size(1051, 771);
      this.Controls.Add(this.cboNameStyle);
      this.Controls.Add(this.txtMiddleName);
      this.Controls.Add(this.lblMiddleName);
      this.Controls.Add(this.txtEmailPromotion);
      this.Controls.Add(this.txtEmail);
      this.Controls.Add(this.txtSuffix);
      this.Controls.Add(this.txtPhone);
      this.Controls.Add(this.txtLastName);
      this.Controls.Add(this.txtFirstName);
      this.Controls.Add(this.txtSaluation);
      this.Controls.Add(this.lblEmail);
      this.Controls.Add(this.lblEmailPromotion);
      this.Controls.Add(this.lblSuffix);
      this.Controls.Add(this.lblPhone);
      this.Controls.Add(this.lblNameStyle);
      this.Controls.Add(this.lblLastName);
      this.Controls.Add(this.lblFirstName);
      this.Controls.Add(this.lblSaluation);
      this.Controls.Add(this.btnInsertContactSPCLR);
      this.Controls.Add(this.btnInsertContactCLR);
      this.Controls.Add(this.btnInsertContact);
      this.Controls.Add(this.btnGetContactSPCLR);
      this.Controls.Add(this.btnGetContactCLR);
      this.Controls.Add(this.txtGetContactId);
      this.Controls.Add(this.lblContactId);
      this.Controls.Add(this.btnGetContact);
      this.Controls.Add(this.txtOutput);
      this.Controls.Add(this.btnSqlBatch);
      this.Controls.Add(this.lblOutput);
      this.Controls.Add(this.txtSqlBatch);
      this.Controls.Add(this.lblSqlBatch);
      this.Name = "frmAdventureWorks";
      this.Text = "AdventureWorks Proxy Application";
      this.Load += new System.EventHandler(this.frmAdventureWorks_Load);
      this.ResumeLayout(false);
      this.PerformLayout();
    }
    #endregion

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main() 
    {
      Application.Run(new frmAdventureWorks());
    }

    private void frmAdventureWorks_Load(object sender, System.EventArgs e)
    {
      // Set the mProxy member variable to the endpoint with the default credentials
      mProxy = new prxyAdventureWorks.sql_AdventureWorks_endpoint();
      mProxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
    }

    private void btnSqlBatch_Click(object sender, System.EventArgs e)
    {
      try
      {
        // Execute the Batch Statements by using the sqlbatch() function generated
        prxyAdventureWorks.SqlParameter[] p = null;

        txtOutput.Text = "Executing Batch Statements...\r\n\r\n";

        // Execute the adhoc statements in the textbox by using the sqlbatch() function generated
        object[] results = mProxy.sqlbatch(txtSqlBatch.Text, ref p);

        DisplayResults(results);
      }
      catch(InvalidOperationException ex)
      {
        txtOutput.Text += "An InvalidOperationException was caught.\r\n";
        txtOutput.Text += "This could be due to a column of type XML
          in the select list.\r\n";
        txtOutput.Text += "This is a known issue within the version
          of the .NET Framework shipped with Yukon.\r\n";
        txtOutput.Text += "To work around this, try removing the columns
          of type XML from the select list.\r\n";
        txtOutput.Text += "\r\n";
        txtOutput.Text += "Contents of the exception:\r\n";
        txtOutput.Text += "\r\n";
        txtOutput.Text += ex.Message;
      }
    }

    private void DisplayResults(object[] results)
    {
      // The results generated by the proxy methods return an array of 
      // results like a dataset, messages, row count, etc. 
      // This function loops through these results and displays them as appropriate.
      if(null == results)
          return;
          
      for (int intCount = 0; intCount < results.Length; intCount++)
      {
        // Use a stringbuilder class when adding on multiple strings for efficiency
        StringBuilder sb = new StringBuilder();
        object objResult = results[intCount];

        // If the type of objResult is a primitive, then it is a return code.  
        if (objResult.GetType().IsPrimitive)
        {
          sb.Append("Return code = ");
          sb.AppendLine(objResult.ToString());
        }
        else
        {
          // Display the different variations of objResult
          switch (objResult.ToString())
          {
            case "System.Data.DataSet" :
              sb.AppendLine("Printing result of SELECT:");
              System.Data.DataSet resultDS = (System.Data.DataSet)objResult;
              sb.Append(resultDS.GetXml());
              break;

            case "AdventureWorksProxy.prxyAdventureWorks.SqlRowCount" :
              sb.Append("AdventureWorksProxy.prxyAdventureWorks.SqlRowCount = ");
              sb.Append((((prxyAdventureWorks.SqlRowCount)results[intCount]).Count));
              break;

            case "System.Xml.XmlElement" :
              sb.AppendLine("Printing result of SELECT ...FOR XML");
              System.Xml.XmlElement xmlResult = (System.Xml.XmlElement)results[intCount];
              sb.Append(xmlResult.OuterXml);
              break;

            case "AdventureWorksProxy.prxyAdventureWorks.SqlMessage" :
              sb.AppendLine("Printing error msg, warning, or other informational msg:");
              prxyAdventureWorks.SqlMessage errorMessage =
                (prxyAdventureWorks.SqlMessage)results[intCount];
                
              sb.Append("Message: ");
              sb.AppendLine(errorMessage.Message);
              sb.Append("Source: ");
              sb.AppendLine(errorMessage.Source);
              break;
            
            case "AdventureWorksProxy.prxyAdventureWorks.SqlParameter" :
              sb.AppendLine("Printing output parameters");
              sb.Append("The type of the corresponding object array element is: ");
              sb.AppendLine(objResult.ToString());
              sb.Append("Output parameter's name is: ");
              sb.AppendLine((((prxyAdventureWorks.SqlParameter)results[intCount]).Name));
              sb.Append("Output parameter's value is: ");
              sb.AppendLine((((prxyAdventureWorks.SqlParameter)results[intCount]).Value).ToString());
              break;

            default :
              sb.Append("Unhandled result case: ");
              sb.AppendLine(objResult.ToString());
              break;
          }
        }
        sb.AppendLine();
        txtOutput.Text += sb.ToString();
      }
    }

    private void cArrayGetContact_Click(object sender, System.EventArgs e)
    {
      // This function is called when the GetControl buttons are clicked.
      // A control array is setup to include btnGetContact, btnGetContactCLR,
      // btnGetContactSPCLR, so this function is invoked whenever those
      // buttons are clicked.
      // The function determines which button was clicked and then calls
      // the appropriate generated function.
      object[] results = null;
      int contactId = Convert.ToInt32(txtGetContactId.Text);
      string MethodCalled = ((System.Windows.Forms.Button)sender).Text;
      
      txtOutput.Text = "Executing " + MethodCalled + "...\r\n\r\n";

      switch (MethodCalled)
      {
        case "GetContact" :
          results = mProxy.GetContact(contactId);
          break;

        case "GetContactCLR" :
          results = mProxy.GetContactCLR(contactId);
          break;

        case "GetContactSPCLR" :
          results = mProxy.GetContactSPCLR(contactId);
          break;
      }
      DisplayResults(results);
    }

    private void cArrayInsertContact_Click(object sender, System.EventArgs e)
    {
      // This function is called when the GetControl buttons are clicked.
      // A control array is setup to include btnInsertContact, 
      // btnInsertContactCLR, btnInsertContactSPCLR,
      // so this function is invoked whenever those buttons are clicked.
      // The function determines which button was clicked and then calls
      // the appropriate generated function.
      object[] results = null;
      string MethodCalled = ((System.Windows.Forms.Button)sender).Text;

      bool nameStyle = true ? ("1" == cboNameStyle.Text) : false;
      
      int emailPromotion = 0;
      if (txtEmailPromotion.Text.Length > 0)
      {
        emailPromotion = Convert.ToInt32(txtEmailPromotion.Text);
      }

      txtOutput.Text = "Executing " + MethodCalled + "...\r\n\r\n";
      switch (MethodCalled)
      {
        case "InsertContact" :
          results = mProxy.InsertContact(txtSaluation.Text, txtFirstName.Text,
            txtMiddleName.Text, txtLastName.Text, nameStyle, txtPhone.Text,
            txtSuffix.Text, txtEmail.Text, emailPromotion);
          break;

        case "InsertContactCLR" :
          results = mProxy.InsertContactCLR(txtSaluation.Text, txtFirstName.Text,
            txtMiddleName.Text, txtLastName.Text, nameStyle, txtPhone.Text,
            txtSuffix.Text, txtEmail.Text, emailPromotion);
          break;

        case "InsertContactSPCLR" :
          results = mProxy.InsertContactSPCLR(txtSaluation.Text, txtFirstName.Text,
            txtMiddleName.Text, txtLastName.Text, nameStyle, txtPhone.Text,
            txtSuffix.Text, txtEmail.Text, emailPromotion);
          break;
      }
      DisplayResults(results);
    }
  }
}

Additional Native HTTP Information

For more information on using Native HTTP SOAP Support within Yukon, please consule the Books Online Book "Accessing SQL Server Using Native HTTP SOAP Support". Within Books Online, this book can be navigated to by clicking Contents->SQL Server Books Online-> Database Engine->Accessing SQL Server Using Native HTTP SOAP Support.

Within this book, there is a good example on how to create another VS.NET GUI application to use the HTTP ENDPOINT as a web reference. This is another tutorial to see how WSDL and HTTP ENDPOINTs work within VS.NET.

The sample code is available here.



Marketplace
(Sponsored Links)
What are the green links?
   



 
Copyright 2007 CMP Tech LLC | Hosted By SecureWebs.com
Privacy Policy (4/10/06) | Your California Privacy Rights (4/10/06) | Terms of Service | Advertising Info | About Us | Help