Filtered by Month (10) and Year (2012)
In this post, we will see how ComplexTypeAwareActionSelector behaves under the covers to involve complex type action parameters during the action selection process.
@ 10-08-2012
by Tugberk Ugurlu


In my previous post on complex type action parameters with ComplexTypeAwareActionSelector in ASP.NET Web API, I showed how to leverage the ComplexTypeAwareActionSelector from WebAPIDoodle project to involve complex type action parameters during the action selection process. In this post, we will go into details to see how ComplexTypeAwareActionSelector behaves under the covers.

Assuming that we have a Person class as below:

public class Person {

    public int FooBar;

    public Nullable<int> Id { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
        
    public string FullName { 

        get {
            return string.Format("{0} {1}", Name, Surname);
        }
    }

    [BindingInfo(NoBinding = true)]
    public string FullName2 { get; set; }

    public Country Country { get; set; }

    internal int Foo { get; set; }

    public bool IsLegitPerson() {

        return Name.Equals("tugberk", StringComparison.OrdinalIgnoreCase);
    }
}

public class Country {

    public int Id { get; set; }
    public string Name { get; set; }
    public string ISOCode { get; set; }
}

In a real world scenario, we wouldn't use the Person class to bind its values from the URI but bare with me for sake of this demo. Person class has five publicly-settable properties: Id, Name, Surname, FullName2 and Country. It also has internally-settable property called Foo. There are also one read-only property (FullName) and one public field (FooBar). Besides those, the FullName2 property has been marked with WebAPIDoodle.BindingInfoAttribute by setting its NoBinding property to true.

Let’s also assume that we have the below controller and action.

public class FooBarController : ApiController {

    public IEnumerable<FooBar> Get([FromUri]Person person) { 

        //...
    }
}

Now, the question is how ComplexTypeAwareActionSelector behaves here and which members of the Person class are going to be involved to perform the action selection. To perform this logic, the ComplexTypeAwareActionSelector uses two helper methods as below:

internal static class TypeHelper {

    internal static bool IsSimpleType(Type type) {

        return type.IsPrimitive ||
                type.Equals(typeof(string)) ||
                type.Equals(typeof(DateTime)) ||
                type.Equals(typeof(Decimal)) ||
                type.Equals(typeof(Guid)) ||
                type.Equals(typeof(DateTimeOffset)) ||
                type.Equals(typeof(TimeSpan));
    }

    internal static bool IsSimpleUnderlyingType(Type type) {

        Type underlyingType = Nullable.GetUnderlyingType(type);
        if (underlyingType != null) {
            type = underlyingType;
        }

        return TypeHelper.IsSimpleType(type);
    }
}

These two methods belong to ASP.NET Web API source code but they are internal. So, I ported them to my project as they are. As you can see, IsSimpleType method accepts a Type parameter and determines if the type is a simple or primitive type. The IsSimpleUnderlyingType method, on the other hand, looks if the Type is Nullable type. If so, it looks at the underlying type to see if it is a simple type or not. This is how the ComplexTypeAwareActionSelector determines if a parameter is simple type or not.

When the ComplexTypeAwareActionSelector sees a complex type action parameter, it hands that type to another private method to get the useable properties. To mimic how that private helper method filters the properties, I created the a little console application which holds the actual filter logic.

class Program {

    static void Main(string[] args) {

        Console.Write(Environment.NewLine);
        Console.WriteLine("===============================================");
        Console.WriteLine("========This is the actual logic in use========");
        Console.WriteLine("===============================================");

        var propInfos = from propInfo in typeof(Person).GetProperties()
                        where TypeHelper
                              .IsSimpleUnderlyingType(propInfo.PropertyType) && 
                              propInfo.GetSetMethod(false) != null
                              
                        let noBindingAttr = propInfo
                            .GetCustomAttributes().FirstOrDefault(attr => 
                                attr.GetType() == typeof(BindingInfoAttribute)) 
                                    as BindingInfoAttribute
                                    
                        where (noBindingAttr != null) 
                              ? noBindingAttr.NoBinding == false 
                              : true
                              
                        select propInfo;

        foreach (var _propInfo in propInfos) {

            Console.WriteLine(_propInfo.Name);
        }

        Console.ReadLine();
    }
}

Here is what it is doing here for the Person type:

  • It first gets all the public properties of the Person class with GetProperties method of the Type class. So, the ForBar field and the Foo property is ignored.
  • Secondly, it looks if the property is simple underlying type and publicly-settable. If any one of them is not applicable, it ignores them. In our case here, the FullName property, which is a read-only property, and the Country property, which is a complex type property, are ignored.
  • As a last step, it looks at the attributes of the each filtered property. If the property is marked with WebAPIDoodle.BindingInfoAttribute and the BindingInfoAttribute’s NoBinding property is set to true, the property gets ignored. In our case here, the FullName2 property will be ignored.

If we run this little console application, we will see the following result:

SNAGHTML12a04389

As a result, the Id, Name and Surname properties will be considered during the action selection. I would like to point out couple of things before finishing up this post:

  • This is a one-time operation per controller action. For example, when we first fire up our ASP.NET Web API application and send a request which is eventually going to correspond to FooBarController, the action selector will look at all the actions under the FooBarController and performs the above logic along with others and cache lots of stuff including the above logic. So, when you hit the FooBarController next time, this process won’t be run and the result will be pulled directly from the cache.
  • The WebAPIDoodle.BindingInfoAttribute lives inside a separate package named as WebAPIDoodle.Meta. The WebAPIDoodle.Meta package contains some runtime components such as Attributes, Interfaces. This assembly has no dependency on ASP.NET Web API so that it would be easy to reference this on Model or Domain Layer projects.

Happy coding and give feedback for this little feature :)

We will see how to make complex type action parameters play nice with controller action selection in ASP.NET Web API by using ComplexTypeAwareActionSelector from WebAPIDoodle NuGet package.
@ 10-07-2012
by Tugberk Ugurlu


Couple of days ago, I wrote a blog post on complex type action parameters and controller action selection with ASP.NET Web API with a solution that I’ve come up with and I encourage you to check that blog post out to get a sense of what this is really about. However, that solution was sort of noisy. Yesterday, I tweaked the ComplexTypeAwareActionSelector implementation a bit and now it directly supports the complex type action parameters without any additional attributes for the action methods. In this post, we will see how we can use it and in the next post, we will see how it works under the covers.

First of all, install the latest WebAPIDoodle package rom the Official NuGet feed:

PM> Install-Package WebAPIDoodle

Let’s go through the scenario briefly. Assume that we have the following controller with two action methods that are expected to serve for different GET requests:

public class CarsByCategoryRequestCommand {

    public int CategoryId { get; set; }
    public int Page { get; set; }

    [Range(1, 50)]
    public int Take { get; set; }
}

public class CarsByColorRequestCommand {

    public int ColorId { get; set; }
    public int Page { get; set; }

    [Range(1, 50)]
    public int Take { get; set; }
}

[InvalidModelStateFilter]
public class CarsController : ApiController {

    public string[] GetCarsByCategoryId(
        [FromUri]CarsByCategoryRequestCommand cmd) {

        return new[] { 
            "Car 1",
            "Car 2",
            "Car 3"
        };
    }

    public string[] GetCarsByColorId(
        [FromUri]CarsByColorRequestCommand cmd) {

        return new[] { 
            "Car 1",
            "Car 2"
        };
    }
}

If we now send a GET request to /api/cars?colorId=23&page=2&take=12 with the default action selector registered, we would get the ambiguity error message because the default action selector doesn’t consider the complex type action parameters while performing the action selection.

Let’s replace the default action selector with our ComplexTypeAwareActionSelector as below. Note that ComplexTypeAwareActionSelector preserves all the features of the ApiControllerActionSelector.

protected void Application_Start(object sender, EventArgs e) {

    var config = GlobalConfiguration.Configuration;
    config.Routes.MapHttpRoute(
        "DefaultApiRoute",
        "api/{controller}/{id}",
        new { id = RouteParameter.Optional }
    );

    // Replace the default action IHttpActionSelector with
    // WebAPIDoodle.Controllers.ComplexTypeAwareActionSelector
    config.Services.Replace(
        typeof(IHttpActionSelector),
        new ComplexTypeAwareActionSelector());
}

As explained inside the previous related post, we previously had to mark the action methods with UriParametersAttribute to give a hint about the action parameters we want to support. However, with the current implementation of the the ComplexTypeAwareActionSelector, it just works as it is. Only thing required to perform is to mark the complex action parameter with FromUriAttribute. By marking the complex type parameters with FromUriAttribute, you are making it possible to bind the route and query string values.

After replacing the default action selector with our own implementation, we will see it working if we send a GET request to /api/cars?colorId=23&page=2&take=12.

image

Now, let’s send a request to /api/cars?categoryId=23&page=2&take=12 and see what we will get back:

image

Working perfectly as expected. The ComplextTypeAwareActionSelector considers simple types inside a complex type parameter which are all primitive .NET types, System.String, System.DateTime, System.Decimal, System.Guid, System.DateTimeOffset, System.TimeSpan and underlying simple types (e.g: Nullable<System.Int32>).

In the next post, we will see how ComplextTypeAwareActionSelector works and behaves with complex type action parameters. Stay tuned! ;)

Yesterday, I received an awesome e-mail telling me that I have been given the Microsoft MVP award on ASP.NET/IIS for 2012.
@ 10-02-2012
by Tugberk Ugurlu


mvp_logo

Yesterday, I received an awesome e-mail telling me that I have been given the Microsoft MVP award on ASP.NET/IIS. :) This was obviously a great news for me because this is my first time being an MVP. If you wonder what the heck is Microsoft MVP Award program is, here is the quote from the official MVP Overview page:

"The Microsoft Most Valuable Professional (MVP) Award is our way of saying thank you to exceptional, independent community leaders who share their passion, technical expertise, and real-world knowledge of Microsoft products with others.

Nearly two decades ago, we awarded 37 technical community leaders as MVPs. Today, there are more than 4,000 MVPs worldwide. They represent more than 90 countries, speak over 40 languages, answer more than 10 million questions a year, and are awarded in almost 90 Microsoft technologies—reflecting the breadth of our products and our global communities."

Microsoft developer community is beyond huge. So many brilliant developers share their knowledge through blogs, webcasts, podcasts, conference talks, user group meetings. Being part of this community has been always a fun but with this award, this fun is now doubled. However, I have never seen the MVP award as a target. I didn’t do anything special to get this award (well, except for filling the evaluation form). I just did what I love and that was enough. I love spending time on Stackoverflow, I love writing blog posts and I love helping others if I can.

Nearly for four years now, I have been trying to find my way with ASP.NET and its sub components, such as ASP.NET MVC, ASP.NET Web API, SignalR and I can see that the product has been evolved so much in a positive direction. Not to mention some huge steps that have been taken such as making nearly the 90% of the ASP.NET stack open source on Codeplex. Being able to see how the product grows commit by commit is simply awesome. This improvements made it possible for me to create better software solutions for the company I work for. Besides that, other Microsoft products such as Window Azure took me and my company to the next level.

I would like to especially thank all the developers at Microsoft, especially the ASP.NET, IIS and Windows Azure team members for the great products they build and the continuous support whenever we need it. I also want to thank all of the developers in this community for sharing their valuable knowledge, answering questions on forums and Q&A sites. I should admit that I am learning a lot by looking at other people’s code and if they weren’t sharing those, I wouldn’t be the developer as I am today.

Lastly, I would like to thank my lovely fiancé Nihan for her support in my life; especially for listening to me talking about tech stuff even if she has no idea about what I say 99% of the time. :)

I am hoping that I will never lose this award and I want to keep getting it every year :)



Hi 🙋🏻‍♂️ I'm Tugberk Ugurlu.
Coder 👨🏻‍💻, Speaker 🗣, Author 📚, Microsoft MVP 🕸, Blogger 💻, Software Engineering at Deliveroo 🍕🍜🌯, F1 fan 🏎🚀, Loves travelling 🛫🛬
Lives in Cambridge, UK 🏡