Alternative ways of developing web sites using EPiServer CMS. An introduction to three open source frameworks that allow us to better tackle complexity, have a more enjoyable development experience and deliver better, well tested sites using EPiServer CMS.
4. I love building beautifull, fast and robust
web sites for high profile customers.
When they have editorial content EPiServer
CMS provides us with a solid foundation to
build upon.
The boring stuff is already in place. We as
developers can focus on delivering business
value from the get-go.
5. But, I also have a passion for ”agile”
software architecture.
A passion for clean code and flexible
systems.
A passion for studying my field.
A passion for learning about principles and
practices such as the SOLID principles.
6. But, I also have a passion for ”agile”
software architecture.
A passion for clean code and flexible
systems.
A passion for studying my field.
A passion for learning about principles and
practices such as the SOLID principles.
’
8. While EPiServer is mature after a decade of
development it was first released long
before many of us had ever heard about Test
Driven Development or MVC.
9. While EPiServer is mature after a decade of
development it was first released long
before many of us had ever heard about Test
Driven Development or MVC.
In other words; it’s built in a way that
makes it hard to apply modern
development practices and principles.
12. EPiServer development revolves around
pages, represented as PageData objects.
While these are primarily intended for
editorial content they aren’t limited to that.
13. In fact we can use them to model just about
anything. Orders, events, comments etc.
When we do that we never have to think
about how to persist them.
EPiServer has done an excellent job at
abstracting the database to the point we’re
we take for granted that saving, reading and
deleting will just work.
14. We also instantly get an administrative
interface for whatever we have modeled.
And access rights management, support for
multiple language versions, versioning and
so on.
Of course all of these are optimized for
editorial content.
15. Of course all of these are optimized for
editorial content.
But the fact that we can create just about
anything without having to think about
persistence and get at least some sort of
administrative UI is powerful.
16. Another strength is its flexibility.
I can often find myself frustrated when I try
to extend the system, but the fact of the
matter is that compared to many other
commercial products it’s highly extendable.
And while I would have preferred a more
open architecture where I could just switch
out or extend standard components there
are extension points for pretty much
everything.
17.
18.
19.
20.
21. Often our customers have bought EPiServer
for a simple public web site.
But once they’ve bought it, they want us to
use it for everything.
In those cases there are three things that
frustrate especially much.
22.
23. Ironically, the thing that frustrate me the
most is closely related to the thing that I like
the most – the way page types and thereby
PageData objects are modeled.
In the database through a UI.
The fact that page types are defined in the
database has several negative consequences.
24. While we’re able to model just about
anything in terms of data, we can’t have
logic, behavior, in our model objects.
The logic still has to go somewhere.
Often it ends up in the presentation layer.
25. We’re also not able to use inheritance or
polymorphism.
There’s no relationship between different
page types.
Similar data has to be modeled multiple
times. So does changes.
26. Deployment is painful.
We can’t just deploy code or scripted
database changes. We have to deploy data.
And we have to use magic strings and casts
to access data.
Actively bypassing the first test that the
compiler otherwise provides us with.
27.
28. The Dependency Inversion Principle states
that our code should “Depend on
abstractions, not on concretions”.
This is essential for truly flexible systems.
And for unit testing.
Unfortunately abstractions are scarce in the
EPiServer API.
29. The class we use for saving, retrieving and
deleting PageData object, DataFactory, is a
singleton with non-virtual methods.
And it doesn’t implement any interface that
defines many of its members.
This makes it hard to isolate our code from
it, and thereby from the rest of the EPiServer
API, the database and HTTP context.
30.
31. My final, big frustration with EPiServer
CMS is its tight coupling to Web Forms.
While I’m not convinced that ASP.NET
MVC, or any other MVC framework for that
matter, is a perfect fit for many of the sites
we build on EPiServer, Web Forms severly
limits our ability to create flexible systems
built using Test Driven Development.
32. Even if the EPiServer API would have had
abstractions, how would we have gotten
concrete implementations of them into our
code?
If we had been using ASP.NET MVC we
could have create a custom controller
factory.
But with Web Forms the framework
instantiates components such as user
controls.
33. Not to mention that the page life cycle and
on-by-default viewstate functionally isn’t
exactly architectural beauty or embracing
how the web works.
Unfortunately though, the current version of
EPiServer CMS has a few fairly important
features such as XForms and Dynamic
Content that requires Web Forms.
35. In 2009 an open source project called Page
Type Builder was born.
At its core it does two things…
36. It scans the application domain for classes
that appear to define page types and creates
and updates the corresponding page types
in the database.
We can create page types using code, and
only code. We don’t have to move data
when we’re deploying. Only code.
And we can use inheritance between page
types.
37. It also listens to events from the EPiServer
API and intercepts requests for PageData
objects.
If a PageData object that is about to be
returned is of a page type that can be
mapped to a class it creates an instance of
that class and copies the data from the
original object.
Finally, it swaps out the object being
returned with the instance of the class.
38. This means that DataFactory no longer
returns plain PageData objects.
It returns instances of classes that we’ve
created.
Those still inherit from PageData, meaning
that they play nice with the rest of
EPiServer’s functionality.
But they can have methods and logic in
property getters and setters.
66. Our page types can inherit base classes and
implement interfaces.
We’re able to use polymorphism.
One page type can return it’s name as link
text in menus while another can return
something completely different.
While the code that renders the menu only
knows that they both implement
IMenuItem.
67. Our page types can have behavior as well as
data.
They can have methods.
Properties can have logic in their getters and
setters.
68. We can build page providers that utilize
that we’re dealing with different classes.
So far I’ve heard about page providers built
using Fluent NHibernate and Raven DB.
69. We can query using LINQ to Objects in a
strongly typed way.
And we can serialize our pages when they
are saved and push them over to a search
server, to later query for them using a
strongly typed, LINQ-like API.
70.
71. EPiAbstractions is an open source project
that wraps EPiServer’s API.
It provides concrete implementations,
facades or adapters, that delegate to
EPiServer’s classes.
These in turn implement interfaces.
Allowing our code to depend on
abstractions.
72. It also provides a simplified API that
doesn’t map directly to EPiServer’s but is
easier to work with.
For this API it also provides in-memory-
implementations, allowing us to write
production like code in tests.
Finally it also provides factory classes for
creating test data.
89. [Test]
public void GetComments()
{
var epiContext = FakeEPiServerContext.Create();
var article = CreatePage.OfType<Article>(
epiContext.PageRepository);
}
90. [Test]
public void GetComments()
{
var epiContext = FakeEPiServerContext.Create();
var article = CreatePage.OfType<Article>();
var articleReference = epiContext.PageRepository
.Publish(article);
}
91. [Test]
public void GetComments()
{
var epiContext = FakeEPiServerContext.Create();
var article = CreatePage.OfType<Article>();
var articleReference = epiContext.PageRepository
.Publish(article);
article = epiContext.PageRepository
.GetPage<Article>(articleReference);
}
92. [Test]
public void GetComments()
{
...
var comments = CreateSetOfPageData
.Containing(11)
.PagesOfType<Comment>()
.ChildrenOf(article);
epiContext.PageRepository
.Publish(comments.Cast<PageData>());
}
96. In cases where we’re building complex
systems, or a particularly complex part of a
system, we can address the Web Forms
problem by applying the Model View
Presenter Pattern.
Model View Presenter, or MVP, is a dialect
of the Model View Controller. It has one
significant difference compared to MVC; UI
events are routed to the view instead of to
the controller as in MVC.
97.
98. While it’s fairly easy to create a basic
implementation of MVP with Web Forms
there are a number of projects that can help
us. One of them is Web Forms MVP.
Given that we’re using Web Forms MVP we
can use the open source project EPiMVP
which provides some ready-to-use
integration with EPiServer.
99. When using Web Forms MVP and EPiMVP
there are four basic components that interact
when rendering an ASPX page or a user
control; A view (an ASPX or ASCX), a
model object (the PageData object), a
presenter and a view model.
100.
101. When a request comes in to a page the Web
Forms MVP framework instantiates a
presenter and view model object.
The view, which implements an interface
which defines members that are relevant for
the presenter, is passed to the presenter.
So is the view model object.
The presenter is also aware of the PageData
object.
102.
103.
104. With access to the view, view model and
PageData object the presenter populates the
view model object with data relevant for
rendering in the view.
It can also interact with the view by
subscribing to events exposed by it or by
calling methods on it.
122. protected void SubmitComment_Click(object sender,
EventArgs e)
{
if (SubmitComment == null)
return;
SubmitComment(this,
new SubmitCommentEventArgs(
CommentAuthor.Text,
CommentText.Text));
}
123. We’ve seen three frameworks that help us
address some of the core problems we may
face as progressive developers using
EPiServer.
With these in our toolbox we’re better
equipped to tackle complexity when
needed.
Remember to choose the right tools for the
job. Be pragmatic.
124. Page Type Builder can be used in all
situations and is likely to have the biggest
impact on your overall experience using
EPiServer.
125. EPiAbstractions allow you to create unit
tests and to use Test Driven Development.
But it can also be misused. EPiServer CMS
and Web Forms wasn’t designed for you to
have 100% code coverage.
Don’t even try.
Use it when drive good design of complex
systems.
126. Web Forms MVP and EPiMVP probably
seems like it’s complex and hard to
understand.
It is.
But it can be a powerful tool to use when
you have complex user interactions.
It’s also great for being able to inject
dependencies into code that you want to
test.