2011-05-26

Getting the ObjectContext from an EntityObject

There are a few situations where it's useful to get an ObjectContext from an EntityObject. Note that in general I do not recommend a design that depends on this; there doesn't appear to be an easy way to do this using code first in EF 4.1 (using the DbContext API). That said, either of the solutions in this blog post will work when using the ObjectContext API.

The most common solution for this problem is from a 2009 Microsoft blog post by Alex James (webcite). Unfortunately, that solution has several limitations (including the requirement that the entities must have relations to other entities). Both of the solutions below do not have these limitations.

We use an example entity container named NorthwindEntites, derived from ObjectContext. To this we will add a factory method FromEntity(EntityObject entity), which retrieves the NorthwindEntities instance to which that entity is attached, or null if the entity is detached.

Solution 1: Dynamic

The idea behind this solution is to add a property to the entity type that points to its own ObjectContext. It's possible to do this by modifying the code-generating template file, but it's also possible to just add the property to each entity type manually and use dynamic duck typing to access it.

The modified NorthwindEntities uses OnContextCreated to hook into its constructor and set up event handlers to respond whenever an entity is added to or removed from this context. Each event handler uses dynamic duck typing to access an "ObjectContext" property on the entity; if no such property exists, the entity is ignored.

using System.ComponentModel;
using System.Data.Objects.DataClasses;
using Microsoft.CSharp.RuntimeBinder;

namespace WindowsFormsApplication1
{
  public partial class NorthwindEntities
  {
    partial void OnContextCreated()
    {
      this.ObjectMaterialized += (_, e) =>
      {
        try
        {
          dynamic entity = e.Entity;
          entity.ObjectContext = this;
        }
        catch (RuntimeBinderException)
        {
        }
      };
      this.ObjectStateManager.ObjectStateManagerChanged += (_, e) =>
      {
        if (e.Action == CollectionChangeAction.Add)
        {
          try
          {
            dynamic entity = e.Element;
            entity.ObjectContext = this;
          }
          catch (RuntimeBinderException)
          {
          }
        }
        else if (e.Action == CollectionChangeAction.Remove)
        {
          try
          {
            dynamic entity = e.Element;
            entity.ObjectContext = null;
          }
          catch (RuntimeBinderException)
          {
          }
        }
      };
    }

    /// <summary>
    /// Gets the object context for the entity. Returns <c>null</c> if the entity is detached or does not define an <c>ObjectContext</c> property.
    /// </summary>
    /// <param name="entity">The entity for which to return the object context.</param>
    public static NorthwindEntities FromEntity(EntityObject entity)
    {
      try
      {
        dynamic dynamicEntity = entity;
        return dynamicEntity.ObjectContext;
      }
      catch (RuntimeBinderException)
      {
        return null;
      }
    }
  }
}

The disadvantage to this approach is that you have to add an ObjectContext property to each entity type, like this:

namespace WindowsFormsApplication1
{
  public partial class Order
  {
    /// <summary> 
    /// Gets or sets the context for this entity.
    ///  This should not be set by end-user code; this property will be set
    ///  automatically as entities are created or added,
    ///  and will be set to <c>null</c> as entities are detached.
    /// </summary> 
    internal NorthwindEntities ObjectContext { get; set; }
  }
}

Alternatively, you could modify the creation template. Either way, it's a fair amount of work.

Solution 2: Connected Properties

The Connected Properties library may be used to "attach" properties to entity objects at run-time. This means it's no longer necessary to add the ObjectContext property on each entity type.

This modified NorthwindEntities uses the same hooks as the one above, but it uses connected properties instead of dynamic duck typing:

using System.ComponentModel;
using System.Data.Objects.DataClasses;
using Nito.ConnectedProperties;
using Nito.ConnectedProperties.Implicit;

namespace WindowsFormsApplication1
{
  public partial class NorthwindEntities
  {
    /// <summary>
    /// The object context connected property type.
    /// </summary>
    private struct ObjectContextProperty { }

    /// <summary>
    /// Gets the object context connected property for a specified carrier object.
    /// </summary>
    /// <param name="entity">The carrier object.</param>
    /// <returns>The connected property.</returns>
    private static IConnectibleProperty<NorthwindEntities> ObjectContext(object entity)
    {
      return entity.GetConnectedProperty<NorthwindEntities, ObjectContextProperty>();
    }

    /// <summary>
    /// Handles post-construction event.
    /// </summary>
    partial void OnContextCreated()
    {
      this.ObjectMaterialized += (_, e) =>
      {
        ObjectContext(e.Entity).Set(this);
      };

      this.ObjectStateManager.ObjectStateManagerChanged += (_, e) =>
      {
        if (e.Action == CollectionChangeAction.Add)
        {
          ObjectContext(e.Element).Set(this);
        }
        else if (e.Action == CollectionChangeAction.Remove)
        {
          ObjectContext(e.Element).Set(null);
        }
      };
    }

    /// <summary>
    /// Gets the object context for the entity. Returns <c>null</c> if the entity is detached.
    /// </summary>
    /// <param name="entity">The entity for which to return the object context.</param>
    public static NorthwindEntities FromEntity(EntityObject entity)
    {
      return ObjectContext(entity).GetOrConnect(null);
    }
  }
}

The disadvantage of this approach is that you do need to take a dependency on the Connected Properties library, but I think that's a reasonable tradeoff.

This post was inspired by a recent SO question.

2011-05-19

Signed and Unsigned Comparisons in C, C#, and T-SQL

As noted earlier, I've been doing a lot of firmware development recently (in C). A long-standing rule of C (and C++) is to convert signed int values to unsigned int values if both are used in a comparison; this is what the standard specifies. It's also traditional to issue a warning (the famous comparison between signed and unsigned integer expressions warning) because such code is usually a mistake.

In C, the expression ( (unsigned)-1 == -1 ) will compile (with a warning), and have a value of 1 (true). C# and T-SQL both handle that situation very differently.

In C#, the expression ( unchecked((uint)-1) == -1 ) will compile without warning and have a value of false. What actually happens (webcite) is that the unsigned value of 0xFFFFFFFF and the signed value of -1 are both converted to long values and then compared.

The C# behavior does makes sense. C# continues the C/C++ tradition of implicitly promoting to int for any integral binary operation (e.g., two byte values added together are converted to ints before the addition). However, the additional implicit promotion to long was a bit of a surprise. This is probably due to 64-bit math becoming more commonplace - not common enough to have an implicit promotion to long for every binary operation, but enough to add the implicit promotion to long when necessary.

In SQL Server's TSQL, the expression select 'true' where -1 = 4294967295; will return an empty result set (meaning -1 is not considered equivalent to 4294967295). Interestingly, it's doing the same kind of promotion as C# (webcite). In this case, the value 4294967295 is typed as a bigint (a 64-bit signed integer).

The C# behavior can be seen when inspecting T-SQL statements generated by Linq to Entites. In my case, I was using code such as this to look up an item by serial number (an unsigned value):

using (var context = new MyEntities())
{
    uint serialNumber = 0xFFFFFFFF;
    var item = context.Items.Where(x => x.SerialNumber == serialNumber).SingleOrDefault();
}

The generated T-SQL statement (for SQL Server Compact Edition) was like this:

SELECT TOP (2) [Extent1].[ID] AS [ID], [Extent1].[SerialNumber] AS [SerialNumber] FROM [Items] AS [Extent1]  WHERE ( CAST( [Extent1].[SerialNumber] AS bigint)) = @p__linq__0

p__linq__0 had a DbType of Int64. Note that the generated T-SQL includes an explicit cast to bigint because the C# language implicitly inserted a cast to long in the expression x.SerialNumber == serialNumber.

Lesson learned: be careful of mixing signed and unsigned types. The warnings that existed in C/C++ are not necessarily present in C# (or T-SQL).

2011-05-12

Managed Services and UIs

One common question that I've seen is how to display a UI from a service.

The answer is: "don't".

Usually, when someone asks this question, the correct solution is to change the application from a service to a background application run whenever a user logs in (e.g., from the Startup folder), possibly with a tray icon. Occasionally, this isn't possible, and the correct solution in that case is to split the application into two applications: a service without a UI, and a UI front-end (which may be a backround application run automatically).

Unfortunately, some people try to push forward with the "service with a UI" approach. This is doomed to fail.

Inevitable Failure

There are two hurdles to displaying a UI from a service; the first is architectural, and the second is technical.

The architectural hurdle is simply that displaying a UI from a service just doesn't make sense. A Win32 service is a program that runs (or can be run) any time the computer is running, regardless of whether or not there is a user logged in. It doesn't make much sense to talk about "displaying a UI" if there isn't a user to show it to. Also consider multi-user (terminal server or fast-user-switching) computers: which user would see the UI?

The technical hurdle is a bit more complex. To summarize: services which display UIs are a security risk.

The Win32 windows messaging system was designed without security in mind. Before you get too mad at Microsoft, remember that the Internet (including email, TCP/IP, and HTTP) were designed without security, too. Back then, it was hard enough just to get it working, without worrying about someone deliberately trying to destroy it. Most security on the Internet today is due to wrapping the original insecure protocols in an encrypted, authenticated stream (SSL/TLS).

In fact, when I first got on the Internet, the common instructions for setting up an email server explicitly stated that it should be set up as an open relay so that anyone could send email through it. Then someone invented spam. The instructions have since been revised.

Similarly, in the early days, Windows had no need for security. In early versions of Windows, multitasking was non-preemptive, so any program could effortlessly cause a denial-of-service attack. Furthermore, each program had direct access to hardware, and causing a complete system crash was trivial.

These days, the situation is much improved. On modern OSes (not including the 9x line), a user-mode program simply cannot crash the system; it can only crash itself. With almost every new OS, Microsoft has enhanced security by trusting programs less (e.g., User Account Control).

One attack vector for malicious programs is a privilege escalation. This is a way for an untrusted program to trick the OS into trusting it more. One privilege escalation attack that has been discovered is called a shatter attack. This "shatter attack" is based on Win32 message passing.

In response, Microsoft made two changes starting in Vista: User Interface Privilege Isolation (see New UAC Technologies for Windows Vista (webcite)); and Session 0 Isolation (see this Application Compatibility blog post (webcite) or this Word document).

User Interface Privilege Isolation is a simple system where less-trusted programs (such as Internet Explorer) are limited in which Win32 messages they may send to more-trusted programs (such as services). This doesn't prevent services from having UIs, but may trip up programmers if they try to communicate with their service via message passing.

Session 0 Isolation is more surprising to most programmers, simply because most programmers are not aware of desktops or window stations. The following MSDN resources provide a good intro to the concept:

In essence, the older versions of Windows (XP and earlier) would run services in the same session as the first user that logged on to the physical computer, and services displaying UIs would be seen by that user. Newer versions of Windows (Vista and later) run services in their own special session (Session 0), which has its own window station and desktop completely independent from anything the user sees.

Naturally, this broke a lot of existing services, so Microsoft implemented a couple of workarounds. One is the "Interactive Service" flag, which would allow a service to display a UI. Another is the Interactive Service Detection Service, which is a special service that detects dialogs on Session 0 and notifies the user (if any) of them.

It is possible to set the Interactive Service flag when installing a service (not through the regular .NET Framework APIs; you have to p/Invoke for it). That is a horrible hack and should never, ever be applied to a new application. Even with that flag, some notification systems may not work as expected (see the end of this blog post from the security team (webcite)).

Remember that the Interactive Service flag is a backwards compatibility hack that weakens overall system security and may be removed from Windows vNext. Similarly, the Interactive Service Detection Service comes with this disclaimer: "This support might be removed from a future Windows release, at which time all applications and drivers must handle Session 0 isolation properly."

So - while it is possible to hack together a service with a UI today - you'd only be setting yourself up for failure in the future.

2011-05-05

Simple and Easy Entity Framework SQL Tracing

There's an easy way to add tracing to an application, but Entity Framework brings some special challenges. ObjectQuery.ToTraceString does allow tracing of SQL SELECT commands, but there's no built-in way to trace database updates.

However, there is an Entity Framework Tracing Provider that allows this. Follow the quick-start instructions on the home page, and you'll be off in no time!

Here's a few tests using SQL Server Compact Edition to access the Northwind sample database. This code:

using (var db = new NorthwindContext())
{
    MessageBox.Show(db.Orders.Count(x => x.Order_Date < DateTime.Now).ToString());
}

will result in this trace:

EntityFramework.NorthwindEntities Information: 0 : Executing 1: SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(1) AS [A1] FROM [Orders] AS [Extent1] WHERE [Extent1].[Order Date] < ( CAST( GetDate() AS datetime)) ) AS [GroupBy1]
EntityFramework.NorthwindEntities Information: 0 : Finished 1 in 00:00:00.0466592: [DbDataReader(C1:Int)]

Note that the total time taken by the query is included in the finishing trace. Another interesting tidbit is that DateTime.Now is not evaluated on the client side; rather, the SQL statement includes a call to GetDate.

Here's some code that deletes an order:

using (var db = new NorthwindContext())
{
    db.Orders.DeleteObject(db.Orders.OrderBy(x => x.Order_Date).First());
    db.SaveChanges();
}

resulting in this trace:

EntityFramework.NorthwindEntities Information: 0 : Executing 2: SELECT TOP (1) [Extent1].[Order ID] AS [Order ID], [Extent1].[Customer ID] AS [Customer ID], [Extent1].[Employee ID] AS [Employee ID], [Extent1].[Ship Name] AS [Ship Name], [Extent1].[Ship Address] AS [Ship Address], [Extent1].[Ship City] AS [Ship City], [Extent1].[Ship Region] AS [Ship Region], [Extent1].[Ship Postal Code] AS [Ship Postal Code], [Extent1].[Ship Country] AS [Ship Country], [Extent1].[Ship Via] AS [Ship Via], [Extent1].[Order Date] AS [Order Date], [Extent1].[Required Date] AS [Required Date], [Extent1].[Shipped Date] AS [Shipped Date], [Extent1].[Freight] AS [Freight] FROM [Orders] AS [Extent1] ORDER BY [Extent1].[Order Date] ASC
EntityFramework.NorthwindEntities Information: 0 : Finished 2 in 00:00:00.0027257: [DbDataReader(Order ID:Int, Customer ID:NVarChar, Employee ID:Int, Ship Name:NVarChar, Ship Address:NVarChar, Ship City:NVarChar, Ship Region:NVarChar, Ship Postal Code:NVarChar, Ship Country:NVarChar, Ship Via:Int, Order Date:DateTime, Required Date:DateTime, Shipped Date:DateTime, Freight:Money)]
EntityFramework.NorthwindEntities Information: 0 : Executing 3: delete [Orders] where ([Order ID] = @0) { @0=[Int32,0,Input]10000 }
EntityFramework.NorthwindEntities Information: 0 : Finished 3 in 00:00:00.0482807: 1 rows affected

As expected, the first command executes a single-row SELECT, followed by a DELETE that affects a single row. Note the use of the parameterized deletion query.

Unfortunately, the Entity Framework Tracing Provider does not support everything; in particular, direct database commands (e.g., ExecuteStoreCommand) are not supported.