Blog

A catalogue of my discoveries in software development and related subjects, that I think might be of use or interest to everyone else, or to me when I forget what I did!

Partially re-hydrating a class instance

August 22, 2016

I was working with some legacy Silverlight code, to add the functionality of saving the current state to a file and re-opening it later. The way that I chose to implement this was simply using the DataContractSerializer to turn the viewmodel state into a string and write it to a file. I marked the viewmodels with the DataContract attribute and marked any user related properties as DataMember. This worked great for saving the state to a file, and to some extent it worked when re-hyrating the state back to a viewmodel instance. However the problem I had, is that the viewmodel instances that are created when the application is initialised are part of a web of events registrations and dependancies between other viewmodels in the app. It was going to be a pain to re-wire the newly hydrated instances into all the places where the "initialised" viewmodels already were. So my solution was to simply "partially re-hydrate" the already existing viewmodel instances. To acheive this with minimal on-going maintenance, I wrote a simple generic class that uses reflection to identify all the DataMember properties of a class and copies the values from one instance to another. I could then re-hydrate an instance from the file and from that partially rehydrate the plumbed in existing instance. Class below:
using System.Runtime.Serialization;

namespace Project.Silverlight.Helpers
{
    public class PartialRehydrator<T>
    {
        public void Rehydrate(T source, T target)
        {
            // loop through each property of the given type
            foreach (var prop in typeof(T).GetProperties())
            {
                // look for the DataMemberAttribute on this property
                var dma = prop.GetCustomAttributes(typeof(DataMemberAttribute), true);

                // if it has a "DMA" then it's in scope for hydration
                if (dma != null && dma.Length > 0)
                {
                    // get the value from the source
                    var sourceValue = prop.GetGetMethod().Invoke(source, null);

                    // copy the value to the target
                    prop.GetSetMethod().Invoke(target, new object[] { sourceValue });
                }
            }
        }
    }
}
Permalink: Partially re-hydrating a class instance

Simple Responsive IFrame using JavaScript

June 23, 2016

I had a requirement to host the content of one responsive web application inside a view of another responsive web application. Since both applications were responsive in design there was no definitive height, width or aspect ratio. I found a tutorial here: https://benmarshall.me/responsive-iframes/ which talks about a library called Pym.js and also has some css/js examples of a simpler approach. I decided that using Pym.js was overkill for my needs, mostly because I didn't want to make any code changes to the target site. The code I found on the above link also didn't quite work for my needs, since I didn't have a particular aspect ratio (it will depend on the viewing device) and also couldn't give a hard-coded initial width/height to the iframe. In my case, the aspect ratio is actually dependant on the viewing devices screen, therefore I changed the script slightly as below:
$(document).ready(function () {
            var $responsive_iframes = $(".responsive_iframe");

            // Resize the iframes when the window is resized
            $(window).resize(function () {
                $responsive_iframes.each(function () {
                    // Get the parent containe's width and the screen ratio
                    var width = $(this).parent().width();
                    var ratio = $(window).height() / $(window).width();

                    $(this).width(width)
                          .height(width * ratio);
                });
                // Resize to fix all iframes on page load.
            }).resize();
        });
(I also made the jQuery selector look for a class name, rather than all iframes)
Permalink: Simple Responsive IFrame using JavaScript

Visual Studio Shared Project "call is ambiguous"

June 01, 2016

Shared projects are a relatively new thing in Visual Studio, they allow you to share code across multiple assemblies without compiling it in its own dll (the code is compiled into the referencing projects dll). Today I came across a bit of a gotcha - If you reference a shared project in an assembly A and in assembly B, now both of those projects define and export all of the public code from the shared project. Now you have a 3rd project C that also has a reference to the shared project, but also references A and B. You will get a compiler error "call is ambiguous" since the namespace/class/method you are trying to use is now defined 3 times. The simple answer, which is counter intuitive to "normal" library development is to make all of your "shared project" classes "internal" instead of "public". That way each assembly that references the shared project can use the code internally but will not export it to other assemblies.
Permalink: Visual Studio Shared Project "call is ambiguous"

User defined repository injection at runtime

March 01, 2016

A common design pattern is to use a dependency injection container in the composition root to switch between various concrete implementations of an interface abstraction (such as for services, repositories etc.). The configuration for these bindings are often dependant on the build configuration, or an application configuration settings and are singular, as such that only one "concrete implementation" is bound at run time. While recently working on a project, we needed to swap out the implementation of each IRepository based on the user's selection. To put this into context, the application is an ASP.NET MVC 5 website that has some common UI functionality, which we can then plug into multiple different data sources, as per the user's choice of repository. Since we are using Ninject, we can rely on it's ability to bind multiple implementations of an abstraction, by name. We can then use that name (as selected by the user) in a factory method to create instances of each type. Example Ninject module:
using MyProject.ApplicationServices.ExampleData;
using MyProject.Domain.RepositoryDefinitions.ExampleDataRepository;
using Ninject.Modules;

namespace MyProject.UI.MVC.DependencyInjection
{
    public class ExampleDataRepositoryModule : NinjectModule
    {
        public override void Load()
        {
            // define the repo names
            var exampleRepo1Name = "Example Repo 1";
            var exampleRepo2Name = "Example Repo 2";
            var exampleRepo3Name = "Example Repo 3";
            
            // setup all the named versions of the service layers for each of the repository names
            this.Bind<ExampleDataService>().ToSelf().Named(exampleRepo1Name);
            this.Bind<ExampleDataService>().ToSelf().Named(exampleRepo2Name);
            this.Bind<ExampleDataService>().ToSelf().Named(exampleRepo3Name);
            
            // set up the repositories that are bound in each of the above cases
            this.Bind<IExampleDataRepository>().To<Repositories.ExampleRepo1.ExampleDataRepository>().WhenAnyAncestorNamed(exampleRepo1Name);
            this.Bind<IExampleDataRepository>().To<Repositories.ExampleRepo2.ExampleDataRepository>().WhenAnyAncestorNamed(exampleRepo2Name);
            this.Bind<IExampleDataRepository>().To<Repositories.ExampleRepo3.ExampleDataRepository>().WhenAnyAncestorNamed(exampleRepo3Name);
        }
    }
}
We can store the user's selection in some kind of state (in ASP.NET this can be backed by the web session), so we can now use this selection along with the above bindings in a service factory, to create instances of the service with the specified repository.
using MyProject.ApplicationServices.ExampleData;
using MyProject.UI.MVC.Helpers;
using Ninject;

namespace MyProject.UI.MVC.ServiceFactories
{
    public class ExampleDataServiceFactory
    {
        private readonly IKernel ninjectKernel;
        private readonly ISessionHelper sessionHelper;

        public ExampleDataServiceFactory(IKernel ninjectKernel, ISessionHelper sessionHelper)
        {
            this.ninjectKernel = ninjectKernel;
            this.sessionHelper = sessionHelper;
        }

        public ExampleDataService CreateInstance()
        {
            return this.ninjectKernel.Get<ExampleDataService>(this.sessionHelper.CurrentExampleRepoName);
        }
    }
}
Now in the controller, we can take a dependency on the factory and have it create us an instance:
public class ExampleDataController : Controller
    {
        private ExampleDataService exampleDataService;
        private ISessionHelper sessionHelper;

        public ExampleDataController(ExampleDataServiceFactory exampleDataServiceFactory, ISessionHelper sessionHelper)
        {
            this.exampleDataService= exampleDataServiceFactory.CreateInstance();
            this.sessionHelper = sessionHelper;
        }
}
Permalink: User defined repository injection at runtime

StyleCop in VS2015

January 11, 2016

In previous versions of Visual Studio, StyleCop was an msi installation of a VS extension and a global settings file was used to configure the application (StyleCop.settings). In VS2015, with Roslyn and Code Analysis, StyleCop comes as a NuGet package "StyleCop.Analyzers" and it requires two files to configure it (I recommend saving these two files to a common folder and adding the linked files from there in each project). Therefore, in each project:
  • The first step is to install the StyleCop.Analyzers package into the desired projects (or entire solution) using NuGet.
  • File 1: MyRuleset.ruleset - Contains your specific rule customizations
  • File 2: stylecop.json - Configures the StyleCop analyzers process
  • Goto Project > Properties > Code Analysis.. Change the "Rule Set" to "My Ruleset" (for all build configs)
  • Edit the .csproj file, change the item entry from "None/Content" to "AdditionalFiles" e.g.
    <AdditionalFiles Include="..\SharedFolder\SyleCop.Analyzers-VS2015\stylecop.json">
         <Link>stylecop.json</Link>
    </AdditionalFiles>
    
Example contents of the files: MyRuleset.ruleset
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="My Ruleset" Description="My code analysis rules for StyleCop.Analyzer" ToolsVersion="14.0">
  <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
    <Rule Id="SA1600" Action="None" />
    <Rule Id="SA1601" Action="None" />
    <Rule Id="SA1602" Action="None" />
    <Rule Id="SA1633" Action="None" />
    <Rule Id="SA1634" Action="None" />
    <Rule Id="SA1635" Action="None" />
    <Rule Id="SA1636" Action="None" />
    <Rule Id="SA1637" Action="None" />
    <Rule Id="SA1638" Action="None" />
    <Rule Id="SA1640" Action="None" />
    <Rule Id="SA1641" Action="None" />
    <Rule Id="SA1652" Action="None" />
    <Rule Id="SA1118" Action="None" />
    <Rule Id="SA1516" Action="None" />
  </Rules>
</RuleSet>
stylecop.json
{
  "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
  "settings": {
    "documentationRules": {
        "companyName": "PlaceholderCompany"
    },
    "orderingRules": {
        "usingDirectivesPlacement": "outsideNamespace"
    }
  }
}
Permalink: StyleCop in VS2015

Spatial Querying example in CDSA

September 07, 2015

The CDSA architecture templates generate managers and a SQLDAL that is capable of performing any combination of the "normal" queries that you might perform in SQL (such as Equals, Like, In, Less, Greater etc..) However, the default template output does not include any code for performing spatial queries. This is where the extensible nature of CDSA helps us, as we can simply define a new abstraction in the DML for performing a spatial query against the entity that supports it, such as:
public abstract class ExampleGeographyManagerExtns
{
    public abstract Dictionary<Guid, double> GetDataIDsInProximityTo(Guid targetExampleId, double distance);

    public abstract Dictionary<Guid, double> GetDataIDsInProximity(double latitude, double longitude, double distance);

    public abstract List<Guid> GetDataIDsInWKT(string wkt);
}
You can then implement that extension in the SQLDAL as a set of SQL queries:
public class ExampleGeographyManagerExtns : DML.ManagementExtns.ExampleGeographyManagerExtns
{
    private Provider.SqlDataProvider provider;
    private Schemas.SqlExampleGeographySchema schema = Schemas.SqlExampleGeographySchema.GetInstance();

    internal ExampleGeographyManagerExtns(Provider.SqlDataProvider providerInstance)
    {
        this.provider = providerInstance;
    }

    public override Dictionary<Guid, double> GetDataIDsInProximityTo(Guid targetExampleId, double distance)
    {
        // use a sql query to get the averaged data
        string sqlQryText = string.Format(
            @"
SELECT ExampleGeography.ExampleId, ExampleGeography.PointGeography.STDistance(b.PointGeography) Distance
from ExampleGeography
inner join ExampleGeography b
on b.ExampleId=@ExampleId
and b.PointGeography.STBuffer({0}).STIntersects(ExampleGeography.PointGeography)=1
where ExampleGeography.ExampleId<>b.ExampleId
order by Distance asc", distance);

        // create the parameters to the query
        Dictionary<string, object> sqlQryParams = new Dictionary<string, object>();
        sqlQryParams.Add("ExampleId", targetExampleId);

        DataSet rawData = this.provider.SqlHelper.Execute(sqlQryText, CommandType.Text, sqlQryParams);

        Dictionary<Guid, double> results = new Dictionary<Guid, double>();

        if (rawData != null && rawData.Tables.Count > 0)
        {
            foreach (DataRow dr in rawData.Tables[0].Rows)
            {
                results.Add((Guid)dr[this.schema.UniqueId], (double)dr["Distance"]);
            }
        }

        return results;
    }

    public override Dictionary<Guid, double> GetDataIDsInProximity(double latitude, double Longitude, double distance)
    {
        // use a sql query to get the averaged data
        string sqlQryText = string.Format(
            @"
Declare @GeogPoint as geography
Declare @GeogShape as geography

SET @GeogPoint = geography::STGeomFromText('POINT (' + Cast(@longitude as varchar) + ' ' + Cast(@latitude as varchar) + ')', 4326)
SET @GeogShape = @GeogPoint.STBuffer({0})

SELECT ExampleGeography.ExampleId, ExampleGeography.PointGeography.STDistance(@GeogPoint) Distance
from ExampleGeography
where @GeogShape.STIntersects(ExampleGeography.PointGeography)=1
order by Distance asc", distance);

        // create the parameters to the query
        Dictionary<string, object> sqlQryParams = new Dictionary<string, object>();
        sqlQryParams.Add("Latitude", latitude);
        sqlQryParams.Add("Longitude", longitude);

        DataSet rawData = this.provider.SqlHelper.Execute(sqlQryText, CommandType.Text, sqlQryParams);

        Dictionary<Guid, double> results = new Dictionary<Guid, double>();

        if (rawData != null && rawData.Tables.Count > 0)
        {
            foreach (DataRow dr in rawData.Tables[0].Rows)
            {
                results.Add((Guid)dr[this.schema.UniqueId], (double)dr["Distance"]);
            }
        }

        return results;
    }

    public override List<Guid> GetDataIDsInWKT(string wkt)
    {
        string sqlQryText = @"
Declare @GeogPolygon as geography
Declare @GeomPolygon as geometry

Set @GeomPolygon = Geometry::STGeomFromText(@WKT, 4326)
Set @GeogPolygon = Geography::STGeomFromWKB(@GeomPolygon.MakeValid().STUnion(@GeomPolygon.STStartPoint()).STAsBinary(), 4326)

SELECT ExampleGeography.ExampleId
from ExampleGeography
WHERE PointGeography.STIntersects(@GeogPolygon)=1";

        // create the parameters to the query
        Dictionary<string, object> sqlQryParams = new Dictionary<string, object>();
        sqlQryParams.Add("WKT", wkt);

        DataSet rawData = this.provider.SqlHelper.Execute(sqlQryText, CommandType.Text, sqlQryParams);

        List<Guid> results = new List<Guid>();

        if (rawData != null && rawData.Tables.Count > 0)
        {
            foreach (DataRow dr in rawData.Tables[0].Rows)
            {
                results.Add((Guid)dr[this.schema.UniqueId]);
            }
        }

        return results;
    }
}
We can then expose the extension in the IDataProvider interface and SQL implemention:
public partial interface IDataProvider : ClauseWrappers.WhereClauseWrapper.IWhereClauseHandler, ClauseWrappers.OrderByClauseWrapper.IOrderByClauseHandler
{
    // expose specialised management functions/classes
    ManagementExtns.ExampleGeographyManagerExtns ExampleGeographyManagerExtns { get; }
}

public partial class SqlDataProvider : DML.Provider.IDataProvider
{
    private ManagementExtns.ExampleGeographyManagerExtns exampleGeographyManagerExtns;

    public DML.ManagementExtns.ExampleGeographyManagerExtns ExampleGeographyManagerExtns
    {
        get
        {
            if (this.exampleGeographyManagerExtns == null)
            {
                this.exampleGeographyManagerExtns = new ManagementExtns.ExampleGeographyManagerExtns(this);
            }

            return this.exampleGeographyManagerExtns;
        }
    }
}
Finally, we can now expose this functionality through our extended business layer manager class:
public partial class ExampleGeographyManager : BaseClasses.ExampleGeographyManagerBase
{
    public Dictionary<long, double> GetRecordIDsInProximityTo(long targetExampleId, double distance)
    {
        return DataProviders.Current.ExampleGeographyManagerExtns.GetDataIDsInProximityTo(targetExampleId, distance);
    }

    public List<long> GetRecordIDsInWKT(string wkt)
    {
        return DataProviders.Current.ExampleGeographyManagerExtns.GetDataIDsInWKT(wkt);
    }

    public Dictionary<long, double> GetRecordIDsInProximity(double latitude, double longitude, double radiusInMeters)
    {
        return DataProviders.Current.ExampleGeographyManagerExtns.GetDataIDsInProximity(latitude, longitude, radiusInMeters);
    }
}
Permalink: Spatial Querying example in CDSA

Bio - Kinetic

March 02, 2015

I have recently become Solution Architect and Development Lead at Kinetic. My new role extends my responsibilities as a Senior Developer, essentially creating 3 main aspects to my job. Firslty, I continue to do software development where necessary, but also have added responsibilities for the overall architecture of the systems going forward, implementing development strategies and also being a technical lead/consultant for the team and the business. Kinetic Logo
Permalink: Bio - Kinetic

Raising PropertyChanged Events on Static Properties

January 02, 2014

If you want to share data amongst all instances of a class you will naturally create some "static" variables. This is fine, except when using the binding engine within Silverlight, as it relies on "PropertyChanged" events to notify the UI of a change to a property, but you can't raise an instance event from within a static property. The way I solved this was to create a static event called "StaticPropertyChanged" which the static properties raise whenever they are changed. Within the constructor of the class I attach to this event (i.e. each instance attaches to the static event) and re-raise the event through the PropertyChanged event for the current instance. In effect, every instance of the class will raise a PropertyChanged event whenever any of the static data is changed. The code is as follows:
public abstract class ViewModelBase : NotificationObject
    {
	//use a shared event so that any instance can propogate the event to all instances
	private static event Action<string> _staticPropertyChanged;

	protected static void OnStaticPropertyChanged(string propertyName)
	{
		if (_staticPropertyChanged != null)
		_staticPropertyChanged(propertyName);
	}         

	public ViewModelBase()
	{
		//when a new instance is created, we subscribe it to shared Busy Property Changed event
		_staticPropertyChanged += ViewModelBase__staticPropertyChanged;
	}

	/// <summary>
	/// Within each instance, handle the shared staticPropertyChanged event by raising the instance version of RaisePropertyChanged event
	/// </summary>
	void ViewModelBase__staticPropertyChanged(string propertyName)
	{
		RaisePropertyChanged(propertyName);
	}


	//example
	private static Dictionary<long, string> _SomeSharedLookup;
	public static Dictionary<long, string> SomeSharedLookup
	{
		get { return ViewModelBase._SomeSharedLookup; }
		set { ViewModelBase._SomeSharedLookup = value; OnStaticPropertyChanged("SomeSharedLookup"); }
	}
}
Permalink: Raising PropertyChanged Events on Static Properties

Generic Fabric Cache Implementation

July 30, 2013

The following code shows an example of implementing the Microsoft AppFabric Caching mechanism (part of the Azure framework). I wanted a generic caching helper which can be used by calling code without too much effort or consideration for the internal workings, such as how data from different sources is partitioned (to avoid ID conflicts). The way I have done this is to the fully qualified type name, supplied by the generic parameter. In the event that the AppFabric server could not be contacted on startup, there is an alternative memory based cache, which allows the programmer to specify names of types which should not be included in the memory based cache.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.ApplicationServer.Caching;
using System.Text.RegularExpressions;

namespace Common.FabricCache
{
    public static class FabricCacheHelper
    {

        public static object SyncLock = new object();
        static DataCacheFactory myCacheFactory;
        static DataCache myFabricCache;

        static FabricCacheHelper()
        {
            PrepareClient();
        }

        public static T GetFromCache<T>(string key)
        {
            if (myFabricCache != null)
            {
                //user the region per type and use the key as the identifier within that region
                return (T)myFabricCache.Get(key, Regex.Replace(typeof(T).FullName, "[^a-z0-9]", "", RegexOptions.IgnoreCase));
            }
            else
            {
                return (T)AlternateCache.Get(key, Regex.Replace(typeof(T).FullName, "[^a-z0-9]", "", RegexOptions.IgnoreCase));
            }
        }

        public static void AddToCache<T>(string key, T value)
        {
            if (value != null)
            {
                if (myFabricCache != null)
                {
                    //create a region per type and use the key as the identifier within that region
                    myFabricCache.CreateRegion(Regex.Replace(typeof(T).FullName, "[^a-z0-9]", "", RegexOptions.IgnoreCase));
                    myFabricCache.Put(key, value, Regex.Replace(typeof(T).FullName, "[^a-z0-9]", "", RegexOptions.IgnoreCase));
                }
                else
                {
                    //create a region per type and use the key as the identifier within that region
                    AlternateCache.CreateRegion(Regex.Replace(typeof(T).FullName, "[^a-z0-9]", "", RegexOptions.IgnoreCase));
                    AlternateCache.Put(key, value, Regex.Replace(typeof(T).FullName, "[^a-z0-9]", "", RegexOptions.IgnoreCase));
                }
            }
        }

        public static void RemoveFromCache<T>(string key)
        {
            if (myFabricCache != null)
            {
                myFabricCache.Remove(key, Regex.Replace(typeof(T).FullName, "[^a-z0-9]", "", RegexOptions.IgnoreCase));
            }
            else
            {
                AlternateCache.Remove(key, Regex.Replace(typeof(T).FullName, "[^a-z0-9]", "", RegexOptions.IgnoreCase));
            }
        }

        private static void PrepareClient()
        {
            //-------------------------
            // Configure Cache Client 
            //-------------------------

            //Define Array for 1 Cache Host
            List<DataCacheServerEndpoint> servers = new List<DataCacheServerEndpoint>(1);

            //Specify Cache Host Details 
            //  Parameter 1 = host name
            //  Parameter 2 = cache port number
            string fabricHost = System.Configuration.ConfigurationManager.AppSettings["FabricHost"];// = "localhost";
            int fabricPort = int.Parse(System.Configuration.ConfigurationManager.AppSettings["FabricPort"]); // 22233;
            servers.Add(new DataCacheServerEndpoint(fabricHost, fabricPort));

            //Create cache configuration
            DataCacheFactoryConfiguration configuration = new DataCacheFactoryConfiguration();

            //Set the cache host(s)
            configuration.Servers = servers;

            //Set default properties for local cache (local cache disabled)
            configuration.LocalCacheProperties = new DataCacheLocalCacheProperties();

            //Disable exception messages since this sample works on a cache aside
            DataCacheClientLogManager.ChangeLogLevel(System.Diagnostics.TraceLevel.Off);

            //Pass configuration settings to cacheFactory constructor
            myCacheFactory = new DataCacheFactory(configuration);

            //Get reference to named cache
            try
            {
                string fabricCacheName = System.Configuration.ConfigurationManager.AppSettings["FabricCacheName"];
                myFabricCache = myCacheFactory.GetCache(string.IsNullOrEmpty(fabricCacheName) ?  "myFabricCache" : fabricCacheName);
            }
            catch (Exception)
            {
                //if anything goes wrong with the fabric, just carry on which will use the alternate method
                myFabricCache = null;
            }
        }

        #region "Alternative Cache - Memory Based"
        private static class AlternateCache
        {
            private static Dictionary<string, Dictionary<string, object>> _alternateMemoryCache = new Dictionary<string, Dictionary<string, object>>();

            //some types are known to be large, so we wouldnt want them in the w3wp process memory of this alternative cache - they should be ignored (as if not cached)
            private static string[] _typeNameRegionRestrictions = new string[]
            {
            };

            internal static object Get(string key, string region)
            {
                Dictionary<string, object> regionCache;
                
                if (_alternateMemoryCache.TryGetValue(region, out regionCache))
                {
                    object value;
                    if (regionCache.TryGetValue(key, out value))
                    {
                        return value;
                    }
                }

                //wasnt in the cache
                return null;
            }

            internal static void CreateRegion(string region)
            {
                //is this region allowed, or are we blocking this type?
                if (!IsRestrictedRegionName(region))
                {
                    if (!_alternateMemoryCache.ContainsKey(region))
                        _alternateMemoryCache.Add(region, new Dictionary<string, object>());
                }
            }

            internal static void Put(string key, object value, string region)
            {
                Dictionary<string, object> regionCache;
                if (_alternateMemoryCache.TryGetValue(region, out regionCache))
                {
                    if (!regionCache.ContainsKey(key))
                        regionCache.Add(key, value);
                    else
                        regionCache[key] = value;
                }
            }

            internal static void Remove(string key, string region)
            {
                Dictionary<string, object> regionCache;
                if (_alternateMemoryCache.TryGetValue(region, out regionCache))
                {
                    if (regionCache.ContainsKey(key))
                        regionCache.Remove(key);
                }
            }

            private static bool IsRestrictedRegionName(string typeName)
            {
                return _typeNameRegionRestrictions.Contains(typeName);
            }
        }
        #endregion


    }
}
Permalink: Generic Fabric Cache Implementation

Unrecognized tag prefix or device filter 'asp'

July 01, 2013

I had this problem recently in Visual Studio that drove me mad! It was a VB ASP.NET web project and Intellisense would not work on ASPX pages, complaining about the asp tag prefix. There is a lot of documented bugs/fixes for this online (google it), including deleting the solution .suo file, clearing out bin/obj files, deleting the visual studio reflected schemas files (under the app data folder), clearing your VS settings. I tried them all but to no avail.. My problem though, was quite different in 2 ways.. Firstly my project was building and running absolutely fine (not sure about this for the other people's problems, but maybe worth noting). Also, in my opinion, the cause of my problem was the way I had set up the project to re-use an existing web projects files and code (I was re-using quite a lot of code files from another project by adding them as linked files for the code-infront and a DLL reference for the code behind.) I have had some problems with VB project in the past due to this kind of thing, because VB does not define the root namespace in the code files it has caused some issues, which led me to believe the problem was being caused by the vbproj settings. I remembered that by default I have option strict set to "on" for VB projects, since the project was building but the designer was just being "whingy" I decided to turn option strict off... It worked! :)
Permalink: Unrecognized tag prefix or device filter 'asp'