![]() |
Thursday, August 22, 2002 |
Cassini. Cassini was released yesterday. I finally got around to downloading it today. It is quite small at 217K. Of course it only includes the source. You have to build it yourself. Since I'm in the process of writing a web server like application, I decided to give the code a perusal to see if there is anything in there I could reuse. First let me say that I know this a web server that was written to embed in the ASP.NET Web Matrix project. But Microsoft should realize by now that people are going to use their sample code as how code should be written. My main concern is the Cassini.Host code. It posts some work to a thread pool thread and then enters an infinite loop. Why tie up a thread pool thread? Just spin off a thread and be done with it. Again I realize that this is not meant to be an IIS replacement, but I'm guessing many people will probably do something like that. I did really enjoy looking through the Cassini.Request class. Very cool to be able to see how to implement the hosting interface. Plus I pulled some of the header parser code which I was in the middle of writing today. So that saved me maybe 30 minutes :-) [News from the Forest]7:49:48 PM ![]() |
What do you do for fun?. A simple question - what do you do for fun with web services? Or do you even have fun with web services? I've found over the past few weeks that I have a lot of fun implementing web services. ASP.NET makes them fun to write and easy to debug. I've got a simple security model that doesn't get in the way. I'm migrating that to an even simpler model using Greg's excellent sample on Digest Authentication. When I get this in place, writing web services will be even more fun. Product management comes to me and says "It would be nice if we could do x". I bang it out using an ASMX and ASHX file. The ASMX for our customers that want to use SOAP. ASHX for those customers of ours that just want to post POX (plain ol' XML). It is a lot of fun. I've learned to look at the project and beyond the politics. Right now I'm investigating how to give access to my data like Microsoft .NET My Services do (or did?) with HSDL. Right now our system requires that custom messages be written to support new types of queries (well...not always but a lot of the time). I'd like to use the HSDL query object paradigm. I think it would be more powerful because the query would then only be constrained to what the user can think of. Of course, I've got to find an XML Database to store all my stuff in or an unstructured database that understands XPath or I'm going to have to parse XPath and apply it to my database directly or maybe my database will support it out of the box. Might be a good time to start looking into XPath support in SQL Server 2000 and Oracle 9i. Hm...lots of stuff to keep me occupied. [News from the Forest]7:47:52 PM ![]() |
Leaving Phoenix. So Lynn and I talked about leaving Phoenix this weekend (as we cleaned out closets). Why would we leave? The one and only reason is the job market. It sucks here. For both of us. The jobs that are available (at least the ones on the job sites) just seem...well...boring. And all of them are lateral moves for me in my career at this time. I want to start moving up the ladder. So we talked about places we want to live. Here's the list that we came up with -
After looking at the job sites, New York appears to have the best market right now. But I'd like to hear from other people that live in those areas. What is the job market like right now for you? Contract or Perm. My best bet for Seattle is of course Microsoft since they are adding 5000 positions and $900 million to their R&D budget. I just perused their job listings and they do have a lot of cool positions open. Anybody from Microsoft reading my blog? If so, mind submitting my resume for me? I know, I know. How shameless of me. But everyone knows that in this business it's not what you know it is who you know. The what you know comes into play after you get an interview. [News from the Forest]7:47:27 PM ![]() |
Standardized Data Access. I'm sitting here looking through some code that I've written over the past week. And one of the things that stuck out at me is how I am doing my business components. Here is an example. I have a class called User. It contains things like failed logon count, password age, etc. When updating the failed logon count, I do things like this - User u = new User(); u.UpdateFailedLogonCount(u.FailedLogonCount + 1); Inside of UpdateFailedLogonCount, I do this - public void UpdateFailedLogonCount(int count) { UserDA.NewInstance().UpdateFailedLogonCount(UserID, count); } UserDA.NewInstance will check a configuration file for the .NET Type to create, check that the type derives from UserDA (an abstract class), and instantiate it. This might seem overkill since User is the business component. I don't believe it is because it allows me to test my business components by swapping in fake implementations of UserDA by simply putting a different type into the configuration file. Also UserDA can return whatever is needed. It can return a DataSet, DataTable, or DataReader (IDataReader of course). So far I really like this pattern because of the testability it gives me. And it allows me to switch providers much easier. I'm interested in hearing about what patterns you use. [News from the Forest]7:46:21 PM ![]() |
Transactions across Business Components. Richard has run into the same problem I have. Transactions across multiple business components. I've written a little about this before here. But I've never given a concrete example. Here goes... In my other entry I had a User object. This object has methods such as UpdateFailedLogonCount, LockAccount, etc. One of the business rules is if the user fails to logon N number of times, the account is locked out. There are several distinct ways to handle this First Pros
Cons
Explanation Second static public void UpdateFailedCount(User user, int maxAttempts) { using(OraConnection cn = new OraConnection(ConnectionString)) using(OraCommand upd = new OraCommand(UpdateSQL)) { int newCount = user.FailedCount + 1; upd.Parameters.Add("newCount", newCount); OraTransaction trans = null; try { cn.Open(); /*Start a transaction just in case */ trans = cn.BeginTransaction(); upd.Transactions = trans; upd.ExecuteNonQuery(); if(newCount >= maxAttempts) { using(OraCommand lock = new OraCommand(LockSQL, cn)) { lock.Transaction = trans; lock.ExecuteNonQuery(); } } /* Do this after the commit to guarantee db is current */ trans.Commit(); user.FailedCount = newCount; } catch(OraException) { if(trans != null) trans.Rollback(); } } } In the above code, I basically took the code from User.UpdateFailedLogonCount and User.LockAccount and made it into one method. This allows me to have them use the same connection and transaction. Pros
Cons
Explanation Third static public void UpdateFailedCount(User user, int maxAttempts) { Context ctx = Context.GetContext(); using(OraConnection cn = new OraConnection(ConnectionString)) { cn.Open(); OraTransaction trans = cn.BeginTransaction(); ctx.Connection = cn; ctx.Transaction = trans; int oldCount = user.FailedCount; try { user.UpdateFailedCount(user.FailedCount + 1); if(user.FailedCount >= maxAttempts) { user.LockAccount(); } trans.Commit(); } catch(OraException) { trans.Rollback(); user.FailedCount = oldCount; } } Context.FreeContext(ctx); } This time UserAction creates a Context that controls the connection and transaction. So how does UserDA look now (since it is the one that implements the logic for User)? It looks like this - public void UpdateFailedCount(int UserID, int count) { OraConnection cn = Context.GetContext().Connection; bool ownConnection = cn == null; try { if(ownConnection) { cn = new OraConnection(ConnectionString); cn.Open(); } OraCommand cmd = new OraCommand(UpdateSQL, cn); cmd.Transaction = Context.GetContext().Transaction; cmd.Parameters.Add("UserID", UserID); cmd.Parameters.Add("newCount", count); cmd.ExecuteNonQuery(); } finally { if(ownConnection && cn != null && cn.State == ObjectState.Open) cn.Close(); } } Of course, UseDA.LockAccount looks very similar to this as well so I won't produce it here. Pros
Cons
This is probably a lot more information than you wanted in a blog entry :-) But it does cover the three ways that I've solved the problem. These three ways are by no means the only ways to solve this problem. I've found myself using all three in the same project. Sometimes you just have to put all the logic in a stored procedure because the code is called so frequently. 80% of the time I find myself doing the third way. I build my objects with methods that perform actions (i.e. User object). These actions are implemented in terms of stateless Data Access components (i.e. UserDA object). Then if I need to compose those actions into more complex transactions, I create a transaction class (i.e. UserAction) and implement the complex methods in terms of methods on the object using a context object to control the connection and transaction. If anyone is interested, I can generate a simple project that shows what I'm talking about. Just let me know. I would also love to hear whether or not people think I'm over complicating everything or if you just think I'm smoking crack for thinking this will work :-) One closing note, I normally fall back to the first way (stored procedures) if after profiling the code I notice that I'm spending a lot of time on the network. But I only fallback to the first way if the time spent on the network is significantly more expensive than the load on the database. So far I've only had to fall back to a stored procedure about 5% of the time. And those are for some very specialized queries that require unions of data and some nasty outer joins. OK...one more note. This code is typed from memory after I've dumbed myself down by watching "Dog Eat Dog". So don't copy and paste it and expect it to work. Think of it as pseudo-code. [News from the Forest]7:45:09 PM ![]() |
Can teach. Won't teach.. Learning, sharing, and doing both. ... I wonder what connections exist between learning and teaching, or, in KM context, between learning and sharing. Are those who dare to share and eager to learn are the same people? Are these two sides of the same coin? May be it’s a coincidence in my case :-) [Mathemagenic] I believe that all sharers are learners. However from my experience there are perhaps five to ten times more people who can learn but won't teach than there are people who'll do both. The implication would be that you can only klog 10-20% of an organization. But watch the generation of kids who are going to grow up with the medium. [Curiouser and curiouser!] 7:41:24 PM ![]() |
Making Them Mind I will take more time this day to listen and respond to all of you. But before I go, keep this in mind: Don't give attention to poor behavior. Reward positive work. That is how you get a good response from children (If you have any, you understand what I'm saying). The rule is no different in society. We spend too much energy on the negative. Rewarding good public policy and positive business policy is a key to change. Making laws to require behavior incites a feeling of suppression. Suppression breads anger, violence and disobedience. [Tara Grubb For Congress Radio Weblog]6:23:18 PM ![]() |
BlogBack: Hey! BlogStreet's Starting to Be Very Cool.. BlogBack: Hey! BlogStreet's Starting to Be Very Cool.[The FuzzyBlog!] 10:52:18 AM ![]() |
This is so cool. I found this site in my referers list. You can see there which books were recently mentioned on weblogs. I think that this kind of automatic gathering interesting news is a cool concept. Need to do that more. [Krzysztof Kowalczyk's Weblog] 6:51:38 AM ![]() |