atashbahar.com

thoughts, ideas and ...

Group by day, week, month, quarter and year in Entity Framework (Linq to SQL)

Comments

Consider having following Product class and you want to get some stats based on the creation date of the product.

public class Product
{
    public int Id { get; set; }
    public string { get; set; }
    public DateTime CreateDate { get; set; }
}

What we want to query here is the number of products created every day, week, month, querter and year; we also want to get the stats for certain number of days.

public ActionResult Stats(int days = 365, DateGroupType group = DateGroupType.Week)
{
    var startDate = DateTime.Now.AddDays(-1 * days);
    var allStats = _db
        .Products
        .Where(x => x.CreateDate > startDate);

    var groupedStats =  GroupByDate(allStats, group, startDate);

    var stats = groupedStats.Select(x => new
        {
            x.Key,
            Count = x.Count()
        })
        .ToList()
        .Select(x => new Stat
        {
            Created = GetDate(group, x.Key.Value, startDate),
            x.Count
        })
        .OrderBy(x => x.Created)
        .ToList();

    return stats;
}

private IQueryable<IGrouping<int?, Product>> GroupByDate(IQueryable<Product> products, DateGroupType group, DateTime startDate)
{
    switch (group)
    {
        case DateGroupType.Day:
            return products.GroupBy(x => SqlFunctions.DateDiff("dd", startDate, x.CreateDate));

        case DateGroupType.Week:
            return products.GroupBy(x => SqlFunctions.DateDiff("ww", startDate, x.CreateDate));

        case DateGroupType.Month:
            return products.GroupBy(x => SqlFunctions.DateDiff("mm", startDate, x.CreateDate));

        case DateGroupType.Quarter:
            return products.GroupBy(x => SqlFunctions.DateDiff("qq", startDate, x.CreateDate));

        case DateGroupType.Year:
            return products.GroupBy(x => SqlFunctions.DateDiff("yy", startDate, x.CreateDate));

        default:
            throw new NotSupportedException($"Grouping by '{group}' is not supported");
    }
}

private DateTime GetDate(DateGroupType group, int diff, DateTime startDate)
{
    switch (group)
    {
        case DateGroupType.Day:
            return startDate.AddDays(diff);

        case DateGroupType.Week:
            return startDate.AddDays(diff * 7);

        case DateGroupType.Month:
            return startDate.AddMonths(diff);

        case DateGroupType.Quarter:
            return startDate.AddMonths(diff * 3);

        case DateGroupType.Year:
            return startDate.AddYears(diff);

        default:
            throw new NotSupportedException($"Grouping by '{group}' is not supported");
    }
}

There are a few classes and enumerations used in this code that are listed below:

public class Stat
{
    public DateTime CreateDate { get; set; }
    public int Count { get; set; }
}

public enum DateGroupType
{
    Day,
    Week,
    Month,
    Quarter,
    Year
}

Contains in array list validation attribute for ASP.NET MVC

Comments

Following custom validation attribute checks if the posted value is one of the values available in the list of valida values for that attribute.

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;

namespace MyWebApplication.Models
{
    public sealed class ContainsAttribute : ValidationAttribute
    {
        private readonly IEnumerable<string> _values;

        public ContainsAttribute(string[] values)
        {
            _values = values;
        }

        public ContainsAttribute(int[] values)
        {
            _values = values.Select(x => x.ToString());
        }

        public ContainsAttribute(double[] values)
        {
            _values = values.Select(x => x.ToString(CultureInfo.InvariantCulture));
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (value == null)
                return ValidationResult.Success;

            if (_values != null && !_values.Contains(value))
            {
                var valuesString = string.Join(", ", _values.Select(x => $"'{x}'"));
                var message = $"Provided value for {validationContext.MemberName} property is not valid. Valid values are {valuesString}.";
                return new ValidationResult(message);
            }

            return ValidationResult.Success;
        }
    }
}

You can use it like this:

[Contains(new[] { "first value", "second value", "third value" })]
public string MyValue { get; set; }

Add "www" prefix to your website using IIS URL Rewrite

Comments

You can use following URL Rewrite rule to force all URLs in your website to start with "www":

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
    <rewrite>
        <rules>
              <rule name="Add WWW" stopProcessing="true">
              <match url="^(.*)$" />
              <conditions>
                 <add input="{HTTP_HOST}" pattern="^(?!www\.)(.*)$" />
              </conditions>
              <action type="Redirect" url="http://www.{C:0}{PATH_INFO}" redirectType="Permanent" />
           </rule>
        </rules>
    </rewrite>
</system.webServer>

Multiple indexes over an in memory collection for faster search

Comments

I have a big in-memory collection of following simplified class:

public class Product 
{
    public int Id { get; set; }
    public string UserName { get; set; }
    public int CategoryId { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
}

I need to search for products based on different properties like UserName or CategoryId. One way of searching would be using linq to objects like:

var userProducts = products.Where(x => x.UserName == "SomeValue")

This takes some processing when collection is too big and in my case it would be called hundreds of time each second.

What I came up with was to introduce a new collection that supports indexing over different properties:

public class FastCollection<T> : IEnumerable<T>
{
    private IList<T> _items;
    private IList<Expression<Func<T, object>>> _lookups;
    private Dictionary<string, ILookup<object, T>> _indexes;

    public FastCollection(IList<T> data)
    {
        _items = data;
        _lookups = new List<Expression<Func<T, object>>>();
        _indexes = new Dictionary<string, ILookup<object, T>>();
    }

    public void AddIndex(Expression<Func<T, object>> property)
    {
        _lookups.Add(property);
        _indexes.Add(property.ToString(), _items.ToLookup(property.Compile()));
    }

    public void Add(T item)
    {
        _items.Add(item);
        RebuildIndexes();
    }

    public void Remove(T item)
    {
        _items.Remove(item);
        RebuildIndexes();
    }

    public void RebuildIndexes()
    {
        if (_lookups.Count > 0)
        {
            _indexes = new Dictionary<string, ILookup<object, T>>();
            foreach (var lookup in _lookups)
            {
                _indexes.Add(lookup.ToString(), _items.ToLookup(lookup.Compile()));
            }
        }
    }

    public IEnumerable<T> FindValue<TProperty>(Expression<Func<T, TProperty>> property, TProperty value)
    {
        var key = property.ToString();
        if(_indexes.ContainsKey(key))
        {
            return _indexes[key][value];
        }
        else
        {
            var c = property.Compile();
            return _items.Where(x => c(x).Equals(value));
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _items.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

You can initialize the collection like this:

var fc = new FastCollection<Product>(products);
fc.AddIndex(x => x.Id);
fc.AddIndex(x => x.UserName);
fc.AddIndex(x => x.CategoryId);

And finally you can search the collection like this:

And finally you can search the collection like this:

The fast collection makes a big difference when it comes to performance.


Native apps vs. web apps; Are web apps there yet?

Comments

I think we have heard this argument a lot recently. These days there is an app for everything. But is it really necessary? Should everything be an app? What about web apps? Can web apps offer the same functionality as native apps?

Native apps are a must have when you want to access the native functionality of the device or need all the raw power a device can offer.

Web standards have grown a lot in recent years and browser's adoption of standards is getting better and better especially on handheld devices.

Benefit of having web applications is the big range of devices and platforms you can reach without doing any change. You can design and code your website to be accessible on huge range of devices. From desktop browsers to mobile browsers and even big screen tvs.

Another big benefit would be discoverability by search engines. This is especially useful for websites that generate content and have a big user base.

Recently I have been involved in developing eCardCanvas.com website. The concept is very simple. Allow users to create and share greeting cards. But there were a few requirements that made it a little challenging. It must use no Flash and be accessible on handheld devices.

No Flash part made it obvious we have to use html5 canvas. Html5 canvas is very well supported on all modern browsers and is very rich in the functionality.

By using responsive design we were able to offer the same desktop experience on handheld devices. It was a bit challenging to optimize the card editor functionality for mobile devices but I think we did a good job in that area.

Feel free to check the website at eCardCanvas.com and try our card editor eCardCanvas.com/editor. Your input is welcome and highly appreciated.

To go back to the original argument, you might not get the same performance you are getting in a native app but in most cases it is enough to offer a good user experience. And when you count in other benefits of having web as your platform it even gets more appealing.


ASP.NET MVC CSS Bundling Pitfalls

Comments

This might seem obvious to some but I think it is still worth mentioning.

You should always bundle CSS files that are in the same folder and the Virtual Path of that bundle must match that folder's path. For example if you are bundling multiple CSS files in "~/Content/CSS/" folder, your bundle's Virtual path should be something like "~/Content/CSS/All".

The reason being images inside CSS files are relative to the location of the CSS file. So if the virtual path doesn't match the CSS file location images won't load.



ASP.NET MVC tab-based navigation

Comments

First of all this is not one of those JavaScript tab navigation scripts. Actually we are going to use no JavaScript.

Each tab is going to be linked to an ASP.NET MVC controller action. This is how end result is going to look like:

ASP.NET MVC Tabbed Navigation

Source code for this article can be accessed from github.com/atashbahar/mvc-tab-nav.

So how exactly this works?

We have a HTML helper method named SimpleNav that renders the HTML to the master page. This is how it is called:

<div id="menubar">
    <%= Html.SimpleNav(new[] {
        new SimpleNavItem{Text="Home", Action="Index", Controller = "Home"},
        new SimpleNavItem{Text="Blog", Action="Index", Controller = "Blog", GetSelected = ((a, c) => (c == "Blog"))},
        new SimpleNavItem{Text="About", Action="About", Controller = "Home", GetSelected = ((a, c) => c == "Home" && a == "About")},
        new SimpleNavItem{Text="Contact", Action="Contact", Controller = "Home", GetSelected = ((a, c) => c == "Home" && a == "Contact")}
    }) %>  
</div>

The code for this helper method is very straightforward. It simply generates an unordered list of links:


public static string SimpleNav(this HtmlHelper html, IEnumerable<SimpleNavItem> navItems)
{
    var urlHelper = new UrlHelper(html.ViewContext.RequestContext);
    string controller = html.ViewContext.RouteData.Values["controller"].ToString();
    string action = html.ViewContext.RouteData.Values["action"].ToString();

    TagBuilder ul = new TagBuilder("ul");
    ul.AddCssClass("clearfix");

    StringBuilder listBuilder = new StringBuilder();
    TagBuilder li = null;
    TagBuilder a = null;
    foreach (var item in navItems)
    {
        a = new TagBuilder("a");
        a.Attributes.Add("href", urlHelper.Action(item.Action, item.Controller));
        a.InnerHtml = item.Text;

        li = new TagBuilder("li");
        if (item.GetSelected != null && item.GetSelected(action, controller))
            li.AddCssClass("sel");
        li.InnerHtml = a.ToString();

        listBuilder.Append(li.ToString());
    }

    ul.InnerHtml = listBuilder.ToString();

    return ul.ToString();
}
public class SimpleNavItem
{
    public string Text { get; set; }
    public string Action { get; set; }
    public string Controller { get; set; }
    public Func<string, string, bool> GetSelected { get; set; }
}

The interesting part of the above code may be GetSelected which is an anonymous method. You might want a tab gets highlighted on certain conditions for example highlight the Blog tab for all Actions of the related Controller. The method accepts two Strings which are name of the current Controller and Action and returns a Boolean which indicated if the tab should be highlighted or not.

The final step which I like the most is to make it pretty. By using a simple background image and a small amount of CSS magic you can easily achieve this:

#menubar {
    border-bottom: solid 3px #8CC740;
    padding-left: 10px;
}
#menubar li {
    display: inline;
}
#menubar li a {
    float: left;    
    line-height: 21px;
    width: 80px;
    margin-right: 1px;
    background: url(tabs.gif) no-repeat 0px 0px;    
    color: #444;    
    text-align: center;
    text-decoration: none;
}
#menubar li a:hover {
    background-position: 0px -22px;
    text-decoration: none;
}
#menubar li.sel a {
    background-position: 0px bottom;
    color: #fff;
}

This may not be the most complete solution but it has helped me in so many projects. Hopefully it does the same for you.


Detect when a JavaScript popup window gets closed

Comments

A while ago in one of my projects I came into this problem that I wanted to detect when a child window that is created with window.open method gets closed.

As you know it is possible to call a JavaScript function in parent page from a popup window using parent.[JavaScript-Method-Name]. But this didn't work for me because the page I was opening was from another domain and couldn't modify its content.

Unfortunately the popup window does not have any close event that you can listen to but there is a closed property that is true when window gets closed. So the solution I came up with was to start a timer and check the closed property of the child window every second and clear the timer when the window gets closed. Here is the code:

var win = window.open('http://www.google.com', 'google','width=800,height=600,status=0,toolbar=0'); 
var timer = setInterval(function() { 
    if(win.closed) {
        clearInterval(timer);
        alert('closed');
    }
}, 1000);

Hope this helps.


Can we build a document-sharing website like Scribd with .Net?

Comments

This is a question I had in my mind for a while. I was very interested to know how document-sharing websites work in general and if it is possible to build one using .Net and other free and open source technologies.

After spending one Internet, readay searching through dig bnlogs and forums I came to the conclusion that it is possible! At least in theory it is possible.

What websites like Scribd do is that they allow their users to upload documents in various formats, then this documents will be shown in a control that is implemented using Adobe Flash. So they convert documents from various formats to Adobe Flash but how they do it and what goes on behind the scene?

I will try to explain different steps of the process and show you with which tool you can do the same with .Net. Just before we start this is not something official about how Scribd or any other websites of this type work, this is only how I think they work and how it is possible to do the same.

Step 1: Convert documents from various formats to PDF

OpenOffice supports various formats (including Microsoft Office formats) and it can export them to PDF format which is what we need.

So we have the tool but how to call it from our code. Luckily there is a great article in CodeProject which solves this problem in an elegant way. This article provides solution alongside the necessary code to easily call OpenOffice to convert documents to PDF format.

Step 2: Index document contents to be able to search through them

Another aspect of document-sharing sites is search. They allow their users to search for documents using keywords. They store hundreds of thousands of documents so having a proficient searching mechanism is very important.

To index documents we need to extract text from the documents. In first step we convert all documents to PDF, so we need to find a way to extract text from PDF files. One way to do this is to use the IFilter interface which was designed by Microsoft for use in its Indexing Service. You can find a great article in CodeProject named Using IFilter in C# which describes how you can use them to extract text from various document formats (which PDF is one of them).

After extracting text we need a tool for index the extracted text and also be able to search through this index in a proficient way. I have been using Lucene.Net which is a port of famous Lucene library for a while and I can say it is amazingly fast and also easy to use. Lucene.Net is exactly what we want here. It has all the necessary features to index the extracted text from documents and search through them very fast.

Step 3: Create thumbnails for the documents

This may look unnecessary but all of document-sharing websites have it and I think it's cool. There are commercial libraries for .Net that allow you to create an image from pages of a PDF document. But we are looking for a free solution here so using commercial components is not an option.

Ghostscript has the ability to raster PDF files. What we need is a .Net wrapper that can call it. There are many implementations that can be easily found by doing a simple search using your favorite search engine. GhostscriptSharp is one of them.

Step4: Convert the PDF files to Adobe Flash

SWFTools is a collection of utilities which one of them is PDF2SWF. PDF2SWF is a command line utility which simply converts your PDF to SWF. I couldn't find a .Net wrapper for this utility but calling a command line program from .Net is very easy.

After the conversion is done we get a SWF file of our PDF that simply is a collection of pages with no navigation. PDF2SWF provides the option to combine a simple navigation UI with the generated SWF but I think it would be better to use a more advanced viewer like SWF Document Viewer and customize it based on your needs.

Conclusion

I think the answer to this article title is yes and we can build such a website. I have not tried to do so but it seems we have all the tools necessary to do so.

I would be glad to hear your thoughts about this and if anyone has tried this approach. I would also like to hear about alternate ways of doing each step in the process.