A View Inside My Head

Jason's Random Thoughts of Interest

NAVIGATION - SEARCH

CodeRush: Anonymous Method Refactoring Fun

I recently had to work with some code that I wrote a few years ago, and stumbled upon this:


(Not that it's relevant to the rest of this blog post, but this code was responsible for deleting a Role in a custom membership provider, but due to foreign key relationships without cascading deletes, all of the User/Role assignments had to be deleted first)

Now, in all fairness to myself, there's really nothing wrong with this code.  Array.ForEach<T> requires an Action<T> delegate, and this anonymous method certainly qualifies as one.

However, since the time that I wrote this particular piece of code, I started using Lambda expressions more often.  To be consistent with the rest of the project's code, I should change this anonymous method into a Lambda expression.

Fortunately, CodeRush makes this a breeze!  Simply put your cursor within with anonymous method itself, and then hit your Refactor Key and choose the "Compress to Lambda Expression" refactoring:


As simple as that, the wordy "delegate" syntax of the anonymous method is compressed into the terse "=>" syntax of a Lambda expression:

delegate"/>
But, suppose that you are just learning Lambda expressions, and come across one in code that you don't fully understand.  CodeRush allows you to go the other way, too, and expand a Lambda expression into an anonymous method, which may be easier to understand.  Similar to above, put your cursor on the Lambda expression, hit the Refactor Key, and then choose "Expand Lambda Expression":


Anonymous methods were introduced as a way to inline functionality that otherwise had to exist in its own named method.  This is really only good if that functionality is used one time.  But, what if you discover that the functionality is needed in multiple places?

CodeRush provides a refactoring for anonymous methods called "Name Anonymous Method" that will extract the logic into a named method that can then be called from other code:


Activating this refactoring will first display the Target Picker (red arrow and line) so that you can select where to add the new method.  Then, the new method's name can be set by editing the text in the green box that will appear.

Finally, suppose that the opposite is true: you have a named method that is only used in one place, and would prefer to just inline that code.  Or, perhaps you would like to create a one-off modification to an existing method, and don't need the new functionality to be in its own named method.

CodeRush has a refactoring called "Inline Delegate" that replaces a delegate referring to a named method with an anonymous method.  If there is only a single reference to that named method, then this refactoring will also delete the named method altogether.



Since I was already familiar with the anonymous method syntax, CodeRush played an instrumental part in my learning Lambda expressions because I could write an anonymous method and then have it transformed into an equivalent Lambda for me.  But, once I knew Lambdas, I found that I wanted to update my older code in order to replace anonymous methods with the newer syntax, and CodeRush made it a trivial task to do this.

Happy Coding!

CodeRush: CodeRush Tool Window

CodeRush is full of templates. Thousands of them, when you combine the basic templates with the various types that are supported by each. How does someone start to learn all of the required mnemonics in order to use CodeRush effectively?

The answer to that is a brilliant feature known as the CodeRush Tool Window:



(DevExpress menu in Visual Studio, Tool Windows -> CodeRush)

The CodeRush Tool Window provides a context-sensitive list of "next characters" in CodeRush templates that are valid at the cursor's current location. As you start to work with CodeRush, leave this window open (perhaps on a second monitor) so that you can train yourself.




In the screenshot above, I have the CodeRush Tool Window docked on the left side of my IDE. Depending on where my cursor is located, the contents of the window will change.

For example, I can create a new Auto-Implemented Property at the cursor's current location (line 49 in the screenshot). In the CodeRush Tool Window, I see that mnemonics for Auto-Implemented Properties start with "a", so I can type that character. But, after typing "a", the contents of the CodeRush window will change:



The letter "a" by itself is a valid mnemonic for a CodeRush Template, as indicated by the the green "expansion" frame at the top of the CodeRush Tool Window. If I were to hit the spacebar here, I'd get code for a new abstract class (a preview of this code appears in the expansion frame). This is not what I want, so I can look in the list to see if typing more characters results in an appropriate mnemonic. Note: If you do accidentally expand a wrong template, just perform an Undo (Ctrl-Z) to return to the pre-expansion state of your code.

Suppose that I was trying to create an Auto-Implemented Property of type Boolean. From the contents of the window, I see that "ab" is listed as "bool", and so I only need to type the second character ("b") and then hit the space bar.

Play around by moving your cursor to various places in your code, and observing how the contents of the CodeRush Tool Window changes. Try out some of the template mnemonics that are listed to see how they work. Remember that Undo (Ctrl-Z) will get you back to where you started.

Happy Coding!

CodeRush: Property Templates

There is A LOT of repetition in coding.  To accomplish certain things, you often need to include boilerplate code that is repeated throughout your program. 

Take Properties, for instance.  Defining Properties on a class, especially a lot of them, can be a very tedious task. 

Traditionally, you have to create a member variable of the class to serve as the Property's backing store, and then create the Property itself (with a getter and setter to interact with that member variable).  Lather, rinse, repeat... ad nauseum.



This type of work is where CodeRush excels by providing you with mnemonic-driven code templates.  In other words, you type a few characters (the mnemonic), hit the space bar, and it will expand into a much larger snippet of code for you (saving you scores of keystrokes in the process).

The most basic template to help with writing Properties is: p

Move your cursor to somewhere within your class { } block, where defining a Property is legal syntax, and then type 'p' followed by a space.  This will expand into the following:


The cursor will be placed in the first orange box, where you can change the data type from "object" to whatever type your Property needs (i.e., "string").  Notice that the Property's type is linked to the backing store's type, so changing one of them will change the other.

The trick with the orange boxes in CodeRush is that you press Enter when you finish editing their contents.  This will remove the orange coloring from that element, and move the focus to the next orange box within the template.  Keep repeating this until there are no more orange boxes left to edit.

Since we knew this was a string Property, we could have saved even more keystrokes by using a mnemonic that included the type: ps



The only real difference between "p" and "ps" is that the type will already be set to "string" for you in the latter.  There are other mnemonic templates that expand into Property definitions for other types, like "pi" for "int" and "pd8" for "DateTime".  (I'll blog about an awesome discovery feature to help you learn these in my next blog post).

But, wait!  There's more!

If you already have a member variable defined (maybe you used the "vs" mnemonic, which expands into a private string variable), and wish to create a Property in your class that uses this variable as a backing store...  well, CodeRush has a trick to help you accomplish that!


Simply copy that line of source code into the copy buffer as you normally would (i.e., select the line, and then hit Ctrl-C).  Now, paste it where you would like the Property to be created (i.e., maybe on the line directly below).  Since it's illegal to define this variable twice, CodeRush does something awesome called a Intelligent Paste.  In this case, based on the contents of the copy buffer, it expands a Property template that uses your variable as the backing store!



Similarly, you can also use the "Encapsulate Field" refactoring instead of the Intelligent Paste.  Move your cursor to the line declaring the variable to use as a backing store, and then hit your Refactor Key.  Use the Down Arrow key to move through the list of available refactorings, and press Enter when "Encapsulate Field" is highlighted.

Encapculate Field refactoring
Next, CodeRush will prompt you where you would like to insert the code.  Use the Up and Down arrows to move through valid places where the new code can be inserted.  Press Enter to select the location designated by the Target Picker (red arrow).


The result will be a new property with a getter and setter that uses your variable as a backing store.



And, finally, as C# evolved, Microsoft recognized that a lot of Properties that were being created were very simple in nature, requiring no logic in the getters and setters other than reading and writing to their backing store.  A new Property syntax was added that did not require a backing store to be explicitly defined (or rather, the compiler actually creates one for you behind the scenes).  This new syntax is referred to as an Auto-Implemented Property.

Similar to the "ps" template, you can use "as" to create an Auto-Implemented Property of type "string". 

CodeRush "as" template expanded
Note: "a" by itself will not expand into an Auto-Implemented Property of type "object" similar to what "p" by itself does.

What? You didn't know about Auto-Implemented Properties, or you want to convert all of your old-style Properties to the new Auto-Implemented Properties?  There happens to be a refactoring for that in CodeRush!

Move your cursor to the Property definition that you would like to convert, and then hit your Refactor Key.  Use the Down Arrow to select "Convert to Auto-implemented Property", and observe the changes that CodeRush will be making to your code (the changes will be painted on top of the code that will be changed).  Press the Enter key, and voila!  No more backing store!



(credit goes to Dennis Burton for telling me about this refactoring... which goes to prove that there are way more features in this tool than you'll likely ever master)

Thanks to the magic of CodeRush, you now have many different ways to quickly create properties in your code, saving hundreds (if not thousands) of keystrokes in the process. 

Happy Coding!

CodeRush: The Refactor Key

Do a search, and you will find that there are a few IDE Productivity Tools available for Visual Studio. As far as feature sets go, you'll also find that there is quite a bit of overlap in what these tools offer. So, deciding on one is largely a matter of personal preference.

However, by not using an IDE Productivity Tool at all, you are doing yourself a great disservice. No, really! You are wasting a lot of time by manually doing things instead of allowing software do it for you. Since time is money, and these tools are not very expensive, you will quickly make up for the cost of the program in time savings alone (I think within the first week, if not the first day).

The one tool that I stand behind is CodeRush by DevExpress. Some of the finest people in the industry work for Devexpress, and over the years, some of these folks have become quite good friends of mine. The company has an outstanding commitment to supporting the developer community year after year, and you will surely find them sponsoring a developer event near you. Aside from the goodwill, their product suite is outstanding, so I'm proud to continue to use and recommend their entire product line whenever I can.

Sidebar: Personally, I think that DX has a bit of a branding problem with their IDE Productivity Tools, because CodeRush includes another product called Refactor! Pro. I would rather see them not offer Rafactor! Pro by itself, and only sell CodeRush with Refactor! Pro, since in my mind they are together one product (and I would never recommend Refactor! to someone without CodeRush). As such, I often refer to features from Refactor! as belonging to CodeRush. But, I digress.

Learning any new tool can be a bit daunting at first, and CodeRush is certainly no exception. DevExpress has produced a collection of short tutorial videos to help new users come up to speed. It should be noted, though, that some of these videos are likely useful to experienced users as well: with so much functionality packed into the product, I find that it's common for someone to master a number of features, be familiar with just as many if not more features, and yet be totally unaware of half of the things that the tool has to offer.

Since you have to start somewhere, the first feature that I recommend that someone master is mapping and using their Refactor key. This is a shortcut key that will open a CodeRush "context menu" to show available refactorings for the code where the cursor is currently located.

Personally, this is the feature that I probably use the most, so finding an appropriate key binding that is easy to hit yet does not interfere with my ability to type code or use Visual Studio key bindings was important. The default is Ctrl-backtick ( ` ), but I landed on the just backtick key to save me from needing to hold Ctrl. I've heard of a few people who have picked F1 as a way of defeating the annoying help system in VS2008 and earlier. It's all a matter of personal preference, so choose something that works for you.

To set the Refactor key shortcut, open the Options from the DevExpress menu in Visual Studio. In the tree on the left, open IDE and click on Shortcuts. After admiring the entire collection of shortcuts that are available, locate the "Refactor!" section in the list. One of the defined shortcuts will be mapped to the "Refactor" command, and by clicking on this, you can set your own key to bind it to on the right.



Trivia: Notice the Alternate Bindings that also appear in the same section. Number Pad 0 is the one preferred by Mark Miller. Dustin Campbell has two bindings mapped: the default Ctrl-`, as well as Number Pad INS.

Now that you have a Refactor key, try moving your cursor to different places in your code and pressing it.



You'll still have to learn about different refactorings that are available in the tool, but hopefully the Refactor key will become your preferred portal for accessing those refactorings (instead of using smart tags or the mouse to right-click on code).

Happy Coding!
A View Inside My Head | All posts tagged 'Azure'

A View Inside My Head

Jason's Random Thoughts of Interest

NAVIGATION - SEARCH

Windows Azure platform AppFabric Access Control: Using the Token

In previous articles (Part 1, Part 2, Part 3), ACS was configured to process token requests from different Issuers, and a Customer application obtained a SWT token from ACS using an intermediate service (that represented its particular Issuer). 

Now that the application has a token, ACS is not needed again until that token expires.  This article will show how to use that token in order for the Customer application to call the Bartender web service.

Note: OAuth WRAP defines terminology for parts of the system as follows:

  • The Customer application is known as the Client
  • The Bouncer (ACS) is known as the Authorization Server.
  • The Bartender web service is known as the Protected Resource.

Passing a Token from Client to Protected Resource

We had to conform to OAuth WRAP specifications while acquiring a token from ACS, but there’s no actual requirement for how a Client must pass that token to the Protected Resource.  An Architect or Developer could come up with any contract that they would like to use.  However, a best practice would be to continue using the OAuth WRAP specification as guidance.

WRAP defines three different ways that a Protected Resource can accept a token:

  • In the HTTP header
  • In the Query String
  • In the Form contents

OAuth WRAP suggests that a Protected Resource at least support the HTTP header method, but makes no mandates.  If a Protected Resource is able to implement all three, then it would be in the position to support the widest variety of Clients.  However, if the Protected Resource is unable to use HTTP headers but could use a value passed in the Query String, then there would be nothing in the WRAP specification to prevent only that implementation.

Regardless of the method used, an unauthorized request (perhaps due to a bad or missing token) will result in a HTTP status of 401 Unauthorized, and a header in the response containing: WWW-Authenticate: WRAP

Tokens passed in the HTTP header are expected to use the “Authorization” header, with this header’s value containing the text: WRAP access_token="tokenstring".  Note that tokenstring is a placeholder for the actual SWT token obtained from ACS and does not need to be URL Encoded. 

Example (using a System.Net.WebClient class):

string headerValue = string.Format("WRAP access_token=\"{0}\"", HttpUtility.UrlDecode(token));
var client = new WebClient();
client.Headers.Add("Authorization", headerValue);

 

Tokens passed in either the Query String or in Form Contents are expected to use the name/value pair of: wrap_access_token=tokenstring.  Again, tokenstring is a placeholder for the actual SWT token obtained from ACS, and should be URL Encoded as needed in order to properly construct the HTTP Request (this may be done automatically by the framework that is used). 

Example (using a System.Net.WebClient class):

var values = new NameValueCollection();
values.Add("wrap_access_token", token);
var client = new WebClient();
client.UploadValues("BartenderWebservice", "POST", values));

Accepting and Validating a Token

SWT tokens are opaque to the Client.  That is, since the Client cannot modify the token, they shouldn’t really care what’s in it or how it’s structured.  The Protected Resource, however, must deconstruct, validate, and then use the claims that are contained within the tokens.  If anything is invalid or malformed, then the Protected Resource should deny access by returning a 401 Unauthorized status in the response.

The Windows Azure platform AppFabric SDK V1.0 contains plenty of boilerplate code in the samples demonstrating how to parse and validate a SWT token (so I won’t be repeating that code here).  In essence, all of the following needs to pass validation before the Client is authorized to access the Protected Resource:

  1. HMACSHA256 signature is valid
  2. Token has not yet expired
  3. The Issuer is trusted (i.e., contains the URL of the ACS server)
  4. The Audience is trusted (i.e., contains the URL of the Protected Resource)
  5. Additional required claims are present

For the nightclub example, the Customer’s Birthdate will be presented as a claim (#5 in the list above).  So, in addition to checking the technical aspects of the token, a business rule must also ensure that the Customer is of legal age to order a drink from the Bartender (in the United States, this means at least 21 years old).

Conclusion

I wrote this series of blog posts because I myself was having a hard time grasping the Hows and Whys of using Windows Azure platform AppFabric Access Control to secure a Protected Resource.  What I discovered was that by using claims based identity in conjunction with a federated identity model, you can incorporate a very scalable authorization scheme into your system without requiring complex code and/or special prerequisite software.  Technically, an organization could build this same functionality into a system without using Azure AppFabric.  However, Windows AppFabric Access Control offers the benefit of already being internet-facing and hosted in a high availability environment, and already includes a rich implementation of OAuth WRAP that supports many different kinds of Issuers.

Further Reading:

Windows Azure platform AppFabric Access Control: Obtaining Tokens

In this, the third part of a series of articles examining Windows Azure platform AppFabric Access Control (Part 1, Part2), I will continue developing the [somewhat contrived] nightclub web service scenario and demonstrate how to obtain a token from ACS that can be used to call into a Bartender web service.

A Quick Review

Our distributed nightclub system has four major components: A Customer application coupled with some external identity management system, a Bartender web service, and ACS, which acts as our nightclub’s Bouncer.

A Customer application ultimately represents a user that wishes to order a drink from the Bartender web service.  The Bartender web service must not serve drinks to underage patrons, so it needs to know the user’s age (this is known as a “claim”).  The nightclub has no interest in maintaining a comprehensive list of customers and their ages, so instead, a Bouncer ensures that the user’s claimed age comes from a trusted source (this is known as an “issuer”).  If the claim’s source can be verified, the Bouncer will give the customer a token containing its own set of claims that the Bartender web service will recognize.  In the end, the Bartender doesn’t have to concern itself with all of the possible issuers – it only needs to recognize a single token generated by the Bouncer (ACS).

separateservice_issuer

 

Anatomy of a Token Request

ACS uses a subset of the OAuth Web Resource Authorization Protocol (WRAP) to request tokens.  The tokens themselves use the Simple Web Token (SWT) format.  The latest specification documents for both WRAP and SWT can be found in the Files section of the “OAuth WRAP WG” Google Group: http://groups.google.com/group/oauth-wrap-wg/files

The power of ACS derives from the simplicity of WRAP/SWT.  All of the token requests are performed as regular HTTP POSTs, and the response is a URL Encoded string of name/value pairs (one of those being the token itself).  Even if your Issuer (Identity Management System) does not natively know how to request a token from ACS, which is very likely, then it is easy to either build this into the application itself, or write a small service to perform this work. 

At the HTTP protocol level, a token request may resemble:

REQUEST:

POST https://jasondemo.accesscontrol.windows.net/WRAPv0.9/ HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: jasondemo.accesscontrol.windows.net
Content-Length: 155
Expect: 100-continue

wrap_name=Ohio&wrap_password=LVMjImkJjIBDrJHbTzyrioeajIFpV27tW2uTuCCOYFY%3d
&wrap_scope=http%3a%2f%2fmyserver.domain%2fBartender&DOB=1979-05-25T00%3a00%3a00

 

RESPONSE:

HTTP/1.1 200 OK
Content-Length: 315
Content-Type: application/x-www-form-urlencoded
Server: Microsoft-HTTPAPI/2.0
x-ms-request-id: ca165b72-5d9f-4196-9272-1b80c8c3e02a
Date: Mon, 22 Mar 2010 13:26:44 GMT

wrap_access_token=Birthdate%3d1979-05-25T00%253a00%253a00%26Issuer%3dhttps%253a%252f%252f
jasondemo.accesscontrol.windows.net%252f%26Audience%3dhttp%253a%252f%252fmyserver.domain%
252fBartender%26ExpiresOn%3d1269307605%26HMACSHA256%3deSgT1Gwx3H6owK8hBR82ixG0DRTgM2osI3v
7NdJLQwY%253d&wrap_access_token_expires_in=43200

 

The response displayed here contains two name/value pairs: wrap_access_token and wrap_access_token_expires_in.  If the token request was invalid, then a HTTP 401 status would have been returned instead of a 200.

Notice that “wrap_access_token_expires_in” contains the value 43200, which is the number of seconds that we defined in the Token Lifetime field of the “BouncerPolicy” token policy (in Part 2).  This value is provided as a convenience to indicate how long the token will be valid.  Taking a cue from systems that use lease lifetimes, like DHCP, it might be a good practice to acquire another token at 50% of the Token Lifetime (21600 seconds in this case, or 6 hours). 

As the name suggests, “wrap_access_token” contains the SWT token itself.  This is a URL Encoded set of name/value pairs that also includes a HMACSHA256 signature to prevent the token from being tampered with.  This token does not need to be parsed by the client application; it can be treated as a magic string.  However, there is nothing special about its contents:

Birthdate=1979-05-25T00%3a00%3a00 &Issuer=https%3a%2f%2fjasondemo.accesscontrol.windows.net%2f &Audience=http%3a%2f%2fmyserver.domain%2fBartender &ExpiresOn=1269309326 &HMACSHA256=NLmcGYITc8aWvhNp6Ge54TGJxhJCVX4Q67DDLBKoIy4%3d

 

“Birthdate” is the result of the Passthrough Claim Mapping (Part 2) that took the inbound claim called “DOB” and mapped it to this outbound claim called “Birthdate”.  ACS has no idea that this is a date – it just knows that it’s a string of characters that will be understood by the destination.  The other claims that are present in this SWT token (Issuer, Audience, ExpiresOn, and HMACSHA256) are all system claim types that are reserved for use by SWT. 

Note the value of “Issuer” in this token.  In our Request, the stated Issuer was “Ohio”, which was a trusted Issuer that we defined when configuring the Service Namespace using AcmBrowser.  The Issuer of this SWT token is now the Service Namespace.  Our Bartender web service has no direct trust with the Ohio Issuer, but it will trust tokens signed by the Service Namespace (which trusts the Ohio Issuer).  Just as ACS can trust multiple Issuers, it’s also possible that the Bartender web service could trust multiple ACS Issuers (maintaining a symmetric key for each one to verify the HMACSHA256 signature).  There is a lot of flexibility in how ACS can be incorporated into your own system’s architecture.

Implementation

Because the “Ohio” issuer was created in ACS using a Symmetric 256-bit key, we have two choices for how to use this key in order to request a token from ACS.  We could send the key itself in plaintext, sort of like a password (in fact, this uses a WRAP profile that is intended for username/password authentication).  Alternatively, we could create a SWT of our own, using the key to sign it, and then send that token to ACS as part of the token request.

A simple WRAP request that provides the Issuer’s name and password (symmetric key) in plaintext would contain the following name/value pairs:

  • wrap_name (Issuer Name, as defined in the Issuer definition in ACS)
  • wrap_password (Current Key, as defined in the Issuer definition in ACS)
  • wrap_scope (Applies To, as defined in the Scope definition)
  • additional claims (will be processed by the defined Scope Rules for claim mapping)

private static string RequestTokenFromACS_usingPassword(DateTime dob) { var values = new NameValueCollection(); values.Add("wrap_name", "Ohio"); values.Add("wrap_password", "LVMjImkJjIBDrJHbTzyrioeajIFpV27tW2uTuCCOYFY="); values.Add("wrap_scope", "http://myserver.domain/Bartender"); values.Add("DOB", dob.ToString("s")); var client = new WebClient { BaseAddress = "https://jasondemo.accesscontrol.windows.net" }; return Encoding.UTF8.GetString(client.UploadValues("WRAPv0.9", "POST", values)); }


Using a SWT within a WRAP request is just as simple, but the difficulty is in creating the SWT itself.  The WRAP request would contain the following name/value pairs:

  • wrap_assertion_format (SWT in this case)
  • wrap_assertion (the SWT token that we generate and sign using the Current Key)
  • wrap_scope (Applies To, as defined in the Scope definition)

The SWT token itself would contain the following name/value pairs:

  • Issuer (Issuer Name, as defined in the Issuer definition in ACS)
  • Audience (STS Endpoint, as listed on the Service Namespace overview page)
  • ExpiresOn (integer containing the number of seconds after the Epoch date of January 1, 1970 00:00 UTC that the token will expire)
  • additional claims (will be processed by the defined Scope Rules for claim mapping)
  • HMACSHA256 (URL Encoded Base64 signature of the unsigned token)

private static string RequestTokenFromACS_usingSWT(DateTime dob) { string requestToken = GetRequestToken(dob); var values = new NameValueCollection(); values.Add("wrap_assertion_format", "SWT"); values.Add("wrap_assertion", requestToken); values.Add("wrap_scope", "http://myserver.domain/Bartender"); var client = new WebClient { BaseAddress = "https://jasondemo.accesscontrol.windows.net" }; return Encoding.UTF8.GetString(client.UploadValues("WRAPv0.9", "POST", values)); } private static string GetRequestToken(DateTime dob) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("DOB={0}&", dob.ToString("s")); sb.Append("Issuer=Ohio&"); sb.Append("Audience=https://jasondemo.accesscontrol.windows.net/WRAPv0.9&"); sb.AppendFormat("ExpiresOn={0:0}", (DateTime.UtcNow.AddMinutes(10) - new DateTime(1970, 1, 1)).TotalSeconds); return AddSignature(sb.ToString()); } private static string AddSignature(string unsignedToken) { HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String("LVMjImkJjIBDrJHbTzyrioeajIFpV27tW2uTuCCOYFY=")); var sig = hmac.ComputeHash(Encoding.ASCII.GetBytes(unsignedToken)); string signedToken = String.Format("{0}&HMACSHA256={1}",  unsignedToken,  HttpUtility.UrlEncode(Convert.ToBase64String(sig))); return signedToken; }

Where to Execute this Code

The code to request a token can easily be implemented within an application that uses that token to call into a protected resource.  In the nightclub example, this code could be incorporated right into the Customer application.  However, this would mean that the claim (Birthdate) would originate from the application itself.  It also means that the application would need to have access to the Issuer key, making it possible for a nefarious user to obtain the key and bypass the application to directly access the protected resource.  These may not be concerns for your specific system, though.

A better solution for the nightclub example, which tries to mimic the real-life State ID system, would be to create a service for each Issuer that their Customer applications call into.  This service would then be able to obtain claim information from a source of authority (such as a LDAP directory), obtain a token from ACS, and then return that token to the Customer application.  The Customer application would never communicate with ACS directly, so there would be no reason for the application to have the Issuer key (making it harder for that nefarious user to discover the key).

From Here

This article demonstrated how to obtain a token from ACS.  In the next article, I will show how to use this token in order to access a protected resource (such as our Bartender web service) and how to validate a token when a protected resource receives one. 

(Continued in Part 4)

Further Reading:

Windows Azure platform AppFabric Access Control: Service Namespace

In the previous article, I provided an example scenario of how claims-based access control might map to the real-world event of a customer entering a bar. This article will build upon that concept, eventually enabling a Customer application to obtain a token from our Bouncer (ACS), and then use that token to order a drink from the Bartender web service.

Now let’s walk through how to create a Service Namespace in Windows Azure, which is needed to permit your application and/or web service to utilize AppFabric Access Control.

Service Namespace

At this time, Windows Azure platform AppFabric provides two services for developers to use: Service Bus and Access Control. Within a Project (i.e., the unit of billing for an Azure account), a “Service Namespace” is used to organize a set of these AppFabric service endpoints. Services within a Service Namespace share the same DNS naming convention, geography (datacenter where the services are hosted) and owner key (security for managing the services).

To create a new Service Namespace, start by logging into the Windows Azure portal (http://windows.azure.com). Navigate to the AppFabric section, choose the Project in which the Service Namespace will be created, and then click the “Add Service Namespace” link. The next screen will prompt for a Name, a Region, and the size of the ServiceBus Connection Packs for the new Service Namespace:

create_service_namespace

  • The name must be unique among all Service Namespaces in existence because this name will be incorporated into DNS aliases. The Windows Azure portal provides a “Validate Name” function to ensure that the name entered meets the required syntax criteria and that it has not already been used.
  • Region maps to the Microsoft data center where the services will run. Ideally, this should be as close to the users as possible.
  • “ServiceBus Connection Packs” is to support the Windows Azure platform AppFabric Service Bus. Since this article is only examining Access Control, the number of ServiceBus connections can be set to zero.

Once you click the “Create” button, Windows Azure will generate the services and DNS entries for your new Service Namespace. However, looking at the information page on the portal for the Service Namespace reveals nothing that is noticeably useful for configuring these services:

service_namespace_info

Configuring Access Control

On the portal, the only actions that you can perform are “Generate a New [Management] Key” and “Delete the Service Namespace”. How then do we configure Access Control?

Access Control, like most things in Windows Azure, is configured via a set of web services. While robust tooling is something that is currently being developed (or something that you could develop on your own), there are a few demo tools included as source code in the Windows Azure platform AppFabric SDK V1.0, including a Windows (GUI) application called Access Control Service Management Browser (AcmBrowser).

By default, after installing the SDK, you can find the Visual Studio solution for the AcmBrowser application in:

C:\Program Files\Windows Azure platform AppFabric SDK\V1.0\Samples\AccessControl\ExploringFeatures\Management\AcmBrowser

To use this application, you will need the Service Namespace’s name (the one that you entered during the creation process) and Management Key for that namespace (this is “Current Management Key” string on the screenshot above). After providing these values to AcmBrowser, you can then click the “Load from the Cloud” button to see what is already configured. As you would expect, new namespaces will have nothing pre-configured, as indicated by the “Resources” tree on the left showing Issuers, Scopes, and Token Policies, but these nodes contain no children.

mgt_browser_1

Token Policy

The first thing that we need to create is a Token Policy. This item defines a length of time, in seconds, that a token will be valid until it expires, as well as a symmetric key that is used to sign tokens. This symmetric key will be shared with our Bartender web service, but not the Customer application (else the customer would be able to generate tokens themselves, bypassing ACS and being capable of spoofing any claim).

To create a Token Policy using AcmBrowser, right click on the “Token Policy” node and choose “Create…”:

create_new_tokenpolicy

In this example, tokens created using the “BouncerPolicy” will expire 12 hours (60 * 60 * 12 = 43200 seconds) after they have been generated, and the Signing Key was created by clicking the “Generate” button. Should this key ever be compromised, a new key can be generated in the same way.

Scope

ACS is not an identity provider. You don’t maintain users in ACS, but rather, maintain a list of trusted identity providers (Issuers) that can supply claims on behalf of their users. With this federated model, the claims presented may be named different things, but convey the same information. For example, a claim containing a Birthdate may be named “DOB” by one Issuer and “Date of Birth” by another Issuer, but both sources supply the same type of information.

The web service that will eventually consume these claims, however, shouldn’t be concerned with knowing all of the variations. Instead, ACS provides Claim Mapping capabilities that can rename claims, or express a new claim based on the presence of a known claim in the token request. Before we can configure the claim mappings, though, we need to define a Scope and Issuers.

During the token request, one piece of information that is required is the URL where the token will eventually be used (known as the “Applies To”). ACS uses this in order to know what set of rules to apply when generating that token.

A Scope is the mechanism that ties a URL to a Token Policy, and is created within AcmBrowser by right clicking on the “Scopes” node and choosing “Create…”. In this example, our Scope is defined with the Applies To URL of the Bartender web service and associated to the BouncerPolicy Token Policy. Note that this “Applies To” URL is actually a substring of the real web service URL; any URL that is provided during the token request that starts with this same “Applies To” string will match to this scope, and it’s possible that an actual URL will match multiple Scopes (allowing for chaining of rules from the longest substring match to the shortest).

create_new_scope

Issuers

In a Claims-Based Identity and Access Control system, the destination application or web service does not concern itself with end-user authentication. Instead, the user authenticates itself with its own identity management system (known as an Issuer), and this system then becomes a trusted source of claims about that user. This Issuer might be a standalone application, a custom web service running on an intranet server, another AppFabric Service Namespace, or even an Active Directory Federation Services 2.0 system. As a result, there are different ways to prove that information presented during a token request came from a trusted Issuer.

In the nightclub example, the customer presents a driver’s license that was issued by their state of residence. Keeping with this concept, let’s define a few Issuers in ACS named after states (Ohio, Michigan, Indiana, etc) by first right clicking on the “Issuers” node in AcmBrowser and selecting “Create…”:

create_new_issuer

ACS is able to recognize and validate a token request originating from an Issuer in many different ways. In this example, the “Ohio” Issuer is defined using a Symmetric 256-bit Key (other choices that could have been used include X509 and FedMetadata). After sharing this secret with the Issuer, the “Issuer Name” and “Current Key” can be provided as claims during a token request, much like a username and password, or the key can be used by the Issuer to sign a token request. But, more on that in another article.

[Scope] Rules

During the token request, an arbitrary number of claims will be presented to ACS. The application that will finally consume the token generated by ACS may only require a subset of those claims, if any. To decide what claims should be included in the output token, we need to create a set of Rules (one per output claim).

To create rules for a Scope, you first expand the Scope’s node in AcmBrowser, right-click on the “Rules” node, and then choose “Create…”:

Scope_Rules_Node

A Rule can be defined as either PassThrough or Simple. A PassThrough rule is used to rename a claim from whatever the Issuer called it to whatever the final application will expect it to be called (the value will be preserved). A Simple rule, on the other hand, will generate a claim (name and value) in the output if a specific claim (name and value) was present in the input. Note that the input and output claim values in a Simple rule must be explicitly defined – you cannot use pattern matching, etc.

For the example scenario, we’ll assume that the Ohio Issuer uses “DOB” as the name of the “Birthdate” claim that the Bartender web service will be expecting. A PassThrough rule is used to rename that claim so that the resulting token will include a claim called “Birthdate” instead (the provided value will be preserved).

create_new_rule

Wrapping Up

At this point, everything has been defined in memory on your machine, and nothing has actually been saved to the cloud. To commit your changes, you will need to click on the “Save to Cloud” button in AcmBrowser. Note that AcmBrowser is not sophisticated enough to merge with an existing set of configuration, so if your Service Namespace is not already empty, then you will need to click the “Clear Service Namespace in Cloud” button prior to saving to the cloud. You can also load and save local copies of the configuration using the tool, which is useful for backup purposes as well as working on a particular configuration over the course of multiple days without disturbing what is already running in the cloud.

In the next part of this series, I’ll show code for how everything finally comes together for this contrived example.

(Continued in Part 3)

Further Reading:

Windows Azure platform AppFabric Access Control: Introduction

The Windows Azure platform AppFabricAccess Control service was one aspect of the Windows Azure platform that I found a bit challenging to understand, primarily because identity is not a domain that I regularly work with. This post, the first in a planned series of articles, will explore what the Access Control service is and why it is useful.

Three Geeks Walk Into a Bar…

nightclub_access_control Let’s examine a common real-world scenario: Ordering a drink from a bartender at a nightclub.

Before the nightclub opens, the bouncers inform the bartenders about the token that customers will bear on that night to indicate that they are of legal age. This could be a stamp on the back of the hand, a colored wristband, etc.

At the door, a customer will present their identification to the bouncer that shows, among other things, their date of birth. This ID could be a state-issued driver's license, a passport, or even a school identification card. The point is that the nightclub didn’t issue that ID, but they recognize the authority that did issue it, and will accept the claim (the birth date) that is displayed on that ID.

If the bouncer determines that the ID is authentic and hasn’t been tampered with, then he will give the customer the token of the night (stamped hand or colored wristband), and the customer is free to enter the bar.

Once inside, the customer only needs to show the token to the bartender in order to buy drinks. They do not need to show their ID.

The next night, the token will change, so a customer cannot use a token obtained the night before.

Federated Access Control

Azure_access_control Now let’s look at a similar scenario: Calling a web service from an application. Only, in this case, the web service should not fulfill requests from unauthorized clients. Furthermore, it’s not the web service’s responsibility to authenticate the client; it is simply expecting the client to bear some verifiable proof that it is already authorized to use the service.

Before calling the Web Service, the Service Consumer (application) must first obtain a token that is issued by an Access Control Service (ACS). This is done by sending a number of claims to the ACS, with one of these claims being secrets belonging to an Issuer that the application is associated with.

If the Issuer is recognized and trusted by the ACS, then a token will be created. This token (which is a collection of name/value pairs) will contain claims, an expiration date, and a signature that can be used to ensure that the token was not modified after it was created.

Once the Service Consumer has a valid token, it can then call the Web Service and provide that token in a location where the service expects to find it, such as in a HTTP header. The Web Service validates that the token is well-formed, has not expired, and has not been modified since it was created. If anything fails validation, then the processing aborts. Otherwise, the web service returns data to the Service Consumer, possibly using claims contained in the token as input in the process.

This scenario is considered to be Federated because the ACS doesn’t actually maintain a list of usernames and passwords. Instead, it maintains a list of trusted Issuers with the expectation is that the Issuer is responsible for authenticating its own users.

Correlation

In these examples, the Web Service is analogous to the nightclub’s Bartender: it has something to provide to the Service Consumer (Customer), but the Service Consumer must present an appropriate token that is generated by the Access Control Service (Bouncer).

The web service example above is intentionally vague in the part where a token is obtained. There are a few different ways that an Issuer can be identified in a token request, and while passing the Issuer’s secret in plain text is one of those ways, it certainly shouldn’t be taken lightly. Whoever has the Issuer’s key can spoof any of the claims, and that might prove to be a challenge for the service. In the example where we need a Date of Birth claim to be presented, it would probably be a bad idea to allow the customer themselves to say “I’m from Ohio, here’s a blank driver's license that meets all of the standards of a proper ID, and, oh yeah… I’m writing on here that I am 21 years old.”

Instead, claims should originate from the Issuer in some way that cannot be tampered with by the application (using the assumption that the application itself should not be trusted). With the plain text method, this might require having a separate service that runs within the Issuer’s domain and is aware of its users and also ACS. This service would broker the ACS token request for the application, automatically providing any claim data that might be needed (like the Date of Birth) from the Issuer’s own user database. The application would be provided with the same token, but would never have the Issuer’s secret that is required to obtain the token directly from ACS.

(Continued in Part 2)

Further Reading:

A View Inside My Head | All posts tagged 'EF'

A View Inside My Head

Jason's Random Thoughts of Interest

NAVIGATION - SEARCH

Entity Framework Spatial: A Real World Example

Background

From the Wikipedia article, Leadership in Energy and Environmental Design (LEED) is described as “an internationally recognized green building certification system, providing third-party verification that a building or community was designed and built using strategies intended to improve performance in metrics such as energy savings, water efficiency, CO2 emissions reduction, improved indoor environmental quality, and stewardship of resources and sensitivity to their impacts.”

In my own words, LEED is a certification system that awards points for following certain environmentally-friendly practices when constructing a building. In the end, a building can be qualify for one of four different levels of certifications, based on the number of points: Certified, Silver, Gold, Platinum. There are often tax benefits associated with having a LEED certification, and many new government buildings (especially Federal) are required to be LEED certified.

Two points in particular (out of of 100, or so) from the LEED checklist are related to geospatial data. One point is awarded if at least 20% of the building materials (by cost) used in construction were manufactured within 500 miles of the job site. A second point is awarded if 10% of the raw materials of those building materials were extracted, harvested, or recovered within 500 miles of the job site.

As a window glass manufacturer, Tempuri Glass is often asked to provide data about its products that are being considered for use in construction. Tempuri Glass may have a certain advantage over its competitors if it can quickly show that its products would count towards these two points for any arbitrary job site.

Data

Tempuri is a simple organization, making only a single type of product (Soda Lime glass) that is then cut into different sizes per order. Therefore, regardless of how many different sized glass panes are produced by a given facility, the ingredients for that glass is the same. The formulas used will be different between facilities, though, since the raw ingredients will be sourced from different locations, and adjustments may need to be made to the ratios due to environmental factors (things like: elevation, temperature, humidity, etc).

So, for our data model, we just need to know where each facility is, and then the formula used to make the glass at that facility (including the ingredients of that formula and the location where they were harvested from).

a.EF_Diagram

Within the data store, the [Geocode] columns of the Facility and FormulaComponent tables use the SQL Server geography type. This is useful for the large-scale/real-world distance calculations that Tempuri Glass needs to perform, since the way that you calculate distance on an sphere or ellipsoid (like the Earth) is vastly different than on a flat map.

In the Entity Framework model (using the June 2011 CTP), the SQL Server geography types are mapped as the new System.Data.Spatial.DbGeography type. This makes the geospatial data a first class citizen of our data model, and not just a castable opaque BLOB, as was the case in the past.

Geospatial data can take on many forms, including Points, Line Strings, Polygons, and collections of these shapes. Even though it’s not apparent from the data model, our [Geocode] data will contain only Points (i.e., a single Latitude/Longitude pair). Likewise, a job site will be specified as a single Point, though there is no hard requirement for this because distance can still be calculated between a Polygon and a Point with no coding change required.

Facility Sample Data

FacilityID

FacilityName

City

State

Geocode

1

Greenfield, IA

Greenfield

IA

POINT (-94.4547843933106 41.3151755156904)

2

Spring Green, WI

Spring Green

WI

POINT (-90.053981 43.17431)

3

Tomah, WI

Tomah

WI

POINT (-90.477058 43.989319)

4

Fremont, IN

Fremont

IN

POINT (-84.9314403533936 41.7186070559443)

5

Fargo, ND

Fargo

ND

POINT (-96.8667125701904 46.8985894795683)

6

Waxahachie, TX

Waxahachie

TX

POINT (-96.8427014350891 32.4424403136322)

7

Hood River, OR

Hood River

OR

POINT (-121.51526927948 45.630620334868)

8

Vinton, VA

Vinton

VA

POINT (-79.863876 37.263329)

9

Casa Grande, AZ

Casa Grande

AZ

POINT (-111.78155422210693 32.882073958767954)

10

Mountain Top, PA

Mountain Top

PA

POINT (-75.896477 41.141327)

11

Winlock, WA

Winlock

WA

POINT (-122.926218509674 46.5449155194259)

12

Durant, OK

Durant

OK

POINT (-96.4133548736572 34.0001619910696)

13

Mooresville, NC

Mooresville

NC

POINT (-80.7865476608277 35.6316281732984)

 

FormulaComponent Sample Data

FormulaComponentID

Name

Percentage

SourceLocation

Geocode

14

Limestone

13

Genola, UT

POINT (-111.808204650879 40.0098667779887)

1

Silica Sand

75

Houck, AZ

POINT (-109.241695404053 35.2062151838369)

27

Soda Ash

12

Trona, CA

POINT (-117.311668395996 35.6955040738332)

15

Limestone

13

Genola, UT

POINT (-111.808204650879 40.0098667779887)

2

Silica Sand

75

Houck, AZ

POINT (-109.241695404053 35.2062151838369)

28

Soda Ash

12

Trona, CA

POINT (-117.311668395996 35.6955040738332)

16

Limestone

13

Chicago, IL

POINT (-87.6176834106445 41.5738476278005)

3

Silica Sand

75

Overton, NV

POINT (-114.4313621521 36.5146030619859)

29

Soda Ash

12

Green River, WY

POINT (-109.448783397675 41.5090754257687)

 

Spatial Querying Algorithm

Input: Job Site Latitude/Longitude

Steps:

A. Query for closest facility to Job Site within 500 miles:

  1. Calculate the distance between the job site and each facility.
  2. Filter the list of facilities to just those where distance < 500 miles.
  3. Order the list of facilities by distance in ascending order.
  4. The first element (if any) will be the closest facility, and also signifies that the product qualifies as being manufactured within 500 miles

B. If there is a facility within 500 miles, then sum the percentage of formula components that were sourced from within 500 miles of the Job Site:

  1. Calculate the distance between the job site and each of the facility’s formula components
  2. Filter the list of formula components to just those where distance < 500 miles
  3. Sum the Percentages

Output: Boolean of whether the product qualifies; Percentage of the product’s ingredients that qualifies.

Implementation

Before we can calculate distance using an instance method of the DbGeography type, we need to actually create an instance to represent the Job Site. DbGeography is immutable and does not have a constructor, so instead, a static method must be called to create a new object. There are a number of these factory methods available to create specific kinds of shapes (Point, Line String, Polygon, etc) given different kinds of input (text, byte arrays).

For simplicity, let’s use the .Parse() method, which accepts Well-Known Text (WKT) as input, and assumes a Spatial Reference ID of 4326 (the same coordinate system that GPS and internet mapping sites use).

Note: WKT uses a (Longitude, Latitude) ordering for points, which adheres to the same concept as (X, Y) ordering for Cartesian coordinates.

private static DbGeography CreatePoint(double latitude, double longitude)
{
return DbGeography.Parse(String.Format("POINT({1} {0})", latitude, longitude));
}



The first spatial query, written as a LINQ expression, finds the closest qualifying facility. Since SRID 4326 uses meters as the unit of measure, we need to convert 500 miles into meters within the predicate:

private Facility GetNearestFacilityToJobsite(DbGeography jobsite)
{
var q1 = from f in context.Facilities
let distance = f.Geocode.Distance(jobsite)
where distance < 500 * 1609.344
orderby distance
select f;

return q1.FirstOrDefault();
}



Assuming that a facility was returned, a second LINQ expression can be used to find the sum of Percentage from qualifying Formula Components:

private decimal SumQualifyingPercentages(Facility nearestFacility, DbGeography jobsite)
{
var q2 = from fc in nearestFacility.Formula.FormulaComponents
where fc.Geocode.Distance(jobsite) < 500 * 1609.344
select fc;

return q2.Sum(c => c.Percentage.GetValueOrDefault(0));
}



Finally, putting all of the parts together (using a Tuple<> for the output):

private Tuple<bool, decimal> GetResults(double latitude, double longitude)
{
DbGeography jobsite = CreatePoint(latitude, longitude);
Facility nearestFacility = GetNearestFacilityToJobsite(jobsite);

if (nearestFacility != null)
{
return new Tuple<bool,decimal>(true, SumQualifyingPercentages(nearestFacility, jobsite));
}

return new Tuple<bool, decimal>(false, 0);
}

private void PerformQuery()
{
double latitude = 47.63752;
double longitude = -122.13343;

var results = GetResults(latitude, longitude);
}

Entity Framework Spatial: DbGeography and DbGeometry Members

DbGeography Static Property Return Type DbGeometry Static Property Return Type
DbGeography.DefaultSrid int DbGeometry.DefaultSrid int
       
DbGeography Static Method Return Type DbGeometry Static Method Return Type
DbGeography.FromBinary(byte[] geographyBinary, int srid) DbGeography DbGeometry.FromBinary(byte[] geometryBinary, int srid) DbGeometry
DbGeography.FromGml(string geographyMarkup, int srid) DbGeography DbGeometry.FromGml(string geometryMarkup, int srid) DbGeometry
DbGeography.FromText(string geographyText, int srid) DbGeography DbGeometry.FromText(string geometryText, int srid) DbGeometry
DbGeography.GeographyCollectionFromBinary(byte[] geographyBinary, int srid) DbGeography DbGeometry.GeometryCollectionFromBinary(byte[] geometryBinary, int srid) DbGeometry
DbGeography.GeographyCollectionFromText(string geographyText, int srid) DbGeography DbGeometry.GeometryCollectionFromText(string geometryText, int srid) DbGeometry
DbGeography.LineFromBinary(byte[] geographyBinary, int srid) DbGeography DbGeometry.LineFromBinary(byte[] geometryBinary, int srid) DbGeometry
DbGeography.LineFromText(string geographyText, int srid) DbGeography DbGeometry.LineFromText(string geometryText, int srid) DbGeometry
DbGeography.MultilineFromBinary(byte[] geographyBinary, int srid) DbGeography DbGeometry.MultilineFromBinary(byte[] geometryBinary, int srid) DbGeometry
DbGeography.MultilineFromText(string geographyText, int srid) DbGeography DbGeometry.MultilineFromText(string geometryText, int srid) DbGeometry
DbGeography.MultipointFromBinary(byte[] geographyBinary, int srid) DbGeography DbGeometry.MultipointFromBinary(byte[] geometryBinary, int srid) DbGeometry
DbGeography.MultipointFromText(string geographyText, int srid) DbGeography DbGeometry.MultipointFromText(string geometryText, int srid) DbGeometry
DbGeography.MultipolygonFromBinary(byte[] geographyBinary, int srid) DbGeography DbGeometry.MultipolygonFromBinary(byte[] geometryBinary, int srid) DbGeometry
DbGeography.MultipolygonFromText(string geographyText, int srid) DbGeography DbGeometry.MultipolygonFromText(string geometryText, int srid) DbGeometry
DbGeography.Parse(string geographyText) DbGeography DbGeometry.Parse(string geometryText) DbGeometry
DbGeography.PointFromBinary(byte[] geographyBinary, int srid) DbGeography DbGeometry.PointFromBinary(byte[] geometryBinary, int srid) DbGeometry
DbGeography.PointFromText(string geographyText, int srid) DbGeography DbGeometry.PointFromText(string geometryText, int srid) DbGeometry
DbGeography.PolygonFromBinary(byte[] geographyBinary, int srid) DbGeography DbGeometry.PolygonFromBinary(byte[] geometryBinary, int srid) DbGeometry
DbGeography.PolygonFromText(string geographyText, int srid) DbGeography DbGeometry.PolygonFromText(string geometryText, int srid) DbGeometry
       
DbGeography Instance Property Return Type DbGeometry Instance Property Return Type
g.Area double? g.Area double?
    g.Boundary DbGeometry
    g.Centroid DbGeometry
    g.ConvexHull DbGeometry
g.Dimension int g.Dimension int
g.EndPoint DbGeography g.EndPoint DbGeometry
    g.Envelope DbGeometry
    g.ExteriorRing DbGeometry
g.GeometryType string g.GeometryType  
g.IsClosed bool? g.IsClosed bool?
g.IsEmpty bool g.IsEmpty bool
    g.IsRing bool?
    g.IsSimple bool
    g.IsValid bool
g.Latitude double?    
g.Length double? g.Length double?
g.Longitude double?    
g.M double? g.M double?
g.NumGeometries double? g.NumGeometries int?
    g.NumInteriorRing int?
g.NumPoints int? g.NumPoints int?
    g.PointOnSurface DbGeometry
g.ProviderValue object g.ProviderValue object
g.Srid int g.Srid int
g.StartPoint DbGeography g.StartPoint DbGeometry
g.WellKnownValue WellKnownValue DbGeographyWellKnownValue g.WellKnownValue DbGeometryWellKnownValue
g.WellKnownValue.Srid int g.WellKnownValue.Srid int
g.WellKnownValue.WellKnownBinary byte[] g.WellKnownValue.WellKnownBinary byte[]
g.WellKnownValue.WellKnownText string g.WellKnownValue.WellKnownText string
    g.X double?
    g.Y double?
g.Z double? g.Z double?
       
DbGeography Instance Method Return Type DbGeometry Instance Method Return Type
g.AsBinary() byte[] g.AsBinary() byte[]
g.AsGml() string g.AsGml() string
g.AsText() string g.AsText() string
g.Buffer(double distance) DbGeography g.Buffer(double distance) DbGeometry
    g.Contains(DbGeometry other) bool
    g.Crosses(DbGeometry other) bool
g.Difference(DbGeography other) DbGeography g.Difference(DbGeometry other) DbGeometry
g.Disjoint(DbGeography other) bool g.Disjoint(DbGeometry other) bool
g.Distance(DbGeography other) double g.DistanceDbGeometry other) double
g.GeometryN(int index) DbGeography DbGeography g.GeometryN(int index) DbGeometry
    g.InteriorRingN(int index) DbGeometry
g.Intersection(DbGeography other) DbGeography g.Intersection(DbGeometry other) DbGeometry
g.Intersects(DbGeography other) bool g.Intersects(DbGeometry other) bool
    g.Overlaps(DbGeometry other) bool
g.PointN(int index) DbGeography g.PointN(int index) DbGeometry
    g.Relate(DbGeometry other, string matrix) bool
g.SpatialEquals(DbGeography other) bool g.SpatialEquals(DbGeometry other) bool
g.SymmetricDifference(DbGeography other) DbGeography g.SymmetricDifference(DbGeometry other) DbGeometry
    g.Touches(DbGeometry other) bool
g.Union(DbGeography other) DbGeography g.Union(DbGeometry other) DbGeometry
    g.Within(DbGeometry other) bool

Entity Framework Spatial: First Look

Today, I began to look into the Entity Framework June 2011 CTP which includes first class support for Spatial data types.  The ADO.NET team created an abstraction layer, based on the OGC simple features specification, with a goal being to support spatial implementations from multiple vendors.  As you would expect, SQL Server 2008 Spatial is supported out of the box.

For some reason, I was expecting a lot of work to be done on the client-side within their abstraction data type.  I was pleasantly surprised to see EF pass the heavy lifting to the underlying data store as part of the query.

For instance, I have a table in my database called Facility with a Geography column named [Geocode].  This field contains a point (single latitude/longitude pair) identifying the location of the Facility.  Even though this would normally be represented in client-side code as a SqlGeography type, EF wraps it in the new DbGeography type (i.e., the abstraction data type for ellipsoidal data).

My first query was a LINQ expression to return a list of all facilities that are within 500 miles of a given location:

var q = from f in context.Facilities
let p = DbGeography.Parse("POINT(-83 45)")
where f.Geocode.Distance(p) < 500 * 1609.344
select new { f.FacilityID, wkt=f.Geocode.AsText() };


A couple things about this query:

  1. The default SRID of 4326 is used.  This spatial reference system uses meters for distance, so my predicate needs to convert the 500 miles into meters.  Like the SqlGeography.Parse() method, DbGeography.Parse() will default to 4326.
  2. The return type is an anonymous type.  I wanted to see how the DbGeography type's .AsText() method was executed (i.e., would it be expressed in the resulting query, or would it be handled client side, etc).

When executed, the LINQ expression above generates the following TSQL:

SELECT [Extent1].[FacilityID] AS [FacilityID],
[Extent1].[Geocode].STAsText() AS [C1]
FROM [dbo].[Facility] AS [Extent1]
WHERE ([Extent1].[Geocode].STDistance(geography::Parse(N'POINT(-83 45)'))) < cast(804672 as float(53))


As you can see, the DbGeography.AsText() was translated into the STAsText() method in the query.  And, as you might expect, the predicate's DbGeography.Distance() was properly translated into STDistance() in the TSQL WHERE clause.

The other thing that I was worried about was not having access to the actual SqlGeography type returned from the database.  I was surprised to see that EF's DbGeography has a property called ProviderValue that returns the native type that the provider supports!

Spatial Data and the Entity Framework

July 28, 2011 Note: This is an outdated post.  Recently, the ADO.NET team has released a CTP with Spatial support as a first class citizen of the Entity Framework!!!  See the following posts that I wrote as I explored the new API:

http://www.jasonfollas.com/blog/archive/2011/07/20/entity-framework-spatial-first-look.aspx

http://www.jasonfollas.com/blog/archive/2011/07/21/entity-framework-spatial-dbgeography-members.aspx

http://www.jasonfollas.com/blog/archive/2011/07/27/entity-framework-spatial-a-real-world-example.aspx


The Entity Framework does not support using User Defined Types (at least in the SQLCLR sense of the term) as properties of an entity. Yesterday, Julie Lerman contacted me to see if we could find a workaround to this current limitation, particularly for the SQL Server Spatial Types (Geometry and Geography).

Whenever I hear of someone wanting to use Spatial data in their application, my first thought is always “what do they want to do with the data once they have it?”  This is because most of the time (in my limited observation), an application does not need the spatial data itself, but rather, it just needs to use that data in the predicate of a query (i.e., the query results contain no spatial information).  For example, an application might want all zipcodes that are within 50 km of a point, but the application doesn’t need the actual shapes that define each zip code.

But, assuming that the developer knows what they are doing and has a legitimate reason to include a spatial type in the results, then how can they use the Entity Framework to get the spatial data into their application?  That was our quest.

Entity Framework Primitive Types

Admittedly, I know very little about EF.  So, my approach to this problem spent a lot of time using .NET Reflector to try to understand what the EF designer was doing behind the scenes (this also proved to be a a good way to understand EF better!).  The first thing that I wanted to figure out is how EF determines which primitive type to use for each SQL Server type. 

I downloaded and imported the States data from the US Census Data for SQL Server 2008 project on Codeplex.  Then, I used the Entity Data Model Designer in VS2010 to generate a model based on my database which resulted in an entity without the geometry property.  Looking at the XML for the .edmx file, I saw the following:

<!--Errors Found During Generation:warning 6005: The data type 'geometry' is not supported; the column 'geom' in table 'Spatial.dbo.State' was excluded.--> <EntityTypeName="State"> <Key> <PropertyRef Name="StateID"/> </Key> <Property Name="StateID" Type="int" Nullable="false"/> <Property Name="StateName" Type="nvarchar" Nullable="false" MaxLength="50"/> </EntityType>

 

I don’t believe that EF is hating on “geometry” specifically (the 6005 warning).  Rather, I think that if the SQL Server type cannot be mapped to a .NET type from the BCL, then it simply does not know how to handle it.  Certainly, they don’t want to try to map to a type that is not included in the .NET Framework itself (as would be the case for the Spatial data types).

But, what is EF using to determine the mappings?

I looked long and hard, but couldn’t quite figure out the mechanism that gets invoked when the model is generated.  But, I think the key might lie in the Microsoft.VisualStudio.Data.Providers.SqlServer.SqlMappedObjectConverter.GetFrameworkTypeFromNativeType() method:

// Disassembly by Reflector
protected override Type GetFrameworkTypeFromNativeType(string nativeType)
{
switch (this.GetProviderTypeFromNativeType(nativeType))
{
case 0:
return typeof(long);

case 1:
case 7:
case 0x13:
case 0x15:
return typeof(byte[]);

case 2:
return typeof(bool);

case 3:
case 10:
case 11:
case 12:
case 0x12:
case 0x16:
return typeof(string);

case 4:
case 15:
case 0x1f:
case 0x21:
return typeof(DateTime);

case 5:
case 9:
case 0x11:
return typeof(decimal);

case 6:
return typeof(double);

case 8:
return typeof(int);

case 13:
return typeof(float);

case 14:
return typeof(Guid);

case 0x10:
return typeof(short);

case 20:
return typeof(byte);

case 0x20:
return typeof(TimeSpan);

case 0x22:
return typeof(DateTimeOffset);
}
return typeof(object);
}

 

For SQL Server, the Native Types come from the System.Data.SqlDbType enumeration:

// Disassembly by Reflector
public enum SqlDbType
{
BigInt = 0,
Binary = 1,
Bit = 2,
Char = 3,
Date = 0x1f,
DateTime = 4,
DateTime2 = 0x21,
DateTimeOffset = 0x22,
Decimal = 5,
Float = 6,
Image = 7,
Int = 8,
Money = 9,
NChar = 10,
NText = 11,
NVarChar = 12,
Real = 13,
SmallDateTime = 15,
SmallInt = 0x10,
SmallMoney = 0x11,
Structured = 30,
Text = 0x12,
Time = 0x20,
Timestamp = 0x13,
TinyInt = 20,
Udt = 0x1d,
UniqueIdentifier = 14,
VarBinary = 0x15,
VarChar = 0x16,
Variant = 0x17,
Xml = 0x19
}

 

My conclusion here was that if the SQL Server type could only be mapped to System.Object in the BCL (using the GetFrameworkTypeFromNativeType() method), then EF will not support using that field as a property of the entity.  This coincides with the fact that to ADO.NET, the Geometry (and Geography) type is a User Defined Type (0x1d).

UPDATE: After all of this, I discovered that in System.Data.Entity.dll, there is a method that is probably a better candidate for what is actually used: System.Data.SqlClient.SqlProviderManifest.GetEdmType().  This method contains a similar switch{} as the code listed above, only it is EDM-specific instead of returning BCL types.  Feel free to examine it using Reflector if you're curious about its contents.

The Workaround

Having figured out that piece of the puzzle, I was left with trying to figure out a workaround.  If ADO.NET was unable to map a Geometry to a type in the BCL, then could we cast the Geometry as something that would be mappable?

SQL Server serializes spatial objects to binary when it saves the data in a table (documented here: http://msdn.microsoft.com/en-us/library/ee320529.aspx):

EF-Spatial-1

This binary data can be used to deserialize (“rehydrate”) the object in .NET code, which is exactly what SQL Server does when it needs to use the spatial objects.  So, we just need to find a way for EF to pull these down as a byte array.

Looking back at the GetFrameworkTypeFromNativeType function from above, it appears that EF will likely recognize Binary, Image, Timestamp, and Varbinary all as SQL Server types that need to map to byte arrays.  Perfect!

So, by creating a view in SQL Server that casts the Geometry column as a Varbinary(MAX), EF would recognize it as a type that could be mapped as an entity’s property.

CREATE VIEW vStates
AS SELECT StateID
, StateName
, CAST(geom AS VARBINARY(MAX)) AS geom
FROM dbo.State


 

Note: Julie had come up with this same solution at the same time, as our emails crossed paths reporting to one another.

Regenerating the EF model (using this view instead of the table) proved my assumption: the “geom” column now appeared as a Binary property of the vStates entity.

However, we’re not quite done yet.  The point of this exercise was to get an instance of the spatial type to use in our .NET application.  To do that, the Read(BinaryReader) instance method on SqlGeometry (or SqlGeography) must be invoked (using a MemoryStream as the intermediate between the byte[] and the BinaryReader).

The entire logic to retrieve the contents of the table and instantiate one of the Spatial types is as follows:

var entities = new SpatialEntities();
var vStates = entities.vStates;

// pull one of the entities from the collection
var geo2 = vStates.ToArray()[16];
var sqlGeom = new Microsoft.SqlServer.Types.SqlGeometry();

// Deserialize the bytes to rehydrate this Geometry instance
using (var stream = new System.IO.MemoryStream(geo2.geom))
{
using (var rdr = new System.IO.BinaryReader(stream))
{
sqlGeom.Read(rdr);
}
}

// Now let's prove that we have it. Dump WKT to Debug.
System.Diagnostics.Debug.Write(sqlGeom.ToString());

 

Output:

GEOMETRYCOLLECTION (LINESTRING (-99.530670166015625 39.132522583007812, -99.530670166015625 39.13250732421875), LINESTRING (-99.791290283203125 39.131988525390625, -99.791290283203125 39.131973266601562), …

So it worked!

Finally, an extension method would make this code a bit more general purpose:

public static class Extension
{
public static Microsoft.SqlServer.Types.SqlGeometry AsSqlGeometry(thisbyte[] binary)
{
var ret = new Microsoft.SqlServer.Types.SqlGeometry();

using (var stream = new System.IO.MemoryStream(binary))
{
using (var rdr = new System.IO.BinaryReader(stream))
{
ret.Read(rdr);
}
}

return ret;
}
}

 

The test code above then becomes a bit more readable after the refactoring:

var entities = new SpatialEntities();
var vStates = entities.vStates;

// pull one of the entities from the collection
var geo2 = vStates.ToArray()[16];
var sqlGeom = geo2.geom.AsSqlGeometry();

// Now let's prove that we have it. Dump WKT to Debug.
System.Diagnostics.Debug.Write(sqlGeom.ToString());

 

Helpful information: