Products

Solutions

Resources

Partners

Community

About

New Community Website

Ordinarily, you'd be at the right spot, but we've recently launched a brand new community website... For the community, by the community.

Yay... Take Me to the Community!

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact .

The use of the Community Blog is covered by our Community Blog Guidelines - please read before commenting or posting.


A Store Admin panel with Entity framework and Dynamic Data

In this june blog we invite you to visit one of the website that we are using with Gilles to test the Store module, at http://beta5.dotnetnuke.fr.

This is an experimental - but fonctionnal - admin panel for Store, which is entirely built upon Entity framework and Dynamic Data.

At first sight this may seem like any module you get used to with DotNetNuke.
But a closer look will reveal some interesting and early technologies that are not so common.


Specifications

http://beta5.dotnetnuke.fr is a DNN 5.1 public beta instance, with Store module 2.1.17 beta (which is also a public beta that you can download at www.dotnetnuke.fr). This website runs on the framework 3.5 SP1.

This demo makes use of the Entity framework data model class library 'StoreModel.dll', which I built and explained in my previous blogs.


Guided tour

The Store tab contains a standard 2.1.17 Store module for a fictional horse riding equipement shop.
This is not the focus of this blog, and I suggest that you go straight to the experimental administrative section of this shop, which you will find under the Dynamic Store Admin main menu entry. The current demo tab is StoreDynamicData4. This may change any time, as this is a work in progress. I will fix some issues that you will notice during the tour.

Localization

The auto-generated nature of the scaffold does not make it easy to use DotNetNuke localization resource files. I will not discuss this here. For this demo, I have just tried to ensure that the french words are similar enough to their english counterparts, so it should not be too difficult to guess their meaning when necessary.


Entities.

This page displays an auto-generated list of the tables that are part of the Store module (they are called 'entities' in ORM jargon). For this simple demo, our entities map our database tables 1:1, but it might be different with a more sophisticated model. For example, we might have applied filter to the model to create an entity of non-deleted clothes in stock, and have this entity displayed in our list as if it was a regular table.

Dim visibleTables As System.Collections.IList = MetaModel.Default.VisibleTables
Menu1.DataSource = visibleTables
Menu1.DataBind()

As you may guess, VisiblesTables is the collection of tables we want to display, amoung those in the StoreModel. For these tests, we wanted to see all tables that are specific to Store. But you may also notice that the latest table is the standard DNN Users table, which is Store-related, but not Store-specific.  


Navigation

Let's select either one of the first two tables, StoreCategories or StoreProducts, and have have a look at their properties.

What's interesting is the additional fields which appear after the standard properties of the entity. If you are in list mode, these 'navigational properties' are the latest columns to the right. It may be easier to see them after clicking 'Details', down the detail page.
These extra fiels are links to the related tables, i.e. the category, a review or a cart if you select a product; or Products if you selected a category.
Navigating from a table to the related tables is the essence or entity framework, to the point that the related content in the other table is called a 'navigation property' - kind of an extended property of the entity itself.

The navigation properties work with one-to-one, one-to-many or many-to-many relations. Also note that the Categories entities have a navigation property to their own table. This is because of the hierarchical structure or the sub-categories.


Scaffolding

The notion of scaffolding refers to the automated construction of the CRUD operations (I discovered scaffodling with Ruby On Rails, where the pages for listing, inserting, updating or deleting products would have been 2 words of code : 'scaffold StoreProducts')

There is a major difference beetween RoR's scaffold and Dynamic Data's scaffold though. Due to the interpreted nature of Ruby, RoR builds the scaffold classes on the fly. Scaffolding in Ruby On Rails refers to both the construction of the necessary classes from the database, and the basic generation of the HTML and the code (M, V and C).

With Entity framework and Dynamic Data, these operations are layered. The classes are baked into the StoreModel, and dynamic data is only responsible for the page generation.

You probably noticed that Dynamic Data includes a nice filter component (on top of the lists), and a pager. Both are accessible classes that can be configured.


Data access

There is not a single line of code refering to our database. The only visible layer from Dynamic Data is our Store model, which is contained in our bin/StoreModel.dll. Had we built our model against a non MS-SQL database, we would still have the exact same code. Here is the only line that refers to my StoreModel :

model.RegisterContext(GetType(StoreDynamicData4.StoreDynamicEntities), New ContextConfiguration() With {.ScaffoldAllTables = True})

 

Actions

Our dynamic data module contains 4 mains controls that are responsible of the standard CRUD operations :

list.ascx
details.ascx
edit.ascx
insert.ascx

As you can see, no single piece of code is dedicated to a table in particular. Pages are basically common to every entities, there is a page per action rather than a page per table.

It is possible to override this common behavior with CustomPages. All there is to do is create a custom version of any of the controls above, and place them in a folder that takes his name after the customized table

Altough my customized list.ascx for the StoreProducts is not very different from the others, you can notice minor specific design changes :

 

 

I just copied the standard list.ascx, changed it, and put it into :

CustomPages/Store_Products/List.aspx  

A likely scenario would be to give it its own stylesheet.


Metadata

Not only is our model aware of the relations beetween tables, but it also knows the field types from the metadata. This is why we did not have to write any code to choose the proper control for our fields. Dynamic data contains a set of field templates, which are displayed as needed. Let's have a look at the Boolean.ascx.vb which handles the display of all boolean fields :

Imports System.Web.DynamicData
Partial Class BooleanField
    Inherits System.Web.DynamicData.FieldTemplateUserControl
    Public Overrides ReadOnly Property DataControl As Control
        Get
            Return CheckBox1
        End Get
    End Property

   Protected Overrides Sub OnDataBinding(ByVal e As EventArgs)
        MyBase.OnDataBinding(e)
        Dim val As Object = FieldValue
        If (Not (val) Is Nothing) Then
            CheckBox1.Checked = CType(val,Boolean)
        End If
    End Sub
End Class


Routing

Dynamic Data uses a kind of MVC routing architecture that does not mix well with the existing DotNetNuke routing system.

First of all, the Dynamic Data project template that comes with Visual Studio routes the actions to Pages instead of Controls.  Out of the box you get list.aspx, details.aspx, edit.aspx and insert.aspx instead of controls. Something that's not cool to make a DotNetNuke module.

Then Dynamic Data, pretty much like RoR, has its own convention for the file folders organisation, such as DynamicData/Content/Images or DynamicData/CustomPages.Store_Products/List.ascx

We configure the path to this structure in global.asax.vb :
model.DynamicDataFolderVirtualPath = "~/DesktopModules/StoreDynamicData4/DynamicData"
   
Now we have to define the routing. By default, this routing changes urls like :

StoreProducts/List or StoreProducts/details/xxxx

to the actual webform that will embed the actions controls. This is normally done with a route definition like :

 routes.Add(New DynamicDataRoute("{table}/{action}.aspx") With { _
     .Constraints = New RouteValueDictionary(New With {.Action = "List|Details|Edit|Insert"}), _
      .Model = model})

Private Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
  RegisterRoutes(RouteTable.Routes)
End Sub

But this routing assumes that you want these urls be routed to different pages according to the requested action. This is not what we want, since only Controls (.ascx) can be insertied into a a DotNetNuke module. For this reason, I tried to change the actions pages (.aspx) to actions controls (.ascx), and define the routing to redirect all URL's to the same default.aspx page (not yet the DNN default.aspx, but at least a unique page, assuming that if we could obtain a fully fonctionnal Dynamic Data with a single form, then it should be theorically possible to consider an integration into a pure DotNetNuke module later).

Using Dynamic Data with a single page seems to require a custom route handler in global.asax :

routes.Add(new DynamicDataRoute("{table}/{action}.aspx") With { _
            .Constraints = new RouteValueDictionary(New With { .Action = "List|Details|Edit|Insert" }), _
            .Model = model, _
  .viewName ="MaViewName", _
            .RouteHandler = new StoreDynamicDataRouteHandler() })
    

Public Class StoreDynamicDataRouteHandler
  Inherits DynamicDataRouteHandler

  Public Overrides Function CreateHandler(ByVal route As System.Web.DynamicData.DynamicDataRoute, _
                                          ByVal table As System.Web.DynamicData.MetaTable, _
                                          ByVal action As String) _
                                          As System.Web.IHttpHandler
dim mapage as system.web.ui.page
dim monhandle as IHttpHandler
mapage = BuildManager.CreateInstanceFromVirtualPath( "~/DesktopModules/StoreDynamicData4/Default.aspx", GetType(Page))
monhandle = DirectCast(mapage, IHttpHandler)
return DirectCast(monhandle, IHttpHandler)

Public Class StoreDynamicDataRoute
  Inherits DynamicDataRoute
  Sub New(ByRef url As String)
    MyBase.New(url)
    Me.RouteHandler = New StoreDynamicDataRouteHandler()
  End Sub
End Class


Now that all our action requests are redirected to the same page, how does it know what to do ? Fortunately, the context has kept track of our desired action, and we'll retrieve this information before we load the proper control (default.aspx.vb) :

Dim requestContext = DynamicDataRouteHandler.GetRequestContext(Context)
            Dim action As String = requestContext.RouteData.GetRequiredString("action")
            ' Load the proper user control for the table/action
            Dim ucVirtualPath As String ' replaces : = table.GetScaffoldPageVirtualPath(action)
            Select Case action
                Case "List" : ucVirtualPath = "DynamicData/PageTemplates/list.ascx"
                Case "Edit" : ucVirtualPath = "DynamicData/PageTemplates/Edit.ascx"
                Case "Details" : ucVirtualPath = "DynamicData/PageTemplates/Details.ascx"
                Case "Insert" : ucVirtualPath = "DynamicData/PageTemplates/Insert.ascx"
                Case Else
                    Throw New InvalidOperationException("Bug : action [" & action & "] differente de List, Edit, Details, ou Insert")
            End Select
            ph.Controls.Add(LoadControl(ucVirtualPath))

We are now one step away from integrating Dynamic Data into a pure DotNetNuke module.


Conclusion:

As you can see, using Dynamic Data to leverage the power of Entity Framework, is a very promessing perspective, but it is difficult to integrate nicely in a DotNetNuke website.

If you want to use it as an external project, aimed at the administrators, then it is quite straightforward.

But due to the conflicting natures of DNN's and Dynamic Data's routing architectures, I have not been able to make it a real module, and I could only insert it into an iframe, with it's own default.aspx page.

The iframe is a simple technique, and we get an excellent iframe module with DotNetNuke. Inserting your Dynamic Data project into an iframe is an elegant solution - tough highly politically incorrect. I'm not so sure why we may have dozens of opened windows on our screens, but it is prohibited to have 2 forms in a single page, if we want to remain XHTML compliant.

That said, let's remember that Entity Framework is not only a easy way to build quick scaffoldings. It's a rich framework upon which you can build you own tools. This Dynamic Data demo was just an example of how we can make use of the StoreModel, but it can and will also serve many other purposes.
    

 

    

 

My customised <%=Table.Displayname%>

Comments

Comment Form

Only registered users may post comments.

NewsArchives


Aderson Oliveira (22)
Alec Whittington (11)
Alessandra Daniels (3)
Alex Shirley (10)
Andrew Hoefling (3)
Andrew Nurse (30)
Andy Tryba (1)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (37)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Bogdan Litescu (1)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (213)
Chris Paterra (55)
Clint Patterson (108)
Cuong Dang (21)
Daniel Bartholomew (2)
Daniel Mettler (181)
Daniel Valadas (48)
Dave Buckner (2)
David Poindexter (12)
David Rodriguez (3)
Dennis Shiao (1)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (80)
Francisco Perez Andres (17)
Geoff Barlow (12)
George Alatrash (12)
Gifford Watkins (3)
Gilles Le Pigocher (3)
Ian Robinson (7)
Israel Martinez (17)
Jan Blomquist (2)
Jan Jonas (3)
Jaspreet Bhatia (1)
Jenni Merrifield (6)
Joe Brinkman (274)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Kelly Ford (4)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matt Rutledge (2)
Matthias Schlomann (16)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Miguel Gatmaytan (3)
Mike Horton (19)
Mitchel Sellers (40)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Oliver Hine (1)
Patricio F. Salinas (1)
Patrick Ryan (1)
Peter Donker (54)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Sacha Trauwaen (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott Schlesier (11)
Scott Wilkinson (3)
Scott Willhite (97)
Sebastian Leupold (80)
Shaun Walker (237)
Shawn Mehaffie (17)
Stefan Cullmann (12)
Stefan Kamphuis (12)
Steve Fabian (31)
Steven Fisher (1)
Tony Henrich (3)
Torsten Weggen (3)
Tycho de Waard (4)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (40)
Will Strohl (180)
William Severance (5)
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out