SlideShare une entreprise Scribd logo
1  sur  128
Télécharger pour lire hors ligne
EPiServer
Development
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.
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.
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.


    ’
’
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.
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.
’   ’
EPiServer development revolves around
pages, represented as PageData objects.
While these are primarily intended for
editorial content they aren’t limited to that.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
’
In 2009 an open source project called Page
Type Builder was born.
At its core it does two things…
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.
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.
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.
public class Article
{
}
using PageTypeBuilder;



public class Article
{
}
using PageTypeBuilder;



public class Article : TypedPageData
{
}
using PageTypeBuilder;

[PageType]
public class Article : TypedPageData
{
}
using PageTypeBuilder;

[PageType]
public class Article : TypedPageData
{
}
’
using PageTypeBuilder;

[PageType]
public class Article : TypedPageData
{
}
using PageTypeBuilder;

[PageType(
    Filename = "~/Templates/Article.aspx")]
public class Article : TypedPageData
{
}
using PageTypeBuilder;

[PageType(
    Filename = "~/Templates/Article.aspx",
    Description = "My page type")]
public class Article : TypedPageData
{
}
using PageTypeBuilder;

[PageType(
    Filename = "~/Templates/Article.aspx",
    Description = "My page type")]
public class Article : TypedPageData
{
}
using PageTypeBuilder;

[PageType]
public class Article : TypedPageData
{
}
using PageTypeBuilder;

[PageType]
public class Article : TypedPageData
{
    public virtual string MainBody { get; set; }
}
using PageTypeBuilder;

[PageType]
public class Article : TypedPageData
{
    [PageTypeProperty]
    public virtual string MainBody { get; set; }
}
using PageTypeBuilder;

[PageType]
public class Article : TypedPageData
{
    [PageTypeProperty]
    public virtual string MainBody { get; set; }
}




                  ’
using PageTypeBuilder;

[PageType]
public class Article : TypedPageData
{
    [PageTypeProperty(Type = typeof(PropertyString))]
    public virtual string MainBody { get; set; }
}
get
{
      return this.GetPropertyValue(p => p.MainBody);
}

set
{
      this.SetPropertyValue(p => p.MainBody, value);
}
public partial class ArticlePage
    : TemplatePage
{
}




                ’
using PageTypeBuilder.UI;

public partial class ArticlePage
    : TemplatePage<Article>
{
}




                ’
using PageTypeBuilder.UI;

public partial class ArticlePage
    : TemplatePage<Article>
{
    protected override void OnLoad(EventArgs e)
    {
           var bodyText = CurrentPage.MainBody;
    }
}
<html>
    <body>
           <%= CurrentPage.MainBody %>
    </body>
</html>
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.
Our page types can have behavior as well as
data.
They can have methods.
Properties can have logic in their getters and
setters.
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.
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.
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.
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.
’
[PageType]
public class Article : TypedPageData
{
    public IEnumerable<Comment> GetComments(int max)
    {
           return DataFactory.Instance
                  .GetChildren(PageLink)
                  .OfType<Comment>()
                  .Take(max);
    }
}
[PageType]
public class Article : TypedPageData
{
    public IEnumerable<Comment> GetComments(int max)
    {
           return DataFactory.Instance
                  .GetChildren(PageLink)
                  .OfType<Comment>()
                  .Take(max);
    }
}            ’
[PageType]
public class Article : TypedPageData
{
    IDataFactoryFacade dataFactory;
    public IEnumerable<Comment> GetComments(int max)
    {
           return dataFactory
                  .GetChildren(PageLink)
                  .OfType<Comment>()
                  .Take(max);
    }
}


                                    ’
’
protected void Application_Start(...)
{
    var container = new Container();




}
protected void Application_Start(...)
{
    var container = new Container();
    container.Configure(x =>
       x.For<IDataFactoryFacade>()
        .Singleton()
        .Use<DataFactoryFacade>());




}
protected void Application_Start(...)
{
    var container = new Container();
    container.Configure(x =>
       x.For<IDataFactoryFacade>()
        .Singleton()
        .Use<DataFactoryFacade>());

    PageTypeResolver.Instance.Activator
       = new StructureMapTypedPageActivator(container);
}
[PageType]
public class Article : TypedPageData
{
    IDataFactoryFacade dataFactory;
    public Article(IDataFactoryFacade dataFactory)
    {
           this.dataFactory = dataFactory;
    }

    public IEnumerable<Comment> GetComments(int max)
    {
           return dataFactory
                  .GetChildren(PageLink)
                  .OfType<Comment>()
                  .Take(max);
    }
}
[PageType]
public class Article : TypedPageData
{
    IPageRepository pageRepository;
    public Article(IPageRepository pageRepository)
    {
           this.pageRepository = pageRepository;
    }

    public IEnumerable<Comment> GetComments(int max)
    {
           return pageRepository
                  .GetChildren(PageLink)
                  .OfType<Comment>()
                  .Take(max);
    }
}
[PageType]
public class Article : TypedPageData
{
    IPageRepository pageRepository;
    public Article(IPageRepository pageRepository)
    {
           this.pageRepository = pageRepository;
    }

    public IEnumerable<Comment> GetComments(int max)
    {
           return pageRepository
                  .GetChildren<Comment>(PageLink)
                  .Take(max);
    }
}
[Test]
public void GetComments()
{
}
[Test]
public void GetComments()
{
    var epiContext = FakeEPiServerContext.Create();




}
[Test]
public void GetComments()
{
    var epiContext = FakeEPiServerContext.Create();

    var article = CreatePage.OfType<Article>(
           epiContext.PageRepository);




}
[Test]
public void GetComments()
{
    var epiContext = FakeEPiServerContext.Create();

    var article = CreatePage.OfType<Article>();

    var articleReference = epiContext.PageRepository
           .Publish(article);




}
[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);
}
[Test]
public void GetComments()
{
    ...

    var comments = CreateSetOfPageData
           .Containing(11)
           .PagesOfType<Comment>()
           .ChildrenOf(article);

    epiContext.PageRepository
           .Publish(comments.Cast<PageData>());
}
[Test]
public void GetComments()
{
    ...

    int max = 10;
    comments = article.GetComments(max);




}
[Test]
public void GetComments()
{
    ...

    int max = 10;
    comments = article.GetComments(max);

    Assert.AreEqual(max, comments.Count());




}
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.
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.
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.
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.
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.
public class CommentsModel
{
}




                             ’
public interface ICommentsView :
    IEPiView<CommentsModel>
{
    event EventHandler<SubmitCommentEventArgs>
           SubmitComment;
}




                                                 ’
public class SubmitCommentEventArgs : EventArgs
{
    public string AuthorName { get; private set; }
    public string Text { get; private set; }

    public SubmitCommentEventArgs(
           string authorName, string text)
    {
           AuthorName = authorName;
           Text = text;
    }
}
public class CommentsPresenter :
    EPiPresenter<ICommentsView, Article>
{
}




                  ’
public CommentsPresenter(ICommentsView view,
    Article pageData)
    : base(view, pageData)
{
}
private IPageRepository pageRepository;

public CommentsPresenter(ICommentsView view,
    Article pageData,
    IPageRepository pageRepository)
    : base(view, pageData)
{
    this.pageRepository = pageRepository;
}


               ’
protected void Application_Start(...)
{
    var container = ...




}
protected void Application_Start(...)
{
    var container = ...

    PresenterBinder.Factory
       = new StructureMapPresenterFactory(container);




                ’
}
private IPageRepository pageRepository;

public CommentsPresenter(ICommentsView view,
    Article pageData,
    IPageRepository pageRepository)
    : base(view, pageData)
{
    this.pageRepository = pageRepository;
    view.SubmitComment += SubmitComment;
}

                                               ’
                     ’
void SubmitComment(object sender,
    SubmitCommentEventArgs e)
{




}
void SubmitComment(object sender,
    SubmitCommentEventArgs e)
{
    var comment = pageRepository
           .GetDefaultPageData<Comment>(
                  CurrentPage.PageLink);




}
void SubmitComment(object sender,
    SubmitCommentEventArgs e)
{
    var comment = pageRepository
           .GetDefaultPageData<Comment>(
                  CurrentPage.PageLink);
    comment.Author = e.AuthorName;
    comment.Text = e.Text;
    pageRepository.Publish(comment);
}
void SubmitComment(object sender,
    SubmitCommentEventArgs e)
{
    var comment = pageRepository
           .GetDefaultPageData<Comment>(
                  CurrentPage.PageLink);
    comment.Author = e.AuthorName;
    comment.Text = e.Text;
    pageRepository.Publish(comment);

    HttpContext.Response.Redirect(CurrentPage.LinkURL);
}
[PresenterBinding(typeof(CommentsPresenter))]
public partial class Comments :
    EPiMvpUserControl<CommentsModel>,
    ICommentsView
{
    public event EventHandler<SubmitCommentEventArgs>
           SubmitComment;
}
<fieldset>
   <asp:TextBox ID="CommentAuthor"
    TextMode="SingleLine" runat="server" />

   <asp:TextBox ID="CommentText" TextMode="MultiLine"
    runat="server" />

   <asp:Button OnClick="SubmitComment_Click"
    Text="Post Comment" runat="server" />
</fieldset>
protected void SubmitComment_Click(object sender,
    EventArgs e)
{
   if (SubmitComment == null)
      return;

    SubmitComment(this,
       new SubmitCommentEventArgs(
          CommentAuthor.Text,
          CommentText.Text));
}
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.
Page Type Builder can be used in all
situations and is likely to have the biggest
impact on your overall experience using
EPiServer.
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.
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.
’
http://pagetypebuilder.codeplex.com
http://epiabstractions.codeplex.com
https://github.com/joelabrahamsson/EPiServer-MVP
http://webformsmvp.com/
http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod


Hand #1: http://www.flickr.com/photos/teacherafael/2243271306/ (with permission)
Hand #2: http://www.flickr.com/photos/fabianluque/5220694009/ (with permission)
Fire: http://www.flickr.com/photos/olemartin/3951562058/
Up/down: http://www.istockphoto.com/stock-photo-4700763-up-down-good-bad-future-past.php
Concrete plant: http://www.istockphoto.com/stock-photo-6416445-young-plant-taking-root-on-a-concrete-footpath.php
Potter: http://www.istockphoto.com/stock-photo-6791142-potter.php
Hands in chains: http://www.istockphoto.com/stock-photo-11441892-dependency.php
Enterprise D: http://www.flickr.com/photos/elzey/523568670/
Chain: http://www.istockphoto.com/stock-photo-2135970-breaking-free.php
Viewstate t-shirt: http://www.flickr.com/photos/piyo/3742166635/
Heart: http://www.flickr.com/photos/saraalfred/3199313309/

Contenu connexe

Tendances

Code igniter - A brief introduction
Code igniter - A brief introductionCode igniter - A brief introduction
Code igniter - A brief introductionCommit University
 
Entity frameworks101
Entity frameworks101Entity frameworks101
Entity frameworks101Rich Helton
 
Having fun with code igniter
Having fun with code igniterHaving fun with code igniter
Having fun with code igniterAhmad Arif
 
ASP.NET MVC 5 - EF 6 - VS2015
ASP.NET MVC 5 - EF 6 - VS2015ASP.NET MVC 5 - EF 6 - VS2015
ASP.NET MVC 5 - EF 6 - VS2015Hossein Zahed
 
ASP.NET Presentation
ASP.NET PresentationASP.NET Presentation
ASP.NET Presentationdimuthu22
 
ASP .NET MVC
ASP .NET MVC ASP .NET MVC
ASP .NET MVC eldorina
 
Developing Java Web Applications
Developing Java Web ApplicationsDeveloping Java Web Applications
Developing Java Web Applicationshchen1
 
Java EE and Spring Side-by-Side
Java EE and Spring Side-by-SideJava EE and Spring Side-by-Side
Java EE and Spring Side-by-SideReza Rahman
 
Angular jS Introduction by Google
Angular jS Introduction by GoogleAngular jS Introduction by Google
Angular jS Introduction by GoogleASG
 
Getting started with entity framework 6 code first using mvc 5
Getting started with entity framework 6 code first using mvc 5Getting started with entity framework 6 code first using mvc 5
Getting started with entity framework 6 code first using mvc 5Ehtsham Khan
 

Tendances (20)

Code igniter - A brief introduction
Code igniter - A brief introductionCode igniter - A brief introduction
Code igniter - A brief introduction
 
MVC Training Part 1
MVC Training Part 1MVC Training Part 1
MVC Training Part 1
 
Entity frameworks101
Entity frameworks101Entity frameworks101
Entity frameworks101
 
MVC - Introduction
MVC - IntroductionMVC - Introduction
MVC - Introduction
 
Having fun with code igniter
Having fun with code igniterHaving fun with code igniter
Having fun with code igniter
 
ASP.NET MVC 5 - EF 6 - VS2015
ASP.NET MVC 5 - EF 6 - VS2015ASP.NET MVC 5 - EF 6 - VS2015
ASP.NET MVC 5 - EF 6 - VS2015
 
Azure rev002
Azure rev002Azure rev002
Azure rev002
 
Asp.net.
Asp.net.Asp.net.
Asp.net.
 
ASP.NET Presentation
ASP.NET PresentationASP.NET Presentation
ASP.NET Presentation
 
Yii Introduction
Yii IntroductionYii Introduction
Yii Introduction
 
MVC Training Part 2
MVC Training Part 2MVC Training Part 2
MVC Training Part 2
 
ASP .NET MVC
ASP .NET MVC ASP .NET MVC
ASP .NET MVC
 
Getting started with angular js
Getting started with angular jsGetting started with angular js
Getting started with angular js
 
Asp.net mvc
Asp.net mvcAsp.net mvc
Asp.net mvc
 
Spring Mvc
Spring MvcSpring Mvc
Spring Mvc
 
Developing Java Web Applications
Developing Java Web ApplicationsDeveloping Java Web Applications
Developing Java Web Applications
 
Java EE and Spring Side-by-Side
Java EE and Spring Side-by-SideJava EE and Spring Side-by-Side
Java EE and Spring Side-by-Side
 
Angular jS Introduction by Google
Angular jS Introduction by GoogleAngular jS Introduction by Google
Angular jS Introduction by Google
 
Getting started with entity framework 6 code first using mvc 5
Getting started with entity framework 6 code first using mvc 5Getting started with entity framework 6 code first using mvc 5
Getting started with entity framework 6 code first using mvc 5
 
Spring boot jpa
Spring boot jpaSpring boot jpa
Spring boot jpa
 

En vedette

EPiServer Product Strategy and Roadmap
EPiServer Product Strategy and RoadmapEPiServer Product Strategy and Roadmap
EPiServer Product Strategy and RoadmapIntergen
 
Using the extensibility benefits of EPiServer
Using the extensibility benefits of EPiServerUsing the extensibility benefits of EPiServer
Using the extensibility benefits of EPiServerPatrick van Kleef
 
A guide to EPiServer CMS Scheduled Job
A guide to EPiServer CMS Scheduled JobA guide to EPiServer CMS Scheduled Job
A guide to EPiServer CMS Scheduled JobPaul Graham
 
Secure development in .NET with EPiServer Solita
Secure development in .NET with EPiServer SolitaSecure development in .NET with EPiServer Solita
Secure development in .NET with EPiServer SolitaJoona Immonen
 
The Total Book Developing Solutions With EPiServer 4
The Total Book Developing Solutions With EPiServer 4The Total Book Developing Solutions With EPiServer 4
The Total Book Developing Solutions With EPiServer 4Martin Edenström MKSE.com
 

En vedette (8)

EPiServer Product Strategy and Roadmap
EPiServer Product Strategy and RoadmapEPiServer Product Strategy and Roadmap
EPiServer Product Strategy and Roadmap
 
7
77
7
 
EPiServer 8: First Release Since Ektron Merger
EPiServer 8: First Release Since Ektron MergerEPiServer 8: First Release Since Ektron Merger
EPiServer 8: First Release Since Ektron Merger
 
Using the extensibility benefits of EPiServer
Using the extensibility benefits of EPiServerUsing the extensibility benefits of EPiServer
Using the extensibility benefits of EPiServer
 
A guide to EPiServer CMS Scheduled Job
A guide to EPiServer CMS Scheduled JobA guide to EPiServer CMS Scheduled Job
A guide to EPiServer CMS Scheduled Job
 
Secure development in .NET with EPiServer Solita
Secure development in .NET with EPiServer SolitaSecure development in .NET with EPiServer Solita
Secure development in .NET with EPiServer Solita
 
The Total Book Developing Solutions With EPiServer 4
The Total Book Developing Solutions With EPiServer 4The Total Book Developing Solutions With EPiServer 4
The Total Book Developing Solutions With EPiServer 4
 
Drupal vs. EPiServer
Drupal vs. EPiServerDrupal vs. EPiServer
Drupal vs. EPiServer
 

Similaire à Progressive EPiServer Development

Enterprise Level Application Architecture with Web APIs using Entity Framewor...
Enterprise Level Application Architecture with Web APIs using Entity Framewor...Enterprise Level Application Architecture with Web APIs using Entity Framewor...
Enterprise Level Application Architecture with Web APIs using Entity Framewor...Akhil Mittal
 
Advanced Web Development
Advanced Web DevelopmentAdvanced Web Development
Advanced Web DevelopmentRobert J. Stein
 
Why use .net by naveen kumar veligeti
Why use .net by naveen kumar veligetiWhy use .net by naveen kumar veligeti
Why use .net by naveen kumar veligetiNaveen Kumar Veligeti
 
Entity framework and how to use it
Entity framework and how to use itEntity framework and how to use it
Entity framework and how to use itnspyre_net
 
ASP.NET Presentation
ASP.NET PresentationASP.NET Presentation
ASP.NET PresentationRasel Khan
 
Repository Pattern in MVC3 Application with Entity Framework
Repository Pattern in MVC3 Application with Entity FrameworkRepository Pattern in MVC3 Application with Entity Framework
Repository Pattern in MVC3 Application with Entity FrameworkAkhil Mittal
 
Testing Big in JavaScript
Testing Big in JavaScriptTesting Big in JavaScript
Testing Big in JavaScriptRobert DeLuca
 
ASP.NET MVC 5 Building Your First Web Application (A Beginner S Guide
ASP.NET MVC 5  Building Your First Web Application (A Beginner S GuideASP.NET MVC 5  Building Your First Web Application (A Beginner S Guide
ASP.NET MVC 5 Building Your First Web Application (A Beginner S GuideAlicia Buske
 
Building N Tier Applications With Entity Framework Services 2010
Building N Tier Applications With Entity Framework Services 2010Building N Tier Applications With Entity Framework Services 2010
Building N Tier Applications With Entity Framework Services 2010David McCarter
 
The future of web development write once, run everywhere with angular js an...
The future of web development   write once, run everywhere with angular js an...The future of web development   write once, run everywhere with angular js an...
The future of web development write once, run everywhere with angular js an...Mark Leusink
 
The future of web development write once, run everywhere with angular.js and ...
The future of web development write once, run everywhere with angular.js and ...The future of web development write once, run everywhere with angular.js and ...
The future of web development write once, run everywhere with angular.js and ...Mark Roden
 
AspMVC4 start101
AspMVC4 start101AspMVC4 start101
AspMVC4 start101Rich Helton
 
A report on mvc using the information
A report on mvc using the informationA report on mvc using the information
A report on mvc using the informationToushik Paul
 
Semantic Web Servers
Semantic Web ServersSemantic Web Servers
Semantic Web Serverswebhostingguy
 
Top 10 - ASP.NET Interview Questions And Answers 2023.pdf
Top 10 -  ASP.NET Interview Questions And Answers 2023.pdfTop 10 -  ASP.NET Interview Questions And Answers 2023.pdf
Top 10 - ASP.NET Interview Questions And Answers 2023.pdfRuddarpratap
 
Fundamentals of Web Development For Non-Developers
Fundamentals of Web Development For Non-DevelopersFundamentals of Web Development For Non-Developers
Fundamentals of Web Development For Non-DevelopersLemi Orhan Ergin
 
End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...
End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...
End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...Paul Jensen
 

Similaire à Progressive EPiServer Development (20)

Enterprise Level Application Architecture with Web APIs using Entity Framewor...
Enterprise Level Application Architecture with Web APIs using Entity Framewor...Enterprise Level Application Architecture with Web APIs using Entity Framewor...
Enterprise Level Application Architecture with Web APIs using Entity Framewor...
 
Advanced Web Development
Advanced Web DevelopmentAdvanced Web Development
Advanced Web Development
 
Why use .net by naveen kumar veligeti
Why use .net by naveen kumar veligetiWhy use .net by naveen kumar veligeti
Why use .net by naveen kumar veligeti
 
Entity framework and how to use it
Entity framework and how to use itEntity framework and how to use it
Entity framework and how to use it
 
ASP.NET Presentation
ASP.NET PresentationASP.NET Presentation
ASP.NET Presentation
 
Repository Pattern in MVC3 Application with Entity Framework
Repository Pattern in MVC3 Application with Entity FrameworkRepository Pattern in MVC3 Application with Entity Framework
Repository Pattern in MVC3 Application with Entity Framework
 
Asp
AspAsp
Asp
 
REST full API Design
REST full API DesignREST full API Design
REST full API Design
 
Testing Big in JavaScript
Testing Big in JavaScriptTesting Big in JavaScript
Testing Big in JavaScript
 
ASP.NET MVC 5 Building Your First Web Application (A Beginner S Guide
ASP.NET MVC 5  Building Your First Web Application (A Beginner S GuideASP.NET MVC 5  Building Your First Web Application (A Beginner S Guide
ASP.NET MVC 5 Building Your First Web Application (A Beginner S Guide
 
Building N Tier Applications With Entity Framework Services 2010
Building N Tier Applications With Entity Framework Services 2010Building N Tier Applications With Entity Framework Services 2010
Building N Tier Applications With Entity Framework Services 2010
 
Final paper
Final paperFinal paper
Final paper
 
The future of web development write once, run everywhere with angular js an...
The future of web development   write once, run everywhere with angular js an...The future of web development   write once, run everywhere with angular js an...
The future of web development write once, run everywhere with angular js an...
 
The future of web development write once, run everywhere with angular.js and ...
The future of web development write once, run everywhere with angular.js and ...The future of web development write once, run everywhere with angular.js and ...
The future of web development write once, run everywhere with angular.js and ...
 
AspMVC4 start101
AspMVC4 start101AspMVC4 start101
AspMVC4 start101
 
A report on mvc using the information
A report on mvc using the informationA report on mvc using the information
A report on mvc using the information
 
Semantic Web Servers
Semantic Web ServersSemantic Web Servers
Semantic Web Servers
 
Top 10 - ASP.NET Interview Questions And Answers 2023.pdf
Top 10 -  ASP.NET Interview Questions And Answers 2023.pdfTop 10 -  ASP.NET Interview Questions And Answers 2023.pdf
Top 10 - ASP.NET Interview Questions And Answers 2023.pdf
 
Fundamentals of Web Development For Non-Developers
Fundamentals of Web Development For Non-DevelopersFundamentals of Web Development For Non-Developers
Fundamentals of Web Development For Non-Developers
 
End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...
End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...
End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...
 

Dernier

Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsRavi Sanghani
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesKari Kakkonen
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditSkynet Technologies
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterMydbops
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rick Flair
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityIES VE
 
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...AliaaTarek5
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...panagenda
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 

Dernier (20)

Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and Insights
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examples
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance Audit
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL Router
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a reality
 
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 

Progressive EPiServer Development

  • 2.
  • 3.
  • 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. ’
  • 7.
  • 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.
  • 10.
  • 11.
  • 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.
  • 34.
  • 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.
  • 39.
  • 42. using PageTypeBuilder; public class Article : TypedPageData { }
  • 43. using PageTypeBuilder; [PageType] public class Article : TypedPageData { }
  • 44. using PageTypeBuilder; [PageType] public class Article : TypedPageData { }
  • 45.
  • 46.
  • 47.
  • 48. using PageTypeBuilder; [PageType] public class Article : TypedPageData { }
  • 49. using PageTypeBuilder; [PageType( Filename = "~/Templates/Article.aspx")] public class Article : TypedPageData { }
  • 50. using PageTypeBuilder; [PageType( Filename = "~/Templates/Article.aspx", Description = "My page type")] public class Article : TypedPageData { }
  • 51. using PageTypeBuilder; [PageType( Filename = "~/Templates/Article.aspx", Description = "My page type")] public class Article : TypedPageData { }
  • 52.
  • 53.
  • 54. using PageTypeBuilder; [PageType] public class Article : TypedPageData { }
  • 55. using PageTypeBuilder; [PageType] public class Article : TypedPageData { public virtual string MainBody { get; set; } }
  • 56. using PageTypeBuilder; [PageType] public class Article : TypedPageData { [PageTypeProperty] public virtual string MainBody { get; set; } }
  • 57. using PageTypeBuilder; [PageType] public class Article : TypedPageData { [PageTypeProperty] public virtual string MainBody { get; set; } } ’
  • 58. using PageTypeBuilder; [PageType] public class Article : TypedPageData { [PageTypeProperty(Type = typeof(PropertyString))] public virtual string MainBody { get; set; } }
  • 59.
  • 60. get { return this.GetPropertyValue(p => p.MainBody); } set { this.SetPropertyValue(p => p.MainBody, value); }
  • 61. public partial class ArticlePage : TemplatePage { } ’
  • 62. using PageTypeBuilder.UI; public partial class ArticlePage : TemplatePage<Article> { } ’
  • 63. using PageTypeBuilder.UI; public partial class ArticlePage : TemplatePage<Article> { protected override void OnLoad(EventArgs e) { var bodyText = CurrentPage.MainBody; } }
  • 64. <html> <body> <%= CurrentPage.MainBody %> </body> </html>
  • 65.
  • 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.
  • 73.
  • 74.
  • 75. [PageType] public class Article : TypedPageData { public IEnumerable<Comment> GetComments(int max) { return DataFactory.Instance .GetChildren(PageLink) .OfType<Comment>() .Take(max); } }
  • 76. [PageType] public class Article : TypedPageData { public IEnumerable<Comment> GetComments(int max) { return DataFactory.Instance .GetChildren(PageLink) .OfType<Comment>() .Take(max); } } ’
  • 77. [PageType] public class Article : TypedPageData { IDataFactoryFacade dataFactory; public IEnumerable<Comment> GetComments(int max) { return dataFactory .GetChildren(PageLink) .OfType<Comment>() .Take(max); } } ’
  • 78.
  • 79.
  • 80. protected void Application_Start(...) { var container = new Container(); }
  • 81. protected void Application_Start(...) { var container = new Container(); container.Configure(x => x.For<IDataFactoryFacade>() .Singleton() .Use<DataFactoryFacade>()); }
  • 82. protected void Application_Start(...) { var container = new Container(); container.Configure(x => x.For<IDataFactoryFacade>() .Singleton() .Use<DataFactoryFacade>()); PageTypeResolver.Instance.Activator = new StructureMapTypedPageActivator(container); }
  • 83. [PageType] public class Article : TypedPageData { IDataFactoryFacade dataFactory; public Article(IDataFactoryFacade dataFactory) { this.dataFactory = dataFactory; } public IEnumerable<Comment> GetComments(int max) { return dataFactory .GetChildren(PageLink) .OfType<Comment>() .Take(max); } }
  • 84.
  • 85. [PageType] public class Article : TypedPageData { IPageRepository pageRepository; public Article(IPageRepository pageRepository) { this.pageRepository = pageRepository; } public IEnumerable<Comment> GetComments(int max) { return pageRepository .GetChildren(PageLink) .OfType<Comment>() .Take(max); } }
  • 86. [PageType] public class Article : TypedPageData { IPageRepository pageRepository; public Article(IPageRepository pageRepository) { this.pageRepository = pageRepository; } public IEnumerable<Comment> GetComments(int max) { return pageRepository .GetChildren<Comment>(PageLink) .Take(max); } }
  • 88. [Test] public void GetComments() { var epiContext = FakeEPiServerContext.Create(); }
  • 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>()); }
  • 93. [Test] public void GetComments() { ... int max = 10; comments = article.GetComments(max); }
  • 94. [Test] public void GetComments() { ... int max = 10; comments = article.GetComments(max); Assert.AreEqual(max, comments.Count()); }
  • 95.
  • 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.
  • 105.
  • 106.
  • 108. public interface ICommentsView : IEPiView<CommentsModel> { event EventHandler<SubmitCommentEventArgs> SubmitComment; } ’
  • 109. public class SubmitCommentEventArgs : EventArgs { public string AuthorName { get; private set; } public string Text { get; private set; } public SubmitCommentEventArgs( string authorName, string text) { AuthorName = authorName; Text = text; } }
  • 110. public class CommentsPresenter : EPiPresenter<ICommentsView, Article> { } ’
  • 111. public CommentsPresenter(ICommentsView view, Article pageData) : base(view, pageData) { }
  • 112. private IPageRepository pageRepository; public CommentsPresenter(ICommentsView view, Article pageData, IPageRepository pageRepository) : base(view, pageData) { this.pageRepository = pageRepository; } ’
  • 113. protected void Application_Start(...) { var container = ... }
  • 114. protected void Application_Start(...) { var container = ... PresenterBinder.Factory = new StructureMapPresenterFactory(container); ’ }
  • 115. private IPageRepository pageRepository; public CommentsPresenter(ICommentsView view, Article pageData, IPageRepository pageRepository) : base(view, pageData) { this.pageRepository = pageRepository; view.SubmitComment += SubmitComment; } ’ ’
  • 116. void SubmitComment(object sender, SubmitCommentEventArgs e) { }
  • 117. void SubmitComment(object sender, SubmitCommentEventArgs e) { var comment = pageRepository .GetDefaultPageData<Comment>( CurrentPage.PageLink); }
  • 118. void SubmitComment(object sender, SubmitCommentEventArgs e) { var comment = pageRepository .GetDefaultPageData<Comment>( CurrentPage.PageLink); comment.Author = e.AuthorName; comment.Text = e.Text; pageRepository.Publish(comment); }
  • 119. void SubmitComment(object sender, SubmitCommentEventArgs e) { var comment = pageRepository .GetDefaultPageData<Comment>( CurrentPage.PageLink); comment.Author = e.AuthorName; comment.Text = e.Text; pageRepository.Publish(comment); HttpContext.Response.Redirect(CurrentPage.LinkURL); }
  • 120. [PresenterBinding(typeof(CommentsPresenter))] public partial class Comments : EPiMvpUserControl<CommentsModel>, ICommentsView { public event EventHandler<SubmitCommentEventArgs> SubmitComment; }
  • 121. <fieldset> <asp:TextBox ID="CommentAuthor" TextMode="SingleLine" runat="server" /> <asp:TextBox ID="CommentText" TextMode="MultiLine" runat="server" /> <asp:Button OnClick="SubmitComment_Click" Text="Post Comment" runat="server" /> </fieldset>
  • 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.
  • 127.
  • 128. http://pagetypebuilder.codeplex.com http://epiabstractions.codeplex.com https://github.com/joelabrahamsson/EPiServer-MVP http://webformsmvp.com/ http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod Hand #1: http://www.flickr.com/photos/teacherafael/2243271306/ (with permission) Hand #2: http://www.flickr.com/photos/fabianluque/5220694009/ (with permission) Fire: http://www.flickr.com/photos/olemartin/3951562058/ Up/down: http://www.istockphoto.com/stock-photo-4700763-up-down-good-bad-future-past.php Concrete plant: http://www.istockphoto.com/stock-photo-6416445-young-plant-taking-root-on-a-concrete-footpath.php Potter: http://www.istockphoto.com/stock-photo-6791142-potter.php Hands in chains: http://www.istockphoto.com/stock-photo-11441892-dependency.php Enterprise D: http://www.flickr.com/photos/elzey/523568670/ Chain: http://www.istockphoto.com/stock-photo-2135970-breaking-free.php Viewstate t-shirt: http://www.flickr.com/photos/piyo/3742166635/ Heart: http://www.flickr.com/photos/saraalfred/3199313309/