Thursday, May 13, 2010
The other day I created a simple NastyWord service exposed via OData. It was read-only and used an in-memory backing store for the words. Today I’ll modify it to use a file instead of a list and I’ll accept new nasty words by implementing IUpdatable directly.
The first thing to do is enable the service to accept new entries. This is done at configuration time by adding the “WriteAppend” access rule:
1: public class NastyWords : DataService<NastyWordsDataSource>
2: {
3: // This method is called only once to initialize service-wide policies.
4: public static void InitializeService(DataServiceConfiguration config)
5: {
6: config.SetEntitySetAccessRule("*", EntitySetRights.AllRead | EntitySetRights.WriteAppend);
7: config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
8: }
9: }
Next I placed a file, NastyWords.txt, in the “App_Data” folder and added a few *choice* words to start. This required one simple change to our NastyWordDataSource.cs file:
1: public NastyWordsDataSource()
2: {
3: UpdateFromSource();
4: }
5:
6: private void UpdateFromSource()
7: {
8: var words = File.ReadAllLines(pathToFile);
9: NastyWords = (from w in words
10: select new NastyWord { Word = w }).AsQueryable();
11: }
Nothing too shocking here, just reading each line from the NastyWords.txt file and exposing them. Next, I implemented IUpdatable which comes with a boat-load of methods. We don’t need all of them for now since we are only concerned with allowing new values. Here are the methods we must implement, all the others throw a NotImplementedException:
1: public object CreateResource(string containerName, string fullTypeName)
2: {
3: var nastyWord = new NastyWord();
4: pendingUpdates.Add(nastyWord);
5: return nastyWord;
6: }
7:
8: public object ResolveResource(object resource)
9: {
10: return resource;
11: }
12:
13: public void SaveChanges()
14: {
15: var intersect = (from w in pendingUpdates
16: select w.Word).Intersect(from n in NastyWords
17: select n.Word);
18:
19: if (intersect.Count() > 0)
20: throw new DataServiceException(500, "duplicate entry");
21:
22: var lines = from w in pendingUpdates
23: select w.Word;
24:
25: File.AppendAllLines(pathToFile,
26: lines,
27: Encoding.UTF8);
28:
29: pendingUpdates.Clear();
30:
31: UpdateFromSource();
32: }
33:
34: public void SetValue(object targetResource, string propertyName, object propertyValue)
35: {
36: targetResource.GetType().GetProperty(propertyName).SetValue(targetResource, propertyValue, null);
37: }
I use a simple list to contain the pending updates and only commit them when the “SaveChanges” method is called. Here’s the order these methods are called in our service during an insert:
- CreateResource – here we just instantiate a new NastyWord and stick a reference to it in our pending updates list.
- SetValue – this is where the “Word” property of the NastyWord instance is set.
- SaveChanges – get the list of pending updates, barfing on duplicates, write them to the file and clear our pending list.
- ResolveResource – the newly created resource will be returned directly here since we aren’t dealing with “handles” to objects but the actual objects themselves.
Not too bad, eh? I didn’t find this documented anywhere but a little bit of digging in the OData spec and use of Fiddler made it pretty easy to figure out. Here is some client code which would add a new nasty word:
1: static void Main(string[] args)
2: {
3: var svc = new ServiceReference1.NastyWordsDataSource(new Uri("http://localhost.:60921/NastyWords.svc"));
4: svc.AddToNastyWords(new ServiceReference1.NastyWord() { Word = "shat" });
5:
6: svc.SaveChanges();
7: }
Here’s all of the code so far for to implement the service:
1: using System;
2: using System.Collections.Generic;
3: using System.Data.Services;
4: using System.Data.Services.Common;
5: using System.Linq;
6: using System.ServiceModel.Web;
7: using System.Web;
8: using System.IO;
9: using System.Text;
10:
11: namespace ONasty
12: {
13: [DataServiceKey("Word")]
14: public class NastyWord
15: {
16: public string Word { get; set; }
17: }
18:
19: public class NastyWordsDataSource : IUpdatable
20: {
21: private List<NastyWord> pendingUpdates = new List<NastyWord>();
22: private string pathToFile = @"path to your\App_Data\NastyWords.txt";
23:
24: public NastyWordsDataSource()
25: {
26: UpdateFromSource();
27: }
28:
29: private void UpdateFromSource()
30: {
31: var words = File.ReadAllLines(pathToFile);
32: NastyWords = (from w in words
33: select new NastyWord { Word = w }).AsQueryable();
34: }
35:
36: public IQueryable<NastyWord> NastyWords { get; private set; }
37:
38: public void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
39: {
40: throw new NotImplementedException();
41: }
42:
43: public void ClearChanges()
44: {
45: pendingUpdates.Clear();
46: }
47:
48: public object CreateResource(string containerName, string fullTypeName)
49: {
50: var nastyWord = new NastyWord();
51: pendingUpdates.Add(nastyWord);
52: return nastyWord;
53: }
54:
55: public void DeleteResource(object targetResource)
56: {
57: throw new NotImplementedException();
58: }
59:
60: public object GetResource(IQueryable query, string fullTypeName)
61: {
62: throw new NotImplementedException();
63: }
64:
65: public object GetValue(object targetResource, string propertyName)
66: {
67: throw new NotImplementedException();
68: }
69:
70: public void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
71: {
72: throw new NotImplementedException();
73: }
74:
75: public object ResetResource(object resource)
76: {
77: throw new NotImplementedException();
78: }
79:
80: public object ResolveResource(object resource)
81: {
82: return resource;
83: }
84:
85: public void SaveChanges()
86: {
87: var intersect = (from w in pendingUpdates
88: select w.Word).Intersect(from n in NastyWords
89: select n.Word);
90:
91: if (intersect.Count() > 0)
92: throw new DataServiceException(500, "duplicate entry");
93:
94: var lines = from w in pendingUpdates
95: select w.Word;
96:
97: File.AppendAllLines(pathToFile,
98: lines,
99: Encoding.UTF8);
100:
101: pendingUpdates.Clear();
102:
103: UpdateFromSource();
104: }
105:
106: public void SetReference(object targetResource, string propertyName, object propertyValue)
107: {
108: throw new NotImplementedException();
109: }
110:
111: public void SetValue(object targetResource, string propertyName, object propertyValue)
112: {
113: targetResource.GetType().GetProperty(propertyName).SetValue(targetResource, propertyValue, null);
114: }
115: }
116:
117: public class NastyWords : DataService<NastyWordsDataSource>
118: {
119: // This method is called only once to initialize service-wide policies.
120: public static void InitializeService(DataServiceConfiguration config)
121: {
122: config.SetEntitySetAccessRule("*", EntitySetRights.AllRead | EntitySetRights.WriteAppend);
123: config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
124: }
125: }
126: }
Next time we’ll allow removing nasty words. Enjoy!
Wednesday, May 12, 2010
I wanted to create an OData service with the least amount of code so I fired up Visual Studio and got cracking. I decided to serve up a list of naughty words and make them read-only.
Create a new web project. I created an empty MVC 2 application but MVC is not required for OData.
Add a new WCF Data Service to the project. I named mine NastyWords.svc since I’m serving up a list of nasty words.
Add a class to expose via the service: NastyWord
1: [DataServiceKey("Word")]
2: public class NastyWord
3: {
4: public string Word { get; set; }
5: }
I need to be able to uniquely identify instances of NastyWords for the DataService so I used the DataServiceKey attribute with the “Word” property as the key. I could have added an “ID” property which would have uniquely identified them and would then not need the “DataServiceKey” attribute because the DataService would apply some reflection and heuristics to guess at which property would be the unique identifier. However, the words themselves are unique so adding an “ID” property would be redundantly repetitive.
Then I created a data source to expose my NastyWord objects to the service. This is just a simple class with IQueryable<T> properties exposing the entities for my service:
1: public class NastyWordsDataSource
2: {
3: private static IList<NastyWord> words = new List<NastyWord>
4: {
5: new NastyWord{ Word="crap"},
6: new NastyWord{ Word="darn"},
7: new NastyWord{ Word="hell"},
8: new NastyWord{ Word="shucks"}
9: };
10:
11: public NastyWordsDataSource()
12: {
13: NastyWords = words.AsQueryable();
14: }
15:
16: public IQueryable<NastyWord> NastyWords { get; private set; }
17: }
Now I can go to the NastyWords.svc class and tell it which data source to use and which entities to expose:
1: public class NastyWords : DataService<NastyWordsDataSource>
2: {
3: // This method is called only once to initialize service-wide policies.
4: public static void InitializeService(DataServiceConfiguration config)
5: {
6: config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
7: config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
8: }
9: }
Compile and browse to my NastWords.svc and weep with joy
Now I can query my service just like any other OData service. Next time, I’ll modify this service to allow updates to sent so I can build up my list of nasty words.
Enjoy!
Friday, May 07, 2010
The other day I had a snazzy post on fetching all the video (WMV) files from Mix ‘10. A simple, console application that grabbed the urls from the OData feed and downloaded the videos. I wanted to change that app to fire the OData query asynchronously so here’s what resulted:
1: static void Main(string[] args)
2: {
3: var mix = new Mix.EventEntities(new Uri("http://api.visitmix.com/OData.svc"));
4:
5: var temp = mix.Files.Where(f => f.TypeName == "WMV");
6: var query = temp as DataServiceQuery<Mix.File>;
7:
8: query.BeginExecute(OnFileQueryComplete, query);
9:
10: // waiting...
11: Console.ReadLine();
12: }
13:
14: static void OnFileQueryComplete(IAsyncResult result)
15: {
16: var query = result.AsyncState as DataServiceQuery<Mix.File>;
17: var response = query.EndExecute(result);
18:
19: var web = new WebClient();
20:
21: var myVideos = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyVideos), "Mix10");
22:
23: Directory.CreateDirectory(myVideos);
24:
25: foreach (Mix.File f in response)
26: {
27: var fileName = new Uri(f.Url).Segments.Last();
28: Console.WriteLine(f.Url);
29: web.DownloadFile(f.Url, Path.Combine(myVideos, fileName));
30: }
31: }
There are two important things here that are not explained well in the MSDN docs:
- See lines 5 and 6? That’s where I query for the WMV files and it returns an IQueryable<T>. You *have* to cast that to a DataServiceQuery<T> and then call BeginExecute. The documented example does not filter so it didn’t show that step.
- Line 16 shows the correct way to get the previously executed DataServiceQuery<T> from the async result. If you looked at the MSDN example docs it shows (incorrectly) just casting the result, like this:
// wrong
var query = result as DataServiceQuery<Mix.File>;
Other than those items it is relatively straight forward and we’re all async-ified. Enjoy!
Thursday, May 06, 2010
There has been a lot of talk around OData lately (go to odata.org for more information) and I wanted to get all the videos from Mix ‘10: two great tastes that taste great together. Luckily, Mix has exposed the ‘10 sessions via OData at http://api.visitmix.com/OData.svc, now all I have to do is slap together a bit of code to fetch the videos.
Step 1
(cut a hole in the box)
Create a new console application and add a new service reference.
Step 2
(put your junk in the box)
Write a smidgen of code:
1: static void Main(string[] args)
2: {
3: var mix = new Mix.EventEntities(new Uri("http://api.visitmix.com/OData.svc"));
4:
5: var files = from f in mix.Files
6: where f.TypeName == "WMV"
7: select f;
8:
9: var web = new WebClient();
10:
11: var myVideos = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyVideos), "Mix10");
12:
13: Directory.CreateDirectory(myVideos);
14:
15: files.ToList().ForEach(f => {
16: var fileName = new Uri(f.Url).Segments.Last();
17: Console.WriteLine(f.Url);
18: web.DownloadFile(f.Url, Path.Combine(myVideos, fileName));
19: });
20: }
Step 3
(have her open the box)
Compile and run.
As you can see, the client reference created for the OData service handles almost everything for me. Yeah, I know there is some batch file to download the files, but it relies on cUrl being on the machine – and I wanted an excuse to work with an OData service.
Enjoy!
Saturday, November 21, 2009
I am currently reading Scott Berkun’s book “Confessions of a Public Speaker” and thought this was hilarious and true:
…unless presentation terrorists steal your microphone midsentence or put up their own projector and start showing their
own slide deck—designed specifically to contradict your every
point—you’re free from the pressures other performers face
nightly. Small observations like this make it easier to laugh at
nerves, even if they won’t go away.
I do quite a few presentations to companies and other groups and still get nervous before each presentation. One point Scott is trying to make is that it is natural to be nervous and that most speakers don’t have people intentionally trying to derail them. I thought the idea of “presentation terrorists” was great!
Enjoy!
Monday, October 19, 2009
If you only have one implementation of a registered interface then it is pretty straight forward, but what do you do if you have multiple implementations of an interface? Now you have to get a little more explicit when registering items in your container. Let’s go through a simple example.
Say you have a class, OrderProcessor, that takes one implementation of IMessageWriter:
public class OrderProcessor
{
private readonly IMessageWriter _messageWriter;
public OrderProcessor(IMessageWriter messageWriter)
{
_messageWriter = messageWriter;
}
public void SubmitOrder()
{
// do something special with the order
_messageWriter.Write("Submitting order...");
// do some more with the order
}
}
IMessageWriter is a simple interface:
public interface IMessageWriter
{
void Write(string message);
}
If we have only one implementation of IMessageWriter then registration is simple:
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
container.RegisterType<IMessageWriter, ConsoleMessageWriter>();
var orderProcessor = container.Resolve<OrderProcessor>();
orderProcessor.SubmitOrder();
}
}
In this case our OrderProcessor will use the ConsoleMessageWriter when we call SubmitOrder to write the message to the console. Here’s the implementation of ConsoleMessageWriter:
public class ConsoleMessageWriter : IMessageWriter
{
public void Write(string message)
{
Console.WriteLine(message);
}
}
What if we have two implementations of IMessageWriter? Let’s add DebugMessageWriter:
public class DebugMessageWriter : IMessageWriter
{
public void Write(string message)
{
Debug.WriteLine(message);
}
}
And when we register both types with our IoC container, which one will be used?
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
container.RegisterType<IMessageWriter, ConsoleMessageWriter>();
container.RegisterType<IMessageWriter, DebugMessageWriter>();
var orderProcessor = container.Resolve<OrderProcessor>();
orderProcessor.SubmitOrder();
}
}
That’s right – the only one called will be the DebugMessageWriter implementation! The last one registered wins.
Now let’s say you change your mind and decide to accept all the registered implementations of IMessageWriter:
public class OrderProcessor
{
private readonly IMessageWriter[] _messageWriters;
public OrderProcessor(IMessageWriter[] messageWriters)
{
_messageWriters = messageWriters;
}
public void SubmitOrder()
{
// do something special with the order
foreach (var writer in _messageWriters)
writer.Write("Submit order...");
// do some more with the order
}
}
Which implementation will be used? Neither. How can you get the container to use your implementations? It ends up you have to give each registered implementation a unique name, like this:
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
container.RegisterType<IMessageWriter, ConsoleMessageWriter>("console");
container.RegisterType<IMessageWriter, DebugMessageWriter>("debug");
var orderProcessor = container.Resolve<OrderProcessor>();
orderProcessor.SubmitOrder();
}
}
Now when you run the code both implementations will be called. This was not really clear to me when I started working with Unity so I hope this clears up some fog for others.
Enjoy!
Tuesday, October 06, 2009
A post, possibly flame-bait, was sent out to a group that I subscribe. It was a response to a previous post about the “Duct Tape Programmer.” Incase you’re not familiar, it was started by a post from Joel Spolsky and taken to several extremes by way too many people. Anyway, the poster said something like this:
“I used to idolize Joel Spolsky. However after reading his thoughts and listening to his podcast for the last couple of years I've come to realize he's an arrogant blowhard.”
This made me pause to reflect on my feelings about Joel. You see, I’ve been reading Joel’s blog for a long time. I have read several of his books. I even have a copy of the “Aardvark’d” DVD he put out. When he and Jeff Atwood started out on StackOverflow I was excited because I was also an avid reader of Jeff’s blog. I even listened to their podcasts while StackOverflow was being constructed. But not so much any more.
It’s not that I don’t like Jeff or Joel – they still have wonderful insight and information into the programming and business world. I guess I’ve just moved on. I don’t subscribe to either of their blogs anymore, but I do read them from time to time if an aggregator picks them up. There are times in your life when you need to be fed a certain diet and for a long time that was given to me by Joel and Jeff. I’ve used their technical and business advice on more than one occasion and still do refer others to their writings.
I don’t always agree with Joel, but I wouldn’t feel right telling others he is not worth listening. It may not be my time but others might find just what they need with him. Eventually they will move on as well.
Monday, October 05, 2009
Did you know about the “Repeat” extension method? Enumerable.Repeat generates a sequence of repeated values – perfect for some testing scenarios.
Here’s how I’ve used it…
private static ISearchService CreateSearchServiceWithExpectedResults(string searchText, int ountOfResults)
{
var results = Enumerable.Repeat(new SearchResult
{
Id = searchText,
Description = searchText,
Title = searchText,
Project = searchText
}, countOfResults);
return new MockSearchService(results.ToList());
}
This method takes in a string and sets it to some values of an object, SearchResult, and then creates ‘countOfResults’ copies of that object. A nice, quick way to get some test data. Now I can easily ask for 1, 10, or 100 values to fill my list for testing. Give it a whack and see if it helps your test writing!
Monday, September 28, 2009
Maybe it is just me, but I’m not a big fan of huge amounts of XML configuration. I can get by with a few name-value pairs in an app.config or a web.config but much more makes me nervous that I’m going to mistype something and not know about it until run time. I’ve been using Unity and it has the ability to load up its configuration from the app.config or web.config. Here’s a sample:
Yeah…..what else ya got?
It offers a “fluent” API for programmatic registration. Sweet! Now I just have to convert all that XML into code. Hmmmm…Now I have a whole lotta
Container.RegisterType<IMyThing, MyThing>();
That works for a trivial class but I don’t want to write a bunch of repetitive code that simply registers interfaces for types. StructureMap has some sort of convention based registration, why not Unity? Let’s get busy…
To start off I’ll add a few extension methods to make life a bit easier:
public static class ExtensionMethods
{
public static IEnumerable<Type> GetInterfaces(this Assembly assembly)
{
return assembly.GetTypes().Where(t => t.IsInterface);
}
public static IList<Type> GetImplementationsOfInterface(this Assembly assembly, Type interfaceType)
{
var implementations = new List<Type>();
var concreteTypes = assembly.GetTypes().Where(t =>
!t.IsInterface &&
!t.IsAbstract &&
interfaceType.IsAssignableFrom(t));
concreteTypes.ToList().ForEach(implementations.Add);
return implementations;
}
public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
foreach (var item in enumerable)
{
action(item);
}
}
}
These just offer some shortcuts for getting all the interface from an assembly and then finding all the types which implement a given interface in an assembly. Now we can use these to find and register our interfaces and implementations in our ConventionRegistrar:
public class ConventionRegistrar
{
public static void Configure(IUnityContainer container)
{
var asm = Assembly.GetExecutingAssembly();
var interfaces = asm.GetInterfaces();
foreach (var interfaceType in interfaces)
{
var currentInterfaceType = interfaceType;
var implementations = asm.GetImplementationsOfInterface(interfaceType);
if (implementations.Count > 1)
implementations.ToList().ForEach(i => container.RegisterType(currentInterfaceType, i, i.Name));
else
implementations.ToList().ForEach(i => container.RegisterType(currentInterfaceType, i));
}
}
}
I have this one hard coded to use the executing assembly, but that could easily be changed. Essentially, this just looks up the interfaces then finds all the types that implement those interfaces. The only funky part is where I check if more than one type implements an interface. If that is the case I want to register it as a “named” type, otherwise Unity will only keep the last one registered. This way I can have multiple types implement an interface and get them all by calling
var startupTasks = Container.ResolveAll<IStartupTask>();
That will give me an array of all the classes that implement the IStartupTask interface. So now instead of all that XML or those repetitive Container.Register<I, T>() calls I can simple call ConventionRegistrar.Configure(Container) and most of my work is done. Sure, I may have to do some custom registration for special cases but I’ve taken care of the tedious registration tasks.
Enjoy!
Thursday, September 24, 2009
Tonight Joe Besse gave a great presentation on WCF to our .Net user group. Sparkhound (thanks Mike!) and me were the sponsors and we had 23 people show up despite the nasty, rainy weather. Incase you don’t know, Baton Rouge pretty much shuts down when we get bad weather.
Joe talked about the ABCs (Address Binding Contract) of WCF, showed how to configure a service in the config file as well as in code. He had a little trouble running his demo of a service that returned random pixel values. He’s not the first to run into trouble with demos, we’ve had Caleb Jenkins down here and his demo got derailed quite a bit, but both guys made a strong come back! The demo gremlins are always there…
WCF can be quite daunting when you first dive into it. Hell, it’s still a bit to slug through even when you’ve worked with it for a while. Regardless we had a good turnout and a great presenter, thanks Joe!
Enjoy!