NDepend update brings 64 bit compatibility

September 23, 2008 at 9:00 PMAndre Loker

Patrick Smacchia kept his word: the current version of NDepend added support for dependency graphs under 64 bit operating systems. If you remember, this was one of the few points of criticism I mentioned in my little review on NDepend. Visual NDepend can now visualize the dependencies between types, namespaces and members. If you're hovering over a cell in the Matrix view, NDepend will tell you how the types/namespaces/members on the two axes depend on each other in the small Info window in the lower left area of the screen:

image

When you click the cell a window appears with one or several graphs showing those dependencies visually:

image

While this dependency graph does not show you something completely new, it still a beneficial feature: visualizing the dependencies between types and members makes it much easier to understand them and to communicate them to other developers.

The NDepend people have done their homework. The The dependency graph - like almost every other part of Visual NDepend - uses visual variables effectively to get the maximum information out of the visualization: box sizes, line thickness * and colour are used to not only tell provide the user with additional information on the role and importance of the involved members (lines of code, number of incoming and outgoing dependencies etc.).

All in all, with the 64 bit support for dependency graphs there's one more reason to recommend NDepend.

* There's a drop down that can be used to define what the thickness of edges should represent. As Patrick Smacchia explains in the comments, changing the value does not necessarily lead to a visible change depending on the code that is analysed.

Posted in: Tools

Tags: ,

Getting rid of strings (3): take your app settings to the next level

September 5, 2008 at 1:23 PMAndre Loker

In the previous parts of this series (part 1, part 2) I talked about the problems with literal strings in source code and presented different strategies to avoid those problems. In this episode I'll explain how we can abstract from app settings and leverage the power of the Castle DictionaryAdapter to improve the way our applications access their app settings.

Basics

Probably the easiest way to make certain aspects of a .NET application configurable is by using app settings. You can define app settings by adding (or augmenting) an <appSettings> section to your web.config or app.config, depending on the project type. This could look something like this:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:   <appSettings>
   4:     <add key="MaxUsers" value="20"/>
   5:     <add key="FeedbackMail" value="foo@localhost"/>
   6:   </appSettings>
   7: </configuration>

[As a small side note: you don't have to physically keep the appSettings section in the web.config/app.config file - read Keep your .config clean with external config files to learn how to move settings outside of the config file.]

To access the settings easily use the configuration API exposed by ConfigurationManager, specifically the AppSettings property. Here's a tiny app that accesses the values from the appSettings section:

   1: using System;
   2: using System.Configuration;
   3:  
   4: public class Program {
   5:   private static void Main() {
   6:     string feedbackMail = ConfigurationManager.AppSettings["FeedbackMail"];
   7:     int maxUsers = int.Parse(ConfigurationManager.AppSettings["MaxUsers"]);
   8:     Console.WriteLine("Feedback e-mail address: {0}", feedbackMail);
   9:     Console.WriteLine("Max users: {0}", maxUsers);
  10:   }
  11: }

As you see, that's fairly simple. Some points of interest:

  • ConfigurationManager lives in System.Configuration. You need to add the assembly System.Configuration.dll to your project to use this class
  • AppSettings has two indexers:
    • One indexer accepts a string: the string provided should be one of the keys as defined in the appSettings section. The value returned is the content of the value attribute of the respective appSettings entry or null if the key wasn't found. Keys are case insensitive by the way, so AppSettings["feedbackMAIL"] returns the same value as AppSettings["FeedbackMail"]. Note, however, that white space before or after the key does count, so AppSettings[" FeedbackMail"] will return null. Also be sure to check your config file for accidentally added white space within the key attribute if your app does not find certain keys.
    • The other indexer accepts an integer, which is the index of the app setting to return. Granted, I don't see much use for that indexer.
  • The values returned by the indexers are always strings. Therefore, if you want to have an app setting as an integer you'll need to parse it.

Let's analyse this basic approach:

  • We use strings to index the AppSettings property which - as you should know by now - is very problematic.
    • If you misspell the key, the value returned is null, but you won't notice it before runtime.
    • If you change the key in the app settings, you'll have to update all references to that key in your code. Remember that strings are hard to refactor.
  • Values are always returned as strings so you need to parse them if you need data of a type other than string

Improving the situation

If you read the first article of this series you know that there are two basic steps that can improve the situation:

  1. Avoid spreading literals all over the code, define and use constants instead
  2. Hide any string dependent code behind an appropriate API

Applying those rules might lead you to the idea to write a class that encapsulates the app settings. A good idea indeed! Here's a class that encapsulates the app settings of our tiny example:

   1: class MySettings {
   2:   // constants that define the keys in the app settings
   3:   private const string MaxUsersKey = "MaxUsers";
   4:   private const string FeedbackMailKey = "FeedbackMail";
   5:  
   6:   public static string FeedbackMail {
   7:     get { return ConfigurationManager.AppSettings[FeedbackMailKey]; }
   8:   }
   9:  
  10:   public static int MaxUsers {
  11:     get { return int.Parse(ConfigurationManager.AppSettings[MaxUsersKey]); }
  12:   }
  13: }

I made the properties static because the class is stateless. Now you can access the settings like this:

   1: public class Program {
   2:   private static void Main() {
   3:     string feedbackMail = MySettings.FeedbackMail;
   4:     int maxUsers = MySettings.MaxUsers;
   5:     Console.WriteLine("Feedback e-mail address: {0}", feedbackMail);
   6:     Console.WriteLine("Max users: {0}", maxUsers);
   7:   }
   8: }

This is much better! The strings are neatly hidden, so is the parsing of the integer. You can refactor the names of the properties easily using the refactoring tool of your choice.

Is this solution the final answer? Certainly not. This solution still suffers from some issues :

  • It's tedious to add and implement properties and possible parsing manually for each setting in the app settings section.
  • The settings are now strictly tied to ConfigurationManager. It's difficult to mock some app settings for unit testing using this approach.

Let me elaborate on the second issue: assume you have a class that is responsible for sending an email to the system administrator in case of an error. Here's a possible excerpt of such a system:

   1: // an interface we use to abstract sending of emails.
   2: public interface IMailSender {
   3:   void Send(string to, string subject, string text);
   4: }
   5:  
   6: // Sends error reports by mail
   7: public class ErrorReporter {
   8:   private readonly IMailSender mailSender;
   9:  
  10:   public ErrorReporter(IMailSender mailSender) {
  11:     this.mailSender = mailSender;
  12:   }
  13:  
  14:   public void SendErrorReport(string text) {
  15:     var email = MySettings.FeedbackMail;
  16:     mailSender.Send(email, "Application error", text);
  17:   }
  18: }
  19:  

It's certainly nice that we did not hardcode the email address that the report is sent to. But if we were to unit test the method we'd have to provide a value for the FeedbackMail app setting. (I'm using Rhino Mocks by the way)

   1: [Test]
   2: public void SendErrorReport_UsesMailSender() {
   3:   var mailSender = MockRepository.GenerateMock<IMailSender>();
   4:  
   5:   var text = "test message";
   6:   var email = "foo@localhost";
   7:  
   8:   // need to inject the email into the app settings
   9:   ConfigurationManager.AppSettings["FeedbackMail"] = email;
  10:  
  11:   var reporter = new ErrorReporter(mailSender);
  12:   reporter.SendErrorReport(text);
  13:  
  14:   mailSender.AssertWasCalled(x=>x.Send(email, "Application error", text));
  15: }

To make the test work we need to inject the expected email address into the app settings. I personally think that this situation is awkward and does certainly not isolate the unit test around one class under test. ErrorReporter uses MySettings which again uses ConfigurationManager. For my taste the number of classes involved in this unit test is unnecessarily high.

A solution

If you've never heard of Castle DictionaryAdapter, go and read my article on it, because this little tool will improve our solution a lot.

Here's what we do:

  • Delete MySettings, we won't use it anymore
  • Create instead an interface that represents your app settings:
   1: public interface ISettings {
   2:   int MaxUsers { get; }
   3:   string FeedbackMail { get; }
   4: }
  • Create a dictionary adapter that handles all the plumbing between ISettings and AppSettings:
   1: var factory = new DictionaryAdapterFactory();
   2: var adapter = factory.GetAdapter<ISettings>(ConfigurationManager.AppSettings);
  • Use this object instead of MySettings:
   1: public class Program {
   2:   private static void Main() {
   3:     var factory = new DictionaryAdapterFactory();
   4:     var settings = factory.GetAdapter<ISettings>(ConfigurationManager.AppSettings);
   5:     var feedbackMail = settings.FeedbackMail;
   6:     var maxUsers = settings.MaxUsers;
   7:     Console.WriteLine("Feedback e-mail address: {0}", feedbackMail);
   8:     Console.WriteLine("Max users: {0}", maxUsers);
   9:   }
  10: }

Again, we have a type safe interface for our app settings. But what did we gain?

First we have to use much less code to define the interface for our app settings: ISettings is a no-brainer, just define properties with the desired type and the name matching the app settings key [see this article on DictionaryAdapter to learn how this can be configured in detail]. The DictionaryAdapter will handle all necessary lookup and conversion for you. Less code on our side is A Good Thing™.

Secondly by using an interface we have created a better abstraction of the app settings. Combine this with the power of dependency injection and you've created a basis for well testable, highly configurable code. If you don't see what I mean, read on and let me elaborate.

Why this solution rocks

First of all change ErrorReporter to accept an ISettings instance and use it instead of MySettings:

   1: public class ErrorReporter {
   2:   private readonly IMailSender mailSender;
   3:   private readonly ISettings settings;
   4:  
   5:   // Inject ISettings as well
   6:   public ErrorReporter(IMailSender mailSender, ISettings settings) {
   7:     this.mailSender = mailSender;
   8:     this.settings = settings;
   9:   }
  10:  
  11:   public void SendErrorReport(string text) {
  12:     var email = settings.FeedbackMail; // use ISettings instead of MySettings
  13:     mailSender.Send(email, "Application error", text);
  14:   }
  15: }

Two changes have taken place: I inject the ISettings dependency through the constructor and I use this object to access the email address.

ISettings in action - unit test

Here's the updated version of the unit test from above:

   1: [Test]
   2: public void SendErrorReport_UsesMailSender() {
   3:   var mailSender = MockRepository.GenerateMock<IMailSender>();
   4:  
   5:   var text = "test message";
   6:   var email = "foo@localhost";
   7:  
   8:   // create a stub for ISettings
   9:   var settings = MockRepository.GenerateStub<ISettings>();
  10:   // let this stub's FeedbackMail property return a specific value
  11:   settings.Stub(x => x.FeedbackMail).Return(email);
  12:  
  13:   // inject the settings
  14:   var reporter = new ErrorReporter(mailSender, settings);
  15:   reporter.SendErrorReport(text);
  16:  
  17:   mailSender.AssertWasCalled(x=>x.Send(email, "Application error", text));
  18: }

This approach is far superior to the old approach because we only have to stub a direct dependency of ErrorReporter (ie. ISettings). There's no need to configure an indirect dependency like ConfigurationManager.AppSettings. Furthermore we could now make an ISettings mock to check whether ErrorReporter really uses the settings object. Short, we have the full control of the behaviour of the ISettings instance.

ISettings in action - the real app

To use ISettings and ErrorReporter in a real app, we'd preferably use an IoC container like Castle Windsor to configure the ErrorReporter instance.

Here's how you could configure the container:

   1: var container = new WindsorContainer();
   2: // we'll need an implementation of IMailSender
   3: container.Register(Component.For<IMailSender>().ImplementedBy<SomeClassImplementingIMailSender>());
   4:  
   5: // create the adapter
   6: var adapter = new DictionaryAdapterFactory().GetAdapter<ISettings>(ConfigurationManager.AppSettings);
   7: // register this adapter instance as the component for ISettings
   8: container.Register(Component.For<ISettings>().Instance(adapter));
   9:  
  10: // and finally register the error reporter
  11: container.Register(Component.For<ErrorReporter>());

Whenever we need an instance of ErrorReporter now we can ask the container for it (object locator approach):

   1: var reporter = container.Resolve<ErrorReporter>();
   2: reporter.SendErrorReport("Something went horribly wrong");

Alternatively you could let the IoC container inject an ErrorReporter instance where you need it (dependency injection approach).

Both ways we'll get an ErrorReporter instance that is readily configured to access the app settings in a transparent way.

Conclusion

By using the proposed combination of

  1. an interface defining the app settings
  2. a dictionary adapter that maps between the AppSettings and the interface and
  3. an IoC container that can inject the adapter wherever we need it

we were able to completely get rid of any app settings related strings and created an architecture that is easily configurable and well testable.

By abstracting from the appSettings in the app.config file it's also easy to use a different configuration source instead. DictionaryAdapter can wrap all kinds of dictionaries and NameValueCollections. And if you come to the conclusion that you'd rather want to store the app settings in a database, it's easy to do, as well. Instead of using the DictionaryAdapter you could implement ISettings in a way that loads app settings from a database.

Posted in: C# | Patterns

Tags: , , , ,

Retrieving values from an IDataReader

September 4, 2008 at 3:57 PMAndre Loker

Despite the undoubted advantages of ORM you probably need to fetch data directly from an IDataReader from time to time. Getting values out of the data reader is easy at first glance. However, there are some issues that you should be aware of.

Basic usage

Assume we have a simple table that holds comments for a web log or something similar:

image

(The UI is German, but I guess you know what the columns mean. If not: it's "Column name", "Data type" and "Allow Nulls")

Let's query all data in the table:

   1: using (var con = new SqlConnection(connectionString)) {
   2:   con.Open();
   3:   var cmd = new SqlCommand("SELECT * FROM Comment", con);
   4:   using(var rdr = cmd.ExecuteReader()) {
   5:     while(rdr.Read()) {
   6:       var id = rdr.GetInt32(0);
   7:       var post = rdr.GetInt32(1);
   8:       var position = rdr.GetInt32(2);
   9:       var text = rdr.GetString(3);
  10:       Console.WriteLine("{0,-3} {1,-3} #{2,-3} {3}", id, post, position, text);
  11:     }
  12:   }
  13: }

Nothing fancy here, we simply query all all rows and columns and print their values.

The index problem

Look at the way we retrieve data from he reader:

   1: var id = rdr.GetInt32(0);
   2: var post = rdr.GetInt32(1);
   3: var position = rdr.GetInt32(2);
   4: var text = rdr.GetString(3);

Using indices this way is probably not the best solution, especially because we use SELECT * to retrieve all columns. If the order of the columns change in the database, your application either crashes or it will using the wrong columns (the latter can arguably be the worse situation). Errors regarding this problem what be visible until runtime, which makes the code quite hard to maintain.

If we changed the query to something like

   1: SELECT ID, Post, Position, Text FROM Comment

we could at least prevent the index related issues because we would fetch the columns in an order that is defined by our application, not by the database.

As an alternative we could use IDataReader.GetOrdinal to determine the index of the columns at runtime:

   1: var cmd = new SqlCommand("SELECT * FROM Comment", con);
   2:  
   3: using (var rdr = cmd.ExecuteReader()) {
   4:  
   5:   // determine the indices of the columns and cache them for efficiency
   6:   var idIndex = rdr.GetOrdinal("ID");
   7:   var postIndex = rdr.GetOrdinal("Post");
   8:   var positionIndex = rdr.GetOrdinal("Position");
   9:   var textIndex = rdr.GetOrdinal("Text");
  10:  
  11:   while (rdr.Read()) {
  12:     var id = rdr.GetInt32(idIndex);
  13:     var post = rdr.GetInt32(postIndex);
  14:     var position = rdr.GetInt32(positionIndex);
  15:     var text = rdr.GetString(textIndex);
  16:     Console.WriteLine("{0,-3} {1,-3} #{2,-3} {3}", id, post, position, text);
  17:   }
  18: }

Here I again used SELECT *, but it would work exactly the same way with explicit column selection.

There are more ways to achieve the same effect. You can use the indexer of the data reader to fetch the columns by name:

   1: using (var rdr = cmd.ExecuteReader()) {
   2:  
   3:   while (rdr.Read()) {
   4:     var id = rdr["ID"];
   5:     var post = rdr["Post"];
   6:     var position = rdr["Position"];
   7:     var text = rdr["Text"];
   8:     Console.WriteLine("{0,-3} {1,-3} #{2,-3} {3}", id, post, position, text);
   9:   }
  10: }

Be aware though that the indexer unlike the explicit GetXYZ() methods only returns objects. If you need the values to have the correct type you have to cast:

   1: while (rdr.Read()) {
   2:   int id = (int)rdr["ID"];
   3:   int post = (int)rdr["Post"];
   4:   int position = (int)rdr["Position"];
   5:   string text = (string)rdr["Text"];
   6:   Console.WriteLine("{0,-3} {1,-3} #{2,-3} {3}", id, post, position, text);
   7: }

(I didn't use variable type inference (var) in this example to stress the fact that we are using ints and strings instead of objects)

"OK", you say, "with this knowledge I can now master data readers easily". Maybe not yet. There are two more issues.

The data type problem

Assume that you decide that your app will never have more than a few hundred comments per post. To save space in the database you change the data type of the Position column (which describes the order of comments for a specific post) from int to smallint. If you run any of the code examples above you'll probably be surprised that they'll all (except the one that uses the string indexer without casting) fail with an InvalidCastException:

Unhandled Exception: System.InvalidCastException: Specified cast is not valid.

Why is that? In the case of GetInt32 let's look at the remarks in the documentation:

No conversions are performed; therefore, the data retrieved must already be a 32-bit signed integer.

If the data coming from the database is a 16-bit integer (aka smallint) this call will therefore fail. To make the code work again you'd need to use GetInt16 instead.

And what about the cast in  (int)rdr["Position"]? After all, a 16-bit signed integer (short) should be castable to an int. While this is true, keep in mind the indexer of the data reader returns a boxed version of the short value as an object. Unboxing a value must always be done using the type of the boxed value (or one of its interfaces). The conversion from short to int can only take place after the value has been unboxed. That is, use either this (for implicit conversion to int):

   1: int position = (short)rdr["Position"];

or this (for explicit conversion to int):

   1: var position = (int)(short)rdr["Position"];

The data type problem can be really annoying because data type mismatches just like the index problem will be visible at runtime only. It's tedious to hunt down these bugs and it makes modification to the database excessively expensive.

You can avoid this problem to great extent if you don't force a "hard" conversion of the column value with GetXYZ and casts. Instead use the "soft" conversion methods provided by the Convert class. Here's the example from above again, but this time it's more robust against data type changes.

   1: var cmd = new SqlCommand("SELECT * FROM Comment", con);
   2:  
   3: using (var rdr = cmd.ExecuteReader()) {
   4:   while (rdr.Read()) {
   5:     var id = Convert.ToInt32(rdr["ID"]);
   6:     var post = Convert.ToInt32(rdr["Post"]);
   7:     var position = Convert.ToInt32(rdr["Position"]);
   8:     var text = Convert.ToString(rdr["Text"]);
   9:     Console.WriteLine("{0,-3} {1,-3} #{2,-3} {3}", id, post, position, text);
  10:   }
  11: }

(Again, feel free to improve the code by replacing SELECT * with an explicit column list and/or use the index based indexer of the data reader instead)

The DBNull problem

There's one final issue I want to write about. In the examples above all columns are explicitly NON NULL. What if the columns contain NULL?

Let's assume for now that the columns Post, Position and Index could be NULL (ignoring the fact that it wouldn't make much sense in that context). How would our code look like? Maybe like this:

   1: int id = Convert.ToInt32(rdr["ID"]);
   2: int? post =     rdr["Post"]     == null ? (int?)null : Convert.ToInt32(rdr["Post"]);
   3: int? position = rdr["Position"] == null ? (int?)null : Convert.ToInt32(rdr["Position"]);
   4: string text =   rdr["Text"]     == null ? null       : Convert.ToString(rdr["Text"]);

(I aligned the code a bit fore readability in this example)

You'd maybe expect that rdr["Position"] returns null if the column contains NULL. Run the example and you'll see that it's not the case. This is important to now: columns that contain NULL in the database will be returned as an instance of DBNull by the data reader! Furthermore DBNull can't be converted to any other datatype (int, short etc.) with one exception: if Convert.ToString is called on a DBNull object, an empty string is returned (at least in the Sql Server implementation of IDataReader).

To check whether a column in the database contains NULL it's therefore not valid to check whether a value returned by the data reader equals null (it won't ever). Instead, check whether the returned value is a DBNull. There are basically two ways for this. Either use IsDBNull:

   1: if(rdr.IsDBNull(1 /* column index */) {
   2:   // value is NULL
   3: }

or check the type of the value directly:

   1: if(rdr["TheColumn"] is DBNull){
   2:   // value is NULL
   3: }

The example from above should therefore look something like:

   1: int id = Convert.ToInt32(rdr["ID"]);
   2: int? post     = rdr["Post"]     is DBNull ? (int?)null : Convert.ToInt32(rdr["Post"]);
   3: int? position = rdr["Position"] is DBNull ? (int?)null : Convert.ToInt32(rdr["Position"]);
   4: string text   = rdr["Text"]     is DBNull ?       null : Convert.ToString(rdr["Text"]);

(As always: using the string based indexer is just one option to retrieve values, the same is applicable in case you use indices)

While the code above is not the most efficient piece of C# ever written it covers many of the problems I mentioned in this article:

  • the code does not depend on the order of the columns in the database.
  • the code can handle a fair amount of possible data type changes made to the table
  • the code can handle NULL values

For convenience, you might want to write some helper methods that simplify the task of retrieving values from the data reader.

   1: public static int? GetInt32(IDataRecord dr, string columnName) {
   2:   var value = dr[columnName];
   3:   return value is DBNull ? (int?) null : Convert.ToInt32(value);
   4: }
   5:  
   6: public static int? GetInt32(IDataRecord dr, int columnIndex) {
   7:   return dr.IsDBNull(columnIndex) ? (int?) null : Convert.ToInt32(dr[columnIndex]);
   8: }
   9:  
  10: public static string GetString(IDataRecord dr, string columnName) {
  11:   var value = dr[columnName];
  12:   return value is DBNull ? null : Convert.ToString(value);
  13: }
  14:  
  15: public static string GetString(IDataRecord dr, int columnIndex) {
  16:   return dr.IsDBNull(columnIndex) ? null : Convert.ToString(dr[columnIndex]);
  17: }

You can then use those methods like this:

   1: int id = Convert.ToInt32(rdr["ID"]);
   2: int? post = GetInt32(rdr, "Post");
   3: int? position = GetInt32(rdr, "Position");
   4: string text = GetString(rdr, "Text");

Of course, if you're using C# 3 you could make the methods above extensions to IDataRecord. In fact, I've written those extension methods for you (download ISC licensed source here). It basically does two things:

  • Provide equivalents to all those GetXYZ methods in IDataRecord that accept a column name instead of an index. Those methods are shortcuts for casting the values of reader["ColumnName"] to the proper type, but they suffer from the same data type and NULL value problem as their index based counterparts. Use them only for non null columns of which you know the data type exactly.
  • Provide "safe" versions of those methods that don't suffer from the data type problem and the NULL problem. I called those methods GetSafeXYZ (where XYZ is the data type of course). You won't find "safe" methods that accept a column index, but with the knowledge you - hopefully - gained from this article you should be able to write them yourself.

Here's the example from above using the "safe" methods:

   1: var cmd = new SqlCommand("SELECT * FROM Comment", con);
   2:  
   3: using (var rdr = cmd.ExecuteReader()) {
   4:   while (rdr.Read()) {
   5:     int id = rdr.GetInt32("ID");
   6:     int? post = rdr.GetSafeInt32("Post");
   7:     int? position = rdr.GetSafeInt32("Position");
   8:     string text = rdr.GetSafeString("Text");
   9:  
  10:     Console.WriteLine("{0,-3} {1,-3} #{2,-3} {3}", id, post, position, text);
  11:   }
  12: }

Attachments:

DataRecordExtensions.cs (20.37 kb)

Posted in: C# | Databases | Patterns

Tags: , ,

Chrome didn't survive long...

September 3, 2008 at 9:31 PMAndre Loker

... on my computer. Less than 24 h after I downloaded Google's first own browser I already uninstalled it. Sure, it's slick and lightning fast. But I can't help it: I don't trust it.

Excerpt from the "Google Chrome Privacy Notice":

Your copy of Google Chrome includes one or more unique application numbers. These numbers and information about your installation of the browser (e.g., version number, language) will be sent to Google when you first install and use it and when Google Chrome automatically checks for updates.  If you choose to send usage statistics and crash reports to Google, the browser will send us this information along with a unique application number as well.  Crash reports can contain information from files, applications and services that were running at the time of a malfunction.

It's not completely new that software has a unique ID which is frequently sent back "home". Firefox also has a unique ID used for the auto update feature (see Firefox Privacy Policy, search for "Automated Update Service"). It's the fact that everything you search for, everything you enter into the "Omnibox" is sent to Google (at least in the default configuration if Google is your search engine). It does not take much to come up with some really scary scenarios in which your ID is combined with your search profile. I'm not saying Google is doing it or planning it, I'm just pointing out that with Chrome there's a much higher potential for Google to profile individual usage behaviour.

Still convinced of Chrome? Read on. Excerpt from the "Google Chrome Terms of Service" (Update: this has been changed in the meantime by Google and does not represent the current state of the EULA, see "Update 3" below)

11. Content license from you

11.1 You retain copyright and any other rights you already hold in Content which you submit, post or display on or through, the Services. By submitting, posting or displaying the content you give Google a perpetual, irrevocable, worldwide, royalty-free, and non-exclusive license to reproduce, adapt, modify, translate, publish, publicly perform, publicly display and distribute any Content which you submit, post or display on or through, the Services. This license is for the sole purpose of enabling Google to display, distribute and promote the Services and may be revoked for certain Services as defined in the Additional Terms of those Services.

11.2 You agree that this license includes a right for Google to make such Content available to other companies, organizations or individuals with whom Google has relationships for the provision of syndicated services, and to use such Content in connection with the provision of those services.

11.3 You understand that Google, in performing the required technical steps to provide the Services to our users, may (a) transmit or distribute your Content over various public networks and in various media; and (b) make such changes to your Content as are necessary to conform and adapt that Content to the technical requirements of connecting networks, devices, services or media. You agree that this license shall permit Google to take these actions.

11.4 You confirm and warrant to Google that you have all the rights, power and authority necessary to grant the above license.

I'm no lawyer, but this sounds very much like "Google has the right to do whatever they like with the data you send and receive using their services". This is unacceptable.

Call me a follower, call be paranoid, call be simple-hearted. But I'm not willing to take part in this new chapter of informational transparency. I know that Google is by far not the only threat for privacy. But the more we combine different services of one specific provider the more traceable we become. I'm always open for a discussion, so if you feel like being able to convince me, have a shot at it!

Thanks to Hennie for pointing me to the Chrome terms of service.

Update: "This Post Not Made In Chrome; Google's EULA Sucks" - a nice post from someone who actually is a lawyer.

Update 2: As far as I understand, Chromium (the open source project on which Google Chrome is based) does not fall under the same terms of service, so chances are that if you're using a Chromium build you don't grant any license for submitted content to Google.

Update 3: In the meantime Google has replaced paragraph 11 of the Chrome Eula:

11. Content license from you

11.1 You retain copyright and any other rights you already hold in Content which you submit, post or display on or through, the Services.

Posted in: Tools

Tags: ,

Upgrading BlogEngine.NET from 1.4 to 1.4.5.x

September 3, 2008 at 8:31 PMAndre Loker

About two month ago I wrote about small issues I faced when I upgraded from BlogEngine.NET 1.3.1 to version 1.4. Today I updated my blog software again, this time to the trunk version of BlogEngine.NET. Almost everything went smoothly there were a few glitches I had to fix before I was satisfied with the results.

Here are the most important points: 

  • First of all, the issues with the strange author name in the RSS feed (mail.nospam@nospam.andreloker.de) has been taken care of in version 1.4.5.5. Nice! Note that the official 1.4.5 release from august 1st does not yet fix the issue. You'll need a revision 16044 or higher.
  • The strange e-mail fields (second point in my first post) are not really fixed - as far as "fixed" is the correct term - according to Mads Kristensen this was attentional. Mads has changed the behaviour a bit, however to the worse if you ask me. As mentioned in my first post if someone contacts you with the contact form you'd get an e-mail with your name and your email address as the "From" field. "Sender" and "Reply-To" headers are added which include the author's name and e-mail address. I mentioned some issues that are caused by this, for example that Thunderbird uses the "From" field when quoting a mail ("Andre Loker wrote:")
    Now it has changed slightly: the "From" field contains the name of the mail's author but the e-mail address of your blog. While this fixes the issue when quoting the mail it causes a worse issue: if you try to add the author to your address book, chances are that your mail application uses the author's name but your e-mail address. I created an issue for this bug - at least I think it should be considered a bug.
    To sanitize the situation I modified the code to create one reasonable "from" header and don't add any further headers to the mail:
       1: // Contact.aspx.cs - replace this:
       2: mail.From = new MailAddress(BlogSettings.Instance.Email, name);
       3: mail.ReplyTo = new MailAddress(email, name);
       4: mail.Sender = mail.ReplyTo;
       5:  
       6: // with:
       7: mail.From = new MailAddress(email, name);
  • The current version of the contact form behaves a bit odd or doesn't work at all if attachments are disabled in the contact form, as it is in my blog. The issue is known, so we can expect a fix in the future. As a preliminary fix you can change contact.aspx like this:
       1: // line 48ff:
       2: // replace:
       3: if ($('<%=txtAttachment.ClientID%>').value.length > 0)
       4:   return true;
       5:  
       6: //with
       7: <% if(BlogSettings.Instance.EnableContactAttachments) {%>
       8: if ($('<%=txtAttachment.ClientID%>').value.length > 0)
       9:   return true;
      10: <%}%>

Aside from these issues the people behind BlogEngine.NET have done a great task to improve their product.  I wholeheartedly recommend it to anyone asking for .NET based blogging software.

Posted in: ASP.NET | Meta

Tags: ,