Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only

/// <summary>
/// Gets the value in a single dimensional array that represents a three dimensional sequence.
/// </summary>
/// <typeparam name="T">The type of the array.</typeparam>
/// <param name="array">The array whose value is to be retrieves.</param>
/// <param name="width">The width of the three dimensional sequence.</param>
/// <param name="height">The height of the three dimensional sequence.</param>
/// <param name="x">The x index (0 to width - 1).</param>
/// <param name="y">The y index (0 to height - 1).</param>
/// <param name="z">The z index (0 to depth - 1).</param>
/// <returns>Returns the value stored in the array.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// width or height is less then 1.
/// </exception>
/// <remarks>
/// <p>This method provides an alternative to working with three dimensional arrays "var value = new int[3,3,3];" by operating 
/// on a single dimensional array using a math formula to determine the index into the array.</p>
/// <p>Think of a multi-layered image. Each image layer consists of a grid of cells defined by width * height.</p>
/// <p>We can use the formula "layer * (width * height)" to get the starting index of the layer in the array. 
/// To get the index in the image we can use the formula "(y * width) + x". 
/// Combining these two formulas we can access any grid cell of any layer in the array like so "(layer * (width * height)) + ((y * width) + x)".</p>
/// <p>This method does not perform range checking and will throw index out of range exceptions if invalid arguments are specified.</p></remarks>
public static T Get3D<T>(this T[] array, int width, int height, int x, int y, int z)
{
    if (width < 1)
    {
        throw new ArgumentOutOfRangeException("width");
    }

    if (height < 1)
    {
        throw new ArgumentOutOfRangeException("height");
    }

    return array[(z * (width * height)) + ((y * width) + x)];
}

Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only

/// <summary>
/// Sets the value in a single dimensional array that represents a three dimensional sequence.
/// </summary>
/// <typeparam name="T">The type of the array.</typeparam>
/// <param name="array">The array whose value is to be set.</param>
/// <param name="width">The width of the three dimensional sequence.</param>
/// <param name="height">The height of the three dimensional sequence.</param>
/// <param name="x">The x index (0 to width - 1).</param>
/// <param name="y">The y index (0 to height - 1).</param>
/// <param name="z">The z index (0 to depth - 1).</param>
/// <param name="value">The value to set.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// width or height is less then 1.
/// </exception>
/// <remarks>
/// <p>This method provides an alternative to working with three dimensional arrays "var value = new int[3,3,3];" by operating
/// on a single dimensional array using a math formula to determine the index into the array.</p>
/// <p>Think of a multi-layered image. Each image layer consists of a grid of cells defined by width * height.</p>
/// <p>We can use the formula "layer * (width * height)" to get the starting index of the layer in the array.
/// To get the index in the image we can use the formula "(y * width) + x".
/// Combining these two formulas we can access any grid cell of any layer in the array like so "(layer * (width * height)) + ((y * width) + x)".</p>
/// <p>This method does not perform range checking and will throw index out of range exceptions if invalid arguments are specified.</p>
/// </remarks>
public static void Set3D<T>(this T[] array, int width, int height, int x, int y, int z, T value)
{
    if (width < 1)
    {
        throw new ArgumentOutOfRangeException("width");
    }

    if (height < 1)
    {
        throw new ArgumentOutOfRangeException("height");
    }

    array[(z * (width * height)) + ((y * width) + x)] = value;
}

If you are writing custom scripts there may be situations where you don’t want the same component added more then once to a game object. For such situations Unity provides the DisallowMultipleComponent attribute that you can specify in your scripts code.


The fallowing script allows you to control fog settings on a per camera basis, allowing you to use say green fog for one camera but red fog for another camera.

Unity 5 package demo is available here CameraFog.unitypackage (46.66 kb)

Camera Fog Screen Shot

CameraFog.cs script

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CameraFog.cs" company="Codefarts">
//   Copyright (c) 2012 Codefarts
//   All rights reserved.
//   contact@codefarts.com
//   http://www.codefarts.com
// </copyright>   
// --------------------------------------------------------------------------------------------------------------------

// Per-camera fog
// This is a simple class that, when added to a GameObject with a camera, allows you to control the fog settings for that camera separately from the global ones. 
// I'd love to hear from you if you do anything cool with this or have any suggestions :)
// Original author: http://wiki.unity3d.com/index.php/User:Tenebrous
// Author website as of 2015: www.tenebrous.co.uk
// Source: http://wiki.unity3d.com/index.php/CameraFog

namespace Codefarts.GeneralTools.Scripts.Camera
{
    using UnityEngine;

    /// <summary>
    /// Modifies a camera to allows you to control the fog settings for that camera separately from the global scene fog or other cameras. 
    /// </summary>
    [RequireComponent(typeof(Camera))]
    [ExecuteInEditMode]
    public class CameraFog : MonoBehaviour
    {
        /// <summary>
        /// The enabled state weather or not fog will be visible.
        /// </summary>
        public bool Enabled;

        /// <summary>
        /// The start distance from the camera where the fog will be drawn.
        /// </summary>
        public float StartDistance;

        /// <summary>
        /// The end distance from the camera where the fog will be drawn.
        /// </summary>
        public float EndDistance;

        /// <summary>
        /// The fog mode that controls how the fog is rendered.
        /// </summary>
        public FogMode Mode;

        /// <summary>
        /// The density of the fog that is rendered.
        /// </summary>
        public float Density;

        /// <summary>
        /// The fog color.
        /// </summary>
        public Color Color;

        /// <summary>
        /// Stores the pre-render state of the start distance.
        /// </summary>
        private float _startDistance;

        /// <summary>
        /// Stores the pre-render state of the end  distance.
        /// </summary>
        private float _endDistance;

        /// <summary>
        /// Stores the pre-render state of the fog mode.
        /// </summary>
        private FogMode _mode;

        /// <summary>
        /// Stores the pre-render state of the density.
        /// </summary>
        private float _density;

        /// <summary>
        /// Stores the pre-render state of the fog color.
        /// </summary>
        private Color _color;
        
        /// <summary>
        /// Stores the pre-render state wheather or not the fog is enabled.
        /// </summary>
        private bool _enabled;

        /// <summary>
        /// Event that is fired before any camera starts rendering.
        /// </summary>
        private void OnPreRender()
        {
            this._startDistance = RenderSettings.fogStartDistance;
            this._endDistance = RenderSettings.fogEndDistance;
            this._mode = RenderSettings.fogMode;
            this._density = RenderSettings.fogDensity;
            this._color = RenderSettings.fogColor;
            this._enabled = RenderSettings.fog;

            RenderSettings.fog = this.Enabled;
            RenderSettings.fogStartDistance = this.StartDistance;
            RenderSettings.fogEndDistance = this.EndDistance;
            RenderSettings.fogMode = this.Mode;
            RenderSettings.fogDensity = this.Density;
            RenderSettings.fogColor = this.Color;
        }

        /// <summary>
        /// Event that is fired after any camera finishes rendering.
        /// </summary>
        private void OnPostRender()
        {
            RenderSettings.fog = this._enabled;
            RenderSettings.fogStartDistance = this._startDistance;
            RenderSettings.fogEndDistance = this._endDistance;
            RenderSettings.fogMode = this._mode;
            RenderSettings.fogDensity = this._density;
            RenderSettings.fogColor = this._color;
        }
    }
}

With the introduction to Unity 5 there comes some api changes. Specifically this foot note was interesting “[2] in Unity5 we also cache the transform component on the c# side, so there should no longer be a performance reason to cache the transform component yourself.

I decided to test it out by writing a few performance test scripts and comparing performance numbers. Below is a screen shot of my results along with the scripts used.

As you can see caching a reference to the transform component in the Start method then using that reference is still faster then calling “this.transform” directly albeit only slightly by about 10-20 ticks. And calling “this.GetComponent<Transform>()” is almost twice as slow.

Unity5TransformPerformance

The code for the PerformanceTesting class is availible here.

TransformCachedGetComponentPerformance script

    using UnityEngine;

    public class TransformCachedGetComponentPerformance : MonoBehaviour
    {
        private Transform reference;

        /// <summary>
        /// Awake is called when the script instance is being loaded.
        /// </summary>
        public void Awake()
        {
#if PERFORMANCE
            var perf = PerformanceTesting.PerformanceTesting<string>.Instance;
            perf.Create("UnityTesting/TransformCachedGetComponentPerformance/Update");
#endif
        }

        /// <summary>
        /// Start is called just before any of the Update methods is called the first time.
        /// </summary>
        public void Start()
        {
            this.reference = this.GetComponent<Transform>();
        }

        /// <summary>
        /// Update is called every frame, if the MonoBehaviour is enabled.
        /// </summary>
        public void Update()
        {
#if PERFORMANCE
            var perf = PerformanceTesting.PerformanceTesting<string>.Instance;
            perf.Start("UnityTesting/TransformCachedGetComponentPerformance/Update");      
#endif

            var rnd = new System.Random();
            this.reference.localPosition = new Vector3(rnd.Next(-3, 3), rnd.Next(-3, 3), rnd.Next(-3, 3));

#if PERFORMANCE
            perf.Stop("UnityTesting/TransformCachedGetComponentPerformance/Update");
#endif
        }
    }

TransformGetComponentPerformance script

    using UnityEngine;

    public class TransformGetComponentPerformance : MonoBehaviour
    {
        /// <summary>
        /// Awake is called when the script instance is being loaded.
        /// </summary>
        public void Awake()
        {
#if PERFORMANCE
            var perf = PerformanceTesting.PerformanceTesting<string>.Instance;
            perf.Create("UnityTesting/TransformGetComponentPerformance/Update");
#endif
        }
        
        /// <summary>
        /// Update is called every frame, if the MonoBehaviour is enabled.
        /// </summary>
        public void Update()
        {
#if PERFORMANCE
            var perf = PerformanceTesting.PerformanceTesting<string>.Instance;
            perf.Start("UnityTesting/TransformGetComponentPerformance/Update");
#endif

            var rnd = new System.Random();
            this.GetComponent<Transform>().localPosition = new Vector3(rnd.Next(-3, 3), rnd.Next(-3, 3), rnd.Next(-3, 3));

#if PERFORMANCE
            perf.Stop("UnityTesting/TransformGetComponentPerformance/Update");
#endif
        }
    }

TransformFieldPerformance script

    using UnityEngine;

    public class TransformFieldPerformance : MonoBehaviour
    {
        /// <summary>
        /// Awake is called when the script instance is being loaded.
        /// </summary>
        public void Awake()
        {
#if PERFORMANCE
            var perf = PerformanceTesting.PerformanceTesting<string>.Instance;
            perf.Create("UnityTesting/TransformFieldPerformance/Update");
#endif
        }

        /// <summary>
        /// Update is called every frame, if the MonoBehaviour is enabled.
        /// </summary>
        public void Update()
        {
#if PERFORMANCE
            var perf = PerformanceTesting.PerformanceTesting<string>.Instance;
            perf.Start("UnityTesting/TransformFieldPerformance/Update");
#endif

            var rnd = new System.Random();
            this.transform.localPosition = new Vector3(rnd.Next(-3, 3), rnd.Next(-3, 3), rnd.Next(-3, 3));

#if PERFORMANCE
            perf.Stop("UnityTesting/TransformFieldPerformance/Update");
#endif
        }
    }

The fallowing code snip is designed to take in a flat list of file paths (or similar data) and produce a hierarchy of tree nodes representing those file paths.

        /// <summary>
        /// Constructs a nested hierarchy of types from a flat list of source types.
        /// </summary>
        /// <typeparam name="TSource">The source type of the flat list that is to be converted.</typeparam>
        /// <typeparam name="TReturn">The type that will be returned.</typeparam>
        /// <typeparam name="TPart">The type of the art type.</typeparam>
        /// <param name="sourceItems">The source items to be converted.</param>
        /// <param name="getParts">A callback function that returns a array of <see cref="TPart"/>.</param>
        /// <param name="comparePart">The compare part callback.</param>
        /// <param name="getChildren">The get children callback.</param>
        /// <param name="addChild">The add child callback.</param>
        /// <param name="createItem">The create item callback.</param>
        /// <returns>Returns an collection of <see cref="TReturn"/> representing the hierarchy.</returns>
        /// <exception cref="Exception">A delegate callback throws an exception. </exception>
        private static IEnumerable<TReturn> ToHierarchy<TSource, TReturn, TPart>(
          IEnumerable<TSource> sourceItems,
        Func<TSource, TPart[]> getParts,
        Func<TReturn, TPart, bool> comparePart,
        Func<TReturn, IEnumerable<TReturn>> getChildren,
        Action<IEnumerable<TReturn>, TReturn> addChild,
        Func<TPart[], int, TSource, TReturn> createItem)
        {
            var treeModels = new List<TReturn>();
            foreach (var keyName in sourceItems)
            {
                IEnumerable<TReturn> items = treeModels;
                var parts = getParts(keyName);
                for (var partIndex = 0; partIndex < parts.Length; partIndex++)
                {
                    var node = items.FirstOrDefault(x => comparePart(x, parts[partIndex]));
                    if (node != null)
                    {
                        items = getChildren(node);
                        continue;
                    }

                    var model = createItem(parts, partIndex, keyName);
                    addChild(items, model);
                    items = getChildren(model);
                }
            }

            return treeModels;
        }

An example of how one could use the ToHierarchy method would be like this …

        var separator = new[] { Path.AltDirectorySeparatorChar.ToString(CultureInfo.InvariantCulture) };
        // paths varible could be something from Directory.GetDirectories method for example.
        var nodes = ToHierarchy<string, TreeViewNode, string>(
            paths.OrderBy(x => x),
            x => x.Split(separator, StringSplitOptions.RemoveEmptyEntries),
            (r, p) => string.CompareOrdinal(r.Name, p) == 0,
            r => r.Nodes,
            (r, c) => ((List<TreeViewNode>)r).Add(c),
            this.CreateTreeNode);

        private TreeViewNode CreateTreeNode(string[] parts, int index, string source)
        {
            var node = new TreeViewNode() { Name = parts[index] };
            node.Value = string.Join(Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture), parts, 0, index + 1);
            if (index == parts.Length - 1)
            {
                node.Name = Path.GetFileName(source);
            }

            node.IsFile = File.Exists(node.Value);
            return node;
        }

Where paths is a array of file paths from say Directory.GetFiles.


Source: http://stackoverflow.com/questions/616718/how-do-i-get-common-file-type-icons-in-c

    public static class FileIcon
    {
        [DllImport("shell32.dll")]
        private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);

        [StructLayout(LayoutKind.Sequential)]
        private struct SHFILEINFO
        {
            public IntPtr hIcon;
            public IntPtr iIcon;
            public uint dwAttributes;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szDisplayName;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            public string szTypeName;
        };

        private const uint SHGFI_ICON = 0x100;
        private const uint SHGFI_LARGEICON = 0x0; // 'Large icon
        private const uint SHGFI_SMALLICON = 0x1; // 'Small icon

        public static System.Drawing.Icon GetLargeIcon(string file)
        {
            var shinfo = new SHFILEINFO();
            var hImgLarge = SHGetFileInfo(file, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), FileIcon.SHGFI_ICON | FileIcon.SHGFI_LARGEICON);
            return System.Drawing.Icon.FromHandle(shinfo.hIcon);
        }

        public static System.Drawing.Icon GetSmallIcon(string file)
        {
            var shinfo = new SHFILEINFO();
            var hImgLarge = SHGetFileInfo(file, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), FileIcon.SHGFI_ICON | FileIcon.SHGFI_SMALLICON);
            return System.Drawing.Icon.FromHandle(shinfo.hIcon);
        }
    } 

// <copyright>
//   Copyright (c) 2012 Codefarts
//   All rights reserved.
//   contact@codefarts.com
//   http://www.codefarts.com
// </copyright>

namespace Codefarts.ObjectPooling
{
    using System;

    /// <summary>
    /// Provides a generic object pooling manager.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ObjectPoolManager<T> where T : class
    {
        /// <summary>
        /// Holds a reference to a singleton instance.
        /// </summary>
        private static ObjectPoolManager<T> instance;

        /// <summary>
        /// Used to track the number of items that have been pushed to the pool.
        /// </summary>
        private int count;

        /// <summary>
        /// Holds the pooled item references.
        /// </summary>
        private T[] cachedItems = new T[10000];


        /// <summary>
        /// Gets or sets the creation callback.
        /// </summary>
        public Func<T> CreationCallback { get; set; }

        /// <summary>
        /// Gets the number of items in the pool.
        /// </summary>
        public int Count
        {
            get
            {
                return this.count;
            }
        }

        /// <summary>
        /// Pops a item from the pool.
        /// </summary>
        /// <returns>A pooled object reference.</returns>
        /// <exception cref="System.NullReferenceException">'CreationCallback' property must be set if you try to pop a item and there are no items available.</exception>
        public T Pop()
        {
            // lock here to prevent treading conflicts with array manipulation
            lock (this.cachedItems)
            {
                // check if there are any pooled objects
                if (this.count < 1)
                {
                    // check if creation callback is null
                    if (this.CreationCallback == null)
                    {
                        throw new NullReferenceException("'CreationCallback' property must be set if you try to pop a item and there are no items available.");
                    }

                    // there are no available objects so create a new one.
                    return this.CreationCallback();
                }

                // reduce the count
                this.count--;

                // retrieve the item and return it
                return this.cachedItems[this.count];
            }
        }

        /// <summary>
        /// Pushes the specified value.
        /// </summary>
        /// <param name="value">The value to push into the pool.</param>
        public void Push(T value)
        {
            // lock here to prevent treading conflicts with array manipulation
            lock (this.cachedItems)
            {
                // update the count
                this.count++;

                // if we need more room for storage increase the size of the cache array
                if (this.count > this.cachedItems.Length)
                {
                    Array.Resize(ref this.cachedItems, this.cachedItems.Length * 2);
                }

                // store the value 
                this.cachedItems[this.count - 1] = value;
            }
        }

        /// <summary>
        /// Gets the singleton instance of the class.
        /// </summary>
        public static ObjectPoolManager<T> Instance
        {
            get
            {
                return instance ?? (instance = new ObjectPoolManager<T>());
            }
        }
    }
}

And some unit tests to go along with it.

// <copyright>
//   Copyright (c) 2012 Codefarts
//   All rights reserved.
//   contact@codefarts.com
//   http://www.codefarts.com
// </copyright>

namespace Codefarts.Tests.ObjectPooling
{
    using System;

    using Codefarts.ObjectPooling;

    using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;

    [TestClass]
    public class ObjectPoolingManagerTests
    {
        ObjectPoolManager<TestObject> manager;

        [TestInitialize]
        public void Setup()
        {
            this.manager = new ObjectPoolManager<TestObject>();
        }

        [TestCleanup]
        public void Cleanup()
        {
            this.manager = null;
        }

        public class TestObject
        {
            public string stringValue;
            public int intValue;
        }

        [TestMethod]
        public void Pop_With_Empty_Pool_NoCallback()
        {
            try
            {
                var item = this.manager.Pop();
                Assert.IsNotNull(item);
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is NullReferenceException);
            }
        }

        [TestMethod]
        public void Pop_With_Empty_Pool_WithCallback()
        {
            try
            {
                this.manager.CreationCallback = this.Callback;
                var item = this.manager.Pop();
                Assert.IsNotNull(item);
                Assert.AreEqual(0, item.intValue);
                Assert.AreEqual(null, item.stringValue);
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is NullReferenceException);
            }
        }

        private TestObject Callback()
        {
            return new TestObject();
        }

        [TestMethod]
        public void Push_Object()
        {
            try
            {
                Assert.AreEqual(0, this.manager.Count);
                this.manager.Push(new TestObject());
                Assert.AreEqual(1, this.manager.Count);
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.ToString());
            }
        }

        [TestMethod]
        public void Push_Pop_Objects()
        {
            try
            {
                Assert.AreEqual(0, this.manager.Count);
                for (var i = 0; i < 3; i++)
                {
                    this.manager.Push(new TestObject() { stringValue = "Item" + i, intValue = i });
                }

                Assert.AreEqual(3, this.manager.Count);

                for (var i = 3 - 1; i >= 0; i--)
                {
                    var item = this.manager.Pop();
                    Assert.AreEqual(i, item.intValue);
                    Assert.AreEqual("Item" + i, item.stringValue);
                }

                Assert.AreEqual(0, this.manager.Count);
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.ToString());
            }
        }
    }
}

Did you know that the GUI class has a matrix property that you can use to rotate and scale your gui elements.

The sample behavior that is provided below will scale and rotate a gui label in the center of the screen.

public class GuiMatrixDemo : MonoBehaviour
{
    private float rotation;

    /// <summary>
    /// OnGUI is called for rendering and handling GUI events.
    /// </summary>
    public void OnGUI()
    {
        var matrix = GUI.matrix;

        GUI.Label(new Rect(5, 5, 100, 20), "before matrix");

        this.rotation += 15f * Time.deltaTime;
        var scale = Mathf.Clamp((float)Math.Sin(Time.time) + 1 * 2, 1, 3);
        GUI.matrix = Matrix4x4.TRS(new Vector3(Screen.width / 2, Screen.height / 2, 0), Quaternion.Euler(0, 0, this.rotation), Vector3.one * scale);
        var size = GUI.skin.label.CalcSize(new GUIContent("test string"));
        var rect = new Rect((-size.x / 2f), (-size.y / 2f), size.x, size.y);
        GUI.Label(rect, "test string");
        GUI.matrix = matrix;
        GUI.Label(new Rect(5, 25, 100, 20), "after matrix");
    }
}

CMS theory for websites part 1

Published 12/18/2013 by createdbyx in News | Programming
Tags:

NOTE: Originally written in March 2013 I’m only getting around to posting this now. :(

A long sorted history of technological bloat warez …

I have been kicking the following ideas around for a while now and may soon start to implement them. I have become frustrated with the whole slew of content management systems from Wordpress to BlogEngine. They all have a tendency to lock you into there system and there way of doing things not to mention that there is no guarantee that these platforms will exist or still be popular 5, 10, 20+ years from now as technology is constantly changing. The only thing that has remains relatively consistent over the last 20 years has been html markup. in other words the raw data.

I have maintained the content on this personal website of mine for over a decade even before I registered the domain createdbyx.com. And the one thing that has remained consistent is the manual labor involved every time I decided to port the content of this site over to a new platform from straight html pages, to DotNetNuke, to BlogEngine, to a partial port over to asp.net mvc etc. Porting the content over from one platform to the next, and having to adapt and convert the content from one database to another, one theme/skin system to another simply is not going to cut it any longer. As time goes on and as the volume of content continues to grow porting that content over to yet another platform becomes more and more tedious.

I am a long term thinker when it comes to this type of stuff because I fully intend to maintain and update this site for the next 50+ years and beyond. I care about preserving the content & data on my various web sites in a human readable platform independent format.

I began playing around with some ideas on my test server boobietaunt.com using asp.net mvc. My intension was to develop a single page website that had a similar Live Tiles system as the windows 8 start screen. The whole thing would in fact be rendered via jQuery GET requests and dynamically replace content on the page so there would actually be no page loading. But as I discovered search engines like Google frown on this because it’s too difficult for there systems to crawl & index the website content. And it would ultimately obliterate my SEO search rakings. So that approach was not going to work, not to mention the issues with managing history via JavaScript and browser incompatibility issues etc. *sigh* just kill me nao :(

Although I never fully abandon any of my coding work I did stop working on the asp.net mvc implementation of my prototype createdbyx.com website in favor of a even simpler solution. Or so I thought. With Asp.net mvc again I found myself needing to learn new ways of doing things IE: the mvc way of doing things, and not only that I was using the Razor view engine. As much as I applaud the effort of the asp.net mvc team for helping to make asp.net development more easier and cleaner, I decided to stop using it before I devoted too much time going down that rabbit hole.

With asp.net mvc I was locking my self into a system of Razor syntax and Controllers that was again pushing me further and further away and putting more technological layers in between what I was trying to do which was to simply serve up html content. At this point for reasons unknown I got it in my head that I could write a better system then the asp.net mvc team, and in some ways that’s just what I did. And I did it in around 1000 lines of code. I essentially created a simplified MVC clone with Controllers and Views that could be extended upon. A feat I am actually personally proud of considering it has many of the same core features as mvc but does it in just under 1000 lines of code. I wrote it back when mvc 1 was still in beta and just being introduced and then I abandoned it to go work on my various other projects.

The custom built mvc clone I created is (as of this writing) powering my codefarts.com website. After having dusted it off and used it to power my codefarts website I have again come to the conclusion that it is far too complicated a system to use even though it’s hardly any code at all and the compiled assemblies for handling localization, security, settings, blogging, Views, Controllers, and extensions only amount to a combined 175k worth of (debug) dll files.

CodeFartsbinaryfiles

The future going forward …

Trying to think up a ridiculously simple solution for publishing html content is deceptively complex with so many CMS choices out there, but there have been some new ways of doing things as of late that could change all that.

What if you could power a personal website without databases & without using a traditional content management system? What if you could create and update the content on your local machine, have it automatically backed up to the cloud, automatically synchronized across multiple computers, and have it support versioning & branching like a CVS all without even having to log in. You could search for content you have previously written, you could even create or edit content even if you were using someone else's computer, and it could support multiple contributors to your site.

Now what if you could do all of that using just html files and some popular free software. The answer is pretty much YES!

Here is a potential publishing scenario …

  1. Open up notepad or your favorite html editor and write some content
  2. Save to a specific folder on your computer
  3. The system automatically syncs the file to the cloud and all other computers of your choosing (Google Drive, SkyDrive, DropBox, AeroFS etc) providing automatic off site backups.
  4. Automatic syncing your local working copy of your site file to the webserver involves a program like SyncBack that runs at scheduled times via windows scheduler to sync files to the web server.
  5. A program always running in the background could detect the changes and commit the changes to a local git repository. As well as the option to publish the files to a git server to provide yet another secondary off site back up.

These are just some of the scenarios that you could set up to automatically publish your website content to the web server.

The end goal?

The elimination of any and all unnecessary server side code. If I could think of a way to go back to managing a website using pure html pages I would, but there are some key pieces of server side code that still need to be present like site templates, a blogging and page caching system.

From a security standpoint the most secure code you can write is no code at all. The more code you write the more vulnerable you make yourself. So focusing on your absolute core needs is essential.

--------------------------------------

Since I originally wrote this post back in march 2013 I have since written a entirely new (and more simplified) web server back end and have ported the local copy of my codefarts.com website over to it. I’ll be making future posts regarding this new system and the reasons why it is even better then the custom built MVC clone I described earlier in this post.


Created by: X

Just another personal website in this crazy online world

Name of author Dean Lunz (aka Created by: X)
Computer programming nerd, and tech geek.
About Me -- Resume