Dec 01

Introduction

The goal of this post is to create a simple example of an application with an architecture domain-driven using Entity Framewrok 4.0 and POCO, the RIA services and Silverlight.

Installation Prerequisites

Microsoft Visual Studio 2010 Version 10.0.21006.1 B2Rel

Microsoft .NET Framework Version 4.0.21006 B2Rel

WCF RIA Services
Microsoft WCF RIA Services simplifies the traditional n-tier application pattern by bringing together the ASP.NET and Silverlight platforms. The RIA Services provides a pattern to write application logic that runs on the mid-tier and controls access to data for queries, changes and custom operations. It also provides end-to-end support for common tasks such as data validation, authentication and roles by integrating with Silverlight components on the client and ASP.NET on the mid-tier.

Silverlight 4 Beta Tools for Visual Studio 2010
This will install the developer runtime of Silverlight 4 Beta, the Visual Studio project support and the Silverlight 4 SDK. If you are developing Silverlight 4 Beta applications, this will be the minimum you want to install!

For more information: http://silverlight.net/getstarted/silverlight-4-beta/

Architecture Overview

image

Data Access Layer

The data access layer is simply constituted by a project of type "Class Library" which contains only the "ADO.NET Entity Data Model.

Business Layer

For the business layer, we create 2 projects of type "Class Library":

  • "MyNamespace.Business" which contains the template that is to say the business objects, the data context and some interfaces of my repositories.
  • "MyNamespace.Business.EF" which contains the "EntityFramework" implementation of my interfaces.

Service Layer

The service layer is a Web project that contains the "RIA Services," which is the point of entry for the Silverlight application.

UI Layer

The user interface consists of a Silverlight project with a .NET RIA Services to the Website.

Sample

In our example we use the "Northwind" database downloadable from:

http://www.microsoft.com/downloads/details.aspx?familyid=06616212-0356-46a0-8da2-eebc53a68034&displaylang=en

Data Layer

Creating a new "Class Library", then we add the "ADO.NET Entity Data Model" in our example Northwind.edmx. Then in order to use Entity Framework with POCO (Plain Old CLR Object) should remove the "Custom Tool" as:

image

In our case, we use only the table "Category" and "Product". Our model is as follows:

image

Business Layer

For the business layer we use 2 "Class Library":

  • A "Class Library" which contains the interface and the model.
  • A "Class Library" which contains the implementation EntityFramework (which might be of NHibernate, this will be the subject of an article soon)

Having the interface and implementation separately allows me to make an inversion of control (IoC), which allows me to decouple the dependencies between objects. (In my case I use Castle Windsor but we could use others)

Here is how to effectively present the business section:

image

Business interface

The business section is composed of "Repository" interfaces :

public interface IRepository<T>
{
    IQueryable<T> GetQuery();
    IEnumerable<T> GetAll();
    IEnumerable<T> Find(Func<T, bool> where);
    T Single(Func<T, bool> where);
    T First(Func<T, bool> where);

    void Delete(T entity);
    void Add(T entity);
    void Attach(T current);
    void Attach(T current, T original);
    void ApplyCurrentValues(T current);
    void SaveChanges();
}

And the model is composed of a set of business objects presented as follows:

public class Category
{
    public virtual int CategoryID { get; set; }
    public virtual string CategoryName { get; set; }
    public virtual string Description { get; set; }
    public virtual Byte[] Picture { get; set; }
    public virtual IList<Product> Products { get; set; }

    public Category()
    {
        
    }
}

Business implementation

The implementation of business consists of implementing a context in Entity Framework:

public class NorthwindContext : ObjectContext
{
    #region [Fields]

    private ObjectSet<Category> _categories;
    private ObjectSet<Product> _products;

    #endregion

    #region [Properties]

    public ObjectSet<Category> Categories
    {
        get
        {
            return _categories;
        }
    }

    public ObjectSet<Product> Products
    {
        get
        {
            return _products;
        }
    }

    #endregion

    #region [Constructors]

    public NorthwindContext()
        : base("name=NorthwindEntities", "NorthwindEntities")
    {
        _categories = CreateObjectSet<Category>();
        _products = CreateObjectSet<Product>();
    }

    #endregion
}

It also contains the implementation of the "Repsitories" in Entity Framework:

public class EFRepository<T> : IRepository<T> where T : class
{
    #region [Fields]

    private ObjectContext _context;
    private IObjectSet<T> _objectSet;

    public ObjectContext Context
    {
        get
        {
            if (_context == null)
            {
                _context = new NorthwindContext();
            }
            return _context;
        }
    }

    private IObjectSet<T> ObjectSet
    {
        get
        {
            if (_objectSet == null)
            {
                _objectSet = this.Context.CreateObjectSet<T>();
            }
            return _objectSet;
        }
    }

    #endregion

    #region [Constructors]

    public EFRepository(ObjectContext context)
    {
        _context = context;
    }

    #endregion

    #region IRepository<T> Members

    public IQueryable<T> GetQuery()
    {
        return ObjectSet;
    }

    public IEnumerable<T> GetAll()
    {
        return GetQuery().ToList();
    }

    public IEnumerable<T> Find(Func<T, bool> where)
    {
        return this.ObjectSet.Where<T>(where);
    }

    public T Single(Func<T, bool> where)
    {
        return this.ObjectSet.Single<T>(where);
    }

    public T First(Func<T, bool> where)
    {
        return this.ObjectSet.First<T>(where);
    }

    public void Delete(T entity)
    {
        this.ObjectSet.DeleteObject(entity);
    }

    public void Add(T entity)
    {
        this.ObjectSet.AddObject(entity);
    }

    public void ApplyCurrentValues(T current)
    {
        _context.ApplyCurrentValues<T>(typeof(T).Name, current);
    }

    public void Attach(T current)
    {
        this.ObjectSet.Attach(current);
    }

    public void Attach(T current, T original)
    {
        throw new NotImplementedException();
    }

    public void SaveChanges()
    {
        this.Context.SaveChanges();
    }

    #endregion
}

Service Layer

The service layer is a website containing the entry point for the Silverlight application, the RIA Services and a set of DTO (Data Transfer Object).

Here is an example of DTO:

[Serializable()]
public class CategoryDTO
{
    [Key]
    public int CategoryID { get; set; }
    public string CategoryName { get; set; }
    public string Description { get; set; }
    public Byte[] Picture { get; set; }
    public IList<ProductDTO> Products { get; set; }

    public CategoryDTO()
    {
        
    }
}

And here is the corresponding “Domain Service”:

[EnableClientAccess()]
public class CategoryDomainService : DomainService
{
    #region [Fields]

    private ICategoryRepository CategoryRepository;

    #endregion

    #region [Constructors]

    public CategoryDomainService()
    {
        IocContainer iocContainer = new IocContainer("DomainDriven.Business.cfg.xml");
        CategoryRepository = iocContainer.Resolve<ICategoryRepository>();
    }

    #endregion

    #region [Methods]

    public List<CategoryDTO> GetCategories()
    {
        var query = from category in CategoryRepository.GetAll()
                    select new CategoryDTO()
                    {
                        CategoryID = category.CategoryID,
                        CategoryName = category.CategoryName,
                        Description = category.Description,
                        Picture = category.Picture
                        //Products = (from product in category.Products
                        //            select new ProductDTO()
                        //            {
                        //                ProductID = product.ProductID,
                        //                Discontinued = product.Discontinued,
                        //                ProductName = product.ProductName,
                        //                QuantityPerUnit = product.QuantityPerUnit,
                        //                ReorderLevel = product.ReorderLevel,
                        //                SupplierID = product.SupplierID,
                        //                UnitPrice = product.UnitPrice,
                        //                UnitsInStock = product.UnitsInStock,
                        //                UnitsOnOrder = product.UnitsOnOrder,
                        //            }).ToList()
                    };

        if (query != null)
            return query.ToList();
        return null;
    }

    [Insert]
    public void InsertCategory(CategoryDTO category)
    {
        CategoryRepository.Add(MapCategory(category));
    }

    [Update]
    public void UpdateCategory(CategoryDTO category)
    {
        Category cat = MapCategory(category);
        CategoryRepository.Attach(new Category { CategoryID = category.CategoryID });
        CategoryRepository.ApplyCurrentValues(cat);
    }

    [Delete]
    public void DeleteCategory(CategoryDTO category)
    {
        Category cat = new Category { CategoryID = category.CategoryID };
        CategoryRepository.Attach(cat);
        CategoryRepository.Delete(cat);
    }

    public override bool Submit(ChangeSet changeSet)
    {
        bool test = base.Submit(changeSet);
        CategoryRepository.SaveChanges();
        return test;
    }

    private Category MapCategory(CategoryDTO category)
    {
        return new Category()
        {
            CategoryID = category.CategoryID,
            CategoryName = category.CategoryName,
            Description = category.Description,
            Picture = category.Picture
        };
    }

    #endregion
}

There are just two things to note:

  • The instantiation of my object "CategoryRepository" through Windsor Castle. (In the constructor)
  • Overloading of method "Submit" which allows me to do "SaveChanges in the background.

UI Layer

The UI layer is relatively simple. I use the RIA controls in conventional manner. I let you discover the source code by yourself.

Here are the results:

image

Conclusion

The purpose of this post was here using the RIA Services in the context of a Domain Driven architecture containing a service layer and DTO. I’m waiting for your comments to improve this architecture.

 

You can download the full source code here:

Comments

Jacques

Posted on Thursday, 1 July 2010 10:18

I recommend AutoMapper for mapping between entity & DTO: http://automapper.codeplex.com/

Antoine Bachas

Posted on Wednesday, 7 July 2010 19:22

I don't know if you've been making changes, but your pages aren't displaying correctly for me. The edges of the text are running into each other.

realtouch toy

Posted on Monday, 30 August 2010 05:53

I care for your blog, Its wonderful to find not everyone is just posting a lot of waste now a days!

Jayme

Posted on Sunday, 5 September 2010 13:34

Comfortably, the post is really the freshest on this valuable topic. I agree with your conclusions and will eagerly look forward to your coming updates. Saying thanks will not just be sufficient, for the phenomenal lucidity in your writing. I will at once grab your rss feed to stay informed of any updates. Admirable work and much success in your business enterprize!

Travel Charger

Posted on Wednesday, 8 September 2010 02:26

Thumbs up for this article.  You are my absolute inspiration.

Gewinnspiele

Posted on Thursday, 16 September 2010 11:09

Advantageously, the article is in reality the greatest on this deserving topic. I fit in with your conclusions and will eagerly look forward to your upcoming updates. Just saying thanks will not just be enough, for the exceptional clarity in your writing. I will directly grab your rss feed to stay privy of any updates. Pleasant work and much success in your business enterprize!

wedding party favors

Posted on Saturday, 18 September 2010 05:25

Let cool. I frost with cream cheese frosting.I worked in a bakery for several years.  We used the same cake for weddings and birthday cakes, as well as everyday cakes.  Now, the wedding cakes tend to have layers that are much bigger; the different sizes are a little challenging to deal with, but other than that, they were identical to our other cakes.  The only thing that might change is that the fillings in a wedding cake might be more interesting because the brides sometimes suggested something different.The other difference is $2- $3 a slice.  Good luck!The price?they both are the sameI think the difference is in the quality.  Most people dont think too much about b-day cake. If they dont make it themselves, they just buy it at the grocery store.  For the wedding cake, people actually spend time trying different ones out & get it at a bakery or specialty cake shop.Usually wedding cakes are made with fancy flavorings like almond or cherry, when birthday cakes are usually just the classic vainilla or chocolate.Never knew a difference?But i like Birthday cakes more..wedding cakes are usually just plain vanilla usually people want a better tasting cake for weddings then birthdaysso wedding cakes bakers are more rare and require allot of skill

Gewinnspiele

Posted on Friday, 24 September 2010 20:14

Merely want to say your article is stunning. The clearness in your post is simply striking and i can assume you are an expert on this field. Well with your permission allow me to grab your rss feed to keep up to date with succeeding post. Thanks a million and please keep up the gratifying work.

outlook pst repair

Posted on Tuesday, 28 September 2010 15:00

Nice post....When I read this post it reminded me of my class mate. He always kept talking about this. I will forward this URL link to him. I am very sure he will love to read it. Thanks for sharing. You are bookmarked

Calgary IT Consulting services

Posted on Tuesday, 28 September 2010 15:03

Thanks for the post, it was nice. I read your other post as well, all were good. I really appreciate the author. You are bookmarked.

tarot

Posted on Friday, 1 October 2010 02:08

I'm out of my mind, but feel free to leave a message.

new laptop battery

Posted on Wednesday, 13 October 2010 20:04

Personally I know a guy is gay when we meet and i feel the need to check my fly.

pożyczki forum

Posted on Thursday, 14 October 2010 12:15

Oh! What a excellent blog. I got here by an accident, throught my friend's blog. I love your texts. They are very interesting. And I'm thinking if I could use a part of your words in my article. Please write me back if I can. Great thanks.

video

Posted on Friday, 15 October 2010 12:40

Great message given there. Promise only what you can deliver. Then deliver more than you promise.   Author Unknown

cloudwork

Posted on Saturday, 16 October 2010 14:57

Thanks for the Information, thanks for this fine Post. I will come back later  .

Annis Haverfield

Posted on Saturday, 16 October 2010 17:02

Hi everybody this particular had been an important quite interested read... This kind of could possibly not be the particular time as well as site although mabey somebody can help me out. I'm seeking a website that will could develop a excellent web page for my brand-new firm.

Hidden objects

Posted on Saturday, 16 October 2010 23:59

I think cute site. Check out my blog too.

3D Technology

Posted on Monday, 18 October 2010 18:47

HAHAHAHAHA yes!

Mahjong games online

Posted on Tuesday, 19 October 2010 21:37

This was a really good portal. Nice design.

Add comment




  Country flag

biuquote
Loading