EPiServer 10 – Restrict any Block Types on XHtmlString property using the Validation Attribute

I couldn’t find a similar solution online as I believe there is an emerging pattern where we are now instructing clients to drag EPiServer Blocks into Rich Text editors.

Requirement:

As an Editor I want to limit certain blocks types from being dragged into the rich text editor

Solution #1:

Apply this attribute to any of your xhtml properties to enable to validation functionality

[Display(Name = "Text", GroupName = SystemTabNames.Content)]
[XHtmlStringAllowedBlockTypes(new[] { typeof(TextBlock), typeof(ImageBlock) })]
public virtual XhtmlString RichText { get; set; }

 

Implement the following attribute where your other validation attributes reside.

 public class XHtmlStringAllowedBlockTypes : ValidationAttribute
{
private readonly Type[] allowedTypes;
public XHtmlStringAllowedBlockTypes(Type[] allowedTypes)
{
this.allowedTypes = allowedTypes;
}

protected override ValidationResult IsValid(object value, ValidationContext context)
{
var contentData = context.ObjectInstance as IContentData;

if (contentData != null && contentData.Property[context.MemberName].Value is XhtmlString)
{
var richTextProperty = (XhtmlString)contentData.Property[context.MemberName].Value;

foreach (ContentFragment fragment in richTextProperty.Fragments.Where(x => x is ContentFragment))
{
var content = ServiceLocator.Current.GetInstance<IContentRepository>().Get<IContentData>(fragment.ContentLink);

foreach (var allowedType in allowedTypes)
{
if (allowedType.IsInstanceOfType(content))
{
return new ValidationResult(string.Format("You cannot add {0} to {1}", content.GetType(), context.MemberName));
}
}
}
}

return ValidationResult.Success;
}
} 

 

References:

http://world.episerver.com/documentation/Items/Developers-Guide/Episerver-CMS/9/Content/Properties/Property-types/Writing-custom-attributes/

http://world.episerver.com/documentation/Items/Developers-Guide/Episerver-CMS/9/Content/Validation/

Creating a SQL Alias

To help standardize the connectionstrings across your team’s development machines. You can all use the same sql alias, database name, username and password. The last three are easily configurable however the sql alias isn’t so obvious. Here’s a simple set of instructions to get it working.

My environment at time of this post is Windows 8.1, SQL Server 2014 Express.

  • First you must find the port your server is using through tcp/ip.
  • Open SQL Server Network Configuration
  • Click on the server in question
  • in the right hand pane, right click TCP/IP and select Properties
  • Hit the IP Addresses tab and scroll all the way to the bottom
  • The TCP Dynamic Ports is the port you need to use in the next section.

sqlalias_portconfig

  • Open up Sql Server Configuration Manager
  • Expand SQL Native Client. Choose 32-bit or 64-bit depending on your setup
  • Expend Aliases and create a new entry
  • The port must match the port you found above

sqlserver_sqlalias

Sources:

Disabling NuGet Package Restore

You’ve enabled NuGet Package Restore and want to reverse that decision? Follow the steps below for every csproj in your solution:

  • Close down the solution
  • Delete the .nuget folder on the solution level
  • Open up each csproj in a text editor
  • Find the following XML tags and delete them:
<RestorePackages>true</RestorePackages>  
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />  
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">  
    <PropertyGroup>
      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
    </PropertyGroup>
    <Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
</Target>

EPiServer 7.5 – Exception – More than one content model is assigned to the guid

When running an EPiServer site and you get the exception “More than one content model is assigned to the guid”. This is usually because you’ve changed a namespace.

There will be a reference to the old namespace cached somewhere so do the following:

1) Clear your bin folder

2) Clear the ASP.NET Temporary files folder under the framework version your project is using

AngularJS – Why?

Why Angular?

AngularJS is written in Javascript and is a HTML compiler. It was written by developer, Misko Hevery who originally built AngularJS as a solution for building HTML components with functionality. It is now a fully fledged open source framework. It allows you to build complete applications.

It is very easy to learn and you will find a team of developers will quickly get up to speed. It is extremely popular and backed by Google so there are plenty of blogs, solutions and discussions out there.

Features

Angular reduces time building an application compared to other mvc frameworks and thus saves money.

Two way binding is one of the most important features Angular provides. It enables real time updating of a model as soon as the variable binded to the scope is changed.

Similiar to jQuery, Angular allows you to write code on a higher level than as if you were writing raw Javascript.

Accessibility and locality is also supported. The ngAria module automatically makes most of your site accessible.

Currency, Dates and Number data types are localized out of the box. For the String data type, you will have to manage locals yourself. There are several 3rd party libraries out there that can help you with this.

Testing is what angular is all about. There are several frameworks created by the team at Google that allows you cover all aspects of testing. ngMock is used for unit testing, Protractor is used for end to end testing and Karma is an automation test tool.

AngularJS 1.4 – Declaring a Controller

I’ve been following a few tutorials that describe declaring a MainController. However the tutorials a pre AngularJS 1.3x and are no longer valid. Previous AngularJS allowed you to define a controller globally . As of 1.3x this is no longer the case and you must declare your Controllers inside angular modules. Here’s an example:


var githubViewerApp = angular.module('githubViewer', []);

Declare a new module and give it a unique name. Then assign module to a variable.


var MainController = function MainController($scope, $http) { }

Create your MainController. This is where all your functions and service calls will sit.


githubViewerApp.controller("MainController", ['$scope', '$http', MainController]);

Now bind the MainController variable to the module variable. The variables with $ signs are included in the function parameters to help support minification. Without this minifiers would rename the variable and angular would be unable to bind the parameters to the view.

Javascript – Revealing Module Pattern

This Javascript pattern allows you to define a piece of code with a private scope but have it accessible with a public method. Easy to implement and simple to understand.
<blockquote><code>
var createWorker = function() {</code>

var task1 = function() {
console.log(“moo1”);
}

var task2 = function() {
console.log(“moo2”);
}

return {
job1: task1,
job2: task2
}
}

var worker = createWorker();

worker.job1();</blockquote>
<code>task1</code> and <code>task2</code> functions are confined to the scope of the <code>createWorker</code> function.

In order to make them public to the outside scope, the <code>return<code> method ties public accessors to the inner scoped functions.</code></code>

<code>worker.job1();</code> calls job1

Web Performance – IIS GZip Compression

There’s nothing like performance tuning your website and watching benchmarks better themselves. Sometimes it can be tricky but fortunately this is one of the easier fixes. YSlow and Chrome Dev tools recommend gzip compression and you are looking at around a 70% reduction in file size for your static and dynamic resources. Great! So how do we do it?

First of all this blog post applies to IIS7 and above. IIS7 has Dynamic Content Compression un-installed so install it by heading to Windows Features.

enableDynamicCompression

In your solution, add the following config to your web.config:

<urlCompression doDynamicCompression="true" />

You can check your dynamic content is now being compressed with gzip by looking at the response header in fiddler, firebug or chrome developer tool:

gzip_response

Implementing UAT into Scrum

Definition of uat

User acceptance testing is an a process that validates the deliverable conforms and meets the business requirements initially laid out.

 

Proposed Agile Process with UAT

Support Process - Support Process (1)

This proposal introduces a period of time after the sprint has ended to allow for UAT. It provides business analysts, product owners and stakeholders to look at the feature before going live on to the production website.

This also gives them the opportunity to raise bugs which we can triage and categorize into either an immediate hotfix or to be put into the backlog.

Current Issues & resolutions to those by using the proposal

 

Testing within the sprint

Issue

The awaiting approval status within the sprint against user stories is effectively forcing business analysts to perform UAT within the sprint.

This caused numerous problems because the features crossing multiple stories were being tested and bugs were being raised despite the entire feature not being complete.

Additionally business decisions were being made within the sprint without the knowledge of the product owner or stakeholders.

Resolution

Introducing UAT after the sprint ends allows not only business analysts but the product owner and stakeholders to look at the features together once we have declared them as finished.

We will only release completed features for UAT once the develop team has completed all user stories associated with that feature and are satisfied any major bugs have been resolved.

 

Stakeholder Involvement

Issue

Features were going straight into LIVE without allowing the stakeholders to accept with them first.

There were numerous example of the SCRUM team developing features against user stories but once going live, the stakeholders raised complaints about missing components or incorrect assumptions. The scrum team then had to work on hotfixes within the active sprint and forced us to drop some user stories.

Resolution

Any bugs found within UAT and are deemed critical should be raised as a P1 within the active sprint. They must be worked on immediately on a hotfix branch.

25% of the active sprint time should be allocated to each team member to allow us to fix any issues raised from UAT.

 

Technical Actions needed to adopt the proposal

We will now need to extend our use of development branches in order for the proposal to run smoothly.

In addition to our current workflow with branches we will now introduce Release branches.

These are created from the develop branch and represents the latest code ready for UAT. This will happen at the end of the sprint. Any left over work will require the developer to work on this branch and allow other developers to work on the develop branch for the next sprint.

Bug fixes are worked on this branch. They can be re-merged into develop at any time.

If accepted then it is merged into Master ready for deployment to Production.

The Master branch is also tagged for future reference.