Andrew Rea
-
Compiling examples for consuming the REST Endpoints for WCF Service using Agatha
I recently made two contributions to the Agatha Project by Davy Brion over on Google Code, and one of the things I wanted to follow up with was a post showing examples and some, seemingly required tid bits. The contributions which I made where:
- To support StructureMap
- To include REST (JSON and XML) support for the service contract
The examples which I have made, I want to format them so they fit in with the current format of examples over on Agatha and hopefully create and submit a third patch which will include these examples to help others who wish to use these additions.
Whilst building these examples for both XML and JSON I have learnt a couple of things which I feel are not really well documented, but are extremely good practice and once known make perfect sense. I have chosen a real basic e-commerce context for my example Requests and Responses, and have also made use of the excellent tool AutoMapper, again on Google Code.
Setting the scene
I have followed the Pipes and Filters Pattern with the IQueryable interface on my Repository and exposed the following methods to query Products:
IQueryable<Product> GetProducts();
IQueryable<Product> ByCategoryName(this IQueryable<Product> products, string categoryName)
Product ByProductCode(this IQueryable<Product> products, String productCode)
I have an interface for the IProductRepository but for the concrete implementation I have simply created a protected getter which populates a private List<Product> with 100 test products with random data. Another good reason for following an interface based approach is that it will demonstrate usage of my first contribution which is the StructureMap support. Finally the two Domain Objects I have made are Product and Category as shown below:
public class Product { public String ProductCode { get; set; } public String Name { get; set; } public Decimal Price { get; set; } public Decimal Rrp { get; set; } public Category Category { get; set; } }public class Category { public String Name { get; set; } }Requirements for the REST Support
One of the things which you will notice with Agatha is that you do not have to decorate your Request and Response objects with the WCF Service Model Attributes like DataContract, DataMember etc… Unfortunately from what I have seen, these are required if you want the same types to work with your REST endpoint. I have not tried but I assume the same result can be achieved by simply decorating the same classes with the Serializable Attribute. Without this the operation will fail.
Another surprising thing I have found is that it did not work until I used the following Attribute parameters:
- Name
- Namespace
e.g.
[DataContract(Name = "GetProductsRequest", Namespace = "AgathaRestExample.Service.Requests")] public class GetProductsRequest : Request { }Although I was surprised by this, things kind of explained themselves when I got round to figuring out the exact construct required for both the XML and the REST. One of the things which you already know and are then reminded of is that each of your Requests and Responses ultimately inherit from an abstract base class respectively. This information needs to be represented in a way native to the format being used. I have seen this in XML but I have not seen the format which is required for the JSON.
JSON Consumer Example
I have used JQuery to create the example and I simply want to make two requests to the server which as you will know with Agatha are transmitted inside an array to reduce the service calls. I have also used a tool called json2 which is again over at Google Code simply to convert my JSON expression into its string format for transmission. You will notice that I specify the type of Request I am using and the relevant Namespace it belongs to. Also notice that the second request has a parameter so each of these two object are representing an abstract Request and the parameters of the object describe it.
<script type="text/javascript"> var bodyContent = $.ajax({ url: "http://localhost:50348/service.svc/json/processjsonrequests", global: false, contentType: "application/json; charset=utf-8", type: "POST", processData: true, data: JSON.stringify([ { __type: "GetProductsRequest:AgathaRestExample.Service.Requests" }, { __type: "GetProductsByCategoryRequest:AgathaRestExample.Service.Requests", CategoryName: "Category1" } ]), dataType: "json", success: function(msg) { alert(msg); } }).responseText; </script>XML Consumer Example
For the XML Consumer example I have chosen to use a simple Console Application and make a WebRequest to the service using the XML as a request. I have made a crude static method which simply reads from an XML File, replaces some value with a parameter and returns the formatted XML. I say crude but it simply shows how XML Templates for each type of Request could be made and then have a wrapper utility in whatever language you use to combine the requests which are required. The following XML is the same Request array as shown above but simply in the XML Format.
<?xml version="1.0" encoding="utf-8" ?> <ArrayOfRequest xmlns="http://schemas.datacontract.org/2004/07/Agatha.Common" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <Request i:type="a:GetProductsRequest" xmlns:a="AgathaRestExample.Service.Requests"/> <Request i:type="a:GetProductsByCategoryRequest" xmlns:a="AgathaRestExample.Service.Requests"> <a:CategoryName>{CategoryName}</a:CategoryName> </Request> </ArrayOfRequest>It is funny because I remember submitting a question to StackOverflow asking whether there was a REST Client Generation tool similar to what Microsoft used for their RestStarterKit but which could be applied to existing services which have REST endpoints attached. I could not find any but this is now definitely something which I am going to build, as I think it is extremely useful to have but also it should not be too difficult based on the information I now know about the above. Finally I thought that the Strategy Pattern would lend itself really well to this type of thing so it can accommodate for different languages.
I think that is about it, I have included the code for the example Console app which I made below incase anyone wants to have a mooch at the code. As I said above I want to reformat these to fit in with the current examples over on the Agatha project, but also now thinking about it, make a Documentation Web method…{brain ticking} :-)
Cheers for now and here is the final bit of code:
static void Main(string[] args) { var request = WebRequest.Create("http://localhost:50348/service.svc/xml/processxmlrequests"); request.Method = "POST"; request.ContentType = "text/xml"; using(var writer = new StreamWriter(request.GetRequestStream())) { writer.WriteLine(GetExampleRequestsString("Category1")); } var response = request.GetResponse(); using(var reader = new StreamReader(response.GetResponseStream())) { Console.WriteLine(reader.ReadToEnd()); } Console.ReadLine(); } static string GetExampleRequestsString(string categoryName) { var data = File.ReadAllText(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ExampleRequests.xml")); data = data.Replace("{CategoryName}", categoryName); return data; } }Posted by Andrew Rea on March 09 at 4:43 PMComments (0)
-
A BinaryContentResult for ASP.NET MVC
Today in work I had a requirement where I wanted to output binary content to the response output stream. I also want to stay with the MVC Controller for serving this content and so wanted a result I could add my data to and return it. To my knowledge there is a ContentResult, but with this the Content property is of type string, and is not what I wanted. I this particular case, I am physically GZipping content and then writing out to the Response.OutputStream.
Previous to this I have been seeing and using examples where you assign a GZipOutputStream as a Filter on the Response dynamically. For some strange reason on the Live environment the header and filter where being ignored on the response yet on the test, builds and sandbox everything worked as expected and the dynamic resources got GZipped.
So I had to go another way and what I came up with was to physically GZip the output content and send it to the response with the accompanying header. I cannot see why this would not work on the server as the content is physically being served already GZipped opposed to applying a filter which can obviously be removed somewhere in the pipeline. Any way after some reading I found some evidence that a library, http://www.icsharpcode.net/OpenSource/SharpZipLib/ , yields far better results than the out of the box one from .NET, so for this example I have a dependency on this assembly. Apart from that I have added a couple of properties which allow for the conditional Compression and also a list of headers to give a little more flexibility. So here is the code:
/// <summary> /// A content result which can accept binart data and will write to the output /// stream. If GZip is set to true the content will be GZipped and the relevant /// header added to the response HTTP Headers /// </summary> public class BinaryContentResult : ActionResult { public byte[] Data { get; set; } public NameValueCollection Headers { get; set; } public bool Gzip { get; set; } public override void ExecuteResult(ControllerContext context) { foreach (string s in Headers.Keys) { context.HttpContext.Response.AddHeader(s, Headers[s]); } if (Gzip) { using (var os = new GZipOutputStream(context.HttpContext.Response.OutputStream)) { os.Write(Data, 0, Data.Length); } context.HttpContext.Response.AddHeader("Content-Encoding", "gzip"); context.HttpContext.Response.AddHeader("X-Compressed-By", "Custom-Compressor"); } else { context.HttpContext.Response.BinaryWrite(Data); } context.HttpContext.Response.End(); } }Posted by Andrew Rea on February 16 at 1:29 PMComments (0)
-
A StructureMap Container For Agatha
If you have not read about it yet or seen it or used it, please visit Davy Brion's Blog here and download the Agatha project. Another link I need to mention is the following, Integrating Strcuture Map With WCF. Basically what I have attempted to do is create an Agatha.Common.InversionOfControl.IContainer implementation for Agatha which uses StrcutureMap as the IOC Container. I am also not hosting the WCF Service inside a Web Application but in an actual WCF Service Application which I wanted to use the Service Host Factory as demoed in the above link.
The implementation for the Container was relatively straight forward in most parts and allowed me to use some newer features of StructureMap which I do not currently use yet in my job; well I say newer, newer to me!!. I have read on Davy Brion's blog that he is intending to write this Agatha IOC Container for Structure Map, and I look forward to it, but in the mean time I thought I would have a crack at it myself.
While writing the Container for StructureMap I had to make a small change/addition to the Agatha source code, on the interface for the IContainer to make sure that a method had a generic type constraint. The method:
void Register<TComponent,TImplementation>()
A compile time error was raised which stated that there was no information to allow for boxing/unboxing. To solve this I added the following constraint:
void Register<TComponent,TImplementation>() where TImplementation : TComponent
Once added the compile time error went, but I was still left with another issue which at this stage of writing this post I am of the opinion that I need to also make a small addition to StructureMap. I look forward to it, if it is not already available but it would be good to find out that it is already accounted for. The operation which I am talking about is the removal of an instance from the IOC Container. The interface for the Agatha IOC IContainer has a method called Release which takes an object instance as a parameter and with the Castle WInsor you can release an instance.
public interface IContainer { void Register<TComponent, TImplementation>(Lifestyle lifestyle) where TImplementation : TComponent; void Register(Type componentType, Type implementationType, Lifestyle lifeStyle); void RegisterInstance<TComponent>(TComponent instance); void RegisterInstance(Type componentType, object instance); void Release(object component); TComponent Resolve<TComponent>(); object Resolve(Type componentType); }…
After doing a bit more searching I cannot find a function which fits this criteria exactly. There is the EjectAllInstancesOf<T> method, but the one I ended up using is the following:
public void Release(object component) { //throw new NotImplementedException(); _strcutureMapContainer.Model.EjectAndRemove(component.GetType()); }This is a method on the IContainer interface and I am using the component to get its type and releasing all instances of it within the IOC Container. I am not 100% sure this is what other implementation of IOC are doing with this particular type of function. Never the less, this does work fine and I am now up and running with the Agatha library inside a WCF Service Application Project using a ServiceHostFactory and configuring a StructureMap IOC Container for use with Agatha.
I have not made the most consistent approach to the StructureMap usage as I have mixed preferred and deprecated methods. This is because I am not 100% sure how to map the new style of Lifeycle management between Castle Windsor and StructureMap. I look forward to seeing the actual implementation which goes into the Agatha project so I can see where I could have improved my attempt. Here is the finished code of my attempt.
Hope this is of some help,
Cheers,
Andrew
using System; using System.Collections.Generic; using System.Linq; using System.Web; using sm = StructureMap; using Agatha.Common.InversionOfControl; namespace Agatha.StructureMap { public class Container : Agatha.Common.InversionOfControl.IContainer { private readonly sm.IContainer _strcutureMapContainer; private Dictionary<Lifestyle, sm.InstanceScope> _lifeStyleMappings = new Dictionary<Lifestyle, sm.InstanceScope> { {Lifestyle.Singleton, sm.InstanceScope.Singleton}, {Lifestyle.Transient, sm.InstanceScope.Transient} }; private Dictionary<Lifestyle, sm.Pipeline.ILifecycle> _lifeStyleLifeCycleMappings = new Dictionary<Lifestyle, sm.Pipeline.ILifecycle> { {Lifestyle.Singleton, new sm.Pipeline.SingletonLifecycle()}, {Lifestyle.Transient, new sm.Pipeline.UniquePerRequestLifecycle()} }; public Container() : this(new sm.Container()) { } public Container(sm.IContainer structureMapContainer) { _strcutureMapContainer = structureMapContainer; } public void Register(Type componentType, Type implementationType, Lifestyle lifeStyle) { _strcutureMapContainer.Configure(x => x.For(componentType).LifecycleIs(_lifeStyleMappings[lifeStyle]).Use(implementationType)); } public void Register<TComponent, TImplementation>(Lifestyle lifestyle) where TImplementation:TComponent { _strcutureMapContainer.Configure(x => x.ForRequestedType<TComponent>() .CacheBy(_lifeStyleMappings[lifestyle]) .TheDefaultIsConcreteType<TImplementation>()); } public void RegisterInstance(Type componentType, object instance) { _strcutureMapContainer.Configure(x => x.ForRequestedType(componentType).Use(instance)); } public void RegisterInstance<TComponent>(TComponent instance) { _strcutureMapContainer.Configure(x => x.For<TComponent>().Use(instance)); } public TComponent Resolve<TComponent>() { return _strcutureMapContainer.GetInstance<TComponent>(); } public object Resolve(Type componentType) { return _strcutureMapContainer.GetInstance(componentType); } public void Release(object component) { //throw new NotImplementedException(); _strcutureMapContainer.Model.EjectAndRemove(component.GetType()); } } }Posted by Andrew Rea on February 10 at 4:16 PMComments (0)
-
Duel Booting Linux and Windows 7
I want to get a few blog posts out of the way as I have left off blogging until I had a suitable Syntax Highlighter plug-in for Windows Live Writer.
This morning whilst I am literally inside VS 2010 developing, the computer froze, restarted and then informed me that it could not find a valid boot sector…joy! Once this happened following my other computer blowing up and the laptop being on the fritz I thought I would finally take the plunge and get on with using Linux, more than that I want to use Linux and Windows i.e. Duel Boot.
Before I started however I needed to backup the files that I had on the hard drive which has just gone west, this hard drive is a PATA and all the external enclosures I have are for SATA. So one small purchase was an external enclosure for this which only set me back 17.00GBP, bonus. I have another of these PATA hard drive which I had previously tried to install CENT OS onto and it went wrong, period; so with this new hardware I was easily able to wire up and format, bang back into the desktop and boot from CD.
Installing Ubuntu next to Windows 7
IMPORTANT : Install Windows first. I have been told this in person and also read about it afterwards, please read up about the WHY? but either way, it is better with Windows first.
- Install Windows
- Go to Computer Management inside Administrative Tools
- Right click on your main volume which windows is installed on
- Select, Shrink Volume.
After the process calculates how much space it can reduce the volume by, you can select the size of the reduction and in turn giving the amount of space you will be left with on the new partition.
Once complete, restart your computer.
NEXT:
- Insert your Ubuntu disk which you download and burned the ISO to disk
- Close any dialogue it raises for the Auto Run and then restart your machine again
- This should now boot into Ubuntu automatically assuming you allow booting from CD/DVD in the bios.
- Select the second option which is to install Ubuntu and then follow through the steps until you get to the partition manager.
The top line should inform you that it has found WIndows 7 already on your computer, and beneath that it gives you an option to install Ubuntu side by side to this. This is the option you want and after selection continue and confirm all the changes to be written to disk. Continue through the confirmation dialogues until completion.
On Restart
After the above is complete you get a really useful boot screen where you can select to boot Ubuntu or Windows. I am well impressed with this and cannot believe I have not done this sooner.
I am a total newcomer to the Linux scene, but so far so good. One small thing which I would point out is the apparent lack of a desktop blog publishing tool with equal capabilities and extensibility as Windows Live Writer. But hey, reboot, load windows and blog there… for now lol!!
Cheers for now,
Andrew
Posted by Andrew Rea on January 25 at 1:28 PMComments (0)
-
Creating a similar Microsoft ASP.NET MVC 1.0 project template with Django and the Google App Engine
Due to a home dev project I am currently involved in with another contributor, called byteface, it has lead me to using the Google AppEngine and specifically the Python flavour as opposed to the Java flavour. I chose Python as I am enjoying further exposure to different programming languages. The Django framework is nearly entirely supported on the Google AppEngine with some modules omitted due to either security considerations or conflict. Both the DJango framework and the Google AppEngine have their own ORM, so this is one of the module omissions where you have to use the Google ORM, (wonder if they ever thought of doing GHibernate ;-)).
Another point to make also is that you can choose to use the
Google http handler functions or DJango's. I have gone with
Django's so I can get a complete experience of the framework and
utilise all of the powerful utilities and features.In this post I want to show how you can emulate the project structure of a default ASP.NET MVC 1.0 application, i.e. File -> New -> ASP.NET MVC Application inside Visual Studio. The image on the right is an example of one freshly created, all I have done is remove any references to Account, as for the purposes of this example I just want to emulate the core things like structure and behaviour.
The following are considerations which I need to think about in order to emulate Microsoft's ASP.NET implementation of MVC including:
- Master page templates
-
- i.e. Site.Master
- Static content
- Routing
- Controller Actions
-
- Including HTTP Verb restrictions
- General layout
Off the top of my head one thing which will need to be an add in is the routing, as this is due to one of the rules/principles of python:
Explicit is better than implicit
So basically in the context of routing, we would have to define all of our routes as opposed to what we can do in ASP.NET MVC and have a route to match the {controller}/{action}/{id} url pattern. From a little research I did, Ruby on Rails also has this out of the box. So I am not sure if I will be able to manage this part of the project in this post, so when I find a robust way of doing it inside Django I will again post something about it. It may be the case I stick with the explicit route and conform to the Zen of Python(>>> import this).
Google App Engine SDK Console
If you have not done already, you will need to download the SDK and create the application. I am using the GUI for this, so download and create an application. The folder structure should have been created for you. In the case of this example I named my application narbley and in return in created the following folder structure inside my app engine source path:
- narbley
-
- narbley
So it created a folder with the same name inside this folder with the relevant application files for Google App Engine. Because I want to use the Django framework, I deleted the nested narbley folder as I will create this using the django-admin utility.
To create the base django app files I ran the following cmd from inside my application folder:
django-admin-py startproject narbley
What is narbley? Simply a code name for this project I am working on with a fellow contributor. It is a codename for many reasons including, we are not 100% sure on what we are building yet, that and it is very difficult to find a name for a Google AppEngine … App which is not taken, so we tried to be abstract, and failing that we simply kept adding a letter to the end and trying it, hence narbley was created.
Also you will need to follow this short how to, to use the Django Framework completely over the Google one, http://code.google.com/appengine/articles/django.html
The Home Controller
From what I have seen, in Python and Django the views are actually a front controller. I would not class the function which handles the request the view, in the context of DJango I would regard the templates as the views, the controller as the front controller with the different actions on and the model, the model.
For the http verb restriction you find in the ASP.NET MVC 1.0 implementation, I did some searching about and actually came back to finding that one has already been written in DJango and its usage should very familiar to you.
from django.template import Context, loader from django.http import HttpResponse from django.views.decorators.http import require_http_methods 12 @require_http_methods(["GET"]) def index(request): t = loader.get_template('home/index.html') c = Context({ 'message': "Welcome to the Django Framework on the Google App Engine" }) return HttpResponse(t.render(c)) @require_http_methods(["GET"]) def about(request): t = loader.get_template('home/about.html') c = Context({ 'message': "Narbley is the codename" }) return HttpResponse(t.render(c))Great so that is the index and the about page sorted. One thing I will point out here is a point with regards to how python handles namespaces/file structure/packages or how ever you want to call the equivalent. I have created a folder called controllers and inside I have a file called homecontroller.py. I also need to add the file __init__.py . Unfortunately as of this moment I cannot tell you why, only that I know it requires it, and subsequently I think for any other folder nesting.
Master/Content Page Templates
These are self explanatory and their implementation quite similar, with a simple change to the import and the syntax of course. From my experience to date, the DJango templates require the .html extension whether they are content or master. You need to add a reference to any folders which will be deemed as template folders inside the settings.py file, i.e.:
ROOT_PATH = os.path.dirname(__file__) TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. ROOT_PATH + '/views', )Inline with the project files from a default ASP.NET MVC Project I have simply copied and changed the files to use the DJango templating syntax, notice how:
- The content placeholders are defined
- The master page is defined and referenced
The master page (views/shared/master.html)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head runat="server"> <title>{% block title %}{% endblock %}</title> <link href="/content/site.css" rel="stylesheet" type="text/css" /> {% block css_includes %}{% endblock %} {% block script_includes %}{% endblock %} </head> <body> <div class="page"> <div id="header"> <div id="title"> <h1>My MVC Application</h1> </div> <div id="menucontainer"> <ul id="menu"> <li><a href="/home/">Home</a></li> <li><a href="/home/about/">About</a></li> </ul> </div> <br style="clear:both"/> </div> <div id="main"> {% block content %}{% endblock %} <div id="footer"> {% block footer %}{% endblock %} </div> </div> </div> </body> </html>The homepage (views/home/index.html)
I am only attaching the code for the homepage as the about page is very similar.
{% extends "shared/master.html" %} {% block title %}DJango Example{% endblock %} {% block css_includes %}{% endblock %} {% block script_includes %}{% endblock %} {% block content %} <p>{{ message }}.</p> {% endblock %} {% block footer %} Footer here {% endblock %}
Apart from that there is just the default application files
required by Python/DJango and Google App Engine. I am currently
looking into:- Routing
- Extension less Urls
- JSON support libraries in Python
- The Message Queue of the Google App Engine
The resulting project structure for the base project is shown on the right. I opened the website inside Visual Studio to see the structure, not for editing lol.
I should have deleted it but I have not, the http_methods file is not used, I forgot to delete.
Cheers,
Andrew
Posted by Andrew Rea on December 19 at 10:09 PMComments (2)
-
An idea relating to, exposing the resource files of different assemblies for consumption by the client side
Files
Please download the example solution for this post from the following url.
http://lab.andrewrea.co.uk/ResourcesExampleMvc.rar
Summary
Ok, I have been writing this one as I went, whilst thinking and deving so my opinion on this has changed from when I started writing this to what I ended up with and I have to say I am quite chuffed with the outcome as it yields some other possibilities which I want to now blog about, but to cut a long story/blog post short I have made a Http Handler which accepts some parameters so it can locate a resource file, enumerate through its properties and output them as JavaScript variables to the Response Output Stream. This allows me to expose resources the application is using to client script so I am not duplicating any of them and making maintenance and additions much easier.
I have also wrapped in a bit of token based security, although I do kind of ensure that what is attempted to be enumerated is a resource file by passing the type into a ResourceManager I have added the token based security regardless. Another good option would be to encrypt the url like the common .axd resource handler does, but either way I have used a token based approach using HMAC and SHA1.
Example usage:
<%= Html.ClientResourceLink<ResourcesExampleMvc.Core.Resources.Global>("jsloc.axd","fr") %>Example output:
<script type="text/javascript" src="/jsloc.axd?typeName=ResourcesExampleMvc.Core.Resources.Web.Controllers.Home.Home&culture=fr&token=2E935FA9EF23865A9A57B437EC9A7CCE62A7712B×tamp=1260744495"></script>
The handler at work:
var cache_date = "13 December 2009 23:57"; var GlobalString1 = "French Global String 1";
Finally I have made a HtmlHelper which will generate the relevant link / links I need. So the blog that I started writing, dev'd and changed my mind…
here goes…
I have been looking at different examples on the web relating to client side localisation. The two main points I see are:
- Add secondary resources inside JavaScript files (This leads to duplication of resources)
- Make a call to the Resource Manager inside delimiters inside the mark-up. (This is fine as long as you are not using separate JavaScript Files)
I might be wrong, but from what I can see on the Resource Manager, there is only a set way of getting access to a resource, and that is by its name, so if I want to get several related items, I need to know the keys of each. As I am writing this I am now starting to think if what I originally wanted to do is as efficient as I first thought.
Basically I thought that inside each Resource file that is defined, each key could be prefixed with some kind of grouping information, e.g. HomeController , so I could have the following keys:
- HomeController_WelcomeText
- HomeController_Button1
- HomeController_Button2
With this I then thought of making a way to query the resources, so I could apply a prefix and then get in return all matched keys. I would do this by reflection and looping over each property, storing its name and value.
So to summarise I was stuck in the way of thinking one resource file and differentiating based on the string key. DOH!, thinking about it now, I think the best and most clean solution is to use a separate resource file per each localisable entity i.e. a Form, or Controller etc… If you think about it also, this will make things much more organised when you get to a point where you have thousands of resources. Having them logically separated in line with the entity which will be localised makes good sense. Not only that it also make the task I was thinking about much easier.
The Idea
If you think about ASP.NET MVC for example, and the following. You will always have resources which are common or global and then you will have resources which are specific to a certain part of the project, e.g. Home Controller.
I want to be able to output any localisation that I need so that I can consume with JavaScript without any unnecessary AJAX calls. More so I only want to output the required keys from the global resources and the resources specific to the area which it is currently being executed, i.e. Home Controller.
The format which I am thinking for the output of the client side localisation is simply a included JavaScript file with the contents simply declared variables which match the name of those inside the resource files i.e.
var Global_Resource_Key_1 = "Hello World"; var Global_Resource_Key_2 = "Hello Galaxy"; var Local_Resource_Key_1 = "Local Number 1"; var Local_Resource_Key_2 = "Local Number 2";
Going back to what I said above, these will be output by a method using reflection to iterate through each of its properties to then generate the required output. Once the iteration has complete it would be wise to store the resulting collection in Cache or Application object. I am thinking that the generation of the script will be using a HttpHandler, allowing for the variables to be dynamic inside the mark-up and script declaration.
Thinking about it more, this is exactly why we are given the special .NET folders of :
- App_GlobalResources
- App_LocalResources
These are great, but, I need to have the resource files inside another assembly so that they can be referenced both from the web and also internally from the calling assembly. So inside a test project I have done the following to setup:
- Create a MVC Application
-
- Delete the Account View and Controllers
- Move the Controllers, Global.asax.cs and Models to the Class Library project
- Create a separate Class Library Project
-
- Create a folder for resources
- Create a Global Resources and also a Resource file per Controller with the relevant folder structure
- Created a Configuration folder and class to handle the secret key for hmac'ing and cache timeout
- Created an Extension Method folder and HtmlHelper class which will be a shortcut for the deveoper to use which will generate the link
- Created a HttpHandlers folder and the actual handler which I will use to generate and cache the relevant properties
Also, I have omitted any DI/IOC for the purposes of this example. I will go through each of the Class Library project sections separately.
Create a folder for resources & Create a Global Resources and also a Resource file per Controller with the relevant folder structure
Having a separate folder in the resource means I can consume these from the web application but also from any models which are inside the assembly or business data for example where I may state the resource for validation attributes like those used in the DataAnnotations or the MVAB (Microsoft Validation Application Block).
I have but the global resource file directly inside this folder and then created sub folders to reflect different parts of the application which the one being in this instance, Web and then even further by controller. I think grouping the resources by Controller for the web is a logical step, and along with a global resource file, you are pretty much covered.
When you build the solution, .NET will logically group your assemblies by culture, so have many resource files still means they will compile down into one assembly, which is great.
Created a Configuration folder and class to handle the secret key for hmac'ing and cache timeout
I could quite as easily have used the AppSettings but I thought that it would be good to give this attempt its own configuration section, which I could extend and keep encapsulated in the future. The two things which I am using this section for at the moment is to store the key I will use to generate the HMAC hashes and also the sliding timeout for the cache of the resources. The secret key can be anything you want, but I needed it in a centralised place so i can ensure the same one is used to generate and also compare. There is not much to the Configuration Section accept a couple of required attributes and the syntax for retrieving the value declared in the config file.
<clientResourceConfiguration resourceSlidingTimeout="20" resourceHmacKey="470F0BE4675941baBEFBC1134CC1FEAF28C47C15D71543b8A9F57360CFFCD33B"/>The secret key / resourceHmacKey here is simply two GUIDs stripped of the curlies and dashes and concatenated together. To reference this configuration inside the code, I have placed a static property on the MvcApplication class inside the Global.asax.cs file. Seemed like a logical place to put it, and of course made it a singleton.
public class MvcApplication : System.Web.HttpApplication { private static ClientResourceConfiguration _clientResourceConfiguration = null; public static ClientResourceConfiguration ClientResourceConfiguration { get { if (_clientResourceConfiguration == null) { _clientResourceConfiguration = (ClientResourceConfiguration)ConfigurationManager.GetSection("clientResourceConfiguration"); } return _clientResourceConfiguration; } } ...Created an Extension Method folder and HtmlHelper class which will be a shortcut for the developer to use which will generate the link
This is simply to make it easier for the developer to create the link. You can simply add the type you want to parse, the name of the handler which is mapped in the config file and the culture. In this implementation I have designed it to expect the two letter culture name and then go on to resolve the specific culture. I know it would have been easier to just specify the specific culture but I dev'd this with a work related problem I had and wanted to simulate the environment in which I have to work with.
I have created an overloaded method so that if I need to I can force clear the cache for a specific handler. As I will show you further down I also output the date it was cached, again simply for diagnostic purposes.
The token here is simply so i can be sure that the resource file which is being requested has been authorized by the server, as it is the server which is the only entity that has the secret key and can create such links. I have included a timestamp which makes the HMAC hash different each time. The validation of this token will only occur if the requested resource is not in the cache, as I make the assumption that is if it is in the cache, then it has to have been generated for a valid reason by the server.
Oh and there is a small method in there I found on Brad Abrams site which simply gives me back the number of seconds since 1970, which acts as a timestamp.
public static class HtmlHelpers { public static string ClientResourceLink<T>(this HtmlHelper helper, string handler, string twoLetterCultureName) { return ClientResourceLink<T>(helper, handler, twoLetterCultureName, true); } public static string ClientResourceLink<T>(this HtmlHelper helper, string handler, string twoLetterCultureName, bool cache) { var typeName = typeof(T).FullName; var timeStamp = GetTimeStamp().ToString(); var valueToHash = String.Concat(typeName, twoLetterCultureName, timeStamp); var token = CryptoHelper.Hmac(valueToHash, MvcApplication.ClientResourceConfiguration.ResourceHmacKey, HashType.SHA1); var url = String.Format("~/{0}?typeName={1}&culture={2}&token={3}×tamp={4}", handler, typeName, twoLetterCultureName, token, timeStamp); if (!cache) { url += "&cache=ncache"; } return String.Format("<script type=\"text/javascript\" src=\"{0}\"></script>", new UrlHelper(helper.ViewContext.RequestContext).Content(url)); } /// <summary> /// From Brad Abrams : http://blogs.msdn.com/brada/archive/2004/03/20/93332.aspx /// </summary> /// <returns></returns> private static int GetTimeStamp() { TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1)); int timestamp = (int)t.TotalSeconds; return timestamp; } }The CryptoHelper class is one which "I made earlier," and which I blogged about here http://www.andrewrea.co.uk/2009/10/05/ACryptographyHelperClassForHashingAndForKHMACKeyedHashMessageAuthenticationCode.aspx. It is simply a helper method wrapping around some types and methods inside the System.Security.Cryptography namespace. You will see some example usages in the summary above.
Created a HttpHandlers folder and the actual handler which I will use to generate and cache the relevant properties
This is basically the crooks of the solution and it is the handler. I have used the .axd extension simply because it is already recognised and is ignored my the MVC route handler.
Below is the entry I have used to configure the Http Handler for GET only and an example path to map it to
<add verb="GET" path="/jsloc.axd" validate="false" type="ResourcesExampleMvc.Core.HttpHandlers.ClientSideResourceHttpHandler,ResourcesExampleMvc.Core" />
It is in this class where I handle:
- The parameters passed in
- The validation of the token
- The cache of the resources for the client
- The generation of the resources
I simply set the Response.ContentType to text/javascript and then write out the information through a StreamWriter. The first variable I add is the CacheDate and then followed by the resources themselves, as they appear inside the resource file. A point to mention here is if you have defined any of the keys in the resource files with spaces in they will be replaced with underscores.
Major Point : You must set the scope of your Resource File, which ever one you want the Handler to parse as Public, this is due to me put Binding Flags on the reflection as Public and Static. I suppose I could have added Internal, but not sure, so I will leave for now as Public.
public class ClientSideResourceHttpHandler : IHttpHandler { #region IHttpHandler Members public bool IsReusable { get { return true; } } public void ProcessRequest(HttpContext context) { string typeName = context.Request.QueryString["typeName"]; string twoLetterCultureName = context.Request.QueryString["culture"]; string token = context.Request.QueryString["token"]; string timestamp = context.Request.QueryString["timestamp"]; string nocache = context.Request.QueryString["nocache"]; var timeout = MvcApplication.ClientResourceConfiguration.ResourceSlidingTimeout; string key = GetKey(typeName, twoLetterCultureName); if (context.Cache[key] == null || !String.IsNullOrEmpty(nocache)) { var type = Type.GetType(typeName); var resourceManager = new ResourceManager(type); if (!ValidateToken(typeName, twoLetterCultureName, timestamp, token)) throw new SecurityException("Invalid token submitted for client resource"); var list = new List<KeyValuePair<string, string>>(); var properties = type.GetProperties( System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); foreach (var property in properties) { if (property.PropertyType == typeof(string)) { list.Add( new KeyValuePair<string, string>(property.Name, resourceManager.GetString(property.Name.Replace("_", " "), GetCulture(twoLetterCultureName)) ) ); } } context.Cache.Insert(key, list, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(timeout)); } context.Response.ContentType = "text/javascript"; WriteOutClientResources(context.Response.OutputStream, (List<KeyValuePair<string, string>>)context.Cache[key]); context.Response.End(); } #endregion private void WriteOutClientResources(Stream outputStream, List<KeyValuePair<string, string>> values) { using (var sw = new StreamWriter(outputStream)) { sw.WriteLine(String.Format("var cache_date = \"{0}\";", DateTime.Now.ToString("f"))); foreach (var item in values) { sw.WriteLine(String.Format("var {0} = \"{1}\";", item.Key, item.Value)); } sw.Flush(); } } private bool ValidateToken(string typeName, string twoLetterCultureName, string timestamp, string token) { var valueToHmac = String.Concat(typeName, twoLetterCultureName, timestamp); var valueToCompare = CryptoHelper.Hmac(valueToHmac, MvcApplication.ClientResourceConfiguration.ResourceHmacKey, HashType.SHA1); return valueToCompare.Equals(token); } private string GetKey(string controllerName, string twoLetterCultureName) { return String.Format("{0}!{1}", controllerName, twoLetterCultureName); } private CultureInfo GetCulture(string twoLetterCultureName) { switch (twoLetterCultureName) { case "fr": return CultureInfo.CreateSpecificCulture("fr-FR"); default: return CultureInfo.CreateSpecificCulture("en-GB"); } } }If you did not want the overhead of a Handler, or you do not want the actual dynamic script reference, then there is nothing stopping you in cutting this write down, and making a HtmlHelper which simply parsing a type and outputs the JavaScript variables directly to the requesting resource, so instead of an include script tag, it would output a script block directly in the dom. Personally I just like the script tag and the visual reduction in code in the view source, I am unsure of any performance gain if any.
So that is basically it, this is something I am definitely going to test drive and among other things, use it for other purposes. One idea I had was to use this to generate Client Side objects based on say the models. I will do this for the next post I hope.
Posted by Andrew Rea on December 13 at 5:53 PMComments (0)
-
Creating an Extended Content Result for ASP.NET MVC
I had a requirement on a small home project I am working on, where I need to add some more information to a content result than was there. More specifically I had to add the status code and also have access to the response header collection. I did come across an interesting thing with this, where by accessing and adding to the response header collection in a certain way will actually raise an exception and inform you that this is only support when IIS Integrated Pipeline is enabled. I did some looking about and found a post by Phil Haack showing how he had achieved what I was looking for when he made the Download result class.
So the following causes an exception:
public override void ExecuteResult(ControllerContext context) { context.HttpContext.Response.StatusCode = (int)StatusCode; foreach (string s in Headers.Keys) { context.HttpContext.Response.Headers.Add(s,Headers[s]); } base.ExecuteResult(context); }And the following works fine, notice the subtle difference in how the header is added now:
public override void ExecuteResult(ControllerContext context) { context.HttpContext.Response.StatusCode = (int)StatusCode; foreach (string s in Headers.Keys) { context.HttpContext.Response.AddHeader(s,Headers[s]); } base.ExecuteResult(context); }So the full code implementation of the result is below.
public class ExtendedContentResult : ContentResult { public NameValueCollection Headers { get; set; } public HttpStatusCode StatusCode { get; set; } public ExtendedContentResult() { Headers = new NameValueCollection(); } public override void ExecuteResult(ControllerContext context) { context.HttpContext.Response.StatusCode = (int)StatusCode; foreach (string s in Headers.Keys) { context.HttpContext.Response.AddHeader(s,Headers[s]); } base.ExecuteResult(context); } }Posted by Andrew Rea on November 30 at 6:13 PMComments (0)
-
URL Rewriting with Python and the Google AppEngine
Of late I am deving in parallel on a sample at home project for a few reasons including practicing skills both in architecture but also so I can get more exposure to new languages, with the most recent addition being PYTHON. The Google AppEngine currently supports PYTHON and JAVA, and since I am already doing a couple of things in JAVA I thought I would try my hand at PYTHON and I have to say, "I like it."
Before I got onto the AppEngine, an immediate accompaniment to programming in PYTHON for the web was the DJango framework. When you start reading through even the first page of the starting tutorials, you realise how easy and fast it is to get up and running with a saleable application. The Google app engine includes features of DJango, but not all of them. One main example is the fact that Google has defined its own data store and ORM for use with the AppEngine.
So inside the web application, we would want to logically separate different handlers for different situations, and the example which I am including in this post is for a Forum. Two handlers immediately spring to mind being a handler to List all the forums and a handler to view an individual forum by id.
- /Forums
- /Forum/1/somename-of-the-forum
A colleague in the place were I work, pointed out a really handy function called slugify inside the DJango framework which simply took and string and made a url friendly version i.e. "The Forum" because "the-forum."
Unfortunately though, I think this is not included inside the Google AppEngine, so it will probably be best to create an implementation of a "Slug Field" for our objects, and then it will be easy to say something like "forum.slug()." I have not et implemented this yet, just up to the url rewriting part :-)Yep, these functions are included inside the Google AppEngine, I was stupid for thinking otherwise. Check out the import and the implementation I used below on the last code snippet.
I have created a file called handlers.py but I think it will be better to separate the handlers by file and by topic area i.e. Forum, Thread, Post etc… but for this example, the two handlers I create are inside this 1 file. Also, my implementation of the handler is purely for example only, i.e. I am outputting a string so we can recognise the different behaviour in each handler.
ForumListHandler
class ForumListHandler(webapp.RequestHandler): def get(self): for item in Forum.all(): self.response.out.write("%s<br>" % (item.title))ForumViewHandler
class ForumViewHandler(webapp.RequestHandler): def get(self,id,name): self.response.out.write("you are are looking for forum %s with id of : %s" % (name,id))If you notice in the second handler, the function has 3 parameters, which will become clear with the next code snippet how they are populated. The first handler will simply output a list of the forums, and the second will output a string which includes the values it will extract from the url of the get request.
I am currently paid to develop ASP.NET MVC where this syntax of automatically mapping a request with an overloaded function is very familiar and well structured. Inside the main.py file you have a block of code where you add your mappings to handlers. The following is the result of adding the required handlers for this example:
def main(): application = webapp.WSGIApplication([('/', MainHandler), ('/forums',ForumListHandler), ('/forum/(\d+)/(.*)',ForumViewHandler)], debug=True) wsgiref.handlers.CGIHandler().run(application)Of course the url mapping uses regular expressions, and I think from looking at this, that it first checks that the number of matches it has made on the url, is equal to the number of parameters inside the handler. If this is a match it will then supply each parameter in the order in which they are matched using the regular expression. From the above you can see I first match a sequence of digits, so this fits in with my get function shown above with the first parameter after self being id.
UPDATE:
I changed my implementation of the url rewrite rules, and for the forum view I decided that I would make the parameter a slug, with an obvious rule that each slug is unique. The reason I did this, is because the entity key you get with an object inside the Google app engine, is not really the cleanest thing to put in there as it contains the entity type and guid and things. So below is the updated version and also an updated handler for the forum list handler so we can output the forums and follow the links. I will use the datastore admin tool to add some forums in. Oh, just to mention, when a new model is saved to the datastore, you automatically get a CRUD interface for it. A rough equivalence of this on Microsoft technology I would say is dynamic data, makes me wonder if they got inspiration from DJango for that.
def main(): application = webapp.WSGIApplication([('/', MainHandler), ('/forums',ForumListHandler), ('/forum/(.*)',ForumViewHandler)], debug=True) wsgiref.handlers.CGIHandler().run(application)And the updated handlers, which now outputs the link, and the other which simply accepts the slug:
from google.appengine.ext import webapp from models import Forum from django.template import defaultfilters class ForumViewHandler(webapp.RequestHandler): def get(self,slug): self.response.out.write("you are are looking for forum with slug of : %s" % (slug)) class ForumListHandler(webapp.RequestHandler): def get(self): for item in Forum.all(): self.response.out.write("<a href=\"/forum/%s\">%s</a><br>" % (defaultfilters.slugify(item.title), item.title))Cheers,
Andrew
Posted by Andrew Rea on November 29 at 5:38 PMComments (0)
-
Programmatic Drawing with Silverlight 2.0/3.0 – A Digital Clock
This is the second in a small series I am writing on programmatic drawing inside Silverlight. The first post I did on this was an analogue clock and it can be found here:
http://www.andrewrea.co.uk/2009/08/12/ProgrammaticDrawingWithSilverlight2030AnAnalogueClock.aspx
The code for this can be downloaded from the following link: http://lab.andrewrea.co.uk/DigitalClock.rar
In this post I will create a digital clock, with the disjointed digits you see in those stereotypical red digit alarm clocks. The way I tackled this was look at the individual component parts and their grouping to ultimately give the representation of time or any other numerical value. So each digit of the display is made up of individual bars with angle ends. One of the key things with the angle ends, is that they are at a 45 degree angle, so that when brought together they line up with one another.
Image
Working In Silverlight
The parts of this inline with the code files are as follows:
- IDigitalDigitPiece
- IDigitalDigit
- IDigitalState
- IDigitalClockView
The second one in the list is the Digit State. From the above examples you can see that each digit is made up of 7 component pieces, and each one represents their assigned digit by using different combinations of these digits. In this case I have assigned two properties to each Digit being the OnColor and the OffColor.
The IDigitState has the following signature:
public interface IDigitState { void Handle(IDigitalDigit digit); }An example of one of the states is the following. They simply assign the the OffColor or the OnColor to the Color property of the DigitalDigitPiece.
public class FourState : IDigitState { #region IDigitState Members public void Handle(IDigitalDigit digit) { digit.DigitalDigitPieces[0].DigitColor = digit.OffColor; digit.DigitalDigitPieces[1].DigitColor = digit.OnColor; digit.DigitalDigitPieces[2].DigitColor = digit.OnColor; digit.DigitalDigitPieces[3].DigitColor = digit.OnColor; digit.DigitalDigitPieces[4].DigitColor = digit.OffColor; digit.DigitalDigitPieces[5].DigitColor = digit.OnColor; digit.DigitalDigitPieces[6].DigitColor = digit.OffColor; } #endregion }I have pasted both the code for the digit and the digit piece below. In hind sight I think it would have been better to use examples which display the binding. The digit code displays how I am positioning the pieces after any resize or load events and the digit piece displays the code which shows how I am creating the shape of the pieces which make up the digit.
public partial class DigitalDigit : UserControl, IDigitalDigit { public List<DigitalDigitPiece> DigitalDigitPieces { get; protected set; } private double _sepDiameter; public double SepDiameter { get { return _sepDiameter; } set { if (value != _sepDiameter) { _sepDiameter = value; Draw(); } } } private Color _sepColor; public Color SepColor { get { return _sepColor; } set { if (value != _sepColor) { _sepColor = value; Draw(); } } } private Color _onColor = Colors.Red; public Color OnColor { get { return _onColor; } set { _onColor = value; } } private Color _offColor = Colors.Black; public Color OffColor { get { return _offColor; } set { _offColor = value; } } private double _pointSize = 10; public double PointSize { get { return _pointSize; } set { if (value != _pointSize) { _pointSize = value; Draw(); } } } private Color _digitColor = Colors.Red; public Color DigitColor { get { return _digitColor; } set { if (value != _digitColor) { _digitColor = value; Draw(); } } } public DigitalDigit() { InitializeComponent(); CreateDigits(); SizeChanged += new SizeChangedEventHandler(DigitalDigit_SizeChanged); Loaded += new RoutedEventHandler(DigitalDigit_Loaded); } void DigitalDigit_Loaded(object sender, RoutedEventArgs e) { Draw(); } void DigitalDigit_SizeChanged(object sender, SizeChangedEventArgs e) { Draw(); } protected void Draw() { foreach (var digit in DigitalDigitPieces) { digit.PointSize = PointSize; } AlignDigits(); } protected double LongHeight { get { return (ActualHeight / 2) - _pointSize; } } protected void AlignDigits() { if (ActualWidth > 0 && ActualHeight > 0) { DigitalDigitPieces[0].Orientation = DigitalDigitPieceOrientation.Horizontal; DigitalDigitPieces[0].Height = ActualWidth - (DigitalDigitPieces[0].PointSize * 2); DigitalDigitPieces[0].SetValue(Canvas.LeftProperty, DigitalDigitPieces[0].PointSize); DigitalDigitPieces[0].PointSize = PointSize; DigitalDigitPieces[1].SetValue(Canvas.LeftProperty, 0D); DigitalDigitPieces[1].Height = LongHeight; DigitalDigitPieces[1].SetValue(Canvas.TopProperty, (double)DigitalDigitPieces[0].Width / 2); DigitalDigitPieces[1].PointSize = PointSize; DigitalDigitPieces[2].SetValue(Canvas.LeftProperty, (double)ActualWidth - DigitalDigitPieces[2].Width); DigitalDigitPieces[2].Height = LongHeight; DigitalDigitPieces[2].SetValue(Canvas.TopProperty, (double)DigitalDigitPieces[0].Width / 2); DigitalDigitPieces[2].PointSize = PointSize; DigitalDigitPieces[3].Orientation = DigitalDigitPieceOrientation.Horizontal; DigitalDigitPieces[3].Height = ActualWidth - (DigitalDigitPieces[3].PointSize * 2); DigitalDigitPieces[3].SetValue(Canvas.LeftProperty, DigitalDigitPieces[3].PointSize); DigitalDigitPieces[3].SetValue(Canvas.TopProperty, (((double)DigitalDigitPieces[2].GetValue(Canvas.TopProperty)) + (double)(DigitalDigitPieces[2].Height - DigitalDigitPieces[2].PointSize))); DigitalDigitPieces[3].PointSize = PointSize; DigitalDigitPieces[4].SetValue(Canvas.LeftProperty, 0D); DigitalDigitPieces[4].Height = LongHeight; DigitalDigitPieces[4].SetValue(Canvas.TopProperty, (((double)DigitalDigitPieces[3].GetValue(Canvas.TopProperty)) + (double)(DigitalDigitPieces[3].Width / 2))); DigitalDigitPieces[4].PointSize = PointSize; DigitalDigitPieces[5].SetValue(Canvas.LeftProperty, (double)ActualWidth - DigitalDigitPieces[4].Width); DigitalDigitPieces[5].Height = LongHeight; DigitalDigitPieces[5].SetValue(Canvas.TopProperty, (((double)DigitalDigitPieces[3].GetValue(Canvas.TopProperty)) + (double)(DigitalDigitPieces[3].Width / 2))); DigitalDigitPieces[5].PointSize = PointSize; DigitalDigitPieces[6].Orientation = DigitalDigitPieceOrientation.Horizontal; DigitalDigitPieces[6].Height = ActualWidth - (DigitalDigitPieces[6].PointSize * 2); DigitalDigitPieces[6].SetValue(Canvas.LeftProperty, DigitalDigitPieces[3].PointSize); DigitalDigitPieces[6].SetValue(Canvas.TopProperty, (((double)DigitalDigitPieces[5].GetValue(Canvas.TopProperty)) + (double)(DigitalDigitPieces[5].Height - DigitalDigitPieces[5].PointSize))); DigitalDigitPieces[6].PointSize = PointSize; } } protected void CreateDigits() { DigitalDigitPieces = new List<DigitalDigitPiece>(); for (var i = 0; i < 7; i++) { var piece = new DigitalDigitPiece(); DigitalDigitPieces.Add(piece); LayoutRoot.Children.Add(DigitalDigitPieces[i]); } } #region IDigitalDigit Members public void SetState(IDigitState state) { state.Handle(this); } #endregion public void Update() { Draw(); } }public partial class DigitalDigitPiece : UserControl { private double _angle = 0D; private double _pointSize = 10; public double PointSize { get { return _pointSize; } set { if (value != _pointSize) { _pointSize = value; Draw(); } } } private Color _digitColor; public Color DigitColor { get { return _digitColor; } set { if (value != _digitColor) { _digitColor = value; Draw(); } } } private DigitalDigitPieceOrientation _orientation; public DigitalDigitPieceOrientation Orientation { get { return _orientation; } set { if (value != _orientation) { _orientation = value; Draw(); } } } private Polygon _polygon; public Polygon Polygon { get { return _polygon; } set { _polygon = value; } } public DigitalDigitPiece() { _digitColor = Colors.Red; _orientation = DigitalDigitPieceOrientation.Vertical; _polygon = new Polygon(); InitializeComponent(); SizeChanged += new SizeChangedEventHandler(DigitalDigitPiece_SizeChanged); Loaded += new RoutedEventHandler(DigitalDigitPiece_Loaded); LayoutRoot.Children.Add(_polygon); } void DigitalDigitPiece_SizeChanged(object sender, SizeChangedEventArgs e) { Draw(); } void DigitalDigitPiece_Loaded(object sender, RoutedEventArgs e) { Draw(); } protected void Draw() { Width = _pointSize * 2; _polygon.Points = new PointCollection { new Point(Width / 2,0), new Point(Width, _pointSize), new Point(Width, Height - _pointSize), new Point(Width/2,Height), new Point(0,Height-_pointSize), new Point(0, _pointSize), new Point(Width/2,0) }; _polygon.Fill = new SolidColorBrush(DigitColor); _polygon.Stroke = new SolidColorBrush(Colors.Black); _polygon.StrokeThickness = 1D; var rotate = new RotateTransform(); rotate.CenterX = _pointSize; rotate.CenterY = _pointSize; if (_orientation == DigitalDigitPieceOrientation.Horizontal) { if (_angle == 0 || _angle == 90) _angle = -90; } else { if (_angle == -90) _angle = 90; else _angle = 0; } rotate.Angle = _angle; _polygon.RenderTransform = rotate; } }The actual view is simply a user control which contains instances of the digits inside and arranges them accordingly. The class which I have not mentioned is the separator class and that is simply two ellipses which I have added control for, both for size and the colour inside the containers.
<UserControl x:Class="DigitalClock.DigitalClockView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:custom="clr-namespace:DigitalClock"> <Grid x:Name="LayoutRoot" Background="Black"> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition /> </Grid.RowDefinitions> <custom:DigitalDigit x:Name="Hour1" Grid.Column="0" PointSize="20" OnColor="Beige" /> <custom:DigitalDigit x:Name="Hour2" Grid.Column="1" PointSize="20" OnColor="Beige"/> <custom:DigitalClockSeparator x:Name="sep1" Grid.Column="2" HorizontalAlignment="Center" /> <custom:DigitalDigit x:Name="Minute1" Grid.Column="3" PointSize="20" /> <custom:DigitalDigit x:Name="Minute2" Grid.Column="4" PointSize="20" /> <custom:DigitalClockSeparator x:Name="sep2" Grid.Column="5" HorizontalAlignment="Center"/> <custom:DigitalDigit x:Name="Second1" Grid.Column="6" PointSize="20" /> <custom:DigitalDigit x:Name="Second2" Grid.Column="7" PointSize="20" /> </Grid> </UserControl>I found a couple of gotchas and a big one includes that upon an exception, SilverLight will continue to try and render what it has even after an exception and it looks likes values default to zero, which admittedly seems logical. Take a peek at this screen print from the above app during development.
Tis all for now,
Cheers,
AndrewPosted by Andrew Rea on November 22 at 5:22 PMComments (0)
-
Securing your distributed system using OAuth allowing for third party development, consumption and contribution
Whilst thinking about securing an application and system I am currently building I recalled working with both the eBay and Amazon apis and the security features which they employed and remember thinking how good they were. Both required token based authentication and more importantly signing each request with a different signature, whilst still maintaining an identity to the service provider which would handle the request.
The idea is rather simple.
You do not want your users downloading a third party piece of software which then asks them for their user name and password in order to use your service. The security risks of such should be obvious. The fact is, you want to offer your services for public consumption, but you also want to offer the ability for your services to be used in the context of a different user, again allowing third party software vendors to offer your customers applications they can use against your service.
Tokens
A token, i.e. some string, is used whose meaning is only known between a consumer and the service provider and protected by a secret key again only known between the consumer and the service provider. A few objectives for this type of thing are as follows:
- A service provider differentiates between each consumer of its public facing service.
-
- Not a pre requisite but something that goes hand in hand with the above, is that the service provider records each developer who in turn can create consumers.
- A service can create a link between existing users and consumers of its public facing services.
- The identifier of the link between a user and a consumer is absolutely unique.
-
- USER A - CONSUMER A - KEY: A
USER B - CONSUMER A - KEY: B
USER A - CONSUMER B - KEY: C
USER B - CONSUMER B - KEY: D
- USER A - CONSUMER A - KEY: A
- The keys above are for display purposes only just to convey that no link between consumer and user is the same, they are absolutely unique.
My Initial Idea
I want to just put down my initial idea which again is based on both the eBay api and also the Amazon one. It looks at securing the service against applications and also their use on behalf of users.
The fields involved are as follows:
- ApplicationID
- DeveloperID
- Timestamp
- UserToken
- SecretKey
- Signature
The only thing above which I got from Amazon is the timestamp thing, although it was a while ago when I used it, and I know now that this sort of thing is the norm. The idea is you take all these values and concatenate them into a string, which you then hash using one of he many hashing or Hmac algorithms, this then forms the signature parameter. What you send to the service is then all parameters barring the SecretKey, which should remain known only to the consumer and the service provider. Once received the service provider can query its data store for the secret key, hash all the values as the consumer did and make a comparison. If these match then it can be assumed that the origin of the message is valid.
OAUTH
After more research in to this kind of thing I came across the twitter API which in turn led me to the OAUTH. If you haven't yet, then here is the link.
And also here which has some great walk troughs of it and process flows:
http://hueniverse.com/2007/10/beginners-guide-to-oauth-part-ii-protocol-workflow/
I am building a custom implementation of the protocol with a couple of demo layers inside Visual Studio 2010, WCF and MVC 2 which I will get on here in the next few days. They offer code in many different flavours to see examples of the protocol but being a protocol, just stick to it, and design it how you like. That is what I am doing.
My examples will also make use of the previous crypto helper I made, as I think that I will use HMACSHA1 for the signing. HMACSHA512 sounds a bit large when used in REST implementations. If you do not want to offer a REST implementation then why not go the whole hog and secure using HMACSHA512.
The Example
The example that I am building will be a simple website, which offers users a small service. It will contain a section for developers to signup with and create an account with which they can create key sets for different applications they make.
Cheers for now,
Andrew
Posted by Andrew Rea on November 05 at 3:49 PMComments (0)