Making Caching Awesome Again

So, I've recently began a new project. It's no where near stable, or even usable. But I think it's a good enough time to introduce it.

It's called CacheGen and it's hosted at bitbucket and BSD licensed.

Basically, it's a T4 template that generates really awesome helpers for caching. It's geared at ASP.Net, but my goal is to make it so it can be used in other ways as well. So, how does it work? You give it a list of specifications for something you want to cache. Let's say you have a string that's really expensive to generate, but doesn't belong in a database. To go on my theme of markdown being slow, let's call it MarkdownTranslation

You tell the T4 template to create a cache item for it like this:

var tmp=new CacheObject
{
  Name="MarkdownTransform",
  ValueType="string";
}
var cache=new CacheGen("Earlz.Example.MyCache");
cache.Items.Add(tmp);
Write(cache.ToString();

And then, you can use the MyCache class like this:

var text=MyCache.MarkdownTransform ?? (MyCache.MarkdownTransform=Markdown.Translate(foobar));

Much much easier. But, there is a flaw in this. It's possible that we could consume double the server resources required for this. This wouldn't be a problem in this case, but imagine a very heavy SQL query or something. This isn't quite what we want when things are really expensive. So, let's use some other fancy syntax

var text=MyCache.MarkdownTransformCache.LockGetOrLoad(()=>Markdown.Translate(foobar));

What this will do instead is raise a flag so that requests for MarkdownTransform will block and during this time, it will execute the expensive code and other threads will sleep. This way, it only gets executed once. And, when it finally gets the results back, the cache will be loaded with it and the other threads will be able to access it. So, instead of computing the expensive thing multiple times, instead we just hold out other requests for a little while so the expensive thing is done only once.

Sure, you can do this same thing with ASP.Net's cache, but how much code would it require for each time you did this? Hence why it's T4. Also, it's completely statically typed. No casting!

Now, what if you wanted to cache the markdown for multiple posts? Or just want to cache entire post objects? Well, I thought of this too:

You'd make the CacheObject like this in T4:

Name="Transforms";
KeyType="ObjectId";
ValueType="BlogPostData";

Then, you could apply the same lock-first type behavior like so:

var post=MyCache.TransformsCache.LockGetOrLoad(objectid, ()=>LoadPost());

Or, if you prefer the (probably safer) possibly execute twice behavior:

var post=MyCache.Transforms[objectid] ?? (MyCache.Transforms[objectid] = LoadPost());

These are the ideas anyway. None of it is actually implemented yet, and a lot more research must be done to ensure that this is a sane way to go about it. But, you can expect to get something similar to this.

Posted: 12/6/2012 5:17:43 AM

MarkdownSharp is freaking slow!

So, I use MarkdownSharp on this website for translating my posts from markdown to HTML. During a profiling session, I found that MarkdownSharp is horribly HORRIBLY slow. It was the bottle neck of my entire website. On my personal machine, requests per second went from 325 (or ~22ms per request) to 720 (or ~9ms per request) when I cached the markdown translated text.

Personally, I find it pitiful that Markdown was more of a bottleneck than my database. Getting of my post data from my database: ~5 ms. Translating all of the text in the posts to HTML: ~15ms. What the hell is wrong with this!?

I'm sure Markdown isn't trivial to translate of course, and mono generally sucks at string operations anyway. But still, I find this absolutely ridiculous that the only thing so far I've had to cache is markdown translations.

Anyway, this website is updated now and should be capable of handling about 100 requests per second. I suspect the primary reason I can't achieve anything higher than that is a combination of Apache having a lot of overhead and my VPS being rather weak anyway. But, this should be plenty for this low traffic blog.

Posted: 12/3/2012 4:36:54 AM

How to unit test T4 code generators

So, you're like me and have a greater than 500 line T4 template that is a steaming pile of... code. And of course, no syntax highlighting without addons, no intellisense, generally horrible Visual Studio support, and near impossible to unit test.

Well, my friends, I have just the thing for you! After beating my head against a wall for several days, I've found salvation!

To use my method requires some "neat" code, and it requires a few assumptions:

  • You're using T4 to generate C# code
  • You're then taking this C# code and including it in your project
  • You're ready to do some major refactoring for an awesome experience in the end (and your T4 template will be so much cleaner afterwards!)
  • You can have at least 2 tiles tied to T4 (one T4 template and one include file)

The corner stone of making T4 testable is to separate out the "logic" and the "content"; where the content is the generated C# code, and the logic is what you do to generate it.

To do this and enforce this separation cleanly, you must have two files. One of these files is the T4 "view", and another file is the logic, which is capable of being normally compiled outside of T4.

Example Untestable T4 Code

Lets start with a simple example. You have a simple T4 template which takes a file like so:

foo=bar
biz=baz

and turns it into

public class GeneratedClass
{
  public foo="bar";
  public biz="baz";
}

Here is a simple(and untestable) T4 template for it.:

<#@ template language="C#v3.5" hostspecific="true"#>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Linq" #>

using System;
namespace Earlz.SampleT4
{
    public class GeneratedClass
    {
<#
    string filename="fields.txt";

    string path=Path.GetDirectoryName(Host.TemplateFile);
    var f=File.OpenText(Path.Combine(path, filename));
    string text=f.ReadToEnd();
    text=text.Replace("\r", ""); //strip extra line endings (if needed)
    var lines=text.Split('\n');
    foreach(var line in lines)
    {
        var parts=line.Split('='); //split for each element
#>
        public string <#= parts[0] #> = @"<#= parts[1].Replace("\"", "\"\"") #>";
<#
    }
#>
    }
}

There are a few rumored methods of testing this T4 file:

  • Run an integration test manually comparing the code (very very brittle)
  • I can't think of anything else worth mentioning

The Great Refactor

Now, What I suggest:

Let's refactor this and make it so we can eliminate some logic out of our "view". In this case, the view should worry about getting the code into the generated file and that's it. The logic on the other hand should work at a level of abstraction.

Here's what we're going to do:

  • Eliminate most of this code from the view
  • Create a new file for the logic
  • Use a very clever trick so that our logic file will compile outside of T4 and work when included in T4
  • Make it so that instead of just outputting text, we're building an object model that happens to be easily translatable to text

Because I came prepared, I already have the object model abstraction built. you can catch it at the bottom of the last code snippet. (It's easy to rip out and put elsewhere)

Compiling Code In and Out of T4

So, we create a new T4 logic file and name it something like "GenerateClassLogic.tt.cs". Now, you may be thinking "but you can't use the same code in T4 and a regular project!" *WRONG!

I came across a very nifty trick. Behold:

//<#+
/*That line above is very carefully constructed to be awesome and make it so this works!*/
#if NOT_IN_T4
//Apparently T4 places classes into another class, making namespaces impossible
namespace MyNamespace.Foo.Bar
{
    using System;
    using System.Linq;
    using System.Text;
    using System.Collections.Generic;
    using System.IO;
#endif
//regular ol' C# classes and code...

#if NOT_IN_T4
} //end the namespace
#endif
//#>

The key parts are the first and last lines. These begin with a comment so that the C# compiler will ignore them outside of T4, but inside of T4 these instruct the transformer to include this as a "class feature" (which ends up being a nested class)

Note here also that you must define a compile symbol. This is super easy to do. If you add it to your project, then it won't carry over to the T4 template though, making this an easy way to add in a few key things that can't be done without knowing if we're executing within T4 or not.

So, now we have a T4 logic file that will compile inside and outside of T4. Perfect for unit testing! All we need now is some logic!

The Result

Here is what I came up with:

//<#+
/*That line above is very carefully constructed to be awesome and make it so this works!*/
#if NOT_IN_T4
//Apparently T4 places classes into another class, making namespaces impossible
namespace Earlz.SampleT4.Internal
{
    using System;
    using System.Linq;
    using System.Text;
    using System.Collections.Generic;
    using System.IO;
#endif
    //regular ol' C# classes and code...

    public class GenerateClassFromText : ClassGenerator
    {
        public GenerateClassFromText(string text)
        {
            Init(text);
        }
        public GenerateClassFromText(string templatefile, string filename)
        {
            string path=Path.GetDirectoryName(templatefile);
            var f=File.OpenText(Path.Combine(path, filename));
            Init(f.ReadToEnd());
        }
        public void Init(string text)
        {
            text=text.Replace("\r", ""); //strip extra line endings (if needed)
            var lines=text.Split('\n');
            foreach(var line in lines)
            {
                var parts=line.Split('='); //split for each element
                var field=new Field
                {
                    Accessibility="public",
                    Name=parts[0],
                    Type="string",
                    InitialValue=string.Format("@\"{0}\"",parts[1].Replace("\"", "\"\""))
                };
                Fields.Add(field);
            }
        }

    }

    //shove this all into one file so we don't force implementers to hand combine this or copy over more than 2 files
    public class ClassGenerator : CodeElement
    {
        virtual public List<Property> Properties
        {
            get;
            private set;
        }
        virtual public List<Method> Methods
        {
            get;
            private set;
        }
        virtual public List<Field> Fields
        {
            get;
            private set;
        }
        virtual public string Namespace
        {
            get;set;
        }
        virtual public string OtherCode
        {
            get;set;
        }
        public virtual string BaseClass
        {
            get;set;
        }
        public ClassGenerator()
        {
            Properties=new List<Property>();
            Methods=new List<Method>();
            Fields=new List<Field>();
            Accessibility="";
        }
        public override string ToString ()
        {
            StringBuilder sb=new StringBuilder();
            sb.Append("namespace "+Namespace);
            sb.AppendLine("{");
            sb.AppendLine(PrefixDocs);
            sb.Append(GetTab(1)+Accessibility+" class "+Name);
            if(string.IsNullOrEmpty(BaseClass))
            {
                sb.AppendLine();
            }
            else
            {
                sb.AppendLine(": "+BaseClass);
            }
            sb.AppendLine(GetTab(1)+"{");
            foreach(var p in Properties)
            {
                sb.AppendLine(p.ToString());
            }
            foreach(var m in Methods)
            {
                sb.AppendLine(m.ToString());
            }
            foreach(var f in Fields)
            {
                sb.AppendLine(f.ToString());
            }
            sb.AppendLine(OtherCode);
            sb.AppendLine(GetTab(1)+"}");
            sb.AppendLine("}");
            return sb.ToString();
        }

    }
    abstract public class CodeElement
    {
        public const string Tab="    ";
        public string Name
        {
            get;
            set;
        }
        public string Accessibility
        {
            get;
            set;
        }
        string prefixdocs;
        virtual public string PrefixDocs
        {
            get
            {
                return prefixdocs;
            }
            set
            {
                prefixdocs=GetTab(2)+"///<summary>\n"+GetTab(2)+"///"+value+"\n"+GetTab(2)+"///</summary>";
            }
        }
        public override string ToString ()
        {
            throw new NotImplementedException();
        }
        public static string GetTab(int nest)
        {
            string tmp="";
            for(int i=0;i<nest;i++)
            {
                tmp+=Tab;
            }
            return tmp;
        }
        protected CodeElement()
        {
            Accessibility="";
            PrefixDocs="";
        }
    }
    public class Property : CodeElement
    {
        public string Type
        {
            get;set;
        }
        public string GetMethod
        {
            get;
            set;
        }
        public string SetMethod
        {
            get;
            set;
        }
        public override string ToString ()
        {
            string tmp=GetTab(2)+PrefixDocs+"\n";
            tmp+=GetTab(2)+CodeElement.Tab+Accessibility+" "+Type+" "+Name+"{\n";
            if(GetMethod!=null)
            {
                tmp+=GetTab(2)+GetMethod+"\n";
            }
            if(SetMethod!=null)
            {
                tmp+=GetTab(2)+SetMethod+"\n";
            }
            tmp+=GetTab(2)+"}\n";
            return tmp;
        }
        public Property()
        {
            GetMethod="get;";
            SetMethod="set;";
        }
    }
    public class Field : CodeElement
    {
        public string Type
        {
            get;
            set;
        }
        public string InitialValue
        {
            get;
            set;
        }
        public override string ToString ()
        {
            string tmp=GetTab(2)+PrefixDocs+"\n";
            tmp+=GetTab(2)+Accessibility+" " +Type+" " +Name;
            if(InitialValue!=null)
            {
                tmp+="="+InitialValue+";";
            }else{
                tmp+=";";
            }
            return tmp;
        }
    }
    public class Method : CodeElement
    {
        public string ReturnType
        {
            get;
            set;
        }
        public List<MethodParam> Params
        {
            get;set;
        }
        public string Body
        {
            get;set;
        }
        public Method()
        {
            Params=new List<MethodParam>();
            Body="";
            ReturnType="void";
        }
        public override string ToString ()
        {
            string tmp=GetTab(2)+PrefixDocs+"\n";
            tmp=GetTab(2)+Accessibility+" "+ReturnType+" "+Name+"(";
            for(int i=0;i<Params.Count;i++)
            {
                tmp+=Params[i].ToString();
                if(i==Params.Count-1)
                {
                    tmp+=")";
                }
                else
                {
                    tmp+=", ";
                }
            }
            if(Params.Count==0)
            {
                tmp+=")";
            }
            tmp+="\n"+GetTab(2)+"{\n";
            tmp+=Body;
            tmp+="\n"+GetTab(2)+"}";
            return tmp;
        }
    }
    public class MethodParam
    {
        public string Name{get;set;}
        public string Type{get;set;}
        public override string ToString ()
        {
            return Type+" "+Name;
        }
    }
#if NOT_IN_T4
} //end the namespace
#endif
//#>

Wow, so much cleaner! Plus, go to modify it in Visual Studio. What's that? Theirs actually intellisense!? Yes! There is! It will also throw compiler errors when you screw stuff up.

Also, I trimmed the T4 view down significantly as well and of course put in an include statement for our logic file:

<#@ template language="C#v3.5" hostspecific="true"#>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Linq" #>

<#
    string filename="fields.txt";
    var gen=new GenerateClassFromText(Host.TemplateFile, filename);
    gen.Namespace="Earlz.SampleT4";
    gen.Name="GeneratedClass";
    gen.Accessibility="public";
#>

<#= gen.ToString() #>

<#@ include file="GenerateClassLogic.tt.cs" #>

Wow that's simple!

Now note: None of the stuff in your "view" is testable. You should always keep that in mind and keep it as simple as humanely possible.

If you'll notice, other than a bit of boilerplate XML documentation, the generated code is exactly the same. This is intentional :)

Unit Testing T4

What were we trying to do again? Ah yes. Tests. Let's add some NUnit tests for this!

And so, by simply adding a reference to our project in the NUnit test project, we instantly get access to the logic of the code generator. Here is the quick testing I did:

[TestFixture]
public class CodeGeneratorTests
{
    string TestText=
@"Foo=Bar
Biz=Baz
TestQuotes=""foo bar""";

    [Test]
    public void EnsureFieldWritten()
    {

        var gen=new GenerateClassFromText(TestText);
        Assert.IsTrue(gen.Fields.Any(x=>x.Name=="Foo"));
        Assert.IsTrue(gen.Fields.Any(x=>x.Name=="Biz"));
    }
    [Test]
    public void EnsureFieldsPublic()
    {
        var gen=new GenerateClassFromText(TestText);
        var tmp=gen.Fields.Single(x=>x.Name=="Foo");
        Assert.AreEqual(tmp.Accessibility, "public");
    }
    [Test]
    public void EnsureFieldsQuoted()
    {
        var gen=new GenerateClassFromText(TestText);
        var tmp=gen.Fields.Single(x=>x.Name=="TestQuotes");
        Assert.AreEqual(tmp.InitialValue, @"@""""""foo bar""""""");
    }
}

Conclusion and Remarks

So, in conclusion, we've learned that T4 is actually capable of taming. (when I first learned T4, I wouldn't have thought it possible either) The main thing to do is maintain a separation of "content" and logic. Now of course, there are some gotchas to watch for:

  • This only works when your T4 generator's target is to generate C# code
  • When you add a reference to something, you must add it to both the logic file and the view
  • It's still very difficult to reference external assemblies(particularly project assemblies). This doesn't solve that problem at all
  • You must define a compiler symbol for your project if you wish to run unit tests against it.
  • When other people use your T4 template outside of your project(and thus don't need to test it), they must ensure that the logic file is not compiled outside of the T4
  • Unit testing that a piece of code is generated is very difficult and brittle(hence the need for abstractions where possible to make this easier)
  • My abstraction mechanisms for building objects aren't really that good. They're good enough for me, but please someone improve them! (if you do it I'll link to you from here)

Happy code generation!

Posted: 11/21/2012 3:46:10 AM

An analysis of the history of programming paradigms

Hi, so, when did functional programing become such a huge thing that every language implements. What led to it's popularity? And I'm sure some of you may be wondering: now that we have functional programming in mainstream languages, what's next? Well, I'm going to attempt an educated guess at that. But, first, we need a history lesson of the different programming paradigms, and why they came to be implemented in the popular languages that businesses use each day.

As usual, hardly anything in computer science is "new". There was a LOT of experimentation in the 60s and 70s with different programming languages and thus different paradigms. I'd argue to say that everything language related has been tried at least once during that time period even. I'm not going to cover that here though, instead I'm going to cover their introduction to mainstream languages.

Also, one last thing: This is mostly educated guesses. I have no proof to back me up. It's about like answering "why did Pokemon become popular"... No proof exists, but we can make guesses at why.

The First Mainstream Language

First, we have procedural programming. This was especially well marked with the creation and rise of C. The reason I believe this became popular was because you could write code which could translate very closely to assembly language. Resources were scarce, but writing directly in assembly language had begun to be impractical. Now, you may ask, why didn't other paradigms become popular at this point?

I'll list the problems with each paradigm:

Functional programming was there with Lisp and friends. However, garbage collection is practically required and never comes free. With resources being scarce, this was not the best way to go. Also, at this point most people knew assembly language and still were familiar with low level details like punch cards. Putting a huge amount of abstraction on top of that concept meant that it would be quite hard to learn

Stack-oriented programming was there with Forth and friends. This didn't require garbage collection, but was still a huge layer of abstraction on top of the actual instruction set. Despite this, it didn't mean it was slower. My best guess is that this was harder for assembly-skilled programmers to adapt to.

Ok, so it's seen now that procedural programming is the best step forward from assembly coding because assembly basically is procedural programming. C introduced many things though. The biggest thing is it made cross-compiling feasible, and the language was fairly simple which made making new compilers easy. Looking into all this in detail though really makes me wonder why Forth didn't win out against C for the most popular mainstream language.

Object Oriented Programming

Next on the list of big paradigm shifts: object oriented programming. This of course existed long before it went mainstream. The turning point that it really became popular was with the rise of the GUI. Objects are a natural fit with GUI elements. My guess for why it didn't go mainstream sooner is because it made compilers more complicated and have to worry about more than just doing a single pass at code and calling it good. Eventually, compilers caught up though and C++ replaced C for the main programming language spot. This idea of object oriented programming really got kicked into mainstream with the popularity of Java. You can see some more history about object oriented programming at this very helpful Programmers.Stackexchange answer

Garbage Collection

So, what's next? Probably the biggest one is garbage collection. Memory(and good collection algorithms) were finally cheap enough to let programmers forget about managing memory. Of course, this existed long before it went mainstream, but most programmers considered it slow and wasteful(which it arguably was at the time). I think the big reason garbage collection went so mainstream is because we finally reached a tipping point where computing time(and resources) were cheaper than programming time.

Generics

Generics would probably be next: statically typing an object which can take more than a single type. C++ had it first of course. I'm not sure if it became "mainstream" before it hit Java and .Net or not. It arguably has been popular for sometime now. Ada has had generics since it was first designed in the 70s. I believe the primary reason for generics becoming so mainstream is because object oriented programming became mainstream. Doing OOP in a statically-typed way is quite cumbersome without generics. People were beginning to realize that duplicating code and using tons of explicit casts was really a bad practice.

Functional Programming

Next up is everyone's recent favorite: functional programming. I actually saw this trend develop(and was a programmer at the time). Functional programming really seemed to hit mainstream with .Net support, though Javascript has been functional since 1995. Javascript didn't become really used though until at least the early 2000s with the advent of modern browsers and more adherence to standards. (and the beginning of intense hatred for IE 6). So, I wouldn't really consider functional programming to have became mainstream until everyones favorite languages started adding functional aspects. The primary driving reason for functional programming is that suddenly everyone's new PC started coming with dual-core processors. Suddenly, concurrent programming was something everyone was concerned with. Functional programming is a perfect fit for concurrent tasks. Functional programs have no state and naturally are as content working in parallel. This has also seen the popularity of many languages rise as well. Haskell is beginning to be considered "not just a research language". F# is actually used in some production products, Scala appears to be where all of the modern JVM programmers are at. Javascript is now seeing a huge amount of utilization, which naturally requires functional programming to be "proper".

So, what's next? This is only a guess, but I this is what I think the big paradigm of the next decade will be

Next?: Metaprogramming

I'm of course no stranger to this. I use T4 in a lot of my projects. It's a way to take tedious code and turn it into something that just-works, and wouldn't be possible by other means. Another example of this is all of the dependency injection things out there now. That's really just a step away from metaprogramming. Writing programs which write themselves. And of course, reflection with .Net (and Java?) is common place already. However, there aren't many mainstream languages at this point which make metaprogramming particularly easy. However, we're already seeing a rise in this with mainstream languages like Ruby and Python. Where I think metaprogramming really shines though is in statically-typed languages... where there isn't a lot of easy to use support other than some fairly basic APIs. T4 of course is an exception(and my favorite one), but even T4 has definitely not made it to mainstream usage.

So, why isn't metaprogramming already all the rage? I think the big reason is compiler complexity. It can be an enormously difficult thing to implement an interpreter within a compiler. Other than this though, I truly think it's just a matter of time. This is why I do not have a good reason for why it isn't already the rage. All of the problems it use to have such as code bloat and memory issues really don't matter a whole lot now.

Posted: 11/4/2012 6:49:53 AM

Few more projects?

Well, I'm negotiating for partial ownership of the scripting engine I wrote for a past employer a year ago. This is pretty exciting, as that scripting engine was actually fairly well made. I'm going to try to fix it up and sell it over at http://binpress.com This also means I can license it to myself. I've had a really neat idea for a web service where I need such a scripting language. The problem is that one that has little to no startup time, and not insanely overpriced, and is 100% managed code doesn't exist... Well, the scripting engine I'll have a part of does fit this description. And the language implemented isn't too bad, either.

Posted: 5/1/2011 2:58:15 PM

An Example UserStore

This is the real-life example of an implementation of FSCAuth. This is the MongoDB UserStore used by this blog.

Basically, a fully functional UserStore can be created in about 50 lines. This particular example uses MongoDB. It also overrides UserData to add the MongoDB BsonId attribute. This isn't really required, but it makes things a lot easier.

And here is the code:

public class MongoUserData : UserData{
    [BsonId]
    public ObjectId ID{get;set;}
}

public class MongoUserStore : IUserStore
{
    public MongoUserStore ()
    {
    }
    public UserData GetUser (string username)
    {
        var db=Config.GetDB();
        var u=db.GetCollection<MongoUserData>("users").FindOneAs<MongoUserData>(Query.EQ("Username",username));
        return u;
    }

    public bool UpdateUser (UserData user)
    {
        var userdata=(MongoUserData)user;
        var db=Config.GetDB();
        var u=db.GetCollection<MongoUserData>("users");
        if(u.Save<MongoUserData>(userdata)==null){
            return false;
        }else{
            return true;
        }
    }

    public bool AddUser (UserData user)
    {
        var userdata=(MongoUserData)user;
        var db=Config.GetDB();
        var u=db.GetCollection<MongoUserData>("users");
        if(u.Find(Query.EQ("Username",userdata.Username)).Count()!=0){
            return false;
        }
        u.Insert<MongoUserData>(userdata);
        userdata.UniqueID=userdata.ID.ToString();
        u.Save<MongoUserData>(userdata);
        return true;
    }
    public bool DeleteUser(UserData user){
        var userdata=(MongoUserData)user;
        var db=Config.GetDB();
        var u=db.GetCollection<MongoUserData>("users");
        return u.Remove(Query.EQ("ID",userdata.ID)).Ok;
    }
}

This code is BSD licensed:

Copyright (c) 2010 - 2011 Jordan "Earlz/hckr83" Earls http://lastyearswishes.com All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Posted: 4/23/2011 4:34:08 AM

Fast, Secure, and Concise Authentication -- Call for beta testers

Well, I'm announcing it finally. I've broken out the Authentication module from EFramework and I'm going commercial with it(after fixing quite a few things and extending it). If you still have a copy of the BSD licensed code, I ask you kindly to buy a commercial license. But of course, I can't force you to. I can't retroactively remove the BSD license afterall.

Anyway, I need beta testers! What is FSCAuth? Well, it's a very handy authentication module for ASP.Net. It works on Mono/.Net/Webforms/MVC/You name it. And it's easy, even after the initial "hey a user can login" phase. It's designed to be customized and works well no matter what your database is. Like GUIDs as a unique ID? Go ahead, use em'! Prefer integers instead? You can use those too!

A quick summary:

  • My nemesis is Forms Authentication. Why? Well, because I don't like writing 200 lines of code just so I can use something other than the crappy SQL Server Compact database. Or heaven forbid you want your database to be halfway clean without 50 stored procedures(which do nothing) littered in it.
  • My target audience is small and medium size web applications.
  • I find it a breeze to work with. This blog uses it(in a hidden form)

If you are interested in beta testing, please send me an email at earlz at this domain name(lastyearswishes.com). Beta testers that give me feedback will get a non-expiring single-site license when the project is released. The few that give me outstanding feedback will receive a non-expiring multi-site license. In your email please include "fscauth beta testing", a little about yourself, and how you will beta test it(for instance, are you going to put it in your own blog? etc)

Demo Application

Also, if you'd like to see a small demo application you can look at fscauth-demo. It uses an in memory list of users and is limited to 100 users. But you can see the hashes for everyone's account and try hacking stuff.

Below is some more information about it. NOTE: Some of this is not yet implemented(MongoDB and SQL Server UserStores particularly). This is a projection! Some of these features may change or be removed completely.

What is this?

This is a very easy to use authentication module for use in ASP.Net. It's been designed from the beginning to be flexible, but requiring as little setup as possible. It can be used for any database/data store imaginable. I provide as an example 3 different datastores implementations

  1. SQL Server
  2. MongoDB
  3. Generic in-memory list

Why use it?

Well, I created this because I thought ASP.Net Forms Authentication required too much work for simple systems. I wanted something easier, but also more secure out of the box.

Easier?

For setup you only have to populate 2 fields, and call an Authenticate method from Global.asax. After that, you're ready to show off awesome code like this:

//Some secret stuff you don't want to show to people
Authenticate.RequiresInGroup("secret");

or even

if(Authenticate.LoggedIn){
  //show something only logged in people see
}

Security?

Right from the beginning Fast, Secure, and Concise Authentication was designed to be fool proof for security. It was designed to be secure enough that even if a dump of the database behind it got leaked, your user's credentials would be safe, and hackers would still not be capable of logging in. By default, all passwords are SHA256 hashed and salted. All login cookies are impossible(or almost) to forge.

Don't take my word for it though; check out the source code. With every license but Personal No Commercial, full source code is included. The source code is not overly complex and at the core is only a few hundred lines including comments. If you look at it and think I did a horrible job, then return it. Binpress offers a 14 day money back guarantee.

Speed?

Of course, authentication is a core part of a website, so it needs to be fairly fast. Speed was actually the lowest priority of the project, but actually, it's still very fast. The only operation requiring more than one database access is adding a user, and that is only for ease of implementation. On each authentication, there is a total of two hashes computed. With SHA256 this equates to microseconds. This will not be the component that slows your website down.

Also, there is no need for a persistence of session state. So no extra memory used on your servers, nor messy tables in your database. This is what I like to call a "stateless" authentication system.

What's Capable?

Notably, this project does not try to implement everything that is in Forms Authentication. If you require Windows Authentication, or complex Member/Role/Task/Group support, then maybe you should stick with Forms. This is designed rather for the 90% of websites out there that just need a simple user login system with maybe a few groups, and don't want to mess around with writing 200 lines of code to do it.

What's included?

  1. The main authentication module(source code and assembly)
  2. SQL Server example UserStore implementation
  3. MongoDB example UserStore implementation
  4. Generic in-memory list UserStore implementation
  5. ASP.Net Login custom control
  6. ASP.Net UserStatus custom control
  7. ASP.Net Logout custom control
  8. ASP.Net example web application
  9. Offline copy of documentation

Batteries are not included

What Platforms

  • Mono 2.0 and greater
  • .Net 2.0 and greater (below 3.5 must degrade to the slower Managed SHA256 implementation)
  • Designed to run from any database
  • Runs within Medium Trust
  • Works equally well for both Webforms and ASP.Net MVC
  • Runs without modifications in a web cluster
Posted: 4/10/2011 4:55:04 AM

Marketing Stuff

So I've decided to take on of my opensource projects, EFramework, and try to market a portion of it. I need to implement quite a few more things to make it more "out of the box" ready to go friendly for common platforms(ie, WebForms), but other than that, most of the work is already done. Wish me luck that I sell a million copies :D

Posted: 4/6/2011 11:17:22 PM

ASP.Net. Url Rewriting. Postbacks. FUUUUUU

Well, I'm trying to get EFramework to work together with webforms. As you can tell, it's not working so great. Everyone just says "oh just use Context.Rewrite". Well, I'm sorry to tell everyone, but that doesn't do shit.

Basically, I've managed to get it so that everything is good on the client side. Friendly URLs are used in form tags and friendly URLs are used by GET requests. But the problem is postbacks. Basically, I add a button to the page, I attach a click handler, and then I click said button... and nothing happens. The page will POST as normal, the Form field is even filled in Request.. but for some reason, ASP.Net refuses to set the IsPostback property and call my button's click method.

Why? Well, I have no idea. Everyone says it should be working, but it isn't.

Posted: 3/25/2011 3:05:23 AM

All hail Microsoft

So I finally decided I should have a development environment setup in Windows to test against Microsoft's implementation of .Net. So pretty soon, I'll finally have Visual Studio 2008 Express running in Windows XP with Microsoft SQL Server Express installed. This is just for testing though really, my main priority(in hobby projects) is that it works on my own system

Posted: 3/22/2011 12:27:29 AM