Showing posts with label EpiServer. Show all posts
Showing posts with label EpiServer. Show all posts

Friday, October 20, 2017

Beginners Guide: Output caching in EPiServer



Introduction 


Output caching is not a new concept. There is a variety of project that people try to implement output caching, but how to do it in EpiServer?

What is Output caching?

The main purpose of using Output Caching is to dramatically improve the performance of an ASP.NET MVC Application. It enables us to cache the content returned by any controller method so that the same content does not need to be generated each time the same controller method is invoked. 

Why using output caching?

Output Caching has huge advantages, such as:
*Reduces the load on the server because there is no need to generate the results again
* Reduces the load on DB (same reason)
* Faster response

How it is done on MVC?

OutputCacheAttribute class has been implemented in System.Web.Mvc class and can easily being used simply by decorating the Controller with [OutputCache]. There are different variations for using it, which I am not going to discuss now, but you can read more in here.

What is the problem? Lets use it on EpiServer.

Although [OutputCache] attribute works fine for MVC applications, there are some functionalities that are specific to CMS systems. Let me elaborate more with an example:
- You have a page on your CMS and someone tries to view it for the first time. The MVC engine will try to generate the results and then save in in cache.
A second later, another person requests the same exact page. As you've guessed the MVC will receive the request and since it has it on its cache, it will respond with the same exact results.
- On the next step the editor change something on the page and publish it, but s(he) will see the same exact results as before since MVC doen't know about the change and will still return the same response. This also happens for the next people whom request the same page.

So to summarize we have 2 big problem:
1- content should not be cached for the editors
2- After publishing a page the old cache should be invalidate and the whole process should go through


How to fix it?

To fix the problems by yourself you need a lot of knowledge about EPiServer and you need some time to implement it. Luckily EPiServer has implemented their own ContentOutputCacheAttribute that will handle those for you :)

Simply add ContentOutputCache on top of your action 

 public class MyPageController : PageController<PageType>
 {       

   [ContentOutputCache(Duration = 3600, VaryByCustom = "*")]

   public ActionResult Index(StartPage currentPage)
    {
       ...
    }
}

Handle your GetVaryByCustomString in your Global.asax and you are good to go

public class EPiServerApplication : EPiServer.Global
{

 public override string GetVaryByCustomString(HttpContext context, string custom)
    {
       ....
    }

}
What to put into the GetVaryByCustomString depends on your setup, but one simple example could be returning the AbsoluteUri of the page. This way, different pages will differ, language versions will be handled automatically (since the AbsoluteUri will be different regardless of your routing config) but be aware that the personalization will not work since the AbsoluteUri is the same for all different users.

 public override string GetVaryByCustomString(HttpContext context, string custom)
    {
        return context.Request.Url.AbsoluteUri;
    }


****Very Important!!!!


ContentOutputCache will not work, unless you have the httpCacheExpiration in your web.config.
Simply go to your webconfig>
configuration>episerver>applicationSettings and make sure that it has properties for httpCacheability and httpCacheExpiration.

It should be something like this:

<configuration>
...
  <episerver>
    <applicationSettings httpCacheability="Public" httpCacheExpiration="0:10:00" .... />
  </episerver>
....
</configuration>



Thursday, February 9, 2017

Surrounding EpiServer lines with a div in content area


Surrounding EpiServer lines with a div in content area

Some days ago I had a discussion with our frontenders  regarding the rows in ContentArea. They liked to have a div surrounding each line of the items so they can make the styles in a correct way. In this small post I will describe what have I done:
I will use Alloy Demo site to describe the issue and my solution

The problem:

In a ContentArea, if you add some items it will be a big div with multiple lines inside. 
As you can see in the picture item 1 is taking a line, 2 and 3 are in the second line and 4,5,6  are in the third line. And size of each block depends on their display options.





The request

Surrounding each line with a div with CssClass="row" and removing the one for content area.

The solution

Removing the css class from the ContentArea is too easy since it has been added to html.Propertyfor in the index page:


However to remove add the container around each row, you need to override ContentAreaRenderer. In alloy demo website, it has already been overridden to add suitable classes based on the tags and it is called   AlloyContentAreaRenderer. Just override RenderContentAreaItems method and add this code. Then you are good to go :)


       protected override void RenderContentAreaItems(HtmlHelper htmlHelper, IEnumerable contentAreaItems)
        {
            float totalSize = 0;
            if (contentAreaItems.Any())
                htmlHelper.ViewContext.Writer.Write(@"
"); foreach (ContentAreaItem contentAreaItem in contentAreaItems) { var tag = this.GetContentAreaItemTemplateTag(htmlHelper, contentAreaItem); totalSize += GetSize(tag); if (totalSize>1) { htmlHelper.ViewContext.Writer.Write(@"
"); totalSize = GetSize(tag); } this.RenderContentAreaItem(htmlHelper, contentAreaItem, this.GetContentAreaItemTemplateTag(htmlHelper, contentAreaItem), this.GetContentAreaItemHtmlTag(htmlHelper, contentAreaItem), this.GetContentAreaItemCssClass(htmlHelper, contentAreaItem)); } if (contentAreaItems.Any()) htmlHelper.ViewContext.Writer.Write(@"
"); } float GetSize(string tagName) { if (string.IsNullOrEmpty(tagName)) { return 1f; } switch (tagName.ToLower()) { case "span12": return 1f; case "span8": return 0.666666f; case "span6": return 0.5f; case "span4": return 0.333333f; default: return 1f; } }

The result







Thursday, July 14, 2016

EPiServer for beginers, where is version history

Version history is one of the basic features of any CMS and of course EPiServer has complete support over all of your pages and commerce data.
You might say that everyone knows that EPiServer has this feature, but to be honest I didn't expect to find it inside the gadgets pane the first time, so I thought why not mentioning it for beginners :)


So to see the version history follow these steps:
1-  In the editors page find the settings button on top right of your pane.


2- click on add gadgets

3- select "versions" gadget from the list


Version history is available for you. You can see who has done changes to the selected page and if the latest changes has been published or not :)

Monday, June 6, 2016

EpiServer for beginners: How to add custom fields to Order (eCommerce) programatically

Introduction

Some times ago, I had a post about adding a custom field to eCommerce from the user interface. That post got very popular and some folks like Khurram Khan and Steve C. mentioned that it is possible to add fields to eCommerce pragmatically. So in this post I will describe how to do it:

Steps
1- Create an initialization class

Create a class, inherit from IInitializableModule, add InitializableModule and ModuleDependency attribute to your class and you are almost there.

 [InitializableModule]

    [ModuleDependency(typeof(EPiServer.Commerce.Initialization.InitializationModule))]

    public class Initialization : IInitializableModule


* You will need to add "EPiServer.Commerce.Initialization" to have InitializationModule, "EPiServer.Framework" to have InitializableModuleAttribute and "Mediachase.MetaDataPlus.Configurator" to have MetaField methods but of course VS will add them for you when you write the names correctly


2-  Create the constructor and get the context
  public void Initialize(InitializationEngine context)

        {
        var mdContext = CatalogContext.MetaDataContext;

3- Use MetaField.Load to load your field from EPiServer.
        MetaField.Load(mdContext, name)


4- If the result was empty, create the field using MetaField.Create
The structure of the method is like this:

MetaField Create(MetaDataContext context, string metaNamespace, string name, string friendlyName, string description, MetaDataType dataType, int length, bool allowNulls, bool multiLanguageValue, bool allowSearch, bool isEncrypted);


* just to mention, length is the size of your data, so for example bool is 1, or DateTime is 8

5- Load the class that you want to add the field to it using  MetaClass.Load
  var mtClass = MetaClass.Load(mdContext, metaClassName);


6- Check if the meta field already exists in the meta class by checking its fields
  cls.MetaFields.Contains(field);


7- If the meta class doesn't have the class, add it using AddField
mtClass.AddField(field);


8- Smile :)

--------
It is very good idea to have simpler methods for adding fields and joining them to the meta class.

    private MetaField GetOrCreateMetaField(MetaDataContext mdContext, string metaDataNamespace, string name, MetaDataType type, int length, bool allowNulls, bool cultureSpecific)

        {

            var f = MetaField.Load(mdContext, name) ??

                    MetaField.Create(mdContext, metaDataNamespace, name, name, string.Empty, type, length, allowNulls, cultureSpecific, false, false);

            return f;

        }



        private void JoinField(MetaDataContext mdContext, MetaField field, string metaClassName)

        {

            var mtClass = MetaClass.Load(mdContext, metaClassName);



            if (MetaFieldIsNotConnected(field, mtClass ))

            {

                cls.AddField(field);

            }

        }



* And just to say: it is a good practice to have your strings inside enum classes. If you have a project, but you don't have any place for your enums and constants, you have to reconsider some of the stuff in your code :)

The whole code look like this:

 [InitializableModule]

    [ModuleDependency(typeof(EPiServer.Commerce.Initialization.InitializationModule))]

    public class Initialization : IInitializableModule

    {

  public void Initialize(InitializationEngine context)

        {



            MetaDataContext mdContext = CatalogContext.MetaDataContext;



            var myField = GetOrCreateMetaField(mdContext, Constants.Metadata.Namespace.Order,

          Extensions.PurchaseOrderExtensions.myFieldName, MetaDataType.DateTime, 8, true, false);

            JoinField(mdContext, myField, Constants.Metadata.OrderForm.ClassName);

        }



      private MetaField GetOrCreateMetaField(MetaDataContext mdContext, string metaDataNamespace, string name, MetaDataType type, int length, bool allowNulls, bool cultureSpecific)

        {

            var f = MetaField.Load(mdContext, name) ??

                    MetaField.Create(mdContext, metaDataNamespace, name, name, string.Empty, type, length, allowNulls, cultureSpecific, false, false);

            return f;

        }



        private void JoinField(MetaDataContext mdContext, MetaField field, string metaClassName)

        {

            var mtClass = MetaClass.Load(mdContext, metaClassName);



            if (MetaFieldIsNotConnected(field, mtClass ))

            {

                cls.AddField(field);

            }

        }



        private static bool MetaFieldIsNotConnected(MetaField field, MetaClass mtClass )

        {

            return mtClass != null && !cls.MetaFields.Contains(field);

        }

}

A Sample in a project
You can look at Steves  CommerceStarterKit and to be more specific, this page :) 

Acknowledgment
My gratitude to Steve Celius  for sharing his code with us.

Friday, April 29, 2016

String or binary data would be truncated. EPiServer


Introduction
I had a stressful story 2 days ago. Well, we were at the end of a sprint and like many other projects enjoyed our peaceful time solving a few minor issues that our customer has reported when suddenly we faced the error:
String or binary data would be truncated

I know what you are thinking:
"Yup! OK, Someone used a name longer than 50 char..."

But that was not the story!

How did I check

Fortunately, we were at the end of sprint, so I could check all new properties very fast but there was nothing wrong. I've checked my DB with a query like the one that I used for finding my string in here and checked for strings with len>50. And I've shocked since there was nothing wrong.

Then I've asked my good friends in EPiServer to help me. Quan Mai and Daniel Ovaska guided me how to find the cause of the problem.

Faithfully, I had a back up from the last night so I could compare it with my working copy easily using "Visual Studio SQL server database comparison tool" that I've described in here :) and found the problem.


The Problem

As Quan Mai mentioned, when you have mismatch between your code and your DB, you will have this error. Of course I hopped that the error message were more obvious but just keep that in mind :)

Anyways, I've found the problem! Yayyyyy!
We have 2 totally different branches that we are working on for some time and we have a separated DB for each of them. Then I've found the properties of the other one inside my DB....

Why?
Well if you switch your working branch, it will change the web config, but what you don't keep your dlls inside your source control, right? So keep in mind to rebuild your code before browsing your site :)

Tuesday, April 19, 2016

Search for a string in all tables, rows and columns of a DB



Several days ago, I needed to search my database for special string. Then I saw a very good query in here, but since it wasn't an article, I thought why not write a small post about it.



Code:
DECLARE
    @search_string  VARCHAR(100),
    @table_name     SYSNAME,
    @table_schema   SYSNAME,
    @column_name    SYSNAME,
    @sql_string     VARCHAR(2000)

SET @search_string = 'string to search'

DECLARE tables_cur CURSOR FOR SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'

OPEN tables_cur

FETCH NEXT FROM tables_cur INTO @table_schema, @table_name

WHILE (@@FETCH_STATUS = 0)
BEGIN
    DECLARE columns_cur CURSOR FOR SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @table_schema AND TABLE_NAME = @table_name AND COLLATION_NAME IS NOT NULL  -- Only strings have this and they always have it

    OPEN columns_cur

    FETCH NEXT FROM columns_cur INTO @column_name
    WHILE (@@FETCH_STATUS = 0)
    BEGIN
        SET @sql_string = 'IF EXISTS (SELECT * FROM ' + QUOTENAME(@table_schema) + '.' + QUOTENAME(@table_name) + ' WHERE ' + QUOTENAME(@column_name) + ' LIKE ''%' + @search_string + '%'') PRINT ''' + QUOTENAME(@table_schema) + '.' + QUOTENAME(@table_name) + ', ' + QUOTENAME(@column_name) + ''''

        EXECUTE(@sql_string)

        FETCH NEXT FROM columns_cur INTO @column_name
    END

    CLOSE columns_cur

    DEALLOCATE columns_cur

    FETCH NEXT FROM tables_cur INTO @table_schema, @table_name
END

CLOSE tables_cur

DEALLOCATE tables_cur


This query is very useful, specially when you don't know about the structure of a project. For instance, you need to check something in a CMS (lets say for debugging your code) like EpiServer but you know nothing about its structure, then finding your values will be a real pain.


Friday, April 8, 2016

EPiServer: Your changes in code won't take effect?! Check the F@#king Version in your branches!


Yesterday I had a lot to do and therefore I had to switch between a lot of different branches. When I was working on one of my tasks I've found out that my changes doesn't take effect on EpiServer. To be more specific, I had a field with a UIHint before, then my UIHint didn't cause any behavior in the UI! It has been changed to a simple short string field.

To find the problem I tried adding a new property, but surprisingly my new field didn't even show up. So I thought maybe something is wrong with my web-server, temp files or etc. I tried restarting my IIS, deleting my temp files everywhere and then restarting IIS again, and after all restarting my windows! But none of them worked!


But again I've got surprised since even restarting the windows didn't work for me. So I post a question on EpiServer and thanks to Per Gunsarfs I understand what was the problem.

It was pretty simple! Your changes won't take effect if there is a newer assembly version available!

I just needed to change my assembly version to the newest that we have. (right click on project> properties> application tab> assembly information button) or as I did, update your branch with the parent branch (or master) if it has been set to the latest.

Easy? Right?! But just if you know it!

Monday, March 28, 2016

Where my block has been used on server? A question that all back-end developer have in mind



The story started when I had a task to remove old blocks that we don't use any more. From a back-ender's point of view, I just needed to find all references in my code and make sure that it has not been used anywhere. But of course it is not correct when dealing with a CMS like EpiServer since they can be used in a ContentArea.

Yes, I know, we have also [AllowedType] attribute that we use in order to limit contentAreas, but still, there can be some items in blocks tree that has not been used in any page and may cause a problem if an editor click on them.

So what shall we do?

First, Every content in EpiServer will be saved in tblContent. if you want to make sure that there is no instance from your typename it is enough to check that table.Code:
SELECT c.*   FROM [dbo].[tblContent] c
inner join [dbo].[tblContentType] ct on c.fkContentTypeID = ct.pkID
where  [ModelType] like '%TypeName%'

But it is only 10% of the cases, besides where is the fun?!!!
I want to know how many instances of my type exists and where are they now? also I want to know how to find their parent in the tree. So I wrote this code:

Code:
declare @TypeName nvarchar(50)
set @TypeName = 'myBlockType'

select tbl2.contentName as contentName, tbl2.contentSegment as ContentSegment, tbl2.ContentGUID as ContentGUID,
con2pkID ContainerID,con2ContentGUID ContainerGUID, conLang.name as ContainerName,conLang.URLSegment as ContainerURLSegment, contype.Name as ContainerTypeName, 
contype.ModelType as ContainerModelType, con2.fkParentID as ContainersParentId, conContainerParentLanguage.Name as ContainerParentName, conContainerParentType.Name as ContainerParentName

from [dbo].[tblContentProperty] cp  
 inner join 
(SELECT  c.*, cl.name as contentName,  cl.URLSegment as contentSegment FROM [dbo].[tblContent] c
inner join [dbo].[tblContentType] ct on c.fkContentTypeID = ctpkID
inner join tblContentLanguage cL on cL.fkContentID = c.pkID
where  ct.Name like @TypeName)  tbl2 on cp.LongString like '%'+cast( tbl2.ContentGUID as nvarchar(50))+'%'
inner join tblContent con2 on con2.pkID = cp.fkContentID
inner join [dbo].[tblContentType] contype on con2.fkContentTypeID = contypepkID
inner join tblContentLanguage conLang on conLang.fkContentID = con2pkID
inner join tblContent conContainerParent on conContainerParent.pkID = con2fkParentID
inner join tblContentType conContainerParentType on conContainerParent.fkContentTypeID = conContainerParentTypepkID
inner join tblContentLanguage conContainerParentLanguage on conContainerParentLanguage.fkContentID = con2.fkParentID

This code will show you all instances of a type, and where they have been contained including typename and the address that we can find the parent in the tree.


The result will be something like this



But wait a minute! what if I can't find the container it self?!
Well, that is easy :)  the query is 90% the same, but we just need to search for the contentId (instance) instead of the type name.
Of course if you search for the containers type name, you will eventually find it, But it is easier to change 2 lines of code :)

Code:
declare @ContentGUID nvarchar(50)
set @ContentGUID = 'B6845FFC-5475-4FC3-C701-5A5D6FD5F967' -- put you content GUID in here 

select tbl2.contentName as contentName, tbl2.contentSegment as ContentSegment, tbl2.ContentGUID as ContentGUID,
con2pkID ContainerID,con2ContentGUID ContainerGUID, conLang.name as ContainerName,conLang.URLSegment as ContainerURLSegment, contype.Name as ContainerTypeName, 
contype.ModelType as ContainerModelType, con2.fkParentID as ContainersParentId, conContainerParentLanguage.Name as ContainerParentName, conContainerParentType.Name as ContainerParentName

from [dbo].[tblContentProperty] cp
 inner join
(SELECT  c.*, cl.name as contentName,  cl.URLSegment as contentSegment
FROM [dbo].[tblContent] c
inner join tblContentLanguage cL on cL.fkContentID = c.pkID
where c.ContentGUID like @ContentGUID)  tbl2 on cp.LongString like '%'+cast( tbl2.ContentGUID as nvarchar(50))+'%'
inner join tblContent con2 on con2.pkID = cp.fkContentID
inner join [dbo].[tblContentType] contype on con2.fkContentTypeID = contypepkID
inner join tblContentLanguage conLang on conLang.fkContentID = con2pkID
inner join tblContent conContainerParent on conContainerParent.pkID = con2fkParentID
inner join tblContentType conContainerParentType on conContainerParent.fkContentTypeID = conContainerParentTypepkID
inner join tblContentLanguage conContainerParentLanguage on conContainerParentLanguage.fkContentID = con2.fkParentID

Tuesday, March 15, 2016

EpiServer for beginners: How to add custom fields to Order (eCommerce)

Introduction

One of the simplest things that any developer would want is to add some fields to Order table or in related ones. When dealing with content pages, it would be handled automatically using Code-First methodology. But in the eCommerce system you have to do some steps.

Example

When you are dealing with external systems, you will need to have their Id in your system and since it is related to your order, well it is not a good idea to put in somewhere else.
Also, you may want to add external fields like status or etc to your order.

Steps

steps in Ecommerce

1- Go to Commerce Manager> Administration >Meta fields> New Meta Field



2- Fill name and friendly name and choose type of your field. Then choose properties like search option as you need. just have in mind that changing allow null field would be hard.

In these 2 steps, you've created a field in your order. Now you have to assign it to any table that you need.
3-  Go to meta classes right under order systems and select the main table(element) that you want to add your field. For instance, I want to add my field to my order form.

4- Now select the related external table related to that element. For order from it is only one, but it differs from element to element.
5- Select your field and click "OK"

Steps in your code

We have our field in our DB now.It is very easy to use it in your code.
The easiest way is to write a code like this line for setting the field:

Code:
 order.OrderForms[0]["MyFieldsName"] = value;

And Like this one to Getting it (for strings):

Code:
var x=order.OrderForms[0]["MyFieldsName"].ToString();

But It is always good to have a class, that contains names and methods for handling fields and their names.
Use Constants to avoid writing wrong names. Also set and get all fields in the same class so you have them centralized and use those methods.

Code:
 private const string MyFieldName = "MyFieldName";

public static string GetMyField()
{
   return order.OrderForms[0][MyFieldName].ToString();        
}

Edit:

I wrote a post in here  describing how to add the field grammatically.

Tuesday, March 8, 2016

A simple queue for EpiServer

Intro
Queuing is one of the base procedures that you may need as a software developer specially if you are working on web.Think as a task that you want to make sure that it will be done, but you don’t want to suspend your current process for it. for instance you want to send an email in a part of a method or task. you don’t want to wait for email response and you want to try sending it for many times, but you never want your methods to wait for it.
If you are developing on EpiServer, you probably know that there is a dynamic data type which is pretty good for implementing a queue.

Cecilia von Wachenfeldt has a post in here where she describes a simple solution for that. However, I don't like to have both queue and queue item on the same class. From the software architectural view, we have to have a queue class that handles primitive queuing functions (adding to queue, finding unprocessed items, Processing items and deleting them). Then for each type queue, we can just create a corresponding queue-able Item and ask use our queue to handle the object :)

Theory

There has to be a queue, with queue functions. There has to be an enum for the status of the item. Then the queue has to handle everything using each items methods.

This is the list of classes that we need:

1- Queue
2- An interface for Queueable Items (IQueueable)
This interface contains properties that the queue will use like ErrorCount, LastError, Status, etc. and basic methods for processing each special type Like Process().
3- Queueable item which inherits from our IQueueable
This item is simply the object that we want to save into DB. It contains our queue properties/methods and also the required data that you need to use, in order to proceed.

Implementation
Lets say that we want to implement an email queue system, so if the network was down or etc, we won't loose any emails. Our queue and IQueueable are of course the same but for the Queueble Item we have something like this:
First, we have to implement our enum to decide if the item is
Code:
public enum QueueItemState
{
Queued = 0,
Processed = 1,
Retrying = 2,
Failed = 3
}
Then we have to write our Interface:
public interface IQueueableItem
{
int ErrorCount { get; set; }
string LastError { get; set; }
DateTime? QueuedTime { get; set; }
DateTime? CompeletedTime { get; set; }
EnumsQueueItemState State { get; set; }
void AddError(string errorMessage);
bool Process();
Identity Save();
void SetToFaild(string errorMessage);
}

Then we have to implement our interface and add our additional functionality/properties:
(Pay attention to EPiServerDataStore property that cause Episerver to save this item into DynamicData )
Code:
[EPiServerDataStore(AutomaticallyRemapStore = true, AutomaticallyCreateStore = true)]
public class QueueableEmailItem : IDynamicData, IQueueableItem
{
.... [IQueueableItem properties]
public string EmailSubject { get; set; }
public string EmailBody { get; set; }
public string EmailTo { get; set; }
public int? EMailPriority { get; set; }
public bool Process()
{
var priority = EMailPriority.HasValue ? (MailPriority)EMailPriority.Value : System.Net.Mail.MailPriority.Normal;
MailService.Service.Send(EmailSubject, EmailBody, EmailTo, priority, attachedItems);
return true;
}
}

We will need a QueueBase class that handles your queue items. The queue will try to read and execute data that implement IQueueableItem. 
There is only one problem, which is reading items from DB with generics, So I just do the process in the queue base and do the other stuff in the inherited classes using polymorphism.
Code:
public abstract class QueueBase where T : IDynamicData, IQueueableItem
{
public void Proceed()
{
var queue = GetQueuedItems();
if (!queue.Any())
return ;
foreach (var item in queue)
{
try
{
// Exit if the error count is greater or equal to the retry count
if (item.ErrorCount >= RetryCount)
{
item.SetToFaild("RetryCount limit");
continue;
}
if (item.TryProcess())
{
item.State = Enums.QueueItemState.Processed;
item.Save();
continue;
}
item.State = Enums.QueueItemState.Retrying;
item.Save();
}
catch (Exception ex)
{
if (item.State!= Enums.QueueItemState.Failed)
{
item.State = Enums.QueueItemState.Retrying;
}
item.AddError(ex.message);
item.Save();
}
}
}
}
Of course you can have a better code, add logs/ return report/ send email to admin if failed, etc. but this is the simplest code that I could come up with :)
Now we will need to inherit from this class for the emailQueue:
Code:
public class EmailQueue : QueueBase<QueueableEmailItem>
{
public Identity AddToQueue(string to, string emailSubject, string body, MailPriority mailPriority = MailPriority.Normal)
{
var item = new QueueableEmailItem
{
EmailTo = to,
EmailSubject = emailSubject,
QueuedTime = DateTime.Now,
State = Enums.QueueItemState.Queued,
ErrorList = new List<string>(),
EmailBody = body,
EMailPriority = (int)mailPriority
};
return item.Save();
}
protected override List<QueueableEmailItem> GetQueuedItems()
{
var store = typeof(QueueableEmailItem).GetStore();
var query = (
from item in store.Items<QueueableEmailItem>()
where item.State == Enums.QueueItemState.Queued || item.State == Enums.QueueItemState.Retrying
select item);
return query.ToList();
}
}

Fake Entire EpiServer

Intro
When doing the integration testing in EpiServer, you will need to mock more than one or two methods or services. Sometimes you need to implement the same ground for different test classes. but it will be very time consuming and at the same time, very hard to write.
Take a simple collaboration service as an example. Your service probably used 3-4 different EpiServer services and 3-4 of your other services (at least:) ), but when you want to test them you find out that you have to mock all used services for your class/service.

An alternative to this option will be to fake all APIs that you've used from EpiServer and then load the faked content on the initial step of your test classes.

Well, it is like having a huge castle floating in the air. :) time consumable to implement but really easy to expand and change.

FakeMaker
So I have an advice for you if you want to fake EpiServer content. Use the FakeMaker by David Vujic to create your pages which will add them automatically to your repository and serviceLocator.
You can more data about it here or download it from github or even nuget.

Need to mention 2 things:
1- Don't do create a new serviceLocator. Create your pages with FakeMaker and then get your ServiceLocator mock object using this command:
Code:
 var mockLocator = Mock.Get<IServiceLocator>(ServiceLocator.Current);
You will have access to the content repository with your FakeMaker.ContentRepository easily.

2- If you have EpiServer 8 you cannot use the nuget. just download his code from github and use it. It is very well written and easy to use

My Extention
When I saw FakeMaker, I understand that it can be pretty usable for many people including me :)  so I had a discussion with David and he liked my Ideas. Then I realized that I can contribute in the project so I add other features to my branch. It is not that big deal, but it can be useful for many.
I've add 2 options:
1-Supporting EntryContentBase for Commerce system
You can now easily add your products to your fake. It is as easy as creating FakePages. For instance:
Code:
 var shopRoot = FakePage.Create("ShopRoot");
 var fakePhone = FakeEntryContent.Create<PhoneProduct>("Iphone 6").ChildOf(shopRoot);
_fake.AddToRepository(shopRoot);

2-Supporting ContentLoader
In our code, we used ContentLoader in many places while we also used ContentRepository. Of course I wanted to support the ContentLoader when I call AddToRepository :)
You can have access to ContentLoader the same as ContentRepository by FakeMaker.ContentLoader.
Just to mention, it make more sense to create your content in FakeMaker first and then use ContentLoader, ContentRepository, and serviceLocator that it creates for you.


*You can find my code in here. Just to mention, it is not confirmed by David yet, so it is only on EpiServer 8 that I am using right now and it is not available through nuget pakages, yet.


Unit Testing in EpiServer using Moq

Regardless of what do you think about TDD (Test Driven Development)  there are many scenarios that you want to implement an automatic testing in your code. But how do we implement tests in a CMS like EpiServer?
As a basic step, one has to mock some behaviors in EpiServer services like ContentRepository, ContentProviderManager, etrc. To do so, you have to create a mock object from that interface and then use that mock instead of real object. For instance we can do these steps using Moq library:

1- Create a mock for the service that you want to use
for instance you can create a mock for content loader. This class has been used to load contents from EpiServer, like when you want to load and use a specific page (like setting page) or content.
Code:
var mockContentLoader = new Mock<IContentLoader>();
 2- Mock methods that you need
now you have to tell Moq what you want to return instead of the normal behavior.

We can ask for a general behavior like returning an object if there was a request for a type. like
Code:
mockContentLoader.Setup(r => r.Get<StartPage>(It.IsAny<ContentReference>())).Returns(new StartPage());
this code will return a new StartPage when someone uses ContetnLoader.Get<StartPage> method, with any ContentReference.
    Or we can mock an specific request like
    Code:
    mockContentLoader.Setup(r => r.Get<StartPage>(myStartPage.ContentLink)).Returns(myStartPage);
    This code will return your startpage if there is a request with it's content link. Pretty similar to how you code on EpiServer :)
    3-Use the mocked class
    To use the class that you mocked, you need an object from it. For instance, when you want to test a class that need your ContentLoader you can do it like this:
    Code:
    var myServiceToTest = new MyService(mockContentLoader.Object);
    Now you can use your class/service and whenever it wants to use the content loader, it will have the mocked results instead of trying to call DB or etc. :)

    *If you want to use the injection in your code, you have to  create a new mock for ServiceLocator, or get it if you already have it.
    To create a new one use this:
    Code:
                var mockLocator = new Mock<IServiceLocator>();
    To get the existing one use
    Code:
    var mockLocator = Mock.Get<IServiceLocator>(ServiceLocator.Current);
    Now you can easily use the same concept and return your mocked class easily
    Code:
    mockLocator.Setup(l => l.GetInstance<IContentLoader>()).Returns(mockContentLoader.Object);
    You just need to remember to set the new serviceLocator
    Code:
    ServiceLocator.SetLocator(serviceLocator.Object);
     To read more about Moq go to this page