21 Jun 2016
Following custom validation attribute checks if the posted value is one of the values available in the list of valid 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; }
15 Jul 2015
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>
21 Sep 2014
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.
29 Sep 2013
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.
23 Jul 2013
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.