Showing posts with label c#. Show all posts
Showing posts with label c#. Show all posts

Wednesday, January 18, 2012

Creating a Dependency Injected WCF Data Service

In this post, I’ll explain how to decouple your WCF data service from a specific data context. This is useful in many ways including changing out your context implementation at runtime or mocking out your context for testing purposes. The example code will use MEF (Managed Extensibility Framework), but any dependency injection framework, service locator implementation, or factory pattern could be used.

Getting Started

The first thing you will need to get started is an implementation of DbContext. I’ve chosen to go with a code first approach in this example because it gives me explicit control over the code in the context. Entity Framework 4.1, which is available as a Nuget package, provides a simple, purpose-driven API, which allows me to create a new DbContext and specify the entity types that it is responsible for in just a few lines of code. The base class and EF4.1 plumbing does all the hard work.

public class PersonContext : DbContext
{
public IDbSet<Person> People { get; set; }
public IDbSet<Address> Addresses { get; set; }
}

Figure 1: Basic PersonContext implementation

This implementation satisfies the most basic requirements of EF4.1 for a DbContext, but as you’ll see as we go along, we’ll want to flesh it out a bit more in order to support MEF’s requirements.


Give Your DbContext an Interface


Uncle Bob Martin’s SOLID object oriented principles is a must-read for all programmers. The ‘D’ in SOLID is for Dependency Inversion. In a nutshell, dependencies between objects should be based on abstractions not concretions.  Our next step is to create an interface that will represent our DbContext.

 

public interface IDbContext : IDisposable
{
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
}
Figure 2: IDbContext interface

 

Initializing Your Context


The EF4.1 DbContext class can take a connection string in as a constructor parameter. For simple cases, this might be enough for you. However, if your context requires additional information to operate properly, you may want create a configuration class that you can inject into your context through its constructor. I’ve take this approach because it allows for greater flexibility in initialization of the context.


[Export]
public class DbContextConfiguration
{
public string Name { get; set; }
public string ConnectionString { get; set; }
}

Figure 3: DbContextConfiguration needed to initialize your DbContext

 

[ImportingConstructor]
public PersonContext([Import("PersonContextConfiguration", typeof(DbContextConfiguration))] DbContextConfiguration configuration)
: base(configuration.ConnectionString)
{
_configuration = configuration;
}
Figure 4: PersonContext constructor

 

The first thing you’ll notice in the code above are the [Export], [ImportingConstructor], and [Import] attributes that are applied to the DbContextConfiguration class and PersonContext constructor. These are MEF attributes, which are used to support the dependency injection pattern. MEF will handle auto-magically wiring up the dependencies through a call to ComposeParts(). If you are new to MEF or unfamiliar with how it works, here are a couple of useful links to get you started.

 



 

Creating Your WCF Data Service


Writing a WCF data service couldn’t be easier. In a matter of a few mouse clicks, you can be serving up REST-based data. Microsoft has dramatically reduced the effort required to implement a service by providing a rich API that provides a lot of functionality under the covers.


image


Figure 5: Add New Item


Adding a new WCF Data Service through the Add New Item dialog results in an entry point to that API via the DataService<T> class.



   1: public class PersonDataService : DataService< /* TODO: put your data source class name here */ >
   2:     {
   3:         // This method is called only once to initialize service-wide policies.
   4:         public static void InitializeService(DataServiceConfiguration config)
   5:         {
   6:             // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
   7:             // Examples:
   8:             // config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead);
   9:             // config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
  10:             config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
  11:         }
  12:     }

Figure 6: Boilerplate data service code


Simply replace the boilerplate TODO between the generic template brackets with a class that extends DbContext and you’re practically good to go. They even provide code snippets via comments that serve as placeholders for configuration changes that you can use to set access rules for the entity sets exposed by your DbContext.


*Note: in my example above, the DataServiceProtocolVersion.V3 is implemented in the October 2011 CTP release for data services. I began using it in order to integrate with the Entity Framework 4.1 DbContext API.


In our case, we will declare the data service this way:


public class PersonDataService : DataService<IDbContext> {…}


Override CreateDataSource


Next is the final piece of the puzzle. The DataService class provides a convenient way to control the instantiation of your service’s data source dependency. Namely - we will override the CreateDataSource method with an implementation such as this:


protected override IDbContext CreateDataSource()
{
context = compositionContainer.GetExportedValue<IDbContext>();
return context;
}

Figure 7: CreateDataSource implementation

 

Your implementation may differ, but essentially you want to use your MEF composition container, service locator, or other factory implementation in order to get an instance of your context based on the interface type. MEF has numerous ways for you to resolve this dependency.

 

A critical concern for your code in this area is to handle the multiplicity of dependencies you may find in your container. In a future post, I’ll demonstrate how to specify metadata to filter the results of your composition request.

 

Conclusion


Creating a loosely coupled design can sometimes be a challenge. In the case of WCF Data Services, Microsoft had the foresight to make this chore easier. Through abstraction of your data context, use of an extensibility framework like MEF, service locator or factory implementation, and a little glue code, you can decouple the service and context and reap the rewards of runtime composition and increased testability.

 

Friday, November 18, 2011

Duplicate MEF Exports When Export Has Metadata

I just discovered that the Managed Extensibility Framework will produce duplicate exports for parts that are exported with custom metadata. My scenario is pretty simple. I have created an Entity Framework DbContext subclass that is marked up with both [Export] and [DbContextMetadata] attributes. DbContextMetadataAttribute is my own custom metadata attribute.

   1: [Export(typeof(IDbContext))]
   2: [DbContextMetadata(ContextType = "Person")]
   3: public class PersonContext : DbContext, IDbContext
   4: {

The result is shown here:


image


I have verified that this is true by simply commenting out the custom metadata attribute. Interestingly, this behavior is not present when using the MEF ExportMetadataAttribute. I’m planning to dig into this a little more to see why it’s happening, but it certainly was unexpected.


 


Blogger Labels: Duplicate,Exports,Export,Metadata,Framework,custom,scenario,DbContext,DbContextMetadata,DbContextMetadataAttribute,IDbContext,ContextType,Person,PersonContext,behavior,ExportMetadataAttribute

Thursday, July 28, 2011

Entity Framework 4.1 Primary Key Convention

I’m very pleased with the move to EF 4.1. Using a code first approach to implement my Repository pattern has reduced complexity and given me additional control over my code base and that makes me very happy. I want to point out one area that is a potential sticking point when implementing your entities.

In our system we have a number of entities whose tables have primary keys that are not identities. These entities have their IDs set via initial load scripts at the time the database is deployed using initialization scripts. As a result, the ID fields are simply INTs. The repository for these entities supports adding new entities and require the caller to set the IDs on their entities prior to calling save.

The point of contention comes from the fact that Entity Framework, by default, considers properties marked as [Key] to be identities. You must supply an additional data annotation attribute to override this behavior. The attribute you must apply to your key field is:

[DatabaseGenerated(DatabaseGeneratedOption.None)]

Forgetting to apply this attribute will cause Entity Framework to generate SQL statements on insert that attempt to rely on the key being auto-generated by the identity. The result is a error when you attempt to insert new data that your ID field cannot be NULL.

Using data annotations on your entities allows you to customize numerous behaviors that Entity Framework provides as well other consumers of your entities include data binding for your UI.