Blog

Sandbox AppDomain Creation

Application domains provide a unit of isolation for the common language run-time. Creating Sandbox environment to isolate code base that can be used to load and unload assemblies make possible to unload unwanted assemblies to avoid memory leaks, eg. Host for Rosyln Compiler etc.

Security is important aspect when you allow 3rd party assemblies like plugins to run within your application,With the evidence, you can control the pre-defined permissions sets granted to code running in sub app domain.

Code snippet

private PermissionSet GetPermissionSet()
{
//create an evidence of type zone
var ev = new Evidence();
ev.AddHostEvidence(new Zone(SecurityZone.MyComputer));

//return the PermissionSets specific to the type of zone
var permissions = SecurityManager.GetStandardSandbox(ev);

if (permissions != null)
{
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
permissions.AddPermission(new EnvironmentPermission(PermissionState.Unrestricted));
permissions.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
}

return permissions;
}

private AppDomain CreateSandbox()
{
var ps = GetPermissionSet();

var setup = new AppDomainSetup
{
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
ApplicationName = DomainName,
DisallowBindingRedirects = true,
DisallowCodeDownload = true,
DisallowPublisherPolicy = true
};

var trusted = new[]
{
typeof (EngineFactory).Assembly.Evidence.GetHostEvidence<StrongName>()
};

var domain = AppDomain.CreateDomain(DomainName, AppDomain.CurrentDomain.Evidence, setup, ps, trusted);
return domain;
}

Host Website programmatically including apppool

The Powershell reads the sample json file and setup your website based on information in json file..

#Powershell to create web site host from metadata
function Get-Service-Name
{
param(
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[object] $component
)


function Get-Service-Name
{
 param(
 [parameter(Mandatory=$false)] 
 [ValidateNotNullOrEmpty()] 
 [object] $component 
 )
 
 return [System.IO.Path]::GetFileNameWithoutExtension($component.solutionPath)
}

function Get-WebHost-Descriptor
{
 param(
 [parameter(Mandatory=$false)] 
 [ValidateNotNullOrEmpty()] 
 [object] $component 
 )
 $webDescription = $component.hostDescription;
 
 return $webDescription ;
}

function Create-WebHost
{
 param(
 [parameter(Mandatory=$false)] 
 [Object] $component, 
 [bool] $recreateHost = $false
 )

 process
 {
 $webDescription = Get-WebHost-Descriptor $component

 $websitePath = "IIS:Sites$($webDescription.Name)";
 if ($webDescription.appPool)
 {
 $webAppPoolPath = "IIS:AppPools$($webDescription.appPool.Name)"
 }

 if ($recreateHost)
 {
 if (Test-Path $websitePath -PathType Container)
 {
 Write-Verbose "Removing site $($webDescription.Name)"
 Remove-Item $websitePath -Confirm:$false -Force -Recurse 
 if ($webAppPoolPath)
 { 
 Write-Verbose "Removing appPool $($webDescription.appPool.Name)"
 Remove-Item $webAppPoolPath -Confirm:$false -Force -Recurse 
 }
 }
 }

 if ($webAppPoolPath -and -Not (Test-Path $webAppPoolPath -PathType Container))
 {
 Write-Verbose "Creating app pool $($webDescription.appPool.Name)"
 $appPool = New-Item $webAppPoolPath
 $appPool | Set-ItemProperty -Name "managedRuntimeVersion" -Value "v4.0"
 if ($webDescription.appPool.User)
 {
 Write-Verbose "Setting app pool $($webDescription.appPool.Name) identity"
 $appPool.processModel.userName = $webDescription.appPool.User;
 $appPool.processModel.password = $webDescription.appPool.Password;
 $appPool.processModel.identityType = 3;
 $appPool | Set-Item
 $appPool.Stop();
 $appPool.Start();
 }
 }
 
 if (-Not (Test-Path $websitePath -PathType Container))
 {
 New-Item -ItemType Directory -Force -Path $webDescription.PhisicalPath > $null
 
 $bindings =$webDescription.Protocols | % {$i=0}{ @{protocol=$_;bindingInformation="$($webDescription.BindingInformations[$i++])"}} | ? {-Not [string]::IsNullOrWhiteSpace($_.bindingInformation)}
 
 Write-Verbose "Creating web site $($webDescription.Name)"
 New-Website -Name $webDescription.Name -Port $bindings[0].bindingInformation.Replace(":","") -PhysicalPath $webDescription.PhisicalPath > $null

 #$a = New-Item $websitePath -bindings ($b) -physicalPath $webDescription.PhisicalPath

 $bindings | Select -skip 1 | % {New-ItemProperty -path $websitePath -name bindings -value @{protocol=$_.protocol.ToString();bindingInformation=$_.bindingInformation.ToString()}}
 #$bindings | Select -skip 1 | % {New-WebBinding -Name $webDescription.Name -IPAddress "*" -Port $_.bindingInformation.Replace(":","").Replace("*","") -Protocol $_.protocol > $null}
 Set-ItemProperty $websitePath -name EnabledProtocols -Value (($webDescription.Protocols | select -uniq) -join ',')
 if ($webAppPoolPath)
 {
 Set-ItemProperty $websitePath -Name "applicationPool" -Value $webDescription.appPool.Name
 }
 }

 $webAppPath = "$websitePath$(Get-Service-Name $component)"

 if (-Not (Test-Path $webAppPath -PathType Container))
 {
 Write-Verbose "Creating web app $webAppPath"
 New-Item $webAppPath -physicalPath $webDescription.PhisicalPath -type Application > $null
 if ($webDescription.Protocols -and $webDescription.Protocols.Count -gt 0)
 {
 $protocols = (($webDescription.Protocols | select -uniq) -join ',')
 Write-Verbose "Setting EnabledProtocols on WebApp $protocols"
 Set-ItemProperty $webAppPath -name enabledProtocols -Value (($webDescription.Protocols | select -uniq) -join ',')
 if ($webAppPoolPath)
 {
 Set-ItemProperty $webAppPath -Name "applicationPool" -Value $webDescription.appPool.Name
 }
 }
 }
 return @{Name=$webDescription.Name}
 }
}


# Example to create web site from json defination

 [string] $json = '[
 {
 "type": "Web",
 "hostDescription": {
 "BindingInformations": [":323:", "3808:*"],
 "Name": "YourWebsiteName",
 "Protocols": ["http", "net.tcp"],
 "PhisicalPath": "c:\inetpub\wwwroot\",
 "solutionPath": "YourWebDirectoryName",
 "appPool": {
 "Name": "YourAppPoolName",
 "User": "AccountForAppPool",
 "Password": "PasswordForAppPool"
 }
 }
 }
 ]'

$components = ($json | ConvertFrom-Json)
$firstWebSite = $components[0];
Write-Host $firstWebSite
Create-WebHost $firstWebSite , $true

Validate SSIS package on server

SSIS server validation

Untitled

 

  • Any change in database schema will break the associated SSIS package.
  • Generally each change is responsible to identify dependent components to be included in the change scope.
  • But what about any missed dependencies. E.g. Recent production issue.
  • Such broken SSIS can be identified in Pre-Prod only if pre-prod is well controlled and identical copy of prod environment.
  • Process is required to identify packages impacted by dependencies changes like database schema.
  • Proactive validation of SSIS package could help to identify the issue and reduce the system downtime.

High level architecture

Untitled2

 

The solution is capable of validating all ssis packages for sql server version 2008 on-wards. Instead of publishing the full source code below is the pseudo code and sql scripts to validate the packages.

  1. Create C# console base project which takes the server name you want to validate. The app calls the web service to validate the SQL server (validate SSIS packages on that server).
  2. Create web api project and expose following methods (Job Controller)
    1. Validate – start the validation process by creating SQL agent job dynamically on target server
    2. ValidationFinished – this will be invoked by job when validation is finished.
    3. GetValidationStatus – this will provide the SQL agent job status currently validating server

The Validate method works as follows..

  • Get the SQL Server version
private Version GetServerVersion(string serverName)
 {
 var connectionString = string.Format("Server={0};Database=master;Trusted_Connection=True;", serverName);
 using (var connection = new SqlConnection(connectionString))
 {
 connection.Open();
 return new Version(connection.ServerVersion);
 }
 }
  • Create interface IProcessor and implement it for sql server 2008 and 2012 as they both have different way to validate package
  • Based on server version get the eligible concrete implementation.
  • The validation engine will create the validation job on target sql server. for each proxy account, the script will create job step to trigger a network share package running under proxy account. (for details see createValidationJob.sql)
  • Each validation step gets the package scheduled under the current account and validate the package, populate the results back on central server. and in the end extract the job history and delete the job.)
  • The network deployed ssis package uses same engine to validate 2008 and 2012 via IProcessor since validation is done differently for both servers.

The common scripts used for both servers are here (download and rename doc to zip)

Common-Scripts

The SQL server 2008 validation is done via DTEXEC with /validate command (download and rename doc to zip)

SQl 2008-Scripts

The SQL 2012 validation is done via EXECUTE SSISDB.catalog.validate_project stored proc. (download and rename doc to zip)

SQL 2012 Scripts

The centralized server which keeps the status of SSIS validation looks like

Untitled3

The font end to display the data was build on angular 2 API..

Selenium WebDriver – Get Browser Hwnd

While designing some UI automation framework API, which can work with browser and other systems like window, I have to control the z order or IExplore launched by selenium web driver.

 

However out of box, selenium does not expose driver process id or Browser hwnd.

The attached solution with some extensions is able to get the browser hwnd..

The basic logic is

  • When driver is initialized, get the url for hub and extract the port number
  • From port number, find the process id which is using this port for listening, ie. PID of driver
  • After navigation, from all instances of iexplore find the parent PID matches the pid of driver, i.e browser pid.
  • Get the Hwnd of browser pid
Below is some code highlights
// Interface to extend the web driver and expose ProcessId of driver
public interface IWebDriverEx: IWebDriver
{
/// <summary>
/// Get the process id of driver
/// </summary>
/// <returns>process id</returns>
int ProcessId { get; }
}
and few extension methods
public static IntPtr GetBrowserHwnd(this IWebDriverEx driver);
public static void BringToFront(this IWebDriverEx driver);
for more details, see attached sample (download), after launch go to console and press any key to bring the browser in front…

Testing with Dispatcher

The threading model in the Windows Presentation Foundation (WPF) is based on the concept of a “dispatcher”. Every thread has a Dispatcher object associated with it. Dispatcher is responsible for policing cross-thread operations and provides a way for threads to marshal method invocations to each other, via its BeginInvoke and Invoke methods.

Dispatcher contains the WPF version of a Windows message queue and message pump. It provides a prioritized message queue, from which the message pump can pull messages and process them. Most WPF classes have an affinity for the thread on which they are instantiated. That thread affinity is based on an association between the object and the thread’s Dispatcher.

Using IDispatcher in your view models

 /// <summary>
 /// The Dispatcher interface.
 /// </summary>
 public interface IDispatcher
 {
 /// <summary>
 /// The invoke.
 /// </summary>
 /// <param name="callback">
 /// The callback.
 /// </param>
 void Invoke(Delegate callback);

 /// <summary>
 /// The invoke.
 /// </summary>
 /// <param name="method">
 /// The method.
 /// </param>
 /// <param name="priority">
 /// The priority.
 /// </param>
 /// <param name="args">
 /// The args.
 /// </param>
 /// <returns>
 /// The <see cref="object"/>.
 /// </returns>
 object Invoke(Delegate method, DispatcherPriority priority, params object[] args);

 /// <summary>
 /// The begin invoke.
 /// </summary>
 /// <param name="callback">
 /// The callback.
 /// </param>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 DispatcherOperation BeginInvoke(Delegate callback);

 /// <summary>
 /// The begin invoke.
 /// </summary>
 /// <param name="method">
 /// The method.
 /// </param>
 /// <param name="args">
 /// The args.
 /// </param>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 DispatcherOperation BeginInvoke(Delegate method, params object[] args);

 /// <summary>
 /// The begin invoke.
 /// </summary>
 /// <param name="method">
 /// The method.
 /// </param>
 /// <param name="priority">
 /// The priority.
 /// </param>
 /// <param name="args">
 /// The args.
 /// </param>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 DispatcherOperation BeginInvoke(Delegate method, DispatcherPriority priority, params object[] args);

 /// <summary>
 /// The invoke async.
 /// </summary>
 /// <param name="callback">
 /// The callback.
 /// </param>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 DispatcherOperation InvokeAsync(Action callback);

 /// <summary>
 /// The invoke async.
 /// </summary>
 /// <param name="callback">
 /// The callback.
 /// </param>
 /// <param name="priority">
 /// The priority.
 /// </param>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 DispatcherOperation InvokeAsync(Action callback, DispatcherPriority priority);

 /// <summary>
 /// The invoke async.
 /// </summary>
 /// <param name="callback">
 /// The callback.
 /// </param>
 /// <typeparam name="TResult">type of result
 /// </typeparam>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 DispatcherOperation<TResult> InvokeAsync<TResult>(Func<TResult> callback);

 /// <summary>
 /// The invoke async.
 /// </summary>
 /// <param name="callback">
 /// The callback.
 /// </param>
 /// <param name="priority">
 /// The priority.
 /// </param>
 /// <typeparam name="TResult">type of result
 /// </typeparam>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 DispatcherOperation<TResult> InvokeAsync<TResult>(Func<TResult> callback, DispatcherPriority priority);
 }

The real dispatcher

public class DispatcherFactory
 {
 public static IDispatcher GetDispatcher()
 {
 return Application.Current != null ? new AppDispatcher(Application.Current.Dispatcher) : new AppDispatcher();
 }

 private class AppDispatcher : IDispatcher
 {
 private readonly Dispatcher _safeDispatcher;
 private readonly Dispatcher _currentDispatcher;

 public AppDispatcher(Dispatcher dispatcher):this()
 {
 this._safeDispatcher = dispatcher ?? this._currentDispatcher;
 }

 public AppDispatcher()
 {
 this._currentDispatcher = Dispatcher.CurrentDispatcher;
 this._safeDispatcher = this._currentDispatcher;
 }

 private Dispatcher Dispatcher
 {
 get { return this._currentDispatcher.CheckAccess() ? this._currentDispatcher : this._safeDispatcher; }
 }

 void IDispatcher.Invoke(Delegate callback)
 {
 this.Dispatcher.Invoke(callback);
 }

 object IDispatcher.Invoke(Delegate method, DispatcherPriority priority, params object[] args)
 {
 return this.Dispatcher.Invoke(method, priority, args);
 }

 DispatcherOperation IDispatcher.BeginInvoke(Delegate callback)
 {
 return this.Dispatcher.BeginInvoke(callback);
 }

 DispatcherOperation IDispatcher.BeginInvoke(Delegate method, params object[] args)
 {
 return this.Dispatcher.BeginInvoke(method, args);
 }

 DispatcherOperation IDispatcher.BeginInvoke(Delegate method, DispatcherPriority priority, params object[] args)
 {
 return this.Dispatcher.BeginInvoke(method, priority, args);
 }


 DispatcherOperation IDispatcher.InvokeAsync(Action callback)
 {
 return this.Dispatcher.InvokeAsync(callback);
 }

 DispatcherOperation IDispatcher.InvokeAsync(Action callback, DispatcherPriority priority)
 {
 return this.Dispatcher.InvokeAsync(callback, priority);
 }

 DispatcherOperation<TResult> IDispatcher.InvokeAsync<TResult>(Func<TResult> callback)
 {
 return this.Dispatcher.InvokeAsync(callback);
 }

 DispatcherOperation<TResult> IDispatcher.InvokeAsync<TResult>(Func<TResult> callback, DispatcherPriority priority)
 {
 return this.Dispatcher.InvokeAsync(callback, priority);
 }
 }
 }

The testing dispatcher

 /// <summary>
 /// The stub dispatcher.
 /// </summary>
 public class TestingDispatcher : IDispatcher
 {
 private readonly Dispatcher currentDispatcher;

 /// <summary>
 /// Initializes a new instance of the <see cref="TestingDispatcher"/> class.
 /// </summary>
 public TestingDispatcher()
 {
 this.currentDispatcher = Dispatcher.CurrentDispatcher;
 }

 /// <summary>
 /// The invoke.
 /// </summary>
 /// <param name="callback">
 /// The callback.
 /// </param>
 public void Invoke(Delegate callback)
 {
 try
 {
 this.currentDispatcher.Invoke(callback);
 }
 finally
 {
 this.DoEvents();
 }
 }

 /// <summary>
 /// The invoke.
 /// </summary>
 /// <param name="method">
 /// The method.
 /// </param>
 /// <param name="priority">
 /// The priority.
 /// </param>
 /// <param name="args">
 /// The args.
 /// </param>
 /// <returns>
 /// The <see cref="object"/>.
 /// </returns>
 public object Invoke(Delegate method, DispatcherPriority priority, params object[] args)
 {
 try
 {
 return this.currentDispatcher.Invoke(method, priority, args);
 }
 finally
 {
 this.DoEvents();
 }
 }

 /// <summary>
 /// The begin invoke.
 /// </summary>
 /// <param name="callback">
 /// The callback.
 /// </param>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 public DispatcherOperation BeginInvoke(Delegate callback)
 {
 try
 {
 return this.currentDispatcher.BeginInvoke(callback);
 }
 finally
 {
 this.DoEvents();
 }
 }

 /// <summary>
 /// The begin invoke.
 /// </summary>
 /// <param name="method">
 /// The method.
 /// </param>
 /// <param name="args">
 /// The args.
 /// </param>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 public DispatcherOperation BeginInvoke(Delegate method, params object[] args)
 {
 try
 {
 return this.currentDispatcher.BeginInvoke(method, args);
 }
 finally
 {
 this.DoEvents();
 }
 }

 /// <summary>
 /// The begin invoke.
 /// </summary>
 /// <param name="method">
 /// The method.
 /// </param>
 /// <param name="priority">
 /// The priority.
 /// </param>
 /// <param name="args">
 /// The args.
 /// </param>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 public DispatcherOperation BeginInvoke(Delegate method, DispatcherPriority priority, params object[] args)
 {
 try
 {
 return this.currentDispatcher.BeginInvoke(method, priority, args);
 }
 finally
 {
 this.DoEvents();
 }
 }

 /// <summary>
 /// The invoke async.
 /// </summary>
 /// <param name="callback">
 /// The callback.
 /// </param>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 public DispatcherOperation InvokeAsync(Action callback)
 {
 try
 {
 return this.currentDispatcher.InvokeAsync(callback);
 }
 finally
 {
 this.DoEvents();
 }
 }

 /// <summary>
 /// The invoke async.
 /// </summary>
 /// <param name="callback">
 /// The callback.
 /// </param>
 /// <param name="priority">
 /// The priority.
 /// </param>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 public DispatcherOperation InvokeAsync(Action callback, DispatcherPriority priority)
 {
 try
 {
 return this.currentDispatcher.InvokeAsync(callback, priority);
 }
 finally
 {
 this.DoEvents();
 }
 }

 /// <summary>
 /// The invoke async.
 /// </summary>
 /// <param name="callback">
 /// The callback.
 /// </param>
 /// <typeparam name="TResult">type of result
 /// </typeparam>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 public DispatcherOperation<TResult> InvokeAsync<TResult>(Func<TResult> callback)
 {
 try
 {
 return this.currentDispatcher.InvokeAsync(callback);
 }
 finally
 {
 this.DoEvents();
 }
 }

 /// <summary>
 /// The invoke async.
 /// </summary>
 /// <param name="callback">
 /// The callback.
 /// </param>
 /// <param name="priority">
 /// The priority.
 /// </param>
 /// <typeparam name="TResult">type of result
 /// </typeparam>
 /// <returns>
 /// The <see cref="DispatcherOperation"/>.
 /// </returns>
 public DispatcherOperation<TResult> InvokeAsync<TResult>(Func<TResult> callback, DispatcherPriority priority)
 {
 try
 {
 return this.currentDispatcher.InvokeAsync(callback, priority);
 }
 finally
 {
 this.DoEvents();
 }
 }

 private void DoEvents()
 {
 DispatcherFrame frame = new DispatcherFrame();
 this.currentDispatcher.BeginInvoke(new Action(() => frame.Continue = false), DispatcherPriority.ContextIdle);
 Dispatcher.PushFrame(frame);
 }
 }

ViewModel First – ViewCaching

With View model first approach, view are usually created via DataTemplate, and each time a view model is injected in the content control, the corresponding view is recreated.

If you have complex view where it take bit time to create view, you may see the performance hits. To avoid the performance hit you may want to cache the view and use the cached view when available. This can be done via creating CacheContentControl and you choice of view factory.

The basic idea is to wrap the view inside CacheContentControl and delegate the view creation logic to your view factory. The attached sample uses weakreference view factory,say if GC has not collected the view, you may use the cached view instead of creating view each time. This will work with controls like tab control docking controls etc.

The CacheContentControl  code

public class CacheContentControl : ContentControl
    {
        public CacheContentControl()
        {
            Unloaded += ViewCache_Unloaded;
            ViewFactory = WeakReferenceViewFactory.Instance;
        }

        void ViewCache_Unloaded(object sender, RoutedEventArgs e)
        {
            Content = null;
        }

        private Type _contentType;
        public Type ContentType
        {
            get { return _contentType; }
            set
            {
                _contentType = value;
               //  use you favorite factory
                Content = ViewFactory.GetView(value);
            }
        }

        public IViewFactory ViewFactory { get; private set; }
    }

In the DataTemplate, use the ViewCache, pass the type of the real view you want to use:

<DataTemplate DataType=”{x:Type moduleB:Panel3Vm}”>

<Border Background=”Green”>

<local:CacheContentControl ContentType=”{x:Type moduleB:Pane3 }” Margin=”5″/>

</Border>

</DataTemplate>

The example uses standard data template (red option) to demonstrate each time you navigate to panes the corresponding views are recreated with new hash code.

If you select CacheContentControl (green option) and navigate the view is only created once. If you click on button to collected the GC then view are created on navigation if they are claimed by GC.

Why ViewModel first ?

I prefer to use view model first approach. For many reasons:

  • Vms are your application containing most of logic apart from glue code in form of behaviors or triggers.
  • If you creates views then you are responsible for its life and cleanup code. You have to deal with threading and other issues which are difficult to test. On the other hand of you create vms and leave the view creation logic with WPF via data template.. you don’t have to worry about threading issue. And there will be better separation of concerns.
  • With vm first approach zero code behind.
  • With a project level isolation for view and vms you can restrict developers using view specific things like dispatcher in the view model leaving more cleaner and testable code base. I.e view project sprojec to vm. And vm project should not refer to any presentation lib.
  • If there is clear boundary between view and vm. Both can evolve and will be less fragile.
  • Allows more complete testing of logic to open new Views and ViewModels
  • Tends to be DRYer (don’t repeat yourself ) as applications get larger
  • View and ViewModel are more independent and can be worked on separately more easily.

For more details see attached source code (download and rename docx to zip)

ViewCache Source Code

RadDocking With Prism + Mvvm

Features

  • Support MVVM with Prism
  • Supports ViewModel First or ViewFirst Approach
  • Supports styling RadPane in xaml rather than DockingPansFactory
  • Code RadDocking – SourceCode

The XAML

  • Defiine the region names at RadPaneGroup level
  • Set Rad Panel Style via ItemContainerStyle
  • Bind Header property of RadPane with Title Property in View Model
 <Window.Resources>
 <Style x:Key="RadPaneFactoryStyle" TargetType="{x:Type telerik:RadPane}">
 <Setter Property="Header" Value="{Binding Title}"/>
 </Style>
 </Window.Resources>
 <Grid>
 <telerikDocking:RadDocking>
 <telerikDocking:RadDocking.DocumentHost>
 <telerikDocking:RadSplitContainer >
 <telerikDocking:RadPaneGroup regions:RegionManager.RegionName="MainRegion"
 ItemContainerStyle="{StaticResource RadPaneFactoryStyle}"
 >
 
 </telerikDocking:RadPaneGroup>
 </telerikDocking:RadSplitContainer>
 </telerikDocking:RadDocking.DocumentHost>

 <telerikDocking:RadSplitContainer InitialPosition="DockedRight">
 <telerikDocking:RadPaneGroup regions:RegionManager.RegionName="MainRegion1" >
 
 </telerikDocking:RadPaneGroup>
 </telerikDocking:RadSplitContainer>
 
 </telerikDocking:RadDocking> 
 </Grid>

Configure Region Adapter Mappings in Bootstrap

protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
 {
 var mappings = base.ConfigureRegionAdapterMappings();

 mappings.RegisterMapping(typeof(RadPaneGroup), this.Container.Resolve<RadPaneGroupRegionAdapter>());

 return mappings;
 }

Define the RadPaneGroup RegionAdapter

 
Behavior
public class RadPaneGroupRegionAdapter : RegionAdapterBase<RadPaneGroup>
 {
 public RadPaneGroupRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
 : base(regionBehaviorFactory)
 {
 }

 protected override void Adapt(IRegion region, RadPaneGroup regionTarget)
 {
 var docking = regionTarget.ParentOfType<RadDocking>();
 if (docking.DockingPanesFactory == null)
 {
 docking.DockingPanesFactory = new CustomDockingPanesFactory();
 }

 var store = DocumentsStoreAttachment.GetPanesStore(docking);
 if (store == null)
 {
 store = new PanesStore();
 DocumentsStoreAttachment.SetPanesStore(docking, store);
 BindingOperations.SetBinding(
 docking,
 RadDocking.PanesSourceProperty,
 new Binding("PanesSource") { Source = store });
 }
 }

 protected override IRegion CreateRegion()
 {
 return new SingleActiveRegion();
 }

 protected override void AttachBehaviors(IRegion region, RadPaneGroup regionTarget)
 {
 if (region == null)
 throw new System.ArgumentNullException("region");

 var docking = regionTarget.ParentOfType<RadDocking>();
 
 // Add the behavior that syncs the items source items with the rest of the items
 region.Behaviors.Add(RadPaneGroupSyncBehavior.BehaviorKey, new RadPaneGroupSyncBehavior()
 {
 HostControl = regionTarget,
 Docking = docking
 });

 base.AttachBehaviors(region, regionTarget);
 }

 private class PanesStore
 {
 public readonly ObservableCollection<object> Panes = new ObservableCollection<object>();
 ReadOnlyObservableCollection<object> _readonlyDocumentsList;
 public ReadOnlyObservableCollection<object> PanesSource
 {
 get
 {
 return _readonlyDocumentsList ??
 (_readonlyDocumentsList = new ReadOnlyObservableCollection<object>(Panes));
 }
 }
 }

 private static class DocumentsStoreAttachment
 {
 public static readonly DependencyProperty PanesStoreProperty = DependencyProperty.RegisterAttached(
 "PanesStore",
 typeof(PanesStore),
 typeof(DocumentsStoreAttachment),
 new PropertyMetadata(null)
 );
 public static void SetPanesStore(UIElement element, PanesStore value)
 {
 element.SetValue(PanesStoreProperty, value);
 }
 public static PanesStore GetPanesStore(UIElement element)
 {
 return (PanesStore)element.GetValue(PanesStoreProperty);
 }
 }

 private class CustomDockingPanesFactory : DockingPanesFactory
 {
 public RadPaneGroup ActiveGroup { get; internal set; }

 protected override void AddPane(RadDocking radDocking, RadPane pane)
 {
 var group = ActiveGroup;

 pane.SetValue(RadPane.HeaderProperty, DependencyProperty.UnsetValue);

 var style = group.ItemContainerStyle;
 if (style != null)
 {
 pane.SetValue(RadPane.StyleProperty, style);
 }
 group?.Items.Add(pane);
 }
 }

 private class RadPaneGroupSyncBehavior : RegionBehavior, IHostAwareRegionBehavior
 {
 public static readonly string BehaviorKey = "RadPaneGroupSyncBehavior";
 private bool _updatingActiveViewsInManagerActiveContentChanged;
 private RadPaneGroup _radPaneGroup;
 private PanesStore _documentStore;

 public DependencyObject HostControl
 {
 get
 {
 return _radPaneGroup;
 }

 set
 {
 _radPaneGroup = value as RadPaneGroup;
 }
 }



 public RadDocking Docking { get; internal set; }

 /// <summary>
 /// Starts to monitor the <see cref="IRegion"/> to keep it in synch with the items of the <see cref="HostControl"/>.
 /// </summary>
 protected override void OnAttach()
 {
 bool itemsSourceIsSet = _radPaneGroup.ItemsSource != null;


 if (itemsSourceIsSet)
 {
 throw new InvalidOperationException();
 }

 SynchronizeItems();

 Docking.ActivePaneChanged += ManagerActiveContentChanged;
 Region.ActiveViews.CollectionChanged += ActiveViews_CollectionChanged;
 Region.Views.CollectionChanged += Views_CollectionChanged;
 Docking.Close += _dockingManager_DocumentClosed;

 }

 private void _dockingManager_DocumentClosed(object sender, StateChangeEventArgs e)
 {
 foreach (var pane in e.Panes)
 {
 if (Region.Views.Contains(pane.Content))
 {
 Region.Remove(pane.Content);
 }
 }

 }


 private void Views_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
 {
 if (e.Action == NotifyCollectionChangedAction.Add)
 {
 int startIndex = e.NewStartingIndex;

 foreach (var newItem in e.NewItems)
 {
 var panesFactory = ((CustomDockingPanesFactory)Docking.DockingPanesFactory);
 panesFactory.ActiveGroup = _radPaneGroup;
 _documentStore.Panes.Insert(0, newItem);
 }

 }
 else if (e.Action == NotifyCollectionChangedAction.Remove)
 {
 foreach (object oldItem in e.OldItems)
 {
 _documentStore.Panes.Remove(oldItem);
 }
 }
 }

 private void SynchronizeItems()
 {
 var store = DocumentsStoreAttachment.GetPanesStore(Docking);



 _documentStore = store;
 foreach (object view in Region.Views)
 {
 ((CustomDockingPanesFactory)Docking.DockingPanesFactory).ActiveGroup = _radPaneGroup;
 _documentStore.Panes.Insert(0, view);

 }
 }

 private void ActiveViews_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
 {
 if (_updatingActiveViewsInManagerActiveContentChanged)
 {
 return;
 }

 if (e.Action == NotifyCollectionChangedAction.Add)
 {
 if (Docking.ActivePane != null
 && Docking.ActivePane != e.NewItems[0]
 && Region.ActiveViews.Contains(Docking.ActivePane.Content))
 {
 Region.Deactivate(Docking.ActivePane.Content);
 }

 var pane = Docking.Panes.FirstOrDefault(x => x.Content.Equals(e.NewItems[0]));
 Docking.ActivePane = pane;
 }
 else if (e.Action == NotifyCollectionChangedAction.Remove &&
 e.OldItems.Contains(Docking.ActivePane))
 {
 Docking.ActivePane = null;
 }
 }

 private void ManagerActiveContentChanged(object sender, EventArgs e)
 {
 try
 {
 _updatingActiveViewsInManagerActiveContentChanged = true;

 if (Docking.Equals(sender))
 {
 var activePane = Docking.ActivePane;
 if (activePane != null)
 {
 var activeViews = Region.ActiveViews.Where(it => it != activePane.Content).ToList();
 foreach (var item in activeViews)
 {
 Region.Deactivate(item);
 }

 if (Region.Views.Contains(activePane.Content) && !Region.ActiveViews.Contains(activePane.Content))
 {
 Region.Activate(activePane.Content);
 }
 }



 }
 }
 finally
 {
 _updatingActiveViewsInManagerActiveContentChanged = false;
 }
 }

 }
 }