.Nettuce

Code Salad

  Home  |   Contact  |   Syndication    |   Login
  36 Posts | 0 Stories | 36 Comments | 0 Trackbacks

News

Twitter












Archives

Wednesday, June 12, 2013 #

public class RouteFor<T>
{
    readonly string path;
    string verbs;
 
    public static string Path
    {
        get
        {
            return GetRouteAttribute().Path;
        }
    }
 
    public static string Verbs
    {
        get
        {
            return GetRouteAttribute().Verbs;
        }
    }
 
    static RouteAttribute GetRouteAttribute()
    {
        var routeAttribute = TypeDescriptor.GetAttributes(typeof(T)).OfType<RouteAttribute>().SingleOrDefault();
        if (routeAttribute == null)
            throw new NullReferenceException(string.Format("Route not defined for {0}"typeof(T).Name));
        return routeAttribute;
    }
 
    RouteFor(string path)
    {
        this.path = path;
        AndVerbs(HttpMethods.AllVerbs.ToArray());
        AddOrUpdateAttribute();
    }
 
    public static RouteFor<T> WithDefaultPath()
    {
        return new RouteFor<T>("/" + typeof(T).Name);
    }
 
    public static RouteFor<T> WithPath(string path)
    {
        return new RouteFor<T>(path);
    }
 
    public static RouteFor<T> WithPath(string path, params Expression<Func<T, object>>[] expressions)
    {
        return WithPath(FormatRoute(path, expressions));
    }
 
    static string FormatRoute(string path, params Expression<Func<T, object>>[] propertyExpressions)
    {
        path = Regex.Replace(path, "({\\D*})""{${1}}");
        var properties = propertyExpressions.Select(x => string.Format("{{{0}}}", PropertyName(x))).ToArray();
        return string.Format(path, properties);
    }
 
    public RouteFor<T> AndVerbs(params string[] verbs)
    {
        this.verbs = string.Join(",", verbs);
        AddOrUpdateAttribute();
        return this;
    }
 
    void AddOrUpdateAttribute()
    {
 
        var attribute = TypeDescriptor.GetAttributes(typeof(T)).OfType<RouteAttribute>().SingleOrDefault();
        if (attribute == null)
            TypeDescriptor.AddAttributes(typeof(T), new RouteAttribute(path, verbs));
        else
        {
            attribute.Path = path;
            attribute.Verbs = verbs;
        }
    }
 
    public void Create()
    {
        if (EndpointHostConfig.Instance.ServiceManager != null)
            EndpointHostConfig.Instance.ServiceManager.ServiceController.RegisterRestPaths(typeof(T));
    }
 
    static string PropertyName(LambdaExpression propertyExpression)
    {
        return (propertyExpression.Body is UnaryExpression ? (MemberExpression)((UnaryExpression)propertyExpression.Body).Operand : (MemberExpression)propertyExpression.Body).Member.Name;
    }
}

Wednesday, May 29, 2013 #

    static class Program
    {
        static void Main(string[] args)
        {
            var serviceRunner = new ServiceRunner();
            if (Environment.UserInteractive)
            {
                serviceRunner.Run(args);
                serviceRunner.Stop();
            }
            else
            {
                var servicesToRun = new ServiceBase[] { new Service(serviceRunner) };
                ServiceBase.Run(servicesToRun);
            }
        }
    }
 
    class ServiceRunner
    {
        public void Run(string[] args)
        {
        }
 
        public void Stop()
        {
        }
    }
 
    class Service : ServiceBase
    {
        readonly ServiceRunner serviceRunner;
 
        public Service(ServiceRunner serviceRunner)
        {
            this.serviceRunner = serviceRunner;
        }
 
        protected override void OnStart(string[] args)
        {
          serviceRunner.Run(args);  
        }
 
        protected override void OnStop()
        {
            serviceRunner.Stop();
        }
    }

Wednesday, February 20, 2013 #

public static class ArgumentParser<T> where T : classnew()
    {
        delegate bool TryParseFunc<TProperty>(string input, out TProperty output);
 
        public static T Parse(string[] args, params Expression<Func<T, object>>[] propertiesToSet)
        {
            var target = new T();
            var propertyList = propertiesToSet.ToList();
            for (var i = 0; i < args.Count(); i++)
            {
                var property = propertyList[i];
                var propertyName = PropertyName(property);
                var arg = args[i];
                var returnType = typeof(T).GetProperty(propertyName).PropertyType;
                var methodType = Nullable.GetUnderlyingType(returnType) ?? returnType;
                var stringParameter = Expression.Parameter(typeof(string));
                var outParameter = Expression.Parameter(methodType.MakeByRefType());
                var parseExpression = Expression.Call(methodType.GetMethods().Single(x => x.Name == "TryParse" && x.GetParameters().Count() == 2), stringParameter, outParameter);
                var tryParseFunc = typeof(ArgumentParser<T>).GetMethod("InvokeTryParseFunc"BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(methodType).Invoke(nullnew object[] { arg, parseExpression, stringParameter, outParameter }) as Tuple<boolobject>;
                if (!tryParseFunc.Item1)
                    throw new FormatException(string.Format("{0} is not valid for property {1}", arg, propertyName));
                var targetParameter = Expression.Parameter(typeof(T));
                var memberParameter = Expression.Parameter(returnType);
                var member = Expression.PropertyOrField(targetParameter, propertyName);
                var assign = Expression.Assign(member, memberParameter);
                Expression.Lambda(assign, targetParameter, memberParameter).Compile().DynamicInvoke(target, tryParseFunc.Item2);
            }
            return target;
        }
 
        static Tuple<boolobject> InvokeTryParseFunc<TProperty>(string arg, MethodCallExpression parseExpression, ParameterExpression stringParameter, ParameterExpression outParameter)
        {
            TProperty value;
            var result = Expression.Lambda<TryParseFunc<TProperty>>(parseExpression, stringParameter, outParameter).Compile().Invoke(arg, out value);
            return new Tuple<boolobject>(result, value);
        }
 
        static string PropertyName(LambdaExpression propertyExpression)
        {
            return (propertyExpression.Body is UnaryExpression ? (MemberExpression)((UnaryExpression)propertyExpression.Body).Operand : (MemberExpression)propertyExpression.Body).Member.Name;
        }
    }

It's time to start looking for the next gig; please get in touch if there's anything I can help you with

http://about.me/joncanning

Tuesday, February 19, 2013 #

 public static class TryParseExtensions
    {
        delegate bool TryParseFunc<T>(string input, out T output);
        static readonly ConcurrentDictionary<TypeDelegate> Delegates = new ConcurrentDictionary<TypeDelegate>();
 
        static TryParseExtensions()
        {
            CacheTryParseFor<bool>(bool.TryParse);
            CacheTryParseFor<byte>(byte.TryParse);
            CacheTryParseFor<DateTime>(DateTime.TryParse);
            CacheTryParseFor<decimal>(decimal.TryParse);
            CacheTryParseFor<double>(double.TryParse);
            CacheTryParseFor<Int16>(Int16.TryParse);
            CacheTryParseFor<Int32>(Int32.TryParse);
            CacheTryParseFor<Int64>(Int64.TryParse);
            CacheTryParseFor<Single>(Single.TryParse);
        }
 
        public static bool Is<T>(this string s)
        {
            return TryParse<T>(s).Item1;
        }
 
        public static T As<T>(this string s)
        {
            return TryParse<T>(s).Item2;
        }
 
        static Tuple<bool, T> TryParse<T>(string s)
        {
            var dlg = Delegates[typeof(T)] as TryParseFunc<T>;
            T value;
            var result = dlg(s, out value);
            return new Tuple<bool, T>(result, value);
        }
 
        static void CacheTryParseFor<T>(TryParseFunc<T> tryParseFunc)
        {
            Delegates.TryAdd(typeof(T), tryParseFunc);
        }
    }

Tuesday, February 5, 2013 #

 public static class ExpressionCache
    {
        static readonly ConcurrentDictionary<stringAction<objectobject>> Setters = new ConcurrentDictionary<stringAction<objectobject>>();
        static readonly ConcurrentDictionary<stringFunc<objectobject>> Getters = new ConcurrentDictionary<stringFunc<objectobject>>();

        public static void SetProperty(this object obj, string propertyName, object value)
        {
            CreateSetter(obj, propertyName).Invoke(obj, value);
        }

        public static T GetProperty<T>(this object obj, string propertyName)
        {
            return (T)CreateGetter(obj, propertyName).Invoke(obj);
        }

        public static object GetProperty(this object obj, string propertyName)
        {
            return obj.GetProperty<object>(propertyName);
        }

        static Action<objectobject> CreateSetter(object obj, string propertyName)
        {
            var type = obj.GetType();
            var property = type.GetProperty(propertyName);
            var key = type.Name + propertyName;
            if (Setters.ContainsKey(key))
                return Setters[key];
            var instance = Expression.Parameter(typeof(object));
            var value = Expression.Parameter(typeof(object));
            var instanceCast = (!property.DeclaringType.IsValueType) ? Expression.TypeAs(instance, property.DeclaringType) : Expression.Convert(instance, property.DeclaringType);
            var valueCast = (!property.PropertyType.IsValueType) ? Expression.TypeAs(value, property.PropertyType) : Expression.Convert(value, property.PropertyType);
            var methodCallExpression = Expression.Call(instanceCast, property.GetSetMethod(), valueCast);
            var setter = Expression.Lambda<Action<objectobject>>(methodCallExpression, instance, value).Compile();
            Setters.TryAdd(key, setter);
            return setter;
        }

        static Func<objectobject> CreateGetter(object obj, string propertyName)
        {
            var type = obj.GetType();
            var property = type.GetProperty(propertyName);
            var key = type.Name + propertyName;
            if (Getters.ContainsKey(key))
                return Getters[key];
            var instance = Expression.Parameter(typeof(object));
            var instanceCast = (!property.DeclaringType.IsValueType) ? Expression.TypeAs(instance, property.DeclaringType) : Expression.Convert(instance, property.DeclaringType);
            var getMethodCast = Expression.TypeAs(Expression.Call(instanceCast, property.GetGetMethod()), typeof(object));
            var getter = Expression.Lambda<Func<objectobject>>(getMethodCast, instance).Compile();
            Getters.TryAdd(key, getter);
            return getter;
        }
    }

Friday, February 1, 2013 #

 public static class HttpContextBuilder
    {
        public static HttpContext Build(string userName = nullstring url = null)
        {
            var httpContext = new HttpContext(new HttpRequest("", url ?? "http://test"""), new HttpResponse(new StringWriter()));
            if (!userName.IsNullOrWhiteSpace())
            {
                var principal = Substitute.For<IPrincipal>();
                principal.Identity.Name.Returns(userName);
                httpContext.User = principal;
            }
            return httpContext;
        }
    }

Thursday, January 24, 2013 #

        object Bind(object requestDto, NameValueCollection formData)
        {
            var propertyGroups = formData.AllKeys.Where(x => x.Contains('.')).GroupBy(x => x.Substring(0, x.IndexOf('.')));
            foreach (var group in propertyGroups)
            {
                var propertyName = group.Key;
                var propertyInfo = requestDto.GetType().GetProperty(propertyName);
                var propertyType = propertyInfo.PropertyType;
                var bindings = new List<MemberBinding>();
                foreach (var childPropertyKey in group)
                {
                    var childPropertyName = childPropertyKey.Substring(childPropertyKey.IndexOf('.') + 1);
                    var childPropertyInfo = propertyType.GetProperty(childPropertyName);
                    var childPropertyType = childPropertyInfo.PropertyType;
                    if (!childPropertyType.IsPrimitive) continue;
                    var childPropertyValueString = formData[childPropertyKey];
                    var parseExpression = Expression.Call(childPropertyType.GetMethods().Single(x => x.Name == "Parse" && x.GetParameters().Count() == 1), Expression.Constant(childPropertyValueString));
                    var childPropertyValue = Expression.Lambda(parseExpression).Compile().DynamicInvoke();
                    bindings.Add(Expression.Bind(childPropertyInfo, Expression.Constant(childPropertyValue)));
                }
                Expression memberInit = Expression.MemberInit(Expression.New(propertyType), bindings);
                var propertyValue = Expression.Lambda(memberInit).Compile().DynamicInvoke();
                var propertyExpression = Expression.Property(Expression.Constant(requestDto), propertyInfo);
                var assignExpression = Expression.Assign(propertyExpression, Expression.Constant(propertyValue));
                Expression.Lambda(assignExpression, Expression.Parameter(requestDto.GetType())).Compile().DynamicInvoke(requestDto);
            }
            return requestDto;
	}

Sunday, November 11, 2012 #

OSS project using .NET 4.5 async/await and Reactive Extensions. I've included an image scraper and console logger as examples of Observers


Thursday, October 11, 2012 #

Seemingly forever I've been working on a business idea, it's a REST API delivering content to mobiles, and I've never really had much idea about its performance. Yes, I have a suite of unit tests and integration tests, but these only tell me that it works, not how well it works. I was also about to embark on a major refactor, swapping the database from MongoDB to RavenDB, and was curious to see if that impacted performance at all, so I needed a profiler that supported IIS Express that I can run my integration tests against, and Google gave me:
 
http://www.red-gate.com/supportcenter/content/ANTS_Performance_Profiler/help/7.4/app_iise
 
Excellent. Following the above guide an instance of IIS Express and is launched, as is Internet Explorer. The latter eventually becomes annoying, I would like to decide whether I want a browser opened, but thankfully the guide is wrong in that it can be closed and profiling will continue. So I ran my tests, stopped profiling, and was presented with a call tree listing the endpoints called and allowing me to drill down to the source code beneath.
 
calltree
 
Although useful and fascinating this wasn't what I was expecting to see, I was after the method timings from the entire test suite. Switching Show to Methods Grid presented me with a list of my methods, with the slowest lit up in red at the top. Marvellous.
 
capture1
 
I did find that if you switch to Methods Grid before Call tree has loaded, you do not get the red warnings.
 
StructureMap was very busy, and next on the list was a request filter that I didn't expect to be so overworked. Highlighting it, the source code was presented to me in the bottom window with timings and a nice red indicator to show me where to look. Oh horror, that reflection hack I put in months ago, I'd forgotten all about it. It was calling Validate<T>() which in turn was resolving a validator from StructureMap. Note to self, use //TODO: when leaving smelly code lying around.
 
reflection
 
Before refactoring, remember to Save Profile Results from the File menu. Annoyingly you are not prompted to save your results when exiting, and using Save Project will only leave you thankful that you have version control and can go back in time to run your tests again.
 
Having implemented StructureMap’s ForGenericType, I ran my tests again and:
 
capture3
Capture
 
Win, thankyou ANTS (What does ANTS stand for BTW?)
 
There's definitely room in my toolbox for a profiler; what started out as idle curiosity actually solved a potential problem. When presented with a new codebase I can see enormous benefit from getting an overview of the pipeline from the call tree before drilling into the code, and as a sanity check before release it gives a little more reassurance that you've done your best, and shows you exactly where to look if you haven’t.
 
Next I’m going to profile a load test.