Pages: << 1 ... 95 96 97 98 99 100 101 102 103 104 105 >>

10/02/05

Permalink 10:35:48 am
Categories: General, Programming

The Truth About Real Programmers - John Topley's Weblog

A very nice article here that rings a lot of bells:

The Truth About Real Programmers - John Topley's Weblog

09/02/05

Permalink 06:36:02 pm
Categories: General

Exact phrases are evil

<RANT>

Every now and then I want to search for a phrase (or a word) that includes special characters. Nothing fancy, maybe not more than a . (dot) in the "wrong" place. ".NET" comes to mind, or recently, ".Text". The exact phrase search facilities of the various search engines come to mind quickly... but they don't work.

Why is it that Google as well as MSN Search (and probably others) seem to be unwilling to implement a proper exact phrase search that really searches for the phrase entered? Don't they know about these problems? Don't they know that there are search phrases containing dots? I have no explanation.

</RANT>

Permalink 04:17:52 pm
Categories: General

The DNS Client service riddle

If you believe Microsoft's description for the DNS Client service, it's needed to resolve and cache DNS names. They emphasize that if the service is stopped, the computer will not be able to resolve DNS names and locate Active Directory domain controllers. Well, I can't say anything about the Active Directory domain controllers, but as far as the DNS resolutions go, this descriptions appears to be plain wrong.

I first found out about this a while after installing a Windows XP machine, with SP1, if I recall that correctly (it doesn't matter). I have my own DNS server running on a Linux machine, using PowerDNS and working as a "resolution proxy". The same server machine also has a web proxy, a Socks proxy and a mail server setup, which I use from the client. Therefore, browsing the web, reading my email, using Messenger and so forth, I never noticed anything out of the ordinary, because all these services never required my client machine to do any DNS lookups itself.

The problems started when I tried to access news servers from the client machine. No proxy was used for that, so the client needed to resolve DNS names itself, and this behaved highly unreliably. One time it would work, the next time not. Then maybe it would work for quite a while, allowing me to read a newsgroup. Then, when I wanted to post, it wasn't working once again.

With a network analyzer and the log file of my own DNS server, I was able to find out what the Windows machine was doing: it was actually contacting the DNS server only every 15th time or so (not really a reproducible value). In that single instance, everything would work as expected. The client was reliably misbehaving in this way when I repeatedly executed nslookup and ping commands from the command line. After a long while of fiddling around, I found out about the DNS Client service. After an even longer time, I found that once I switched off that service, everything was completely normal, with the client contacting the DNS server for every single lookup.

So, does that service resolve DNS names? Well, sometimes. Does it cache DNS name resolutions? No, I've never seen that.

I decided to blog about this because I wasn't able to find any comprehensive information on this topic on the net. I did actually find a page at The Elder Geek where the service is described to behave in a similar way to what I've seen, so I know I'm not the only one.

To this day I have no idea why that service is misbehaving for me. After I had initially thought it had something to do with my particular setup, I've since had reports from three different friends who have seen the same problem in their network setups, which are all distinctly different from mine. In each of these cases I was able to help them by suggesting they switch off the DNS Client service. The reason remains a riddle, though...

08/02/05

Permalink 06:20:31 pm
Categories: General

USB Vacuum Cleaner

I just came across a fantastic gimmick that I need to get: the USB vacuum cleaner! I found it for sale at getDigital.de, so that's where the product link goes:

getDigital.de - USB Vacuum Cleaner

07/02/05

Permalink 05:53:37 pm
Categories: Programming, .NET

Taking part in a System.Transactions transaction

In a recent MSDN TV interview, Mike Clark talked about (and demonstrated) the capabilities of the technology in the System.Transactions namespace, coming in .NET Framework 2.0. In other blog postings, such as in Angel Saenz-Badillos' posting Whidbey ADO.NET System.Transactions Distributed Transactions and in Florin Lazar's posting Transactions made easy: System.Transactions I found additional information on the topic. But all those publications have one thing in common: they look at the technology purely from the users' point of view, not from the point of view of a participant in such a transaction.

Now, especially considering the availability of the new lightweight transaction manager (LTM), I was interested to find out what I'd have to do to be able to take part in a (potentially distributed) transaction with my own objects, as coordinated by System.Transactions. Before I go on describing my findings (and the things I haven't yet quite understood), let me mention that I have no experience whatsoever with System.EnterpriseServices, so some misunderstandings may certainly be due to my ignorance.

A test object

To get things started, I thought I would need a simple object that would be able to act in the typical way required by any transaction: accept changes to data and commit or rollback those changes according to the transaction. So I wrote the following code for this purpose:

interface ITransactionable {
  void Commit( );
  void Rollback( );
}

class DataObject : ITransactionable {
  string oldDataField = String.Empty;
  string dataField = "preset string";
  
  public string DataField {
    get { return dataField; }
    set {
      if (oldDataField == String.Empty) oldDataField = dataField;
      dataField = value;
    }
  }

  public void Commit( ) {
    if (oldDataField != String.Empty) oldDataField = String.Empty;
  }

  public void Rollback( ) {
    if (oldDataField != String.Empty) {
      dataField = oldDataField;
      oldDataField = String.Empty;
    }
  }
}

Enlisting in a Transaction

To actually take part in a transaction, it's necessary to Enlist in one, an object that implements one of three interfaces with slightly different purposes. In the context of a distributed transaction, the single object that enlists in one may often be a transaction itself. Think of the ADO.NET or SQL-Server transactions, which may be part of a distributed transaction that also involves other software modules or even completely different machines.

What I did to be able to easily test this was to create a collection class typed for my ITransactionable interface above and implement the various System.Transactions interfaces on that class. So my collection, containing some objects, takes the role of a transaction in my own software system, which takes part in a larger overall transaction. The first thing I tried was to implement an interface called IPromotableSinglePhaseNotification, which is specifically made to work with the LTM, the big new thing in the whole namespace. This transaction manager is able to use a very lightweight architecture (hence the name) for the transaction handling as long as all participants are within one AppDomain, and it's also able to promote the participants to full-fledged distributed transactions if it finds that at least one participant is not in the same AppDomain as the others. At least that's what it should do... more about that later. My collection with the implementation of IPromotableSinglePhaseNotification looks like this:

class TransactionableCollection : List<ITransactionable>, 
  IPromotableSinglePhaseNotification {
  public TransactionableCollection( ) {
    Enlist(Transaction.Current);
  }

  void Enlist(ITransaction transaction) {
    ILightweightTransaction lwtrans = transaction as ILightweightTransaction;
    if (lwtrans != null) lwtrans.PromotableSinglePhaseEnlist(this);
  }

  void IPromotableSinglePhaseNotification.Initialize( ) { }

  ITransaction IPromotableSinglePhaseNotification.Promote( ) { return null; }

  void IPromotableSinglePhaseNotification.Rollback(ISinglePhaseEnlistment 
    singlePhaseEnlistment) {
    try {
      foreach (ITransactionable itransactionable in this)
        try {
          itransactionable.Rollback( );
        }
        catch { /* if necessary, handle the exception */ }
    }
    finally {
      singlePhaseEnlistment.Aborted( );
    }
  }

  void IPromotableSinglePhaseNotification.SinglePhaseCommit(ISinglePhaseEnlistment 
    singlePhaseEnlistment) {
    try {
      foreach (ITransactionable itransactionable in this)
        itransactionable.Commit( );
      singlePhaseEnlistment.Committed( );
    }
    catch {
      // if necessary, handle the exception
      singlePhaseEnlistment.Aborted();
    }
  }
}

For the enlistment proper the collection uses an automatic mechanism similar to what SqlClient does, by looking at the current transaction and using that for its enlistment. It's all just a sample, of course :-)
Now, the important thing is that this is all that's really needed to take part in a transaction handled by the LTM. I used a small test program to see if things worked like expected:

  DataObject ob1 = null;

  using (TransactionScope scope = new TransactionScope( )) {
    TransactionableCollection coll = new TransactionableCollection( );
    ob1 = new DataObject( );
    coll.Add(ob1);
    Console.WriteLine("Unchanged object: {0}", ob1);
    ob1.DataField = "changed text";
    Console.WriteLine("Field has been changed: {0}", ob1);
    
    scope.Consistent = true; // try commenting this out
  }

  Console.WriteLine("Out of TransactionScope: {0}", ob1);

As expected, changes to the object are committed as long as the TransactionScope.Consistent flag is set to true before the scope is disposed. Changes are rolled back if the scope is not consistent when disposed. Fine up to this point!

The distributed transaction

You may have noticed that in the code up to this point, the method Promote would simply return null. The reason for that is simple: as long as there are only transaction participants from the same AppDomain, the LTM doesn't see a need to promote a participant. The method isn't called and nobody cares for the return value. So what will happen when I try to add another transaction participant that's not in the same AppDomain? To find out, I inserted the following lines in my main test method, after the lines where I create and change my own object:

  using (SqlConnection conn = new SqlConnection(connStr)) 
    conn.Open( );

The simple call to the Open method of the SqlConnection is enough to make the SqlClient enlist its transaction in the System.Transactions transaction, too, which in turn triggers the promotion of existing participants. What follows is a call to the Promote method of my IPromotableSinglePhaseNotification implementation. The problem is, I have no idea what exactly I should be supposed to do at this point. Returning null or returning the same transaction that we originally enlisted in renders various exceptions. I tried a lot of things at this point, without success... with the current documentation being what it is, I wasn't able to find out what is expected of the Promote method. I'd be grateful if anybody could shed some light on this.

The other interesting thing is, if the lines of code where the Sql Server connection is opened occur before the line where my collection is created, there's no problem at all! In this case, the Promote method is once again not called at all and everything works just fine, together with the Sql Server transaction. In the system Component Services management applet one can see at this point that the DTC actually has a registered transaction, in which we are now taking part.

The road less travelled

Because I was trying to adhere to the new concepts of the automatic promotion by the LTM, I hadn't tried any of the more generic enlistment methods that are available in the "normal" ITransaction interface, as opposed to the ILightweightTransaction interface I was using. Implementing the IEnlistmentNotification interface, for instance, isn't any more complicated at all. Here's the code for that:

  void IEnlistmentNotification.Commit(IEnlistment enlistment) {
    DoCommit( ); // same code as before
    enlistment.EnlistmentDone();
  }

  void IEnlistmentNotification.InDoubt( ) { }

  void IEnlistmentNotification.Prepare(IPreparingEnlistment 
    preparingEnlistment, byte[] recoveryInformation) {
    preparingEnlistment.Prepared();
  }

  void IEnlistmentNotification.Rollback(IEnlistment enlistment) {
    DoRollback( ); // same code as before
    enlistment.EnlistmentDone();
  }

First, I didn't notice any differences to the previous approach. Apparently, the LTM always tries to use the IPromotableSinglePhaseNotification interface as long as (a) it's available and (b) the other participants, if any, are in the same AppDomain. So to really see a difference, it's best to remove the implementation of that interface (or to not register with the PromotableSinglePhaseEnlist method). And then, suddenly, with only the IEnlistmentNotification interface implemented, things started to work! Suddenly I could combine my own code with the SqlConnection code in any way I wanted, without a hitch! Curious...

Confusion

Apart from that stuff with the promotion there's another thing here that didn't seem to make much sense. In that video on MSDN TV, Mike emphasized specifically the significance of the new lightweight model, where a DTC transaction would only be used if really necessary. Of course, the promotion model together with the IPromotableSinglePhaseNotification interface is an important part of that. But now I had things running with IEnlistmentNotification only, my test program behaved just the same as the demo program that Mike used in the video. Although I'm not using nor implementing the lightweight interfaces, a DTC transaction is only created when the Sql Server becomes part of the equation. So these are two things that may be worth writing about again later, when I find out more about them.

Download

I want to clean up my test code a bit before I make my sample available. Feel free to comment if you have any questions!

<< 1 ... 95 96 97 98 99 100 101 102 103 104 105 >>

Enter your email address:

Search

Oliver
MVP logo
May 2013
Sun Mon Tue Wed Thu Fri Sat
 << <   > >>
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31