Filter IQueryable by String for ASP.NET MVC

In ASP.NET web applications, mostly seen in MVC, it is really nice to have a standard way to filter a query based on a pre-defined set of combinators. It is often annoying to have to test for different Request parameters in a controller action for MVC or on a page for WebForms. In this post I will describe what I’m calling StringToIQueryable, an open source parser library I built in a few days that I’m using on a few projects. Basically you feed a string to the parser and it manipulates an IQueryable according to a set of pre-defined combinators. The syntax is URL-friendly… that was the goal. Hopefully I will show you in this post how useful this tool can be for both consumption and extension.

I figure I might as well tell you where the source is first. I decided to use GitHub for this project… so it is hosted on GitHub here. Download it and have at it!

 

MONADS MONADS MONADS!

If Steve Ballmer were a functional programmer, he’d FOR SURE be screaming MONADS MONADS MONADS! I’ve discussed monads in the past (with a little less understanding than I have now :) ). Basically a parser (like what I’ve implemented) is like the IEnumerable monad in C#. There is a whole list of combinators you can use to define exactly what a parser does to arrive at a result. Intermediate results are stored as pairs of the parsed value and the string left to parse. I have defined a few simple combinators (I will talk about Or, When, and OrWhen specifically) that are useful. I’ve also defined some of the standard LINQ query operators… so you can easily use a parser as a LINQ query. As Erik Meijer says, “everything is a query!”.

 

Parser Internals

The parser has really 2 important internals, a delegate and a storage container for the result and “rest” string. Here’s the code for each.

// generic delegate for getting result/rest
public delegate ParserResult<T> Parse<T>(string input);

// class for holding the result and rest
public sealed class ParserResult<T>
{
    public ParserResult(T parsed, string remaining)
    {
        Parsed = parsed;
        Remaining = remaining;
    }

    public T Parsed { get; private set; }
    public string Remaining { get; private set; }
}

 

You’ll notice I’m using a generic… so you can pretty much parse anything here. The Parse delegate takes an input and returns a parser result. The parser’s job is to make sure everything is parsed correctly. This is in the ParserLib project of my source code.

 

The Combinators

Combinators in functional programming are kind of an awesome thing. The main operators are bind and return. Bind is implemented with Select, SelectMany and Then. These are really the important operators, but Or, When, and OrWhen are what I find particularly useful when dealing with constraints and possibilities in my URL to IQueryable configuration.

Or is a combinator that takes 2 Parse delegates. If the first should return null (indication of failure) then the result of the Parse will be the result of the second delegate.

When is a unary parser (takes only 1 parser) and takes a string predicate. If the predicate is satisfied by the input, then the result will be delegated to the Parse instance. Otherwise the parser fails and null is returned. This is especially useful in my implementation of String to IQueryable because I associate a beginning keyword to a parser.

OrWhen is a hybrid of Or and When that I built to mainly chain my parsers together. OrWhen takes a string predicate (like When) and 2 parsers (like Or). If the result isn’t null for the first parser, then that is the result. Otherwise the string is tested against the predicate and fails if the predicate fails or returns the result of the parse if the string predicate passes.

If you download the code, you will see these defined in the ParserLib project. I’m not going to show you the implementation for the sake of brevity. But I would recommend having a look.

 

The Query Parser

Ah now to the good stuff. QuerParser is it’s own separate project in my solution. I have defined what I call “ParserExpressions”, which mostly conform to the LINQ standard query operators. The expressions are take, skip, where, sort, and page (which isn’t a standard query operator). I will discuss why some of the other operators were not implemented in a minute. But you do have the option of extending the parser by creating your own operators. Here is the interface that all the expressions use.

 

public interface IParserExpression<T>
{
    IQueryable<T> Map(IQueryable<T> queriable);
}

 

That’s it. Just one method (plus a ToString… more on that in a bit). The expression has to be able to transform an IQueryable using the Map method. How this method works is up to the expression. For example, the take expression transforms the IQueryable by calling the Take method and passing an integer (which is passed in the constructor) to generate a new IQueryable. You will see how this is useful in a minute.

It is important to note that the ParserExpression does not parse the string. They simply act as containers for state until the IQueryable is mapped upon. The parse delegate, as I said before, is the logic behind the parser.

Let’s now have a look at the parse code.

public class StringQueryParser<T>
{
    private string expressions;
    public StringQueryParser(string exprs)
    {
        expressions = exprs.ToLower();
    }

    protected Predicate<string> StartsWith(string test)
    {
        return str => str.StartsWith(test);
    }

    protected virtual Parse<IParserExpression<T>> Parsers
    {
        get
        {
            return Parser.When(StartsWith(ParserConstants.ExpressionSeparator.ToString()), IgnoreSeparatorParser)
                     .OrWhen(StartsWith(ParserConstants.PageIndicator), PageParser)
                     .OrWhen(StartsWith(ParserConstants.SkipIndicator), SkipParser)
                     .OrWhen(StartsWith(ParserConstants.TakeIndicator), TakeParser)
                     .OrWhen(StartsWith(ParserConstants.SortIndicator), SortParser)
                     .Or(WhereParser); 
        }
    }

    public IEnumerable<IParserExpression<T>> Parse()
    {
        if (string.IsNullOrEmpty(expressions))
            return new List<IParserExpression<T>>();

        return Parsers.Repeat()
                      .Invoke(expressions)
                      .Parsed
                      .Where(x => x != null);
    }

    public IQueryable<T> Map(IQueryable<T> queriable)
    {
        foreach (var parseExpr in Parse())
            queriable = parseExpr.Map(queriable);

        return queriable;
    }
    
    
    // the parsers have been removed for brevity. once
    // again, download the code for have a look at the
    // entire parser code
    ......
}

 

As you’ll see I’ve removed the parsers. Just go download the code to look at the parser code. Those are generally unimportant for this post. I can go in-depth if there is a demand for it.

I’ve implemented a Parsers property that returns a composite parser that encapsulates the logic to parse the string. If you were to override this class, you’d want to override the Parsers property to append your own parsers or just completely start anew. Each indicator (page, take, sort and skip) will be covered in the next section, but basically we filter an expression down to it’s parts and create the expression from there. You’ll have a better idea of how to form these expressions by the end. Don’t worry :) So really there’s no surprises here (other than repeat… that’s in ParserLib. Kind of intuitive… you parse until the input is empty). When all is said and done, the IQueryable is mapped through all the expressions generated by the string. Here’s how accomplish a parse in an ASP.NET MVC controller.

 

public class MyController : Controller
{
    ....
    // option #1, instantiate a StringQueryParser
    public ActionResult List(string query)
    {
        // replace with your data access
        IQueryable<User> usersQueryable = Session.Linq<User>();
        // do the parsing
        var parser = new StringQueryParser<User>(query);
        usersQueryable = parser.Map(usersQueryable);
        
        // manipulate and parse as needed
        return Json(usersQueryable.ToList());
    }

    // option #2, use the extension method
    public ActionResult List2(string query)
    {
        // replace with your data access
        var usersQueryable = Session.Linq<User>().Parse(query);        
        
        // manipulate and parse as needed
        return Json(usersQueryable.ToList());
    }
    ......
}

 

I personally prefer option 2. That’s a little neater, but both do the same thing. You will want to setup a “catch all” route in MVC that maps to this.

 

How to form expressions

At this point, I’ve been blabbering about the internals of the parser. Some of you probably don’t care… which is actually fine with me. The important part of this whole project is the real world application. Basically you will be passing a well-formed expression to your controllers that will manipulate the IQueryable accordingly. Here’s the low down on how to do this by string.

Singular Expressions

/skip-5/

skips the first 5 elements

/take-4/

returns only 4 elements

/take-all/

returns all elements

/page-5-11/

returns a paged result on page 5 (1-based) with page size 11

/page-5/

returns a paged result on page 5, default page size is 10 in my library

/sort-name/

applies an ascending sort on the name property

/sort-desc-name/

applies a descending sort on the name property

/sort-name,age,birthmonth/

applies an ascending sort on name property, then ascending sort on age property, then on birthmonth property

/sort-desc-name,age,birthmonth/

applies a descending sort on the name property, then ascending sort on age property, then on birthmonth property

/name-equals-jon/

applies a where name equals jon

/age-greaterthan-4/

applies a greater than 4 where

/name-not-null/

applies a name must not be null constraint

 

For the where expression, there are a lot of combinators that we support (equals, like, not, greater than, less than, greater than or equal, and less than or equal). We also support null as a “keyword”. So don’t expect your name properties to be null or something… that would be interpreted as null by the parser and not “null” as in the string.

 

Multiple Expressions

It is particularly useful to chain these expressions together. Here’s some examples. Feel free to combine these however you’d like.

/page-5/name-equals-jim/age-lessthan-90/age-greaterthanequal-4/

/skip-4/take-3/name-equals-kim/haschainsaw-equals-true/

/gender-equals-female/page-5-10/

The order is typically of no importance except for using skip and take together. It is a good idea to use a skip before a take. That’s just been my experience. You’ll notice in these examples (which are fictitious, by the way :)) that we support a lot of different types. Strings, int, double, float, enum, and more. In the future I’ll add an interceptor that you can parse where’s differently.

 

How properties work

When designing this solution, I had this idea that you might want to name a property differently or ignore a property. I have added two attributes (ParserIgnore and ParserPropertyName). The parser takes these into effect. If you pass the parser an ignored property then the constraint isn’t parsed. You can define a parser property name to a property and that name will be used in determining which property to apply a constraint. This avoids the issue of property name conflicts… you have to resolve those yourself using the property name attribute for the expected behavior to work when you have the same property name in different case.

Also, it’s worth mentioning that everything is parsed in lower-case. So the case in your expressions are of no importance… it’ll just be changed to lower-case upon parsing.

 

Using the generator

Sometimes you don’t want to form these by hand… concatenation isn’t exactly useful when you’re using paged data, for example. Because of this, I’ve built a generator. Basically you’d pass a few IParserExpression’s to this generator and it’ll generate the string for the query for you. The generator uses the ToString method on each IParserExpression. It is important to note that you must override ToString for the generator to work on your custom expressions. You can take a look at the code yourself, but I thought I might show you an example of how to use this.

 

....
<h2>My MVC Page</h2>
....
<a href="#<% new StringQueryGenerator<User>(new IParserExpression<User>[] 
                                            { 
                                                 new WhereExpression<User>(u => u.Name, WhereCombinator.equals, "foo"),
                                                 new PageExpression<User>(4, 10)
                                            }).Generate() %>
......

 

This will generate a string like /name-equals-foo/page-4/ . Both where and sort have a constructor overload that you can pass in a property expression… so you don’t have to use the property name as a string.

 

 

Conclusion

Wow that was a long blog post :) I hope that you’ve seen that this is useful for ASP.NET MVC in particular and in an instance where a user can define their own query. There are many examples of this sort of thing on the web where people are using this approach to filter results based on a clean-looking query. I hope you check out the source code and let me know if you have any suggestions or comments on my implementation. And with that I say DEATH TO QUERY STRING FILTERING!


kick it on DotNetKicks.com

jQuery DataTables Plugin Meets C#

Over the weekend, I was doing some work on the internal CMS we use over at eagleenvision.net and I wanted to scrap my custom table implementation for a table system that would use JSON to return data rather than have the data be statically allocated on the page. Basically I wanted to have the ability to refresh, etc for editing purposes. My little table marker was too much code for something so simple.

I’m a HUGE fan of jQuery, especially of the recent changes in jQuery 1.4. We have already made a significant investment in jQuery code for our CMS and I didn’t want to simply add another library or framework into the mix… by that I mean I didn’t want to throw in the Ext framework, which specialized in UI controls rather than general purpose JavaScript.

I stumbled upon the jQuery DataTables plugin. It has a lot of great features… one of which is the ability to have server-side processing of your data. The examples on the site are written with PHP, as are the downloadable demos. I don’t use PHP, I use ASP.NET :). So I had to write my own library to process the incoming request. DataTables has a set of pre-defined request variables that are passed to the server for processing. A successful implementation will take all these variables into account and send the correct data back per these variables. (To see a complete list, check out the server-side usage page).

 

Our friend, IQueriable

If you’re a C# developer, there’s no way you don’t already know about LINQ… (double negatives… oops…. every C# knows about LINQ, or they’re not really current with technology… that’s better :) ). This includes VB people as well. IQueriable is the fundamental type of LINQ that drives the functionality of the various sequence operators. In my implementation of DataTables processing, I wanted to leverage LINQ so that you could throw this thing an IQueriable from Linq2Sql, Linq to NHibernate, Entity Framework, LightSpeed, in-memory list, or ANYTHING that has IQueriable functionality and it would just work.

 

How to output

The DataTables plugin accepts either JSON or XML… whichever jQuery will parse. My opinion is never use XML with JavaScript. It’s slower and there’s no point to using XML over JSON… especially in .NET where there are built-in JSON serializers. Having said that, you could certainly use XML… although I haven’t tested my code for this, I think (in theory) it will work the same. He’s the output type, which should be serialized into JSON or XML, which I will cover in a minute.

public class FormatedList
{
    public FormatedList()
    {
    }
    public int sEcho { get; set; }
    public int iTotalRecords { get; set; }
    public int iTotalDisplayRecords { get; set; }
    public List<List<string>> aaData { get; set; }
    public string sColumns { get; set; }
    public void Import(string[] properties)
    {
        sColumns = string.Empty;
        for (int i = 0; i < properties.Length; i++)
        {
            sColumns += properties[i];
            if (i < properties.Length - 1)
                sColumns += ",";
        }
    }
}

Basically the only interesting thing here is the output of the columns. I made a custom Import method that just takes a list of properties and forms the column string that DataTables will parse. Other than that the code here is just basic property holding.

 

ASP.NET MVC

Readers of my blog and twitter will know I am also a HUGE fan of ASP.NET MVC. I don’t think I’ll ever return to ASP.NET WebForms. But who knows. Anyways, here’s how you will output the thing in MVC

public ActionResult List()
{
    IQueriable<User> users = Session.Linq<User>();
    if (Request["sEcho"] != null)
    {
        var parser = new DataTableParser<User>(Request, users);
        return Json(parser.Parse());
    }
    return Json(users);
}

You’ll notice that I referenced DataTableParser, which I will get to in a minute. This takes an HttpRequestBase (or an HttpRequest) and an IQueriable of whatever type. It will output a new FormattedList in the parse method, which you will return via JSON (which is serialized in the Json method for MVC).

 

ASP.NET Webservices

While I don’t claim to be an expert at ASP.NET Webservice, this I can handle :). He’s how would would do the same thing in ASP.NET Webservices.

using System.Web.Script.Serialization;
using System.Linq;
...
public class MyWebservice : System.Web.Services.WebService
{
    public string MyMethod()
    {
        // change the following line per your data configuration
        IQueriable<User> users = Session.Linq<User>();
        
        response.ContentType = "application/json";
        
        if(Request["sEcho"] != null)
        {
            var parser = new DataTableParser<User>(Request, users);
            return new JavaScriptSerializer().Serialize(parser.Parse());
        }
        
        return new JavaScriptSerializer().Serialize(users); 
    }
}

 

This is the same code… it just uses webservices and the JavaScriptSerializer (which MVC uses under the covers) to serialize the FormatedList object.

 

It should be noted that you should ALWAYS check if the request is a DataTables request (which is what that sEcho business is all about).

 

The Parser

Now is the time to show you my parser. I have taken out my code comments to keep this short on my blog… but you can download my code from here and the comments should explain what is going on.

 

public class DataTableParser<T>
{
    private const string INDIVIDUAL_SEARCH_KEY_PREFIX = "sSearch_";
    private const string INDIVIDUAL_SORT_KEY_PREFIX = "iSortCol_";
    private const string INDIVIDUAL_SORT_DIRECTION_KEY_PREFIX = "sSortDir_";
    private const string DISPLAY_START = "iDisplayStart";
    private const string DISPLAY_LENGTH = "iDisplayLength";
    private const string ECHO = "sEcho";
    private const string ASCENDING_SORT = "asc";
    private IQueryable<T> _queriable;
    private readonly HttpRequestBase _httpRequest;
    private readonly Type _type;
    private readonly PropertyInfo[] _properties;
    public DataTableParser(HttpRequestBase httpRequest, IQueryable<T> queriable)
    {
        _queriable = queriable;
        _httpRequest = httpRequest;
        _type = typeof(T);
        _properties = _type.GetProperties();
    }
    public DataTableParser(HttpRequest httpRequest, IQueryable<T> queriable)
        : this(new HttpRequestWrapper(httpRequest), queriable)
    { }
    
    public FormatedList Parse()
    {
        var list = new FormatedList();
        list.Import(_properties.Select(x => x.Name).ToArray());
        
        list.sEcho = int.Parse(_httpRequest[ECHO]);
        
        list.iTotalRecords = _queriable.Count();
        
        ApplySort();
        
        int skip = 0, take = 10;
        int.TryParse(_httpRequest[DISPLAY_START], out skip);
        int.TryParse(_httpRequest[DISPLAY_LENGTH], out take);
        
        list.aaData = _queriable.Where(ApplyGenericSearch)
                                .Where(IndividualPropertySearch)
                                .Skip(skip)
                                .Take(take)
                                .Select(SelectProperties)
                                .ToList();
                                
        list.iTotalDisplayRecords = list.aaData.Count;
        return list;
    }
    private void ApplySort()
    {
        foreach (string key in _httpRequest.Params.AllKeys.Where(x => x.StartsWith(INDIVIDUAL_SORT_KEY_PREFIX)))
        {
            int sortcolumn = int.Parse(_httpRequest[key]);
            if (sortcolumn < 0 || sortcolumn >= _properties.Length)
                break;
                
            string sortdir = _httpRequest[INDIVIDUAL_SORT_DIRECTION_KEY_PREFIX + key.Replace(INDIVIDUAL_SORT_KEY_PREFIX, string.Empty)];
            
            var paramExpr = Expression.Parameter(typeof(T), "val");
            var propertyExpr = Expression.Lambda<Func<T, object>>(Expression.Property(paramExpr, _properties[sortcolumn]), paramExpr);
            
            if (string.IsNullOrEmpty(sortdir) || sortdir.Equals(ASCENDING_SORT, StringComparison.OrdinalIgnoreCase))
                _queriable = _queriable.OrderBy(propertyExpr);
            else
                _queriable = _queriable.OrderByDescending(propertyExpr);
        }
    }
    
    private Expression<Func<T, List<string>>> SelectProperties
    {
        get
        {
            // 
            return value => _properties.Select
                                        (
                                            prop => (prop.GetValue(value, new object[0]) ?? string.Empty).ToString()
                                        )
                                       .ToList();
        }
    }
    
    private Expression<Func<T, bool>> IndividualPropertySearch
    {
        get
        {
            var paramExpr = Expression.Parameter(typeof(T), "val");
            Expression whereExpr = Expression.Constant(true); // default is val => True
            foreach (string key in _httpRequest.Params.AllKeys.Where(x => x.StartsWith(INDIVIDUAL_SEARCH_KEY_PREFIX)))
            {
                int property = -1;
                if (!int.TryParse(_httpRequest[key].Replace(INDIVIDUAL_SEARCH_KEY_PREFIX, string.Empty), out property) 
                    || property >= _properties.Length || string.IsNullOrEmpty(_httpRequest[key]))
                    break; // ignore if the option is invalid
                string query = _httpRequest[key].ToLower();
                
                var toStringCall = Expression.Call(
                                    Expression.Call(
                                        Expression.Property(paramExpr, _properties[property]), "ToString", new Type[0]),
                                    typeof(string).GetMethod("ToLower", new Type[0]));
                
                whereExpr = Expression.And(whereExpr, 
                                           Expression.Call(toStringCall, 
                                                           typeof(string).GetMethod("Contains"), 
                                                           Expression.Constant(query)));
                
            }
            return Expression.Lambda<Func<T, bool>>(whereExpr, paramExpr);
        }
    }
    
    private Expression<Func<T, bool>> ApplyGenericSearch
    {
        get
        {
            string search = _httpRequest["sSearch"];
            
            if (string.IsNullOrEmpty(search) || _properties.Length == 0)
                return x => true;
                
            var searchExpression = Expression.Constant(search.ToLower());
            var paramExpression = Expression.Parameter(typeof(T), "val");
            
            var propertyQuery = (from property in _properties
                                let tostringcall = Expression.Call(
                                                    Expression.Call(
                                                        Expression.Property(paramExpression, property), "ToString", new Type[0]),
                                                        typeof(string).GetMethod("ToLower", new Type[0]))
                                select Expression.Call(tostringcall, typeof(string).GetMethod("Contains"), searchExpression)).ToArray();
                                
            Expression compoundExpression = propertyQuery[0];
            
            for (int i = 1; i < propertyQuery.Length; i++)
                compoundExpression = Expression.Or(compoundExpression, propertyQuery[i]);
                
            return Expression.Lambda<Func<T, bool>>(compoundExpression, paramExpression);
        }
    }
}

 

Caveat

Currently there’s a bug here, that I need to research :). If you have a boolean property and apply a sort on it, you’ll get an exception because I am trying to cast it as an object with the Expression.Lambda<Func<T, object>> call. I’ll look into this and update this blog post accordingly. If you can provide any help, that would be great :)

 

Conclusion

This is just a simple example of parsing a request and mutating IQueriable acordingly. I hope this helps someone out there who would like to use C# with the DataTables plugin. Again, you can download my code from here with full comments.

Posted by zowens | 3 comment(s)

ClubStarterKit – Caching for performance

First of all, if you haven’t heard, I recently released ClubStarterKit v3 Preview. If you haven’t had a chance to look at it, I highly encourage you to take a look at the whole new codebase.

My whole goal when building any application whether it’s an application for a client or the open source ClubStarterKit project is to make the app as fast as possible. There are quite a few layers to the caching mechanisms in CSK that I think could be applied to many other projects. In fact, some of the caching ideas came from an internal web framework we use at eagleenvision.net.

There are two “caches” that CSK uses. One is the HTTP Cache that IIS and other web servers use in the background. The other is the client’s web cache. I will give a brief overview of each in this post.

 

Web Cache

The web cache is the simplest to understand of the two types of caches. When a request comes down from the web application, a response key is set on the server side that informs the browser to not look up the same file until a certain date. The trick we can do is to set the date as far as possible so the cache NEVER expires. (In CSK I think the cache is something like 5 years…). But what happens when you change your website? That’s where the application ID comes into play.

At every application startup, an identifier is pushed in storage (we use HTTP Application) of a string-based token. In CSK the token is the DateTime of the insertion into the cache so that there are no other collisions. This token is appended onto every CSS file request, image request, and Javascript file request so that the client doesn’t have to wait every time a page is loaded for the same CSS, image and Javascript files to load into the browser when running a particular “application instance”. If, for some reason, the application ID is not passed to the request, then the response isn’t cached.

When a part of your application changes, you have the ability to reset the application ID yourself. In CSK you just navigate to /sitecontent/reset and the application ID should be reset.

The obvious advantage to this strategy is the reduction in unnecessary bandwidth. And users don’t have to wait for something to download that they already have on their computer. So there are some real benefits to using client-side caching of static files.

 

HTTP Cache

Just like the web cache, the HTTP cache reduces unnecessary bandwidth. The center of the HTTP cache, however, is around the database. It can sometimes be costly to hit a database for the same query. To counteract this we use HTTP caches. These things store data onto the application server and store them for a certain amount of time until it has expired or is expired. A value can be expired by the application server, when the specified TimeSpan is reached or when the item is removed from the cache by the web application. In the CSK, an item is expired from the cache when something is added, such as a new article or a forum post. Once the item is pulled from the cache, the next request forces the cache to go to the database for the query result and store it in the cache.

In the CSK we are also refreshing caches for every application id. This just ensures that there isn’t a leak in the caching mechanism and the data can be easily refreshed by a website owner.

The rationale for this feature is that hitting the database is a lot more costly when you’re dealing with load. Memory cache is really cheap comparatively. So it just makes sense to “hold” the query results until they are expired by either the application’s usage or the refresh of the application ID. In the worst case, ASP.NET removes the item from the cache because of lack of storage. In that case the query is regenerated anyways.

In the CSK there are a few abstractions that I will detail in later posts that are particularly useful when dealing with data. These are the CollectionDataCache, used for storing a collection from the DB, PagedDataCache, used for storing a paged list from the DB, and the SingleItemDataCache, used for storing single items from the DB. All these abstractions are sortable, constrainable, and easy to use. They all use the HTTP cache as the backing store. The abstractions also take care of the data access using the UnitOfWork and Repository patterns we employ in CSK.

There is also an HttpSession cache, which is particularly useful when storing user data. It operates off the same cache interface as the HttpCacheBase.

 

The Changes Ahead

Like I said, I took a lot of code from the internal framework I built a few years ago. The code I put into the CSK was really useful in that framework. But in the application of CSK, there is a sense of “code smell”. I would really like to do a few things differently, namely abstracting caches even further for CollectionDataCache, PagedDataCache and SingleItemDataCache. So maybe you might want to store a paged list into the session state. Currently you can’t do that without writing your own cache, which isn’t bad… it’s just not particularly fun to do. I would like to add, what I am calling, “cache strategies” to the infrastructure. So expect changes down the line for further abstraction.

 

So you’ve seen that caches are particularly useful when dealing with data, whether it’s file data or database data. As always, questions, comments, and other feedback are GREATLY appreciated. Just send me an email, comment on this blog, or post on the ClubStarterKit forums.

ClubStartKit is Reborn… With a new release

The title says it all. That’s right, I’m back on ClubStarterKit. I’ve tried to assure the CSK community in past blog posts that it isn’t dead. In the last year, I’ve done a lot of thinking and outside programming. I’m FINALLY in a position where I have really progressed in terms of project management skill and web design. Many of the opinions I held when I started the project have simply changed. I’ll detail some of those in a minute.

Here’s a link to the new release.

Open source software is really tricky, especially for someone who has to go to school and keep up with the day job. It’s simply TOO MUCH for someone else to demand so much on a person. However, demanding open source work onto yourself is highly rewarding. That’s why I’m back.

Why the time off?

Well, I simply had to build my business. Ultimately, that takes a lot more priority over any other open source work. As harsh as that is, I simply had too much going on. Also, I was in a bit of a rut with CSK.

The project started from a need by the community to extend the club starter kit originally started by Microsoft that shipped in the box as a starter kit with Visual Studio 2005. I found plenty of ways to extend the kit for myself and decided to share my extended version. It was a tool for beginners. My role was to share my knowledge of ASP.NET with everyone else.

But there was a point where I was just copy and pasting and hacking the crap out of something that wasn’t mine and was written by a bunch of other people. I ripped a lot of things out, especially the data access. What I put in it’s place was a disaster as well, though. I simply didn’t have the forethought to imagine a site that was fully extensible. I simply put out something that was hacked and hacked and hacked. I didn’t put something out that EVERYONE could use, I put something out that EVERYONE had to figure out every little piece and extend. That’s simply irresponsible on my part.

So I decided I needed to completely rewrite the thing. There was a point were I was sick and tired of writing VB. To me, it looks WAY too verbose. I couldn’t stand looking at it… and C# was my primary language at a point anyways, and still is.

The big news

Now I’m ready to come back. I finally have something that I put my stamp on. It’s MINE. I wrote it. There’s not a feeling in this world more satisfying for me than to say a piece of code is completely my creation. No hacks, no copy paste (ok, there’s a little… but at least I know what it does!) and certainly something I think everyone can use, whether it’s bits and pieces or the whole thing.

What’s new!

Well… for starters, it’s written entirely in C#! While I know some VB people are shivering in their boots, I plan on upgrading the web project to VB if there is an apparent need from the community. I’m not here to waste my time converting something to VB if there’s not a need. C# is such an expressive language and it’s something every VB dev should at least TRY to look at. More on that down the line.

Another big new thing is that it runs ASP.NET MVC, not classic web forms. I know that there is some serious turmoil out there over this subject, but it really is a much better way to create web applications in ASP.NET in my opinion. There’s not very much of a difference, as it turns out. It’s a very comfortable shift… more than I thought it would be. It makes applications much easier to understand, write, and test.  I can entertain comments, questions, and concerns by email over this. I’m willing to fight for this :) But really, MVC rocks. It’s simply amazing.

I know it hasn’t been released yet, but this release will be targeting Visual Studio 2010 and the .NET Framework 4.0. There’s a lot of really cool new ASP.NET features that I think CSK would really benefit from.

Now to the big thing that might just turn some people off… we’re primarily going to use NHibernate for data access. I plan on adding a few more providers (Subsonic would be the first to the list). I really started off with NHibernate as a learning experience. It’s a very complex, but WELL written data access solution. I’ve VERY pleased with the results. There’s a learning curve with NHibernate, to an extent. But NHibernate isn’t as hard for simple operations, like what CSK provides. I think I can go back to the fundamental part of CSK and provide some really good samples for people to learn from. NHibernate isn’t really all that hard as long as you have something to look at. Trust me, reading the documentation isn’t as glamorous as it sounds :). Hopefully I can abstract that away from the average CSK user.

A huge reason for adding NHibernate as the primary data access point is because we can use it to generate our DB for us, often called “Domain Driven Design” (although we aren’t completely “DDD”). I can’t tell you how much trouble I’ve had with the SQL stuff in the past. If you start with your data model first, a tool like NHibernate or Subsonic will just generate all the DB code for you! For me, that’s HUGE! I hate having people say the new version broke their DB. That' hurts. Now we can just have the damn thing upgraded!

Speaking of the DB… we will be starting from scratch on that too… sorry to say. I know plenty of people will be really disappointed by this. Just how it is. Hopefully from now on, we will have a better upgrade path. I hate breaking people’s compatibility simply because we release a new version. I’ll be assessing a possible upgrade path for those running v3 beta 1 and v2. But we shall see. This would be a GREAT contribution if someone in the community could code this out.

The fact that we didn’t have a lot of tests in the last few versions proved we really didn’t have a great product. We just didn’t. That simple. I knew that this time, I needed to test EVERYTHING. While I don’t claim to be a TDD expert, I really tried to test first. I’ll detail contributions in a bit, but I can tell you, everything needs to have tests. While we’re a little light on tests right now, hopefully that will change as we get closer to v3.

What’s taken out

There was a serious outcry after v2 for a league management component. What happened in v3 Beta 1 was… interesting. I haven’t really seen anyone use it, and the feedback was mixed. So for this iteration, it’s not going to be a core part of the product. If there is a serious need, I think we (as in the community) should plan and implement an extension to CSK for league management stuff.

League management was a really good idea, but I think the ideas some people had were just out of my scope. It’s something someone needs to write a spec for. I can’t just create what I think will fly. Just not something I’m willing to waste more of my time on.

Also on my list of things taken out, I’ve finally decided to separate the logic of the application into separate projects. While the Visual Studio Express people might be upset, it really comes down to manageability of the project. If you create a large web application, it really defeats the purpose of expansibility. There are 6 main projects: Core, Infrastructure, Web, Data.NHibernate, Domain, and Tests. The core and infrastructure projects are meant to be distributed with ANY web project. It’s not CSK specific. So you can really use those as toolkits. It has some really good logic in it. I’d love to provide something that isn’t just for our little open source project. I will, however, be shipping a template with compiled versions of Domain, infrastructure, core, and Data.NHibernate. Hopefully that will help those who use express. We’ll see. I’d love to hear your feedback on this.


Contributions

In the past, I’ve said everyone can just contribute. That’s going to change. We’re starting with a whole new codebase that I wrote. Because of this, I think it’s time we started accepting patches rather than add contributors. We’ve had only a tiny bit of contribution in the past anyways. So here’s my decision.

I’m going to take every contributor off the list. It’s a tough choice, but it has to be done. I will start to accept patches. These patches HAVE to contain tests. Once you’ve contributed in that way, I will then consider making you a contributor to the source repository.

The release

So I’ve told you wants new, and what not, but I didn’t say anything about a release. Today I am releasing the new codebase. I’m going to name this ClubStarterKit v3 preview. While I would love to call this v4, I think that not having a final v3 would be kind of strange. So this codebase will eventually become version 3. My plans from this point is to get feedback on what I have an release Version 3 when it’s ready. No promises, no false hopes. It’ll be done when I say it’s done. In the mean time, you can download the preview here.

A call to action

I’ve done my thing. I’ve built what I thought you’d want. Now it’s YOUR turn to help me out. Tell me what you like, tell me what you don’t like, tell me what should be in there, tell me what the future of CSK looks like. I need your feedback. It’s the essential ingredient in any open source project. We need to pick up anew and make this a sustainable and polished project that we can call a community-driven project!

 

As always, thank you for your support and contribution. We all can give each other a helping hand in learning to develop software.



kick it on DotNetKicks.com

Fluent NHibernate with System.ComponentModel.DataAnnotations

So I’m building a product with NHibernate and possibly another ORM. The main focus of the app is a ASP.NET MVC 2.0 web application. So I, obviously, want the built in validation client-side in JavaScript and server side. By default, the MVC stuff uses the System.ComponentModel.DataAnnotations attributes to validate properties on your domain.

What I REALLY wanted was to use the Data Annotations with Fluent NHibernate for my DB mapping files. This presents a problem, right? WRONG! Because Fluent NHibernate is so extensible, I can easily create a convention to use the Attributes. Then all I have to do is add the convention to my Fluent NHibernate AutoMapper instance and the properties with the attributes are just taken care of. Isn’t that neat!!

Required is a common notion with domains. Something HAS to be defined for an entity to be considered a reputable entry. Here’s the convention to use the Required attribute in Fluent NHibernate.

 

Code Snippet
using System.ComponentModel.DataAnnotations;
using FluentNHibernate.Conventions;
using FluentNHibernate.Conventions.Instances;

namespace Data.NHibernate.Conventions
{
    public class RequiredConvention : AttributePropertyConvention<RequiredAttribute>
    {
        protected override void Apply(RequiredAttribute attribute, IPropertyInstance instance)
        {
            instance.Not.Nullable();
        }
    }
}

 

 

As you can see… there’s really only 1 line of code!

 

I just showed you one out of the handful of attributes in the DataAnnotations library. To use the other attributes, you just basically follow the same basic outline of the example above. Not bad, eh :)



kick it on DotNetKicks.com

Maybe Monad… my C# version

Functional programming isn’t a new concept. There is Scheme, Haskell and a bunch of other really cool languages. But new on the block is F#. F# is Microsoft’s stab at creating a functional programming in the .NET world as a first-class language.

Functional programming paradigms are increasingly important to all .NET developers. This post will detail the functional elements (in my mind) of the Maybe Monad, something I’m sure everyone has written in some way or another (ok maybe not everyone, but there are certainly a lot of implementations out there in C#). But let’s discuss the application, functionally, of the maybe monad.

 

The Basics

There are three areas of the maybe monad that are really important. The first is the concept of “Nothing” and “Just”. Nothing, in this context, would be either a failed operation (say division by 0, for example) or something that just returns null. The “Just” is the opposite of “Nothing”, it’s something. It’s a successful operation that returns a value. Although this concept seems simple, it’s actually quite powerful. We’ll return to this in a bit.

The second of the important concepts with the maybe monad is the “bind” and “return” verbs. “Bind” is the assigning of a value to a Maybe. “Return” the extraction of the value from the maybe. See the Maybe Monad is a container of a value (or lack thereof). The verbs attached to the container relay a façade of the actual value. While my implementation doesn’t deal with bind/return verbs directly, it is used indirectly with the composition and decomposition of the value container.

The third is something we’re ALL familiar with, a type constraint. The formal declaration of the maybe monad declares that there must be a type parameter of type M. This letter is arbitrary, of course, but the concept is important. Without the constraint, the possible values of the true value bound to the maybe container would be limitless. One more reason where generics in C# are invaluable!

 

Let’s get coding!

Start with Nothing

Let’s start out with some initial xUnit.net tests.

[Fact]
public void Maybe_NothingContructor_SetsNothingFlag()
{
var maybe = new Maybe<int>();
bool isNothing = maybe.Nothing;
Assert.True(isNothing);
}

[Fact]
void Maybe_JustContructor_DoesntSetNothingFlag()
{
var maybe = new Maybe<int>(5);
bool isNothing = maybe.Nothing;
Assert.False(isNothing);
}

[Fact]
public void Maybe_JustContructor_SetsNothingFlag_WhenTheValuePassedIsNull()
{
var maybe = new Maybe<int>();
bool isNothing = maybe.Nothing;
Assert.True(isNothing);
}

As you can see there are 2 constructors. The default is the “nothing” constructor. The constructor with a value is the “nothing” if the value is null and the “just” if there is an actual value. This is an immutable container, so I don’t feel so bad setting these values only in the constructor. Here’s what my “Maybe” looks like now.

/// <summary>
/// Value container for storing
/// a) a value ("Just")
/// b) lack of a value ("Nothing")
/// </summary>
/// <typeparam name="M">Type M of the Maybe Monad</typeparam>
public sealed class Maybe<M>
{

/// <summary>
/// Non-value maybe ("Nothing")
/// </summary>
public Maybe()
{
// assign the nothing flag
Nothing = true;
}

/// <summary>
/// Maybe with a value ("Just")
/// </summary>
/// <param name="value"></param>
public Maybe(M value)
{
// assign the nothing flag
// when not null
Nothing = value == null;
}

/// <summary>
/// Determines the state of the
/// value in the container
/// </summary>
public bool Nothing { get; private set; }
}

 

You might be wondering why I made this class sealed. My rationale for this is that, since Maybe is immutable, we don’t want to get rid of some of the guarantees we have with the default implementation. Having a central “maybe” is a nice, simple way to define the maybe behavior.

Now for the return

The notion of a return for the maybe monad essentially means extracting the value from the container. I could define a “Return” function or even a “Value” property. But this is an unnecessary step. We don’t really need added complexity. My theory is that casting would be the best option. It is, after all, just a façade. Plus casting is a bit more expressive anyways. In your implementation, you can do this if you wish :)

[Fact]
public void Maybe_MCast_ReturnsAValue_WhenThereIsAValue()
{
var maybe = new Maybe<string>("");
string value = maybe;
Assert.NotNull(value);
}

[Fact]
public void Maybe_MCast_ReturnsSameValue_WhenThereIsAValue()
{
var initialValue = "";
var maybe = new Maybe<string>(initialValue);
string value = maybe;
Assert.Same(initialValue, value);
}

[Fact]
public void Maybe_MCast_ReturnsNull_WhenThereIsNotAValue()
{
var maybe = new Maybe<string>();
string value = maybe;
Assert.Null(value);
}

And here is the code that makes the tests pass.

public sealed class Maybe<M>
{
private M _value;

...
// previous code hidden for brevity

public static implicit operator M(Maybe<M> maybe)
{
if (maybe == null)
throw new ArgumentNullException("maybe");

return maybe._value;
}
}

I added the value field and the implicit cast operator.

Another way to bind

The constructor to define the “Just” and “Nothing” is useful, but what if we wanted save a little code when we are returning a maybe from a method? To do that, we’ll define another implicit operator. This time the operator will take an M and return a Maybe<M>. Here’s our test:

[Fact]
public void Maybe_MaybeCast_ReturnsNothingMaybe_WhenTheValueIsNull()
{
string val = null;
Maybe<string> maybe = val;
Assert.True(maybe.Nothing);
}

[Fact]
public void Maybe_MaybeCast_ReturnsJustMaybe_WhenTheValueIsNotNull()
{
string val = "";
Maybe<string> maybe = val;
Assert.False(maybe.Nothing);
}

And here’s the code.

public sealed class Maybe<M>
{
...
// previous code hidden for brevity

public static implicit operator Maybe<M>(M value)
{
return new Maybe<M>(value);
}
}

 

Apply for Chainability

Being able to chain different functions is really a key part of the maybe monad. The verb I will use is “Apply”. In functional languages, this action just happens due to function composition. We have two options here. We can return the Maybe monad as a Func<Maybe<M>, Maybe<M>> or we can define an Apply method to take a Func<Maybe<M>, Maybe<M2>> where M2 is essentially a new value. The Apply method could serve as a converter. If the initial value of M is Nothing, then the converted value should return a Nothing maybe monad. The great thing about the maybe monad is that there is no need to throw exceptions.Although the throwing of exceptions can provide useful information, most simple operations don’t require such complexity. Just test for Nothing on the maybe. Now you don't have to add a try/catch throughout your code.

I am going to use the Apply method. Although returning a Func<Maybe<M>, Maybe<M>> might add expressive syntax, the Apply method will be a little more flexible for most scenarios. Here’s some tests.

[Fact]
public void Maybe_Apply_ReturnsNothingMonad_WhenTheInitialNothingMaybe()
{
Func<Maybe<string>, Maybe<string>> fun= (m) => new Maybe<string>("");
Maybe<string> initialMaybe = new Maybe<string>();
Maybe<string> appliedMaybe = initialMaybe.Apply(fun);
Assert.True(appliedMaybe.Nothing);
}

[Fact]
public void Maybe_Apply_ReturnsNewMaybeWithNewValue()
{
Func<Maybe<string>, Maybe<string>> addBchar = (maybe) =>
new Maybe<string>(((string)maybe) + "b");

string initial = "", final = "b";

Maybe<string> initialMaybe = new Maybe<string>(initial);
string afterApply = initialMaybe.Apply(addBchar);
Assert.Equal(final, afterApply);
}

As you can see, my implementation will automatically return a nothing maybe monad when a nothing maybe monad is the initial value. OK here’s the code.

 /// <summary>
/// Applies the specified function to this object
/// if this maybe is not nothing
/// </summary>
/// <typeparam name="M2">Return Type</typeparam>
/// <param name="applyFunction">Conversion function</param>
/// <returns>A Nothing maybe if the initial maybe is nothing
/// or the value returned by <see cref="applyFunction"/> if
/// this maybe has a value.
/// </returns>
public Maybe<M2> Apply<M2>(Func<Maybe<M>, Maybe<M2>> applyFunction)
{
if (Nothing)
return new Maybe<M2>();
return applyFunction(this);
}

 

Conclusion

The maybe monad is pretty cool for writing structure C# code. Your methods can now return a Maybe<M> to be perfectly clear if your methods returned actual values or null. This also gives you another definition of null. Perhaps your idea of “null” could be returning a 0. We have added flexibility with this new construct.

I’ve just hit the high marks in this post of my implementation of the maybe monad. Here’s an extended version with tests. Enjoy :)

 

DOWNLOAD




kick it on DotNetKicks.com
Posted by zowens | 3 comment(s)

Cache Abstraction

I'm in the middle of a project and I wrote my own Cache logic that melds nicely to my project's needs. But how do I test it? I can't mock the System.Web.Caching.Cache class. So I looked in the Abstractions that ship with ASP.NET MVC. What do you know, they're not there!

So I created my own base class and wrapper. Here's the code. Enjoy.

 

using System;
using System.Collections;
using System.Web.Caching;

namespace WebCommon.Abstractions
{
    public abstract class CacheBase : IEnumerable
    {
        public abstract int Count { get; }
        public abstract long EffectivePercentagePhysicalMemoryLimit { get; }
        public abstract long EffectivePrivateBytesLimit { get; }
        public abstract object this[string key] { get; set; }
        public abstract object Add(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback);
        public abstract object Get(string key);
        public abstract IDictionaryEnumerator GetEnumerator();
        public abstract void Insert(string key, object value);
        public abstract void Insert(string key, object value, CacheDependency dependencies);
        public abstract void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration);
        public abstract void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback);
        public abstract object Remove(string key);

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
}

using System;
using System.Collections;
using System.Web.Caching;

namespace WebCommon.Abstractions
{
    public class CacheWrapper : CacheBase
    {
        private Cache _cache;

        public CacheWrapper(Cache cache)
        {
            _cache = cache;
        }

        public override int Count
        {
            get { return _cache.Count; }
        }

        public override long EffectivePercentagePhysicalMemoryLimit
        {
            get { return _cache.EffectivePercentagePhysicalMemoryLimit; }
        }

        public override long EffectivePrivateBytesLimit
        {
            get { return _cache.EffectivePrivateBytesLimit; }
        }

        public override object this[string key]
        {
            get
            {
                return _cache[key];
            }
            set
            {
                _cache[key] = value;
            }
        }

        public override object Add(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)
        {
            return _cache.Add(key, value, dependencies, absoluteExpiration, slidingExpiration, priority, onRemoveCallback);
        }

        public override object Get(string key)
        {
            return _cache.Get(key);
        }

        public override IDictionaryEnumerator GetEnumerator()
        {
            return _cache.GetEnumerator();
        }

        public override void Insert(string key, object value)
        {
            _cache.Insert(key, value);
        }

        public override void Insert(string key, object value, CacheDependency dependencies)
        {
            _cache.Insert(key, value, dependencies);
        }

        public override void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration)
        {
            _cache.Insert(key, value, dependencies, absoluteExpiration, slidingExpiration);
        }

        public override void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)
        {
            _cache.Insert(key, value, dependencies, absoluteExpiration, slidingExpiration, priority, onRemoveCallback);
        }

        public override object Remove(string key)
        {
            return _cache.Remove(key);
        }
    }
}
Posted by zowens | 1 comment(s)

ClubStarterKit - where do we go?

Wow, what a year. Not exactly what I'd expected. Before I dive into where we are now, let me preface this post by saying I have NOT forgotten ClubStarterKit! Although I was not the original author, I feel like it's my baby. I can't just forget about it. Not going to happen.

 

You might be quick to point out that I have done virtually nothing since the v3 beta 1 release. This, my friends, was a big mistake. Not v3 beta 1, which I will discuss later in this post, but the fact that I was not clear in what I hope to get out of the project. I do take the blame on the lack of development. I'm not going to sit here and tell you I have neglected to look at the code in a while. This is partially due to my work life (I have to make some money.. know that I have 2 jobs) and my personal endeavors (as I am a high school student with more to do than dedicate all my time to ClubStarterKit). No one is perfect. But I do sincerely apologize to the ClubStarterKit community for my lack of communication.

 

My hopes from the project

When I started the project, I knew that there was a void. ClubStarterKit v1 was an obvious success because of the idea of sample-driven learning. It did a lot of things that people needed. Now, I really wanted to bring CSK to the level of open source. With this, I opened up the door for contributors. This is an area that I found fairly problematic. We did get some amazing contributions, such as the CMS and the RSVP system. Without these core contributions, I would have spent more time building the features rather than tracking down bugs or expanding other CSK features. Trust me, building out a feature for CSK is not easy.

Essentially I had hoped for the ClubStarterKit to be a community effort where there would be multiple core developers. In my idea of "core developer", I seem to be the only one. To me, CSK seems more like a sample that goes through active development.

It is my hope to not be a nag about this, but come on CSK community. You guys do some amazing stuff. Then you demand something out of CSK without contributing? I just don't see how this whole thing can work out like this. I'm not a free contractor. I don't even ask for donations!

I have been asked by one member of the community to forget my role in CSK and pass it along to another developer. Guess what, no one stepped up. Interesting. Guess it looks like I'm still in, win or lose.

 

What's the deal with the inactivity?

Like I said, there are many factors to this. Mostly, I am starting to regret hard-coding SubSonic into CSK. I now know, after completely hard-coding this stuff in, that I should have allowed external DALs that people wanted. Not everybody like SubSonic and it's query tool. Some people like NHibernate, LINQtoSQL, XML, whatever. I seriously screwed up. My fault, guys. I've learned, let's move on.

A big reason for inactivity was time. I just couldn't devote a lot of time on CSK like I used to. Luckily, this is about to change for me. Just know that I'm going to have more time to work on CSK. Period.

 

What's next?

I hate to say it, but v3 beta 1 was kind of bad. I really wanted something fresh. That just wasn't what we got with v3 beta 1. The ideas were there, just the delivery was poor. So this is what I plan on doing. What I want to do, and I would LOVE to hear feedback from you on this, is to completely scrap the current codebase and move over to the ASP.NET MVC framework. I am seriously in love with ASP.NET MVC. Honestly, it will move development, deployment, and testability along. I am in the preliminary planning stages. Also, for development, I would like to use C# and convert the C# code over to VB. The fact that the original kit was released in both languages made it all the more appealing. With a refreshed codebase, we can make this process much easier on the person converting (probably me :) ).

Also, we will have an extensive service layer that can be extended to use a custom DAL or any form of data storage.

Lastly, the features listed in my last post will go in.

 

So, what do you think? I would LOVE to hear your feedback AS LONG AS IT IS PRODUCTIVE AND WILL BENEFIT THE PROJECT.

 

THANKS FOR YOUR CONTINUED UNDERSTADING CLUBSTARTERKIT COMMUNITY!

One-Line C# #1 : Remove Whitespace from a string

Thought I'd post a quick extension method that I made today. Hope it helps someone.

 

public static string RemoveWhitespace(this string str)
{
    try
    {
        return new Regex(@"\s*").Replace(str, string.Empty);
    }
    catch (Exception)
    {
        return str;
    }
}
Posted by zowens | 12 comment(s)
Filed under: , , ,

Misuse of Delegates???

In the evolution of the ideas presented in Java, C# has provided the idea of method delegation and delegates, which I'm sure you are well aware of. In C# 3.0 with the introduction of the LINQ, Lambdas were born. With Lambdas, we are able to provide an easy and elegant way to declare delegates. With great power, however, comes great responsibility. Is there a way to overuse Lambdas and Delegates? Here is a sample of code I've written:

/// <summary>
/// If GZIP or DEFLATE compression is accepted
/// by the user's browser, we will go ahead
/// and compress the file upon the controller action
/// </summary>
/// <param name="controller">Controller to invoke Compression</param>
public static void Compress(this Controller controller)
{
    string gzip = "gzip";
    string deflate = "deflate";
 
    //DELEGATES
    Func<string, bool> isAccepted = (encoding) => controller.Request.Headers["Accept-encoding"] != null && controller.Request.Headers["Accept-encoding"].Contains(encoding);
    Action<string> setEncoding = (encoding) => controller.Response.AppendHeader("Content-encoding", encoding);
 
    if (isAccepted.Invoke(gzip))
    {
        controller.Response.Filter = new GZipStream(controller.Response.Filter, CompressionMode.Compress);
        setEncoding.Invoke(gzip);
    }
    else if (isAccepted.Invoke(deflate))
    {
        controller.Response.Filter = new DeflateStream(controller.Response.Filter, CompressionMode.Compress);
        setEncoding.Invoke(deflate);
    }
}

 

As you can see from the code, I use the .NET built-in delegates of Action and Func to do the setting of the encoding and the determination of the encoding, respectively.

 

So here is my question: Is this a misuse of delegates? Should I be putting the code into a separate private method? What are your thoughts?

Posted by zowens | 9 comment(s)
Filed under: , , ,
More Posts Next page »