Slider Binding Miminum, Maximum and Value problem

The Slider is a component that let you slide a small rectangle from one side to the other. You have to put a minimum value and a maximum value and from there, the user can select a value between these two values.

Example of a Slider control

One interesting thing to do is to rely on the business logic to handle all values of this control. This can be done using Binding.

 <Slider 
          SmallChange="{Binding SmallChange, Mode=OneTime}" 
          LargeChange="{Binding LargeChange, Mode=OneTime}" 
          Value="{Binding MyRealValue, Mode=TwoWay}" 
          Minimum="{Binding Minimum, Mode=OneTime}" 
          Maximum="{Binding Maximum, Mode=OneTime}"       
 />

The code above won’t work. The syntax is well written, but it won’t work. The code will compile but the slider won’t be able to slide.

 <Slider 
          SmallChange="{Binding SmallChange, Mode=OneTime}" 
          LargeChange="{Binding LargeChange, Mode=OneTime}" 
          Maximum="{Binding Maximum, Mode=OneTime}" 
          Minimum="{Binding Minimum, Mode=OneTime}" 
          Value="{Binding MyRealValue, Mode=TwoWay}" 
 />

This code works because the Maximum value is the first to be set, then the Minimum and finally the Value is binded. Doing the binding in a different order won’t let you modify the values of the slider.

Remember to always use maximum, minimum and then value when using the Slider. This is viable for Silverlight 3 and 4.

XamlParseException: failed to create a ‘System.Windows.Input.ICommand’ from the text

XamlParseException: failed to create a ‘System.Windows.Input.ICommand’ from the text

This error can occur when binding a Command inside a Xaml file.

    <Button Command="MyCommand"> Click Me </Button>

In fact, the problem with this syntax reside in the way we call the command. The previous example were not using the Binding syntax.

You need to use the Binding keyword.

    <Button Command="{Binding MyCommand}"> Click Me </Button>

Of course, you need bind to a ICommand property to the desired command.

public ICommand MyCommand
{
    get {
        return ....
    }
}

Hope this help some body that has this error 🙂

Silverlight Binding Mode

In Silverlight, you can bind data of the Xaml file to a C# file. In fact, the Xaml file has a context to which it can get or set value. Once the context is set (can be set with static resource or in the code behind using the Context property). you can set the binding.

You can bind with a lot of different syntax. The smallest way to bind data to your Xaml control is to use only the binding keyword and the name of the source property.

<TextBlock Text="{Binding MyProperty}"></TextBlock>

This is in fact the same as using the Path keyword of the Binding. It’s implicit in the first example, and in the following it’s explicit.

<TextBlock Text="{Binding Path=MyProperty}"></TextBlock>

Both of these example hide explicit information that is the mode. The mode indicate how the binding should be done. Three possible values can be used for the mode

  • OneTime
  • OnWay
  • TwoWay

The OneTime mode let you bind from your C# file to your Xaml only when the binding is initialized. That mean that the value won’t change later even if the value change in the C# code.

The OneWay mode let you bind from your C# file to you Xaml in read only. That mean that if the value is changed in the C# code that the value will be updated in the Xaml. But, if the user changes the value to the Xaml that the value won’t be modified in the C# code. This is useful for read only field. Keep in mind that when you do not specify any mode (implicit) that the default value is the OneWay.

The TwoWay binding mode let you get data from the C# file but also takes the change from the user to push it into the C#. This mode is useful to load data and then to let the user modify the value.

Since Silverlight 3 some improvement has been done in the binding to be a little bit more like WPF. You can now bind a component to an other with the ElementName

<TextBlock Text="{Binding ElementName=MyOtherTextBox, Path=Text}"></TextBlock>

Also, what about constant and binding? In some case, you could desire to bind OneTime a constant value. For example, the Slider control can have a SmallChange property that determine the increment of the slider. This can be set as a constant in our application. To be able to bind to this value you would have to create a Getter that will return the value. Silverlight binding won’t let you bind directly to the constant variable.

Decimal literal and Float literal

Some may don’t know but if you want to write a double value in code you cannot write:

double myVariable = 100;

This won’t work because the value will be treated as an integer. To resolve this issue, the simplest way to do it is to mark it as decimal to the compiler with the suffix ‘d’ or ‘D’.

double myVariable = 100d;
//or
double myVariable = 100D;

The same thing is good for float type. Instead of using the literal ‘d’ or ‘D’ you need to use the character ‘F’ or ‘f’.

This is so basic that sometime you may wonder why Visual Studio mark it as an error. You could ask yourself also what is the character to mark a number into a specific type like double or float. Well, the first letter of each of type is the answer.

POCO Proxy and Lazy Loading

POCO objects using Entity Framework as ORM require the creation of a proxy. When the proxy is created, the rest is exactly the same as if you were using standard entity from the object context.

Creating the proxy

In fact, the proxy will be generated by the Entity Framework (in runtime). To be more accurate, each of the POCO classes have a proxy. This proxy will derive from your POCO classes. This will let the Entity Framework keeping track of the state change and enable the use of lazy loading. Since the proxy class derive from POCO classes, these one must not be sealed, private or abstract.

We have said that the proxy is created in the runtime and this is a good thing because we can enable and disable the proxy. If you desire to enable the proxy, you must use the ProxyCreationEnabled to true. This property reside inside the context object, inside the context option.

var db = new NorthWindContext();
db.ContextOptions.ProxyCreationEnabled = true; //Enable the proxy creation in runtime

This is not always enabled because in some case, like while using serialization with WCF, only [known] class can be serialized. This won’t be the case of the runtime generated proxy.

From here, you need to do some changes in your POCO class and the change varies depending if you want only the lazy loading or also the change tracking.

Lazy Loading

To have lazy loading enable the navigation properties (the one that link to an other object that need to be loaded or a collection to be loaded) must be public and virtual and not sealed. This way, it’s possible for the proxy to change some call to add the lazy loaded statement.

Change Tracking

The first step is to make you POCO class legit for lazy loading. So, all information in the previous paragraph must remain true. Each collection of object must return a type that derive from a generic ICollection. It’s also require to use the CreateObject method instead of using new to create your class.

var db = new NorthWindContext();
var myPoco = db.CreateObject<MyPocoObject>();

You can fine further information on MSDN.

Complete example

Let’s make this theory in practice. We are gonna use the Northwind database and the table Customers and Orders.

Preparation

Lets create a new ADO.NET entity data model and use the generator creating the model for us. Do not forget to remove the Custom Tool text on the Edmx file.

After that, lets create the 2 POCO classes.

namespace PocoAndLazy.POCO
{
    public class Customer
    {
        public string CustomerID { get; set; }
        public string CompanyName { get; set; }
        public string ContactName { get; set; }
        public string ContactTitle { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string Region { get; set; }
        public string PostalCode { get; set; }
        public string Country { get; set; }
        public string Phone { get; set; }
        public string Fax { get; set; }

        public virtual List<Order> Orders { get; set; } //Virtual + ICollection<T>
    }
}

and

namespace PocoAndLazy.POCO
{
    public class Order
    {
        public int OrderID { get; set; }
        public string CustomerID { get; set; }
        public int EmployeeID { get; set; }
        public DateTime? OrderDate { get; set; }
        public DateTime? RequiredDate { get; set; }
        public DateTime? ShippedDate { get; set; }
        public int? ShipVia { get; set; }
        public decimal? Freight { get; set; }
        public string ShipName { get; set; }
        public string ShipAddress { get; set; }
        public string ShipCity { get; set; }
        public string ShipRegion { get; set; }
        public string ShipCountry { get; set; }
        public string ShipPostalCode { get; set; }
    }
}

After the ObjectContext class.

namespace PocoAndLazy
{
    public class ModelContext : ObjectContext
    {
        private ObjectSet<Customer> customers;
        private ObjectSet<Order> orders;

        public ModelContext(): base("name=NorthwindEntities", "NorthwindEntities")
        {
            customers = CreateObjectSet<Customer>();
            orders = CreateObjectSet<Order>();
        }

        public ObjectSet<Customer> Customers
        {
            get
            {
                return customers;
            }
        }

        public ObjectSet<Order> Order
        {
            get
            {
                return orders;
            }
        }
 
    }
}

And lets do a quick test.

ModelContext db = new ModelContext();
var bigCustomers = db.Customers.Where(c => c.Orders.Count > 20);
foreach (var customer in bigCustomers)
{
    Debug.WriteLine("Customer#" + customer.CustomerID);
}

Output:

Customer#ERNSH
Customer#QUICK
Customer#SAVEA

This display the list of customer that have over 10 orders. I have not given the explication of how to create POCO objets with Entity Framework here because this is covered in an other article. The important information is that we have now a stable structure to continue to the core of the goal : lazy loading.

Currently, no order can be show if we loop through the list of order of each of these 3 clients. The reason is the default value is eager loading the use of Include is missing and no explicit loading with Load is provided.

ModelContext db = new ModelContext();
var bigCustomers = db.Customers.Where(c => c.Orders.Count > 20);
foreach (var customer in bigCustomers)
{
	Debug.WriteLine("Customer#" + customer.CustomerID);
	foreach (var order in customer.Orders)
	{
		Debug.WriteLine("---Order#" + order.OrderID);
	}
}
Code with VS error saying that the Orders are NULL

POCO Eager Loading

Of course we can add in the constructor of the Customer the initialization of the Orders collection.

public Customer()
{
    Orders = new List<Order>();
}

But, you and me understand that it still does not load the list of orders. Let for fun just enable the Lazy Loading.

ModelContext db = new ModelContext();
db.ContextOptions.LazyLoadingEnabled = true;
var bigCustomers = db.Customers.Where(c => c.Orders.Count > 20);
foreach (var customer in bigCustomers)
{
	Debug.WriteLine("Customer#" + customer.CustomerID);
	foreach (var order in customer.Orders)
	{
		Debug.WriteLine("---Order#" + order.OrderID);
	}
}

We can not see in the output:

Customer#ERNSH
---Order#10258
---Order#10263
---Order#10351
---Order#10368
---...
Customer#QUICK
---Order#10273
---Order#10285
---Order#10286
---...
Customer#SAVEA
---Order#10324
---Order#10393
---Order#10398
--- ...

If we check the SQL profiler we see N+1 call to the database (1 to get all customers and 3 to gets each of their orders).

SQL profiler screenshot of the 4 calls

SQL profiler showing the 1+3 call.

With the use of eager loading, a single query is done.

protected void Page_Load(object sender, EventArgs e)
{
	ModelContext db = new ModelContext();
	db.ContextOptions.LazyLoadingEnabled = false;
	var bigCustomers = db.Customers.Include("Orders").Where(c => c.Orders.Count > 20);
	foreach (var customer in bigCustomers)
	{
		Debug.WriteLine("Customer#" + customer.CustomerID);
		foreach (var order in customer.Orders)
		{
			Debug.WriteLine("---Order#" + order.OrderID);
		}
	}
}
SELECT 
[Project2].[C1] AS [C1], 
[Project2].[CustomerID] AS [CustomerID], 
[Project2].[CompanyName] AS [CompanyName], 
[Project2].[ContactName] AS [ContactName], 
...
FROM ( SELECT 
	[Project1].[CustomerID] AS [CustomerID], 
	[Project1].[CompanyName] AS [CompanyName], 
	[Project1].[ContactName] AS [ContactName], 
	[Project1].[ContactTitle] AS [ContactTitle], 
...
	1 AS [C1], 
	[Extent3].[OrderID] AS [OrderID], 
	[Extent3].[CustomerID] AS [CustomerID1], 
	[Extent3].[EmployeeID] AS [EmployeeID], 
	[Extent3].[OrderDate] AS [OrderDate], 
	[Extent3].[RequiredDate] AS [RequiredDate], 
	[Extent3].[ShippedDate] AS [ShippedDate], 
...
	FROM   (SELECT 
		[Extent1].[CustomerID] AS [CustomerID], 
		[Extent1].[CompanyName] AS [CompanyName], 
		[Extent1].[ContactName] AS [ContactName], 
		[Extent1].[ContactTitle] AS [ContactTitle], 
...
		(SELECT 
			COUNT(1) AS [A1]
			FROM [dbo].[Orders] AS [Extent2]
			WHERE [Extent1].[CustomerID] = [Extent2].[CustomerID]) AS [C1]
		FROM [dbo].[Customers] AS [Extent1] ) AS [Project1]
	LEFT OUTER JOIN [dbo].[Orders] AS [Extent3] ON [Project1].[CustomerID] = [Extent3].[CustomerID]
	WHERE [Project1].[C1] > 20
)  AS [Project2]
ORDER BY [Project2].[CustomerID] ASC, [Project2].[C2] ASC

So without Lazy Loading, nothing is shown until explicit load is called, with Lazy loading N+1 query is done to the database and with Eager loading a single query is done to the database.

Entity Framework and the Connection String

A connection string is a string with key value pair in it that indicate where to get the connection to the server for persistence. In Entity Framework something change from the standard and it’s the location of the CSDL, SSDL and MSL file.

Here is an example of connection string that connect to a file database named “qwe”.

<add name="AdventureWorks_DataEntities"  
 connectionString="metadata=res://*/MyEFModel.csdl|res://*/MyEFModel.ssdl|res://*/MyEFModel.msl;
 provider=System.Data.SqlClient;
 provider connection string=&quot;
  Data Source=.\SQLEXPRESS;
  AttachDbFilename=|DataDirectory|\qwe.mdf;
  Integrated Security=True;
  Connect Timeout=30;
  User Instance=True;
  MultipleActiveResultSets=True
 &quot;" 
providerName="System.Data.EntityClient" />

Here is an example of connection string for entity framework 4 to a Sql Server:

<add name="NorthwindEntities" 
 connectionString="metadata=res://*/NorthWindEntityDataModel.csdl|res://*/NorthWindEntityDataModel.ssdl|res://*/NorthWindEntityDataModel.msl;
 provider=System.Data.SqlClient;
 provider connection string=&quot;
  Data Source=.\SQLEXPRESS;
  Initial Catalog=Northwind;
  Integrated Security=True;
  MultipleActiveResultSets=True&quot;"
 providerName="System.Data.EntityClient" />

You can see one major difference that is the AttachDbFilename for one when the other has a Initial Catalog. Also, the file based database lets you to use the User Instance when the SQL server won’t. But it’s not a big deal because User Install just make the database use the current user as the runner of the database instance instead of the “NT AUTHORITY\NETWORK SERVICE. Also you can see the use of |DataDirectory| keyword in the path of the database file. This keyword is read by the System.Data.Common.DbConnectionOptions and will translate this string with AppDomain.CurrentDomain.BaseDirectory. The base directory is the assembly directory.

How Entity Framework Manage Connection String?

Entity Framework generates the Object Context with multiple constructor. One of the constructor takes the name of the connection string where it should read it. This is the case of the first line of the code below. This name is an entry in the connectionString element inside the configuration element of the app.config (or web.config for web application).

public AdventureWorks_DataEntities() : base("name=AdventureWorks_DataEntities", "AdventureWorks_DataEntities")
public AdventureWorks_DataEntities(string connectionString) : base(connectionString, "AdventureWorks_DataEntities")
public AdventureWorks_DataEntities(EntityConnection connection) : base(connection, "AdventureWorks_DataEntities")

The second constructor let you put in a string format directly the connection string. You could also get the connection string from the .config file and to load it with this second constructor.

string connectionString = ConfigurationManager.ConnectionStrings["qwe"]; 

The third constructor let you use an EntityConnection object. This object contain not only the traditional connection string but also the conceptual model data (CSDL, MSL, SSDL files). This let you create dynamically connection string with object. To use EntityConnection class, the help of EntityConnectionStringBuilder and SqlConnectionStringBuilder can be wise. You can get a MSDN Tutorial about creating EntityConnection at Microsoft.

How to encrypt connection string in .Net?

It’s always more secure to not have the user and password in clear text. This is true for application but also for web application.

Microsoft .Net Framework comes with tool to encrypt the connection string. This tool is aspnet_regiis.exe and you can find it at C:\Windows\Microsoft.NET\Framework\v2.0.50727\ if you are working on .Net 2.0 or at C:\Windows\Microsoft.NET\Framework\v4.0.30319 if you are working with .Net 4.0.

Two providers come with the .Net Framework. The RSAProtectedConfigurationProvider and the DataProtectionConfigurationProvider.

How to use aspnet_regiis.exe

You can get help by using the /? parameter but you will rapidly see that this tool has a lot of parameters.

To encrypt the connection string, you will need to use these parameters:

aspnet_regiis.exe -pef "connectionStrings" "c:\myProject\myFolder\web.config"

But, what about the provider? You can also add “-prov DataProtectionConfigurationProvider” to use DataProtectionConfigurationProvider provider.

What to code to decrypt inside the application?

Nothing. .Net Framework automatically decrypts configuration sections, therefore you do not need to write any additional decryption code.

Possible errors

You can have this error message while doing this command: “the configuration for physical path cannot be opened”. If you have this error you should be sure that the file is not in read-only. Also, check if you have the permission to edit this file. Then, be sure that the file is no used by any program that may lock the file.

SSPI

This option let you use the Windows credential instead of using username and password directly in the connection string. To use, modify the connection string to have Integrated Security=SSPI or Integrated Security=True and remove the username and password. Of course, this mean that the database must let the user connect. This is a good practice to handle the security of you web application with the web Windows credential.

Conclusion

For more information about the security you should visit Microsoft MSDN documentation.

Entity SQL Query (ESQL)

Entity SQL Query (ESQL) is not like Linq to Entity. The latest use the Linq query while the first one do not. However, they serve the same purpose and they are both in the Entity Framework.

ESQL looks more like SQL query. Even if ESQL is not SQL, it will let developer use SQL query to the database. So, they are 2 ways to use ESQL : using EntityCommand or using the generic ObjectQuery class.

The first thing to do is to create a EDMX file like we would do with Linq to Entity. The generated connection string that it will provides in the web.config (or app.config) will be used after that with the EntityConnection. For that, you will need to use the System.Data.EntityClient namespace (Add System.Data.Entity).

The connection string will look like this:

<add name="NorthwindEntities1" connectionString="metadata=res://*/NorthwindModel.csdl|res://*/NorthwindModel.ssdl|res://*/NorthwindModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=PATRICK-PC\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" /></connectionStrings>

You need to have this syntax with the metadata and provider connection. Traditional ADO.NET connection string won’t work.

To try your connection string for ESQL you can use this kind of code:

string connectionString = ConfigurationManager.ConnectionStrings["NorthwindEntities1"].ConnectionString;
using (EntityConnection conn = new EntityConnection(connectionString))
{
    conn.Open();
    System.Diagnostics.Debug.WriteLine("Connected");
    conn.Close();
} 

In the code above, we can see the use of EntityConnection. This derive from DbConnection like SqlConnection do it with ADO.NET. It will also use a EntityCommand that also inherit from an ADO.NET object, the DbCommand.

ESQL is more error prone than Linq to Entity because the query is in a string. You do not have Intellisense, neither the compiler to tell you that you have error. Here is an example of showing with ESQL all regions of the Northwind database.

string connectionString = ConfigurationManager.ConnectionStrings["NorthwindEntities1"].ConnectionString;
using (EntityConnection conn = new EntityConnection(connectionString))
{
    conn.Open();
    string sqlQuery = @"SELECT reg.RegionId
                                , reg.RegionDescription 
                        FROM NorthwindEntities1.Region as reg";
    using (EntityCommand command = new EntityCommand(sqlQuery, conn))
    {
        var reader = command.ExecuteReader(System.Data.CommandBehavior.SequentialAccess);
        while (reader.Read())
        {
            System.Diagnostics.Debug.WriteLine(reader["RegionId"] + " : " + reader["RegionDescription"]);
        }
    }
    conn.Close();
} 

This code use an EntityDataReader that derive from DbDataReader. Like its inherited class, it can only be used to read forward. The major change is in the sqlQuery variable. As you can see, it does not do it’s query against the table but against the Entity Model. You have to use the Entity Container Name.

Where to find the Entity Container Name.

Also, in SELECT, it’s not the name of the column of the table that you have to use but the name of the property of the entity. So, people with a SQL background may feel comfortable with the syntax.

Object Context

The previous section show that ESQL let you have a very tight control over the query by using a SQL type of statement. But, on the other hand, it’s not very interesting because we could just use ADO.NET object to almost do the same. Wherefore, that is why ESQL has more under the hood.

ESQL can use Object Context to retrieve Entity Object without having to build them like with the ADO.NET. This start to be interesting. Let check an example.

using System.Data.Objects;
//...
string connectionString = ConfigurationManager.ConnectionStrings["NorthwindEntities1"].ConnectionString;
using (EntityConnection conn = new EntityConnection(connectionString))
{
    using (ObjectContext objectContext = new ObjectContext(connectionString))
    {
        objectContext.Connection.Open();
        string sqlQuery = @"SELECT  reg.RegionId
                                    , reg.RegionDescription 
                            FROM NorthwindEntities1.Region as reg";
        var allRegions = new ObjectQuery<DbDataRecord>(sqlQuery, objectContext).ToList();
        foreach (var region in allRegions)
        {
            System.Diagnostics.Debug.WriteLine(region.GetInt32(0) + " : " + region.GetString(1));
        }
        objectContext.Connection.Close();
    }
} 

The line 12 and line 15 contains new code. The line 12 execute the query and return a DbDataRecord. A DbDataRecord is inherit IDataRecord and can only access elements by index. This is not very convenient and from my personal perspective does not give an interesting way to get data from the database. However, some extension let you handle ObjectQuery easier but at the end you will still need to non typed object.

C# System.Transactions namespace

You can use you DbConnection to get your transaction but the System.Transactions namespace give you an other option for handling transaction.

This namespace work with SQL Server 2005 and later and offers support for distributed transactions. At first, this transactions namespace will handle the transaction has a local lightweight transaction but if detect that multiple connection is open that the transaction switch to distributed transactions. This behavior is also known as “implicit transaction” because the developer does not explicit how to handle it.

DTC's service needs to be started

For example, here is the example we previously did with the SqlDbConnection with the use of the System.Transactions instead of the one provided by the connection.

public int SaveCustomers(IEnumerable<Customer> customers)
{
	ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings["ApplicationServices"];

	int rowsAffected=0;
	using (var connection = new SqlConnection(connectionStringSettings.ConnectionString))
	{
		connection.Open();
		using (System.Transactions.TransactionScope ts = new System.Transactions.TransactionScope())
		{
			using (var command = new SqlCommand())
			{
				command.Connection = connection;
			  
				foreach (var customer in customers)
				{
					if (customer.IsNew)
					{
						command.CommandText = "INSERT INTO customers (CustomerID, CompanyName) VALUES (@id, @name)";
					}
					else
					{
						command.CommandText = "UPDATE customers SET CompanyName = @name WHERE CustomerID = @id";
					}
					command.CommandType = System.Data.CommandType.Text;
					command.Parameters.Clear(); //Remove 
					command.Parameters.Add(new SqlParameter("id", customer.Id));
					command.Parameters.Add(new SqlParameter("name", customer.Name));
					rowsAffected += command.ExecuteNonQuery();
				}

				ts.Complete();
			}
		}
		connection.Close();
	}
	return rowsAffected;
}

As you can see, few lines have been removed and some changed. You will notice that we do not have anymore any try-catch. That’s right, the USING handle any problem and if the Transaction.Complete() is not called, it’s automatically a RollBack. If multiple connections are inside the transaction using, all of them will be under the scope of the transaction distributed transactions coordinator.

Ssytem.Transactions Reference DLL

Unfortunately, this namespace is only pertinent if you use Sql Server 2005 and more. In fact, you should always use this one if you are in a Microsoft Sql server 2005, 2008 and more. The only time that it’s not possible to use it is with other type of database. The reason to use this one instead of the ADO.NET transactions is the automatic handling of lightweight transaction and distributed transactions.

Transaction Scope Options

System.Transactions let you set you set a type for you transaction via the enumeration TransactionScopeOption.

Transaction Scope Option

  • Required
  • If a transaction exist, a new declaration of the a transaction will simply join the first one. If none is defined, a new transaction will be initiated. This can be useful in the scenario that you that you have 1 method that call 2 methods. You put the a transaction and inside you add the two methods. Inside those methods you can have some database call with or without transaction scope. At the end, all will be under the same transaction. This is very powerful and let you have atomic transaction over multiple methods.

  • RequiresNew
  • This will create a new independent transaction. This can be useful if you want to execute something what ever the state of the existing transaction. For example, you have a logging system that log data into the database. You may want to log even if they are problem.

  • Suppress
  • This remove the transaction behavior for all call inside the transaction. This give you the leverage to do stuff outside the transaction while being inside an existing transaction.

The use of System.Transactions to handle DTC is very useful. First, it let you use Lightweight Transaction Manager(LTM) instead of DTC when possible. This give you a big performance boost. Second, you do not need to inherit from ServicedComponent, so you can have cleaner object with the possibility to inherit from what you desire. The last thing is that it does not use any COM+ object. So nothing is loaded in the Component Services.