Monday, March 01, 2010
This post is a follow up to to 2 posts: Find/Replace on Render – an MVC alternative to Response Filters and Response.Flush and the crimes against Page Caching.
In the first post I explored a way to parse special tags before rendering a page. I’m working on a CMS that accepts special tags inside content. Those tags are then replaced on render. For example, an author might place a tag like:
1: <CustomAmazonBestSellers Count=”5” />
to display the 5 best selling products on Amazon (we don’t support this but you get the point).
I came up with a solution but quickly ran into an issue with caching. In fact, the solution caused Page Caching to be effectively disabled which is very, very bad.
There are a number of solutions to this issue. I’ll run through 2 of them and explain why I chose to implement the one I did.
First, the solution I did not implement:
Override Page Render
The issue with Page Caching was caused by the way I was parsing through the page’s output. Inside the Render method of my custom IView, I had a routine that flushed the Response to a MemoryStream, parsed through that, and then wrote the result back to Response. This is what caused the Page Cache issue but it’s also what allowed me to do the parsing in one shot.
A single request can mean rendering a half dozen pages. You might have a Master and a Nested Master page (that makes 2). You might have your main page (which makes 3) that has a bunch of RenderPartial and/or RenderAction calls (which can add 1 or more per call).
Overriding Page Render would mean that each time any of these is rendered I would first render to string, then parse out the tags, then add the result to the Response. However, that would mean that every one of my pages would have to Inherit from MySpecialViewPage instead of System.Web.Mvc.ViewPage. This creates a bit of a tooling issue since Visual Studio automatically creates Views that inherit from System.Web.Mvc.ViewPage. Another reason I didn’t like this approach was that it felt a little dirty requiring each page to be responsible for rendering its own custom tags.
Back to Response Filters
There is a built in way of manipulating output in ASP.NET. It’s called Response Filters. A Response Filter is just a Stream that wraps the Response Output so that you can manipulate the data before sending it downstream. Our original solution used Response Filters to render these special tags. The reason I wanted a different solution in the first place was because we were outputting HTML from the Response Filter Stream (in code, using an HtmlTextWriter!) which is very ugly and unwieldy. It was very painful to create a new tag or change an existing one!
The solution I came up with is the best of both worlds. I’m using most of the code from my original IView-based solution (first link above), but instead of parsing the output on Render (which created the Page Caching issue), I do it inside a Response Filter (which was created expressly for this purpose). And when I encounter a custom tag? I have an ASPX page designed to handle just that tag and I use Server.Execute to let the ASP.NET runtime render that “template” page. BTW, Rick Strahl has a terrific write-up on Server.Execute on his blog.
And now for the code :)
The Reponse Filter (look at the RenderCustomTags method. I removed some logging and other misc stuff):
1: /// <summary>
2: /// This is a generic class that is used to parse all CustomTags
3: /// It will search for all CustomTagsin the output of an ASPX
4: /// page and, if there is a Template defined in the TagParsers
5: /// it renders that template (passing the parameters in the QueryString)
6: /// it makes MAX_PASSES passes over the HTML to account for
7: /// CustomTags that output other CustomTags
8: /// </summary>
9: class CustomTagParser : Stream
10: {
11: const int MAX_PASSES = 20;
12: private Stream _OutputStream;
13: private MemoryStream _BufferStream;
14: public CustomTagParser(Stream outputStream)
15: {
16: _OutputStream = outputStream;
17: _BufferStream = new MemoryStream();
18: }
19: public override bool CanRead
20: {
21: get { return false; }
22: }
23:
24: public override bool CanSeek
25: {
26: get { return false; }
27: }
28:
29: public override bool CanWrite
30: {
31: get { return true; }
32: }
33:
34: public override void Flush()
35: {
36: string html;
37: _BufferStream.Position = 0;
38: using (StreamReader reader = new StreamReader(_BufferStream, ASCIIEncoding.UTF8))
39: {
40: html = reader.ReadToEnd();
41: }
42: html = RenderCustomTags(html);
43: byte[] utf8Bytes = ASCIIEncoding.UTF8.GetBytes(html);
44: _OutputStream.Write(utf8Bytes, 0, utf8Bytes.Length);
45: _OutputStream.Flush();
46: }
47:
48: private static Dictionary<string, string> GetTagParameters(string tag)
49: {
50: Dictionary<string, string> paramDictionary = new Dictionary<string, string>();
51: // Get param/value pairs
52: Regex parameterRegex = new Regex("([a-z0-9]+)=\"([\\w\\s#|]*)\"", RegexOptions.IgnoreCase);
53: foreach (Match paramMatch in parameterRegex.Matches(tag))
54: {
55: string paramName = paramMatch.Groups[1].Value;
56: string paramValue = paramMatch.Groups[2].Value;
57: paramDictionary.Add(paramName.ToLower(), paramValue);
58: }
59: // Get params with no value pair (e.g. "notable" in <zifftag notable>)
60: Regex novalueRegex = new Regex("\\s\\b([a-z0-9]+)\\b(?!=)", RegexOptions.IgnoreCase);
61: foreach (Match paramMatch in novalueRegex.Matches(tag))
62: {
63: string paramName = paramMatch.Groups[1].Value;
64: paramDictionary.Add(paramName.ToLower(), null);
65: }
66: return paramDictionary;
67: }
68:
69: private static string GetPageAndQueryString(string templateLocation, string innerText, Dictionary<string, string> parameters)
70: {
71: StringBuilder pageAndQueryString = new StringBuilder();
72: pageAndQueryString.Append(templateLocation);
73: pageAndQueryString.Append("?innerText=");
74: pageAndQueryString.Append(HttpUtility.UrlEncode(innerText));
75: foreach (var param in parameters)
76: {
77: pageAndQueryString.Append("&");
78: pageAndQueryString.Append(HttpUtility.UrlEncode(param.Key));
79: pageAndQueryString.Append("=");
80: pageAndQueryString.Append(HttpUtility.UrlEncode(param.Value));
81: }
82: return pageAndQueryString.ToString();
83: }
84: private string RenderCustomTags(string html)
85: {
86: StringWriter writer = null;
87: Regex customTagRegex = new Regex("<(CUSTOM[A-Z0-9]*)([^>]*)>((.*?)</\\1>)?", RegexOptions.IgnoreCase);
88: for (int i = 0; i <= MAX_PASSES; i++)
89: {
90: int currentOffset = 0;
91: writer = new StringWriter();
92: MatchCollection customTagMatches = customTagRegex.Matches(html);
93: if (customTagMatches.Count == 0)
94: break; // no need to keep going
95: foreach (Match match in customTagMatches)
96: {
97: // Get tag info
98: string fullTag = match.Value;
99: string tagName = match.Groups[1].Value;
100: string innerText = string.Empty;
101: string parameterString = match.Groups[2].Value;
102: if (match.Groups.Count == 5 /* has closing tag */)
103: innerText = match.Groups[4].Value;
104:
105: // Get template location
106: string templateLocation;
107: if (!TagParsers.TryGetValue(tagName, out templateLocation))
108: continue; // No template defined for this tag
109:
110: // Write text before this tag
111: writer.Write(html.Substring(currentOffset, match.Index - currentOffset));
112:
113: Dictionary<string, string> parameters = GetTagParameters(parameterString);
114:
115: string pageAndQueryString = GetPageAndQueryString(templateLocation, innerText, parameters);
116: try
117: {
118: HttpContext.Current.Server.Execute(pageAndQueryString.ToString(), writer);
119: }
120: catch (Exception ex)
121: {
122: // Some logging
123: }
124: finally
125: {
126: // Update current offset before next pass
127: currentOffset = match.Index + match.Length;
128: }
129: }
130: // Write remainder of html to writer
131: writer.Write(html.Substring(currentOffset));
132: html = writer.ToString();
133: }
134: return html;
135: }
136: public override long Length
137: {
138: get { return _BufferStream.Length; }
139: }
140:
141: public override long Position
142: {
143: get
144: {
145: throw new NotImplementedException();
146: }
147: set
148: {
149: throw new NotImplementedException();
150: }
151: }
152:
153: public override int Read(byte[] buffer, int offset, int count)
154: {
155: throw new NotImplementedException();
156: }
157:
158: public override long Seek(long offset, SeekOrigin origin)
159: {
160: throw new NotImplementedException();
161: }
162:
163: public override void SetLength(long value)
164: {
165: throw new NotImplementedException();
166: }
167:
168: public override void Write(byte[] buffer, int offset, int count)
169: {
170: _BufferStream.Write(buffer, offset, count);
171: }
172: }
I created a static class called TagParsers that basically acts as a case-insensitive dictionary (so that tags are found regardless of cASe):
1: public static class TagParsers
2: {
3: private static IDictionary<string, string> _TagParsers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
4:
5: #region IDictionary<string,string> Members
6:
7: public static void Add(string tagName, string relativeTemplateLocation)
8: {
9: _TagParsers.Add(tagName, relativeTemplateLocation);
10: }
11:
12: public static bool ContainsKey(string tagName)
13: {
14: return _TagParsers.ContainsKey(tagName);
15: }
16:
17: public static ICollection<string> Keys
18: {
19: get { return _TagParsers.Keys; }
20: }
21:
22: public static bool Remove(string tagName)
23: {
24: return _TagParsers.Remove(tagName);
25: }
26:
27: public static bool TryGetValue(string tagName, out string relativeTemplateLocation)
28: {
29: return _TagParsers.TryGetValue(tagName, out relativeTemplateLocation);
30: }
31:
32: public static ICollection<string> Values
33: {
34: get { return _TagParsers.Values; }
35: }
36:
37: #endregion
38:
39: }
And the last piece of the puzzle was adding all of my custom tags to my TagParsers dictionary (inside Global.asax):
1: TagParsers.Add("CustomAmazonBestSellers", "~/CustomTagTemplates/AmazonBestSellers.aspx");
The AmazonBestSellers.aspx page has code-behind that just interprets the QueryString parameters (in the fictional Amazon best-selling case above, “count=5”)
And just for the sake of completion, attaching the Response Filter goes something like this (don’t forget to add the HttpModule it to the Web.Config):
1: class CustomTagParserHttpModule : System.Web.IHttpModule
2: {
3: ...
4: void System.Web.IHttpModule.Init(System.Web.HttpApplication context)
5: {
6: context.PostRequestHandlerExecute += new EventHandler(context_PostRequestHandlerExecute);
7: }
8: void context_PostRequestHandlerExecute(object sender, EventArgs e)
9: {
10: HttpApplication application = (HttpApplication)sender;
11: application.Response.Filter = new CustomTagParser(application.Response.Filter);
12: }
13: }
Tuesday, February 09, 2010
It looks like I might be giving a course on Beginning .NET Development to non developers with IT backgrounds. I'm putting together my lectures and it's really hard. I want to make sure that I explain things so others can understand them.
Even though this is a .NET course (with a web-based slant), I really see it as a fundamental software development (crash) course. You can’t become a great developer without understanding what’s going on behind the scenes. If you have any thoughts or advice on any of the topics at hand (am I missing a topic? are they poorly ordered? do you have a great analogy for something?) or just some general thoughts or advice, I'd be grateful if you would pass them along.
Here's what I have in regards to topics for the course:
Principals in software engineering
- What are numbers (decimal, binary, hex)
- Memory & microprocessors (rundown on how code gets executed)
Into to OOP
- What's assembly language
- C and low level languages
- Beginning OOP (concepts relevant to OOP)
Microsoft .NET Platform
- Native executable vs intermediate language (history, how it works)
- Basic types & operators
- Pass by Value vs reference
- Using Visual Studio
Principals of web architecture
- What's the internet?
- State vs stateless
Fundamentals of ASP.NET
- What is ViewState?
- Configuration
Proficiency in C#
- Basic structure
- Flow control, ifs, fors, whiles, methods
- OOP (classes, interfaces, polymorphism)
- Generics*
- Lambda expressions & functional programming*
* These topics might have to be left for the next, more advanced course depending on time contraints
Wednesday, February 03, 2010
Update: FIX posted here
In a previous post (http://blog.statichippo.com/archive/2009/11/16/findreplace-on-render-ndash-an-mvc-alternative-to-response-filters.aspx), I wrote about how to render a ViewPage to a string before writing it to the OutputStream. This would be helpful, for instance, to replace certain text with other text (in my case, I used this to replace special tags with other content). The method used basically worked like this:
- Add MemoryStream as a ResponseFilter
- Render output
- Flush the Response so that now the text is in the MemoryStream
- Use a StreamReader to ReadToEnd
- Do the transformations and Write to the Response stream
As it turns out this effectively disabled Page Caching. We tracked it down to step 3 – Response.Flush. To me this call looked innocuous, but that’s not how it looks to IIS. I posted the issue to StackOverflow (http://stackoverflow.com/questions/2193628/response-flush-breaking-page-caching) and user Womp referred me to this blog post at IIS.NET.
If some module already flushed the response by the time request reaches UpdateRequestCache stage or if headers are suppressed, response is not cached in output cache module.
That sort of makes sense though, since caching the response requires the entire response to be available.
I have a solution I’m working on, and I plan to write about it soon. In the meantime, don’t flush your response if you need page caching.
Thursday, January 28, 2010
The NY ALT.NET Meetup group met last night and Scott Weinstein delivered a terrific presentation on the Reactive Framework (also known as Rx Framework). If you haven’t heard about it, the Rx Framework is a framework for composing (and consuming) asynchronous events.
The way that the framework works is that you subscribe to an IObservable and get notified of new events. Since this is all done async, one of my questions was whether a single subscriber’s consumption of these events is blocking (to itself) or not. That’s probably not the best way to phrase the question, but the code’s easy enough to understand. Anyway, Scott said he thought so, but it would be worth testing, so I did.
1: static void Main(string[] args)
2: {
3: var range = Observable.Range(1, 5)
4: .Subscribe((int i) =>
5: {
6: DateTime future = DateTime.Now.AddSeconds(5);
7: DateTime lastPrint = DateTime.MinValue;
8: if (i % 2 == 0)
9: {
10: while (DateTime.Now < future)
11: {
12: if (DateTime.Now.Subtract(lastPrint).Milliseconds >= 900)
13: {
14: Console.WriteLine("Sleeping...");
15: lastPrint = DateTime.Now;
16: }
17: }
18: }
19: Console.WriteLine("Sleeper {0}", i);
20: });
21: Console.ReadLine();
22: }
Basically, my IObservable is counting from 1 to 5 but taking it’s time on 2 and 4. So the question was, will the Action passed to the subscribe be called in order (each one blocks) or will we have some (like 3 and 5) called before others (like 2 and 4, which means they don’t block).
And the output shows that they block, which is what Scott (and I) expected since it really is the only way that makes sense, but it was worth a look-see.
Sleeper 1
Sleeping...
Sleeping...
Sleeping...
Sleeping...
Sleeping...
Sleeping...
Sleeper 2
Sleeper 3
Sleeping...
Sleeping...
Sleeping...
Sleeping...
Sleeping...
Sleeper 4
Sleeper 5
In case you were worried though, other subscribers are not blocked just because one subscriber blocks itself.
1: static void Main(string[] args)
2: {
3: var range = Observable.Range(1, 5);
4: range.Subscribe((int i) =>
5: {
6: DateTime future = DateTime.Now.AddSeconds(5);
7: DateTime lastPrint = DateTime.MinValue;
8: if (i % 2 == 0)
9: {
10: while (DateTime.Now < future)
11: {
12: if (DateTime.Now.Subtract(lastPrint).Milliseconds >= 900)
13: {
14: Console.WriteLine("Sleeping...");
15: lastPrint = DateTime.Now;
16: }
17: }
18: }
19: Console.WriteLine("Sleeper {0}", i);
20: });
21: range.Subscribe((int i) => { Console.WriteLine(i); });
22: Console.ReadLine();
23: }
renders (and this obviously isn’t deterministic because this is all async, so it may be slightly different order every run, but it proves the point):
1
Sleeper 1
2
3
4
5
Sleeping...
Sleeping...
Sleeping...
Sleeping...
Sleeping...
Sleeping...
Sleeper 2
Sleeper 3
Sleeping...
Sleeping...
Sleeping...
Sleeping...
Sleeping...
Sleeping...
Sleeper 4
Sleeper 5
Wednesday, January 20, 2010
Yesterday I posted a question to StackOverflow (http://stackoverflow.com/questions/2097364/mapping-to-serializabletype-in-fluent-nhibernate) asking whether anyone could tell me how to map a Serializable type using Fluent NHibernate. The outcome was disappointing to say the least. In 24 hours there have been less than 20 views. It was voted up twice, but no comments or answers were posted.
Even worse, there’s another post on StackOverflow (http://stackoverflow.com/questions/2000798/map-to-serializable-in-fluent-nhibernate) that asks this same question and has an answer that’s incorrect (it compiles but throws an exception at runtime).
Serializable types in NHibernate (XML)
Before I continue, I’ll give a little background. Feel free to skip this part. Suppose you want to map the following object (contrived, I know):
1: public class Person
2: {
3: public virtual string FirstName { get; set; }
4: public virtual string LastName { get; set; }
5: public virtual BirthCertificate BirthCertificate { get; set; }
6: }
1: public class BirthCertificate
2: {
3: public virtual DateTime DOB { get; set;}
4: public virtual string BirthCity { get; set; }
5: public virtual string BirthState { get; set; }
6: public virtual string HospitalName { get; set;}
7: }
Imagine, however, that you don’t want to map the BirthCertificate fields to a table. Imagine you want to serialize the BirthCertificate object and store it in a single column in the Person table.
NHibernate makes this really easy. When mapping the BirthCertificate property on Person, you would write something like this:
1: <property name="BirthCertificate" column="BirthCertificate" type="Serializable" />
and of course you would have to add a [Serializable] attribute to the BirthCertificate class like so:
1: [Serializable]
2: public class BirthCertificate
3: {
4: .......
Mapping Serializable using Fluent NHibernate
This is actually surprisingly easy.
The Fluent interface provides a CustomType method that allows you to map your entity to a custom, IUserType. The incorrect answer that was posted on the old StackOverflow post (link above) mentioned combining this CustomType method with the SerializableType type, like this:
1: CustomType<NHibernate.Type.SerializableType>();
That will build, but it throws an Exception at runtime:
An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
InnerException:
Could not instantiate IType SerializableType: System.MissingMethodException: No parameterless constructor defined for this object.
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean fillCache)
at System.RuntimeType.CreateInstanceImpl(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean fillCache)
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Activator.CreateInstance(Type type)
at NHibernate.Bytecode.ActivatorObjectsFactory.CreateInstance(Type type)
at NHibernate.Type.TypeFactory.HeuristicType(String typeName, IDictionary`2 parameters)
I’m not a contributor to the Fluent NHibernate project (though I’m considering it after some other things calm down and I have more time), so I wasn’t particularly familiar with the codebase. In order to find the solution, I downloaded the latest code and stepped through it to see how it works.
Basically, the fluent interface collects all your mapping settings and then outputs the appropriate hbm’s at configure-time. Using the incorrect answer above resulted in the following mapping for the BirthCertificate property:
1: <property name="BirthCertificate"
2: type="NHibernate.Type.SerializableType, NHibernate,
3: Version=2.1.2.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4">
4: <column name="`BirthCertificate`" />
5: </property>
Hey – that should read type=”Serializable”! We don’t want the whole Type info there!
Turns out one of the overloads of the CustomType method takes….. you guessed it (!)…. a String!
The following is the correct way of mapping a Serializable type in Fluent NHibernate
1: CustomType("Serializable");
Yes I feel stupid for not figuring this out from the start! One comfort though is that it doesn’t seem that many people know this, even though it seems so obvious.
Stupid as I feel, I also feel like I gained a lot from the hour I spent on this; I finally got to delve into the Fluent NHibernate code.
Friday, January 08, 2010
Problem
I have a model that uses the State pattern. Some States allow read/write access to the Model’s properties and some are read-only. I wanted a good way to separate the logic for this from my Views; the View shouldn’t have to decide whether properties are displayed as TextBoxes or inside Divs.
First Thought
At first I was going to create a custom ViewEngine. That ViewEngine would be responsible for choosing the right View – that is, if the View was called “Edit” but the model was in a readonly state, it would change the View to “ReadOnly”. However, that just didn’t sound right – why was that responsibility falling on the ViewEngine? Plus, it’s kind of inflexible – what if some editable Views are called “Edit” but some are called “Details”.
Solution
I ended up with a mixture of a custom ActionFilter and a base Controller class. Before I show you the code, let me show you the usage:
1: [AcceptVerbs(HttpVerbs.Get)]
2: [StateItemEditView("ReadOnly")]
3: public ActionResult Edit(int id)
4: {
5: var module = _Repository.GetByID(id);
6: return View(module);
7: }
Notice Line 2 – this specifies that:
- The current action has editable content
- The ReadOnly View name is called “ReadOnly”
The code for the controller, which I use as a base class for my controllers that act upon StateItems:
1: public class StateItemController : Controller
2: {
3: protected override ViewResult View(string viewName, string masterName, object model)
4: {
5: object readOnlyViewName;
6: if (ControllerContext.Controller.TempData
7: .TryGetValue(StateItemEditViewAttribute.key_ReadOnlyView, out readOnlyViewName))
8: {
9: var stateItem = model as IStateItem;
10: if (workflowItem != null && stateItem.CurrentState.IsReadOnly)
11: viewName = readOnlyViewName as string;
12: }
13: return base.View(viewName, masterName, model);
14: }
15: }
Before returning the View, which has a ViewName string, we want to make sure the ViewName is correct. We check the Controller’s TempData for a predefined key. If that key exists, the value will be the name of the View to display for ReadOnly states. We then check if the Model exists and is a StateItem, and if it’s ReadOnly we change the ViewName before returning the View.
The StateItemEditViewAttribute is just responsible for setting the TempData key:
1: public class StateItemEditViewAttribute : ActionFilterAttribute
2: {
3: public StateItemEditViewAttribute(string readOnlyView)
4: {
5: _ReadOnlyView = readOnlyView;
6: }
7: private string _ReadOnlyView;
8: public const string key_ReadOnlyView = "ReadOnlyView";
9: public override void OnActionExecuting(ActionExecutingContext filterContext)
10: {
11: filterContext.Controller.TempData.Add(key_ReadOnlyView, _ReadOnlyView);
12: }
13: }
I’m using this for a binary dicision – Edit/ReadOnly – but this could be used for a lot of other purposes too.
Thursday, January 07, 2010
Does size matter?
.NET’s DateTime class supports a range between 01/01/0001 00:00:00 and 12/31/9999 23:59:59.9999999. Sql Server’s calendar is not quite as big – it starts at 1/1/1753. Therefore, if you have an object with a DateTime that’s set to DateTime.MinValue (or any other date before 1/1/1753) and you try to save that to a database, you’ll get the following exception:
SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
This recently got in my way. I’m building an application on top of a legacy database. There’s a table with a CreatedDate column that’s nullable. However, in my domain model I didn’t want CreatedDate to be a Nullable<DateTime> because everything should have a CreatedDate – is there anything that wasn’t created at some point in time?
My object looks like this:
1: public class MyObject
2: {
3: public MyObject()
4: {
5: CreatedDate = DateTime.Now;
6: }
7:
8: public virtual string Name { get; set; }
9: public virtual DateTime CreatedDate { get; protected set; }
10: }
Existing data in legacy database
The problem is that many of the existing entries in the database have a NULL entry for CreatedDate. Because of this, CreatedDate will be set to DateTime.MinValue. When I tried to save the object back to the database I got the above mentioned SqlDateTime overflow exception.
Going forward I don’t want any more NULL entries, but I don’t have the ability to update all existing NULLs to some arbitrary date (without having a whole back and forth with the DBAs). What I decided would be the best idea would be to support NULL entries in the DB transparently – NULL entries will map to DateTime.MinValue on the GET side, and DateTime.MinValue will map to NULL on the UPDATE/SAVE side. Since a new object always has its CreatedDate property set to DateTime.Now on instantiation, only really old objects will show 1/1/0001 as their created date in the system.
Implementation of IUserType
NHibernate has an IUserType interface which allows you to specify your own type for saving and retrieving data. Here’s what I wrote to handle my requirements:
1: public class NullDateTimeAsMinDateType : IUserType
2: {
3: public new bool Equals(object x, object y)
4: {
5: if (ReferenceEquals(x, y))
6: return true;
7: if (x == null || y == null)
8: return false;
9: return x.Equals(y);
10: }
11: #region IUserType Members
12:
13: public object Assemble(object cached, object owner)
14: {
15: return cached;
16: }
17:
18: public object DeepCopy(object value)
19: {
20: return value;
21: }
22:
23: public object Disassemble(object value)
24: {
25: return value;
26: }
27:
28: public int GetHashCode(object x)
29: {
30: return x == null ? typeof(DateTime).GetHashCode() : x.GetHashCode();
31: }
32:
33: public bool IsMutable
34: {
35: get { return false; }
36: }
37:
38: public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner)
39: {
40: var obj = NHibernateUtil.DateTime.NullSafeGet(rs, names[0]);
41: if (obj == null)
42: return DateTime.MinValue;
43:
44: DateTime dateTime = (DateTime) obj;
45: return dateTime;
46: }
47:
48: public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index)
49: {
50: if (value == null)
51: {
52: ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
53: return;
54: }
55: DateTime dateTime = (DateTime)value;
56: if (dateTime.CompareTo(System.Data.SqlTypes.SqlDateTime.MinValue.Value) < 0)
57: ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
58: else
59: ((IDataParameter)cmd.Parameters[index]).Value = dateTime;
60: }
61:
62: public object Replace(object original, object target, object owner)
63: {
64: return original;
65: }
66:
67: public Type ReturnedType
68: {
69: get { return typeof(DateTime); }
70: }
71:
72: public NHibernate.SqlTypes.SqlType[] SqlTypes
73: {
74: get { return new[] { NHibernateUtil.DateTime.SqlType }; }
75: }
76:
77: #endregion
78: }
I’m using FluentNHibernate, so my mapping looks like:
1: Map(x => x.CreateDDate)
2: .Column("create_date")
3: .CustomType<NullDateTimeAsMinDateType>()
4: .Nullable();
That’s it. Now the CreatedDate column in the DB doesn’t have to get touched and SQL Server’s date fields play nice with .NET DateTime.
Sunday, December 27, 2009
My laptop has not been behaving lately and I figured it’s time for a wipe & a fresh install. I was compiling a list of all the apps I need to install and figured I’d share it with the world. My current feeling is that anything not on this list will have to be installed on a VM, but we’ll see how long that lasts. I really just want my new install to be clean and tidy.
Development
Visual Studio 2008
Expression Studio 3
SQL Server 2008
CodeRush & Refactor! Pro – you’d have to be a masochist not to use some sort of code assistance plugin
TortoiseSVN
VisualSVN – integrates SVN (runs on top of TortoiseSVN) straight into Visual Studio. $49 and worth every penny!
WinMerge – it’s free and so much better than WinDiff
Fiddler2 – a terrific web debugging proxy. It’s free and worth every penny (and then some)
Communication
Pidgin – my officemates use AIM (and probably Win95 too), but I use GTalk for everything else. 1 (free) app is better than 2
uTorrent – I was an Azureus guy until they turned into Vuze and increased their bloat exponentially. uTorrent does the job, and does it well.
Windows Live Writer – it’s actually a great blogging software. Seriously!
- CodeSnippet plugin
TweetDeck – my twitter client of choice
Tools
Notepad++ – because notepad sucks
VirtualBox – really great Virtualization software, and it’s free
Paint.NET – comes in handy way more than I thought
PeaZip – open source, handles tons of file formats, and it’s prettier than 7zip
Virtual CloneDrive – freeware tool to mount ISO and other images. Don’t ask me why Windows doesn’t come with this!
Firefox Plugins
Firebug
YSlow
Adblock Plus
Windows Media Player Plugin
Tuesday, December 08, 2009
I was watching the video entitled How Do I: Get started with 3D Elements in WPF and was just completely thrown off by author, Todd Miranda’s, complete lack of visuals. So I played around with his example until I better understood what was going on and I figured I’d share. Please understand that I am not a XAML master and certainly not in 3D, so if you find any errors please let me know.
The XAML that Todd starts off with is:
1: <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2: xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
3: <Grid>
4: <Viewport3D>
5: <Viewport3D.Camera>
6: <PerspectiveCamera Position="-50,20,15" LookDirection="50,-15,-10" UpDirection="0,0,1" />
7: </Viewport3D.Camera>
8: <ModelVisual3D>
9: <ModelVisual3D.Content>
10: <Model3DGroup>
11: <DirectionalLight Color="White" Direction="-1,-1,-3" />
12: <GeometryModel3D>
13: <GeometryModel3D.Geometry>
14: <MeshGeometry3D Positions="0,0,0 10,0,0 10,10,0 0,10,0 0,0,10 0,10,10"
15: TriangleIndices="0 1 3 1 2 3 0 4 3 4 5 3" />
16: </GeometryModel3D.Geometry>
17: <GeometryModel3D.Material>
18: <DiffuseMaterial Brush="Red" />
19: </GeometryModel3D.Material>
20: </GeometryModel3D>
21: </Model3DGroup>
22: </ModelVisual3D.Content>
23: </ModelVisual3D>
24: </Viewport3D>
25: </Grid>
26: </Page>
The output is:
Camera Perspective
First off, let’s play with the Camera perspective. I think the best way to do this is first to define the different parts of the Camera Perspective, the most important being Position and LookDirection.

Take the grid above. It’s hard to show a Z axis, so I made the font smaller to try to trick your eye into believing it’s farther away.
Position
So the grid above is akin to a room, right? You have a top & bottom, right & left, and depth – we’ll call Z0 Backward and Z50 Forward so that if you’re walking into the room you’re walking Forward, ok?
Now here we have a video camera pointed at a box. It’s way too close to the box, as you can see, since all you can see in the viewfinder is part of the box. Well to get a better picture we have 3 directions to move the camera: forward/back, right/left, up/down:
(This might be a Position of -5(Z), 25(X), and 25(Y))
So in this instance, I might want to move the camera backwards, like so:
(This might be a position of –25,25,25)
Now notice how I moved the camera backwards and got the whole box in the viewfinder. I’m farther away from the box so I can see the whole thing.
The same principle holds true for the X & Y axis:
Perhaps this is –25,5,25 -- I moved the camera too far to the right and only see the right most part of the box.
The above is all the job of the Position attribute. But there’s another important element to how the camera picks up the image and that is the angle of the camera
LookDirection
“Well my head went back and to the left.”
In WPF, just like in real life, once you have your camera setup where you want it, you also need to angle the camera to point in the direction of the object you want to see. For instance, if you want to catch a right-hand side (from your view) shot of a box, what would you need to do? You would place your camera to the right side of the box at a depth that was equal with the center of the box. Then you would need to turn your camera to the left in order for the lens to face the box.
Step 1, move your camera to the side of the box
Step 2, turn your camera to the left:
XAML
This post was actually a lot of work to write. I think I’ll have to break up the other elements into other blog posts and write those at another time. However, for the sake of completion, let’s fold these new concepts back into the XAML from before.
Suppose you want to look change the direction so that you’re facing the red shape head-on. In other words, you want to look at the shape so that it looks just like a square (instead of an L shaped 3D shape). You might change the XAML so that line 3 reads
1: <PerspectiveCamera Position="-50,0,15" LookDirection="50,0,-10" UpDirection="0,0,1" />
The output looks like this:
Now don’t mind that it’s black on top – that has to do with the light source and is out of the context of this post. But let’s just see how we got here. Here are the two lines juxtaposed (I added spacing so that everything lines up):
1: <PerspectiveCamera Position="-50,20,15" LookDirection="50,-15,-10" UpDirection="0,0,1" />
2: <PerspectiveCamera Position="-50,0 ,15" LookDirection="50, 0 ,-10" UpDirection="0,0,1" />
So first I changed the Position’s X to 0 from 20, so I’m moving the camera to the right. Now if I didn’t change the LookDirection it would mean that the camera would be facing slightly downwards (-10) and slightly to the left (-15), so you’re not looking at it straight on. That’s why I dropped the X value of LookDirection up from –15 to 0.
Just keep in mind that it is very easy to place the Postion and/or LookDirection of the camera so that the shape is completely out of view.
Hopefully this helps put some of what Todd says in his video in context.
Thursday, December 03, 2009
Take the following XML fragment
1: <?xml version="1.0" encoding="iso-8859-1"?>
2: <con:search-results
3: xmlns:con="http://namespace.contoso.com/business-objects"
4: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5: xsi:noNamespaceSchemaLocation="http://www.contoso.com/dtd/syndication/biz-objects.xsd">
6: <con:search-query>ipod</con:search-query>
7: <con:result-count>2207</con:result-count>
8: <con:start-index>0</con:start-index>
9: <con:result-count>15</con:result-count>
10: <con:results>
11: <con:result>
12: ...
13:
Now suppose you loaded this XML into an XmlDocument, how would you query for all the <con:result> nodes? Using XPath you’d write something like
1: /search-results/results/result
So you might try writing something like
1: XmlDocument doc = new XmlDocument();
2: doc.LoadXml(response);
3: var resultNodes = doc.SelectNodes("/search-results/results/result");
but you would find that resuldNodes would be null. You have to instantiate an XmlNamespaceManager to help correctly maneuver your namespaces. That’s done like so:
1: XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
2: nsmgr.AddNamespace("con", "http://namespace.contoso.com/business-objects");
Then you would query your xml like so:
1: var resultNodes = doc.SelectNodes("/con:search-results/con:results/con:result")
That took me a little searching to dig up, but it makes sense, right?