U
UAError
Lasse Edsvik said:in this example i dont have to use transactions..... so i'll skip that and
learn that some other time then...
Serviced components are a bit harder to explain:
The following is an example from Amit Kalani's book for 70-320
It assumes that you have SQL Server with the Northwind database running locally
You can always get this:
Microsoft SQL Server 2000 Desktop Engine (MSDE 2000) Release A
http://www.microsoft.com/downloads/...D1-A0BC-479F-BAFA-E4B278EB9147&displaylang=en
The example involves to serviced components one for shipping, one for billing which
are used by an ordering component and finally a windows form client to use them.
Start by creating a blank solution in Visual Studio: ESTransApp
(File->New->Blank Solution)
CREATE NEW TABLES
-----------------
Open a Visual Studio .NET Command Prompt Window
Navigate to the project directory "ESTransApp" and create a file "ShipBill.sql" with the following contents:
SET quoted_identifier on
USE "Northwind"
GO
IF EXISTS (SELECT 1 FROM sysobjects WHERE id = object_id('dbo.Shipping') and sysstat & 0xf = 3)
drop table "dbo"."Shipping"
GO
IF EXISTS (SELECT 1 FROM sysobjects WHERE id = object_id('dbo.Billing') and sysstat & 0xf = 3)
drop table "dbo"."Billing"
GO
CREATE TABLE "Shipping" (
"ShippingID" "int" IDENTITY (1, 1) NOT NULL,
"CustomerID" "nchar" (5) NOT NULL ,
"ProductID" "int" NOT NULL ,
"DateTime" "datetime" NOT NULL,
CONSTRAINT "PK_Shipping" PRIMARY KEY CLUSTERED (
"ShippingID"
),
CONSTRAINT "FK_Shipping_Customers" FOREIGN KEY (
"CustomerID"
) REFERENCES "dbo"."Customers" (
"CustomerID"
),
CONSTRAINT "FK_Shipping_Products" FOREIGN KEY (
"ProductID"
) REFERENCES "dbo"."Products" (
"ProductID"
)
)
GO
CREATE TABLE "Billing" (
"BillingID" "int" IDENTITY (1, 1) NOT NULL,
"CustomerID" "nchar" (5) NOT NULL ,
"ProductID" "int" NOT NULL ,
"DateTime" "datetime" NOT NULL,
CONSTRAINT "PK_Billing" PRIMARY KEY CLUSTERED (
"BillingID"
),
CONSTRAINT "FK_Billing_Customers" FOREIGN KEY (
"CustomerID"
) REFERENCES "dbo"."Customers" (
"CustomerID"
),
CONSTRAINT "FK_Billing_Products" FOREIGN KEY (
"ProductID"
) REFERENCES "dbo"."Products" (
"ProductID"
)
)
GO
The in the command prompt window run the following command:
osql -E -i ShipBill.sql
This should create the new tables
CREATE Strong Name key
----------------------
The in the command prompt window navigate to the solution directory "ESTransApp"
and the strong name key file "ESTransApp.snk":
sn -k ESTransApp.snk
CREATE Shipping Component
-------------------------
1) Add a new Visual C#: Class Library "ShipTrans" to your "ESTransApp" Solution.
2) Add a reference to enterprise services. Right-Click the project
"Add Reference->.NET System.Enterprise.Services"
Click "Select", Click "OK"
3) Rename the file "Shipping.cs" and enter the following:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.EnterpriseServices;
using System.Runtime.InteropServices;
namespace ShipTrans {
public interface IShipping {
void ShipItem( string customerID, int productID );
}
// Get your own GUID: Tools->Create GUID "Registry Format" - Copy
[Transaction(TransactionOption.Supported)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("8D8B0556-FB6B-4ce6-948C-20F158987236")]
public class Shipping : ServicedComponent, IShipping {
SqlConnection cnn_ = null;
public Shipping() {
cnn_ = new SqlConnection(
"data source=(local)"
+ ";initial catalog=Northwind"
+ ";integrated security=SSPI"
);
}
#region IShipping Members
[AutoComplete(true)]
public void ShipItem(string customerID, int productID) {
SqlDateTime dt = new SqlDateTime( DateTime.Now );
SqlCommand cmd = cnn_.CreateCommand();
cmd.CommandText = string.Format(
"INSERT INTO Shipping ("
+ "CustomerID, ProductID, DateTime"
+ ") VALUES ("
+ "'{0}','{1}','{2}'"
+ ")",
customerID,
productID,
dt
);
cnn_.Open();
cmd.ExecuteNonQuery();
}
#endregion
}
}
4) Add the following at the top to the AssemblyInfo.cs file of the "ShipTrans" project:
using System.EnterpriseServices;
and modify (or add) the following in AssemblyInfo.cs
[assembly: ApplicationName("Shipping Application")]
[assembly: Description("Ship Orders")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyKeyFile("../../../ESTransApp.snk")]
[assembly: ApplicationAccessControl(false)]
5) Build the project
6) Install the component to the Global assembly Cache (not technically required but good practice)
The in the command prompt window navigate to the project output directory "ESTransApp\ShipTrans\bin\Debug"
and issue the following command:
gacutil -i ShipTrans.dll
7) Register the serviced component with the COM+ Catalog:
The in the command prompt window navigate to the project output directory "ESTransApp\ShipTrans\bin\Debug"
and issue the following command:
regsvcs ShipTrans.dll
Ignore - WARNING: The class 'ShipTrans.Shipping' has no class interface, which means that unmanaged
late bound calls cannot take advantage of AutoComplete methods.
8) Check Serviced components.
Open the "Component Services" MMI plugin (Control Panel->Adminstrative Tools->Component Services) or
on the command line:
%SystemRoot%\system32\Com\comexp.msc
Drill down
Component Services->Computers->My Computers->COM+ Applications
One of the applications should state "Shipping Application" - the recently registered serviced component.
CREATE Billing Component
-------------------------
1) Add a new Visual C#: Class Library "BillTrans" to your "ESTransApp" Solution.
2) Add a reference to enterprise services. Right-Click the project
"Add Reference->.NET System.Enterprise.Services"
Click "Select", Click "OK"
3) Rename the file "Billing.cs" and enter the following:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.EnterpriseServices;
using System.Runtime.InteropServices;
namespace BillTrans {
public interface IBilling {
void BillCustomer( string customerID, int productID );
}
// Get your own GUID: Tools->Create GUID "Registry Format" - Copy
[Transaction(TransactionOption.Supported)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("2B2A9DE2-2CD9-40cf-BA34-2323B52B0F31")]
public class Billing : ServicedComponent, IBilling {
SqlConnection cnn_ = null;
public Billing() {
cnn_ = new SqlConnection(
"data source=(local)"
+ ";initial catalog=Northwind"
+ ";integrated security=SSPI"
);
}
#region IBilling Members
[AutoComplete(true)]
public void BillCustomer(string customerID, int productID) {
SqlDateTime dt = new SqlDateTime( DateTime.Now );
SqlCommand cmd = cnn_.CreateCommand();
cmd.CommandText = string.Format(
"INSERT INTO Billing ("
+ "CustomerID, ProductID, DateTime"
+ ") VALUES ("
+ "'{0}','{1}','{2}'"
+ ")",
customerID,
productID,
dt
);
cnn_.Open();
cmd.ExecuteNonQuery();
}
#endregion
}
}
4) Add the following at the top to the AssemblyInfo.cs file of the "BillTrans" project:
using System.EnterpriseServices;
and modify (or add) the following in AssemblyInfo.cs
[assembly: ApplicationName("Billing Application")]
[assembly: Description("Bill Customers")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl(false)]
[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyKeyFile("../../../ESTransApp.snk")]
5) Build the project
6) Install the component to the Global assembly Cache (not technically required but good practice)
The in the command prompt window navigate to the project output directory "ESTransApp\BillTrans\bin\Debug"
and issue the following command:
gacutil -i BillTrans.dll
7) Register the serviced component with the COM+ Catalog:
The in the command prompt window navigate to the project output directory "ESTransApp\BillTrans\bin\Debug"
and issue the following command:
regsvcs BillTrans.dll
Ignore - WARNING: The class 'OrderTrans.Shipping' has no class interface, which means that unmanaged
late bound calls cannot take advantage of AutoComplete methods.
8) Check Serviced components.
Open the "Component Services" MMI plugin (Control Panel->Adminstrative Tools->Component Services) or
on the command line:
%SystemRoot%\system32\Com\comexp.msc
Drill down
Component Services->Computers->My Computers->COM+ Applications
One of the applications should state "Billing Application" - the recently registered serviced component.
CREATE Ordering Component
-------------------------
1) Add a new Visual C#: Class Library "OrderTrans" to your "ESTransApp" Solution.
2) Add a reference to enterprise services. Right-Click the project
"Add Reference->.NET System.Enterprise.Services"
Click "Select", Click "OK"
3) Add references to the other projects. Right-Click the "OrderTrans" project
"Add Reference->Projects BillTrans"
Click "Select"
"Add Reference->Projects ShipTrans"
Click "Select"
Click "OK"
4) Rename the file "Ordering.cs" and enter the following:
using System;
using System.EnterpriseServices;
using System.Runtime.InteropServices;
using ShipTrans;
using BillTrans;
namespace OrderTrans {
public interface IOrdering {
void PlaceOrder( string customerID, int productID );
}
// Get your own GUID: Tools->Create GUID "Registry Format" - Copy
[Transaction(TransactionOption.RequiresNew)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("D229FB99-2FC7-4961-94FA-981E747F215B")]
public class Ordering : ServicedComponent, IOrdering {
public Ordering() {}
#region IOrdering Members
[AutoComplete(true)]
public void PlaceOrder(string customerID, int productID) {
Billing billing = new Billing();
billing.BillCustomer( customerID, productID );
Shipping shipping = new Shipping();
shipping.ShipItem( customerID, productID );
}
#endregion
}
}
5) Add the following at the top to the AssemblyInfo.cs file of the "OrderTrans" project:
using System.EnterpriseServices;
and modify (or add) the following in AssemblyInfo.cs
[assembly: ApplicationName("Ordering Application")]
[assembly: Description("Places an Order")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl(false)]
[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyKeyFile("../../../ESTransApp.snk")]
6) Build the project
7) Install the component to the Global assembly Cache (not technically required but good practice)
The in the command prompt window navigate to the project output directory "ESTransApp\OrderTrans\bin\Debug"
and issue the following command:
gacutil -i OrderTrans.dll
8) Register the serviced component with the COM+ Catalog:
The in the command prompt window navigate to the project output directory "ESTransApp\BillTrans\bin\Debug"
and issue the following command:
regsvcs OrderTrans.dll
Ignore - WARNING: The class 'OrderTrans.Shipping' has no class interface, which means that unmanaged
late bound calls cannot take advantage of AutoComplete methods.
9) Check Serviced components.
Open the "Component Services" MMI plugin (Control Panel->Adminstrative Tools->Component Services) or
on the command line:
%SystemRoot%\system32\Com\comexp.msc
Drill down
Component Services->Computers->My Computers->COM+ Applications
One of the applications should state "Ordering Application" - the recently registered serviced component.
CREATE Serviced Components Client (Windows Forms)
-------------------------------------------------
1) Add a new Visual C#: Windows Application "OrderApp" to your "ESTransApp" Solution.
Right-Click the project and click "Set As Start-up Project".
2) Add a reference to enterprise services. Right-Click the project
"Add Reference->.NET System.Enterprise.Services"
Click "Select", Click "OK"
3) Add references to the "OrderTrans" project. Right-Click the "OrderApp" project
"Add Reference->Projects OrderTrans"
Click "Select"
Click "OK"
4) Rename the file "Form1.cs" to "OrderForm.cs" and enter the following:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
using OrderTrans;
namespace OrderApp {
public class OrderForm : System.Windows.Forms.Form {
private System.Windows.Forms.GroupBox gbOrderInfo;
private System.Windows.Forms.Label lblCustomer;
private System.Windows.Forms.Label lblProduct;
private System.Windows.Forms.Button btnOrder;
private System.ComponentModel.Container components = null;
private System.Windows.Forms.ComboBox cboProducts;
private System.Windows.Forms.ComboBox cboCustomers;
private DataSet dsInfo_ = null;
public OrderForm () {
InitializeComponent();
}
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.gbOrderInfo = new System.Windows.Forms.GroupBox();
this.lblProduct = new System.Windows.Forms.Label();
this.lblCustomer = new System.Windows.Forms.Label();
this.cboCustomers = new System.Windows.Forms.ComboBox();
this.cboProducts = new System.Windows.Forms.ComboBox();
this.btnOrder = new System.Windows.Forms.Button();
this.gbOrderInfo.SuspendLayout();
this.SuspendLayout();
//
// gbOrderInfo
//
this.gbOrderInfo.Controls.Add(this.btnOrder);
this.gbOrderInfo.Controls.Add(this.cboProducts);
this.gbOrderInfo.Controls.Add(this.lblProduct);
this.gbOrderInfo.Controls.Add(this.lblCustomer);
this.gbOrderInfo.Controls.Add(this.cboCustomers);
this.gbOrderInfo.Location = new System.Drawing.Point(8, 8);
this.gbOrderInfo.Name = "gbOrderInfo";
this.gbOrderInfo.Size = new System.Drawing.Size(336, 136);
this.gbOrderInfo.TabIndex = 0;
this.gbOrderInfo.TabStop = false;
this.gbOrderInfo.Text = "Ordering Information";
//
// lblProduct
//
this.lblProduct.Location = new System.Drawing.Point(16, 57);
this.lblProduct.Name = "lblProduct";
this.lblProduct.Size = new System.Drawing.Size(64, 23);
this.lblProduct.TabIndex = 2;
this.lblProduct.Text = "&Product";
this.lblProduct.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lblCustomer
//
this.lblCustomer.Location = new System.Drawing.Point(16, 25);
this.lblCustomer.Name = "lblCustomer";
this.lblCustomer.Size = new System.Drawing.Size(64, 23);
this.lblCustomer.TabIndex = 0;
this.lblCustomer.Text = "&Customer";
this.lblCustomer.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// cboCustomers
//
this.cboCustomers.Location = new System.Drawing.Point(96, 24);
this.cboCustomers.Name = "cboCustomers";
this.cboCustomers.Size = new System.Drawing.Size(216, 24);
this.cboCustomers.TabIndex = 1;
//
// cboProducts
//
this.cboProducts.Location = new System.Drawing.Point(96, 56);
this.cboProducts.Name = "cboProducts";
this.cboProducts.Size = new System.Drawing.Size(216, 24);
this.cboProducts.TabIndex = 3;
//
// btnOrder
//
this.btnOrder.Location = new System.Drawing.Point(104, 96);
this.btnOrder.Name = "btnOrder";
this.btnOrder.Size = new System.Drawing.Size(96, 23);
this.btnOrder.TabIndex = 4;
this.btnOrder.Text = "Place Order";
this.btnOrder.Click += new System.EventHandler(this.btnOrder_Click);
//
// OrderForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
this.ClientSize = new System.Drawing.Size(352, 153);
this.Controls.Add(this.gbOrderInfo);
this.Name = "OrderForm";
this.Text = "Order Form";
this.Load += new System.EventHandler(this.OrderForm_Load);
this.gbOrderInfo.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
[STAThread]
static void Main() {
Application.Run(new OrderForm());
}
private void OrderForm_Load(object sender, System.EventArgs e) {
SqlConnection cnn = new SqlConnection(
"data source=(local)"
+ ";initial catalog=Northwind"
+ ";integrated security=SSPI"
);
// Load Customers
SqlCommand cmdCustomers = cnn.CreateCommand();
cmdCustomers.CommandType = CommandType.Text;
cmdCustomers.CommandText =
"SELECT CompanyName, CustomerID FROM Customers";
SqlDataAdapter daCustomers = new SqlDataAdapter();
daCustomers.SelectCommand = cmdCustomers;
// Load Products
SqlCommand cmdProducts = cnn.CreateCommand();
cmdProducts.CommandType = CommandType.Text;
cmdProducts.CommandText =
"SELECT ProductName, ProductID FROM Products";
SqlDataAdapter daProducts = new SqlDataAdapter();
daProducts.SelectCommand = cmdProducts;
dsInfo_ = new DataSet();
daCustomers.Fill( dsInfo_, "Customers" );
daProducts.Fill( dsInfo_, "Products" );
// Bind comboboxes
cboCustomers.DataSource = dsInfo_;
cboCustomers.DisplayMember = "Customers.CompanyName";
cboCustomers.ValueMember = "Customers.CustomerID";
cboProducts.DataSource = dsInfo_;
cboProducts.DisplayMember = "Products.ProductName";
cboProducts.ValueMember = "Products.ProductID";
} // end event handler OrderForm_Load
private void btnOrder_Click(object sender, System.EventArgs e) {
try {
// Ordering Serviced component is used here
Ordering ordering = new Ordering();
ordering.PlaceOrder(
cboCustomers.SelectedValue.ToString(),
(int) cboProducts.SelectedValue
);
MessageBox.Show( "Order Placed Successfully" );
} catch ( Exception ex ) {
MessageBox.Show( ex.Message );
}
} // end event handler btnOrder_Click
}
}
5) Build the project
6) Run OrderApp. You should be able to place an order.
7) Now go into the "Component Services" console and disable the "Shipping Application".
If you try to place an order now, an exception will be thrown and the transaction is aborted;
i.e. there will be no Billing record without a shipping record.