After various conversations on both internal and external projects, I’ve noticed that some of our web projects were being developed using a Session state called InProc.

InProc means In-Process, so IIS is hosting all of the

Session[“Dom”] = “Idiot!”; 

variables. Now, if the web application eats up too much memory, IIS 6 and above can be configured to recycle the Application pool – a contained unit of web sites, in order to free up memory. This is good for IIS but baaaad news for your website, as everything in the Session is lost – that could be shopping basket, current order status, user details! InProc is a bit of a quick and nasty method of developing as it just does its job, assuming that you are not going to host this to a larger audience (over about 5 users).

As I found out with any large project, nothing goes to plan, so, the best thing to do is to use StateServer and not InProc – but WHY?

StateServer is a totally out-of-process service that runs on either the same web server or a different server entirely. Session data is saved to this service so if the AppPool recycles, you have no problems whatsoever. Also, the data needs to serialize properly in order for it to be saved to the service.

Whats the point I hear you ask? Well, the point is that if you use InProc and your application gets load balanced (often without your knowledge), the website won’t work properly. Remember, load balancing is decided, by either the hardware or the software, to help manage the network traffic to a destination server. So 1 request to go to Server1 and another or Server2, or even ServerX! Youch! So your site’s Session could be stored on another machine.

StateServer works because all of the web.config’s point to the same machine, so they all work off that one service.

The other option is SQLServer, which stores it in SQL Server, which is more for web farms (multiple physical PCs), rather than web gardens (multiple virtualized PCs). Or you can use Custom for a custom implementation (e.g ODBC or XML), or Off to turn it off completely.

Therefore, a good recommendation is to always change your web.config to say:

<sessionState mode=”StateServer” … />

And start the ASP.NET State Service on your machine. This way to can always revert to InProc if you need to, but you are still ready for the switch over.

Believe me, it’s a lot easier to start out this way, rather than have to work backwards.

It is always a worthwhile exercise!


Bookmark with :
Digg It! DZone StumbleUpon Technorati Reddit Del.icio.us Newsvine Furl Blinklist
posted @ Thursday, October 09 2008 at 03:35 PM by Dominic

When working on a project recently, the data saved back to the database was huge. We are talking well over 100 properties. After talking to my Java buddy, he said that one way is to create an IsDirty method that returns if the object has changed state.

The IsDirty() method is used to query the state of an object - if it has been modified or not. The implementation is up to the developer, but ultimately it's use can save you a trip to the data source.

I have split this example into 3 stages:

  1. First attempt
  2. Refactored
  3. Event Handled

N.B. This article helps someone in (archaic) .NET 2.0 - but if you've looking to develop for .NET 3.5, it might be worth looking into DependencyProperty's, which caters for this sort of problem.

First Attempt

The problem I found when prototyping this is that it can be quite impractical at first glance:

class Customer
{
    private string firstName, surname;
    public Customer(string firstName, string surname)
    {
        this.firstName = firstName;
        this.surname = surname;
    }

    public string FirstName
    {
        get { return firstName; }
        set 
        { 
            if( firstName != value )
            {
                IsDirty = true;
                firstName = value;
            }
        }
    }
    public string Surname
    {
        get { return surname; }
        set 
        { 
            if( surname != value )
            {
                IsDirty = true;
                surname = value;
            }
        }
    }

    public bool IsDirty { get; private set; }
}

 

This is a bit bloated. Also, it relies on every property having to check for itself whether it is equal or not, setting the IsDirty property and also assigning the value.

After writing this and implementing a few more properties I found this to be a bit too impractical. Instead, I realised that they are all basically doing 3 steps:

  1. Checking the previous value to the new value.
  2. Setting IsDirty.
  3. Assigning the new value.

This example needs simplifying - or refactoring to be more precise.

Refactoring

Instead, I decided to implement this behaviour in a method called SetValue<T>() , which would raise events when a property has changed. This allows the IsDirty property to be changed centrally and debugging to be centralized.

Firsty I created the method:

private void SetValue<T>(ref T varName, T value)
{
    if (varName.Equals(value))
        return;
    
    IsDirty = true;
    varName = value;
}

 

Now, we can change our properties to:

public string FirstName
{
    get {return firstName; }
    set
    {
        SetValue<string>(ref firstName,value);
    }
}

public string Surname
{
    get {return surname; }
    set
    {
        SetValue<string>(ref surname,value);
    }
}

This is one implementation of it, but I decided to extend it to event handling as well, so that even the outside world can be notified about what is changing.

Event Handling

I decided to also implement this is in a typical Microsoft fashion: OnPropertyChanging and OnPropertyChanged.

In order to turn this into an event driven model I need to do a few things:

  1. Create some event arguments describing what is being changed.
  2. Add some event handlers to trigger a notification that they have been changed.
  3. Trigger the events from within your code
  4. (Optionally) wire up the events.
  5. Trigger the events from within your code

Create event arguments

Since I am using events, I want to create event arguments detailing what has changed. I have implemented this in 2 identical classes (and 1 base class). Here I have implemented a base class, and 2 classes which improve the clarity of the base class. I have chosen clarity over code bloat:

//Base class implementation
public abstract class PropertyChangeEventArgs : EventArgs
{
    public string PropertyName { get; protected set; }
    protected object Value { get; set; }

    public PropertyChangeEventArgs(string propertyName, object before)
    {
        this.PropertyName = propertyName;
        this.Value = before;
    }
}

//Holds arguments before the proerty has changed
public class PropertyChangingEventArgs : PropertyChangeEventArgs
{
    public object ValueBeforeChange
    {
        get
        {
            return this.Value;
        }
    }

    public PropertyChangingEventArgs(string propertyName, object before) 
        : base(propertyName,before)
    {
    }
}

//Holds arguments after the proerty has changed
public class PropertyChangedEventArgs : PropertyChangeEventArgs
{
    public object ValueAfterChange
    { 
        get 
        { 
            return this.Value; 
        } 
    }

    public PropertyChangedEventArgs(string propertyName, object after) 
        : base(propertyName, after)
    {
    }
}

Create event handlers

Now implement some event handlers:

public event PropertyChangingEventHandler PropertyChanging;
public delegate void PropertyChangingEventHandler(object o, PropertyChangingEventArgs e);

public event PropertyChangedEventHandler PropertyChanged;
public delegate void PropertyChangedEventHandler(object o,PropertyChangedEventArgs e);

Trigger the events from within your code

Now I need to trigger these events from the SetValue<T>() method. I will also need to find out what property was called by this SetValue<T>() method.

private void SetValue<T>(T varName, T value)
{
       if (varName.Equals(value))
           return;

       //TODO: Find the property's name that is calling this method
       string propertyName = "MyProperty";

       if (PropertyChanging != null)
           OnPropertyChanging(this, new PropertyChangingEventArgs(propertyName, varName));

       varName = value;

       if (PropertyChanged != null)
           OnPropertyChanged(this, new PropertyChangedEventArgs(propertyName, varName));
   }

The last thing to do is to find the property that is calling this method. This can be done using Reflection, by looking up the call stack. By getting the previous "frame", we can deduce where this is being called from. In our case, this is called "set_FirstName". Remove the "set_" and we have our property name:

StackTrace st = new StackTrace();
StackFrame current = st.GetFrame(1);
string propertyName = current.GetMethod().Name.Replace("set_", "");

(Optionally) wire up the events

I want to subscribe to the OnPropertyChanged event, so that I can set the IsDirty property within it. I have done this within a private constructor:

private Customer()
{
   PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged);
}

public Customer(string firstName, string surname) : this()
{
   this.firstName = firstName;
   this.surname = surname;
}

(Optionally) trigger the events from within your code

Now, I want to move the IsDirty assignment out of the SetValue() method because although overkill, it is not related to the setting of the value. It is related to the event but not the assignment. It also means that you have just wasted 15 minutes reading this article! :-) :

private void OnPropertyChanged(object sender, PropertyChangedEventArgs ea)
{
   IsDirty = true;
}

Summary

So what have we done? We've looked at ways in which we can implement notification within a class, so that we can save a database access. When getting to a large number of properties, we can bypass each save and also allow the outside world to be notified of its changes.

In the first example,we saw a cheap and nasty way of doing it, but impractical for larger classes. In the second example we saw a better implementation and in the third example we added event handling to extend the functionality further.

I hope this article helps someone - but if you've looking to develop for .NET 3.5, it might be worth looking into DependencyProperty's, which caters for this sort of problem.

Here is the full source code to have a play with:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer c = new Customer("Dominic", "Zukiewicz");
            c.FirstName = "Dommy dom dom";

            Console.WriteLine("Customer.IsDirty = " + c.IsDirty);

            Customer c2 = new Customer("Dominic", "Zukiewicz");
            c.Surname = "Zukiewicz";

            Console.WriteLine("Customer2.IsDirty = " + c2.IsDirty);
        }
    }

    class Customer
    {
        private string firstName;
        private string surname;

        private Customer()
        {
            PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged);
        }

        public Customer(string firstName, string surname) : this()
        {
            this.firstName = firstName;
            this.surname = surname;
        }

        public string FirstName
        {
            get
            {
                return firstName;
            }
            set
            {
                SetValue(ref firstName, value);
            }
        }

        public string Surname
        {
            get 
            { 
                return surname; 
            }
            set
            {
                SetValue(ref surname,value);
            }
        }

        public bool IsDirty { get; private set; }


        private void SetValue(T varName, T value)
        {
            if (varName.Equals(value))
                return;

            StackTrace st = new StackTrace();
            StackFrame current = st.GetFrame(1);
            string propertyName = current.GetMethod().Name.Replace("set_", "");

            if (PropertyChanging != null)
                OnPropertyChanging(this, new PropertyChangingEventArgs(propertyName, varName));

            varName = value;

            if (PropertyChanged != null)
                OnPropertyChanged(this, new PropertyChangedEventArgs(propertyName, varName));
        }

        public event PropertyChangingEventHandler PropertyChanging;
        public delegate void PropertyChangingEventHandler(object o, PropertyChangingEventArgs e);

        public event PropertyChangedEventHandler PropertyChanged;
        public delegate void PropertyChangedEventHandler(object o,PropertyChangedEventArgs e);

        private void OnPropertyChanged(object sender, PropertyChangedEventArgs ea)
        {
            Debug.Print("Property: {0}, After: {1}", ea.PropertyName, ea.ValueAfterChange);
            IsDirty = true;
        }

        private void OnPropertyChanging(object sender, PropertyChangingEventArgs ea)
        {
            Debug.Print("Property: {0}, Before: {1}", ea.PropertyName, ea.ValueBeforeChange);
        }
        
    }

    //Base class implementation
    public abstract class PropertyChangeEventArgs : EventArgs
    {
        public string PropertyName { get; protected set; }
        protected object Value { get; set; }

        public PropertyChangeEventArgs(string propertyName, object before)
        {
            this.PropertyName = propertyName;
            this.Value = before;
        }
    }

    //Holds arguments before the proerty has changed
    public class PropertyChangingEventArgs : PropertyChangeEventArgs
    {
        public object ValueBeforeChange
        {
            get
            {
                return this.Value;
            }
        }

        public PropertyChangingEventArgs(string propertyName, object before) 
            : base(propertyName,before)
        {
        }
    }

    //Holds arguments after the proerty has changed
    public class PropertyChangedEventArgs : PropertyChangeEventArgs
    {
        public object ValueAfterChange
        { 
            get 
            { 
                return this.Value; 
            } 
        }

        public PropertyChangedEventArgs(string propertyName, object after) 
            : base(propertyName, after)
        {
        }
    }
}

Bookmark with :
Digg It! DZone StumbleUpon Technorati Reddit Del.icio.us Newsvine Furl Blinklist
posted @ Thursday, October 09 2008 at 11:57 AM by Dominic

When writing stored procedures or views, I always create them in Visual Studio (2005/2008) and then run them on a specified database. When using "SELECT *", it is compact, but obviously does not help you find the columns of the table or view.

When using the IDE, I added a new SQL Script for Stored Procedures, and then I typed:

SELECT *
FROM Customers

and a blue box surrounded the statement. I right-clicked -> Design SQL Block.

The designer then listed all of the column names for me, and when clicking OK, instantly put them back into the SQL script I was creating!

SELECT  CustomerID, CompanyName, ContactName, ContactTitle, 
Address, City, Region, PostalCode, Country, Phone, Fax
FROM Customers

For the table I was using, this list over 60 columns for me!

So if you want a quick way of listing all of the column names for table of view:

  1. Add a database project to your site (if you haven't already done so)
  2. Right click Queries -> Add SQL Script
  3. Choose Stored Procedure Script
  4. Type your SELECT * From XYZ statement
  5. Right click -> Design SQL Block
  6. Click OK.

The designer will be updated with the new query.


Bookmark with :
Digg It! DZone StumbleUpon Technorati Reddit Del.icio.us Newsvine Furl Blinklist
posted @ Wednesday, October 08 2008 at 04:13 PM by Dominic

Just a little note here that we noticed testing something (how it had not occurred before, I do not know).  We have a function that we were referencing from a referenced assembly that would format values to the slightly odd format being used by the ERP that we were talking too.  In  most cases it seamed to work OK, but for smaller values it didn't quite product the result we expected.

It turns out that the result of the Division functiod in BizTalk Server 2006 is a double.  The mapper being the way it is converts this to a string (assumably using .ToString()).  At least this is how it looks when I point ildasm.exe at Microsoft.BizTalk.BaseFunctoids.dll.

Now, rather simply put, I was being a fool and trying to convert this to a decimal and wondering what was going on.  I was passing what I though was a value of "0.00002" to my referenced method and expecting it to be formatted properly.  When we looked deeper in to the issue, we noticed that the value coming out was in fact "2E-05", which is how a float or a double would represent the value 0.00002.

 

Quick use of the double.TryParse() fixes this issue and off we trundle.


Worth keeping in mind, and also worth having a look at the base functoids using ildasm.exe when relying on their output.


Bookmark with :
Digg It! DZone StumbleUpon Technorati Reddit Del.icio.us Newsvine Furl Blinklist
posted @ Wednesday, October 01 2008 at 03:49 PM by Matt Nield

My XP laptop had ground to a halt - 6 months without a rebuild and it had got so clogged that it literally took 5 minutes just to boot. I needed to wipe it and start again but the head of our technical team offered me a fresh laptop with a clean Vista Business build. Deciding that being a guinea pig was a nice idea, I accepted it. The 4 gig of ram (up from 2 gig) was the sweetener that made up my mind for sure :)

As I was setting it up just how I wanted it, one of the things I needed to do was sync my two mobile phones with it. I have both an HTC 4350 (Herald) from work and my own personal HTC TyTN II. On my XP laptop I used ActiveSync to sync up my calendar, tasks and contacts.

Knowing that ActiveSync has been replaced on Vista, I was hoping for an easy experience. After plugging in my TyTN II, Vista offered to sync my media files. Fine, but I wanted to sync with Outlook so I cancelled the dialog and started my hunt. In Control Panel I found 'Sync Centre' which offered to sync my media files again. This was getting annoying. Contacts and/or Outlook were mentioned nowhere.

Maybe the 'Windows Mobile Device Centre' in Control Panel was my best bet? Nope. That just had settings on whether I wanted to connect via USB and Bluetooth or not. Nothing about syncing. Googling didn't help me that much. There doesn't seem to be much info about this. Is it that obvious? Am I missing something?

Actually, I was missing something. The latest download of Windows Mobile Device Centre (currently 6.1 as I write). This is basically what ActiveSync used to be, and syncs up all the bits and pieces you'd expect with Outlook. In fact, it's very smart and clean and appears to be a nice improvement on ActiveSync.

I thought it worth blogging this for two reasons. Firstly, hopefully this will get indexed so that it can be a quick help to others who were in the same boat as me. Secondly, is this part of the problem with Vista? It's not exactly intuitive that you have to install an updated version of a Control Panel applet to be able to sync (although behind the scenes it's more than that, of course). It almost seems that the out-the-box install is half baked. And the help isn't much help.

It's possible that I still missed a trick, of course, and if I have done then please feel free to comment here and set me straight!


Bookmark with :
Digg It! DZone StumbleUpon Technorati Reddit Del.icio.us Newsvine Furl Blinklist
posted @ Wednesday, October 01 2008 at 10:37 AM by Dan Matthews

When trying to access remote content in Silverlight, you need to add a clientaccespolicy.xml file to the root of the web server that you are trying to access.  I did this, my file looked like this:

<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
    <cross-domain-access>
        <policy>
            <allow-from http-request-headers="*">
                <domain uri="*"/>
            </allow-from>
            <grant-to>
                <resource include-subpaths="true" path="/"/>
            </grant-to>
        </policy>
    </cross-domain-access>
</access-policy>

So essentially, anyone can access this.

I wrote my code to retrieve the information in a C# console app, just to test it out the WebClient as follows:

using System;
using System.IO;
using System.Net;
using System.Linq;
using System.Xml;
using System.Xml.Linq;

namespace GetBlogContentTest
{
    class Program
    {
        static void Main(string[] args)
        {
            WebClient w = new WebClient();

            string result = w.DownloadString(new Uri("http://blogs.interakting.co.uk/MainFeed.aspx"));
            
            if (!String.IsNullOrEmpty(result))
            {
                XDocument xDoc = XDocument.Parse(result, LoadOptions.SetBaseUri);

                var blogItems = from item in xDoc.Descendants("item")
                                select new ChannelItem
                                {
                                    Title = (string)item.Element("title"),
                                    Link = (string)item.Element("link"),
                                    PubDate = (DateTime)item.Element("pubDate"),
                                    SourceUrl = (string)item.Element("source").Attribute("url"),
                                    Description = (string)item.Element("description"),
                                    Author = (string)item.Element(XName.Get("creator","http://purl.org/dc/elements/1.1/"))
                                };

                foreach (ChannelItem item in blogItems)
                {
                    Console.WriteLine("Title: {0}", item.Title);
                    Console.WriteLine("Link : {0}", item.Link);
                    Console.WriteLine("SUrl : {0}", item.SourceUrl);
                    Console.WriteLine("Auth : {0}", item.Author);
                    Console.WriteLine("Date : {0}", item.PubDate);
                    Console.WriteLine("Content Length: {0}{1}", item.Description.Length, Environment.NewLine);
                }

            }
            else
            {
                Console.WriteLine("No Results Retrieved");
            }

            Console.ReadLine();
        }
    }
}

This also, worked fine.  However, when I put the same code in to my shiny new Silverlight application and run it through debug I get myself a nice little error.  The error message itself is a little bit on the ambiguous as we sometimes come to expect from technologies in their infancy.  Essentially the error I got was "Security error".  Gee, thanks for that?!

Digging a  little deeper in tot eh actual exception, we get the stack etc and the actual error (sort of):

SecurityException

at MS.Internal.InternalWebRequest.Send()
at System.Net.BrowserHttpWebRequest.BeginGetResponseImplementation()
at System.Net.BrowserHttpWebRequest.InternalBeginGetResponse(AsyncCallback callback, Object state)
at System.Net.AsyncHelper.BeginOnUI(BeginMethod beginMethod, AsyncCallback callback, Object state)
at System.Net.BrowserHttpWebRequest.BeginGetResponse(AsyncCallback callback, Object state)
at InteraktingMainFeed.Page.GetMainFeed()
at InteraktingMainFeed.Page..ctor()
at InteraktingMainFeed.App.Application_Startup(Object sender, StartupEventArgs e)
at System.Windows.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, String eventName)

I was trying everything to fix this until I hit upon the idea of taking Casini (Visual Studio's web server) out of the question (just in case) and setting up a virtual directory on my local IIS to server the Silverlight web app.

That actually fixes it.  I don't know why this effects the way the Silverlight app works, but it does.  It's highly frustrating and in my opinion completely under-tested.  As developers, we generally need to be able to debug our applications but there is now a nice hurdle in the way and you can't just use F5.  Basically, I'm going to have to attach to the web process to debug.  It's not the end of the world, but it would be nice if I could just debug the lazy way.

I can see that picking up Silverlight is going to have some nice little challenges along the way.


Bookmark with :
Digg It! DZone StumbleUpon Technorati Reddit Del.icio.us Newsvine Furl Blinklist
posted @ Friday, September 19 2008 at 04:47 PM by Matt Nield

My previous post talks about learning some Silverlight and going through some of ScottGu's articles about getting started with Silverlight.  As I have been trundling through then I have started to notice one thing that is getting particularly irritating.

When you're styling up your application, you need to be very careful about typing the Setter properties correctly.  I admit, I am using Visual Studio and not Expression <insert useful variant here>, but I would still expect a little more intelligence or when editing the XAML.

Let me explain...

Consider the following XAML from my App.xaml file in Scott's article:

<Style x:Key="ThumbNailPreview" TargetType="Image">
<Setter Property="VerticleAlignment" Value="Center" />
<
Setter Property="Margin" Value="7,7,5,5" />
<
Setter Property="Height" Value="55" />
<
Setter Property="Width" Value="55" />
</
Style>

Note how (me being me), I have spelt VerticalAlignment incorrectly.  The result of this will be that the part of the XAML that uses that Style will not render correctly and seems to cause the entire application to 'white-out'.  Now, when this is a Style that is visible to us at design-time, then the design view of the XAML will go blank and we'll get some kind of indication that something is not correct.  We don't know what is incorrect and no compilation errors appear.  In which case, get someone to check your code over for you (at the end of the day, you typed it wrong and someone else will probably pick up your mistake quicker, we all know how it is ^^).

So cool, we can fix the problem - lovely.  However, if the Style is being used by a control that is in a template for data binding, the problem does not reveal itself in design view insider Visual Studio.  It lurks somewhere in a dark corner waiting for you to run your application and bind some data to it.  At which point; BLAM!, you're application pulls a whitey and the screen goes blank.  Ye then need to go back to Visual Studio and figure out what was wrong.  Again, get someone to look over your shoulder perhaps to quickly spot your blatant typo.

I'm sure Expression Whatever is very good at all this Style stuff, and I will shortly try it out, but I really was hoping for better intellisense in Visual Studio to let me know what properties I can use in setters for the Style's TargetType.  Maybe v.Next will do this?  that would be nice.


Bookmark with :
Digg It! DZone StumbleUpon Technorati Reddit Del.icio.us Newsvine Furl Blinklist
posted @ Wednesday, September 17 2008 at 01:03 PM by Matt Nield

I found myself with a little time between BizTalk Server tasks recently and decided it was high time I took a look at trying out Silverlight and seeing what it is worth.  It's still early days for me at the moment, but I thought I would share my starting point.

I was lucky enough to find a series of posts buy Scott Guthrie that give a good 8-step tutorial on building a Silverlight application in Visual Studio 2008.

I've really only just started and am taking the time to read some surrounding content on the web about each step, but I have to say that it looks quite impressive so far (as I think we all know).

One thing I did notice is that the WatermarkedTextBox control seems to have been removed from the current release of Silverlight and there at present does not seem to be a Watermark option on the standard TexBox control, but that's a pretty small issue when I'm effectively just getting to grips with it.


Bookmark with :
Digg It! DZone StumbleUpon Technorati Reddit Del.icio.us Newsvine Furl Blinklist
posted @ Tuesday, September 16 2008 at 01:00 PM by Matt Nield

Summary

Quite often we want to be able to perform the same operation on some information given a differing number of arguments.  Typically, you might pass these arguments in as an array, thus avoiding the need to specify the number of arguments.  In order to call a function like this, we then need to go ahead and build and array of to pass in our arguments.  To me that seems like a little bit of an effort, at each point in my application, I know how many things I want to pass in.  So how else can I do this?

Solution

Now, consider the funtion System.String.Format().  In one form, the Format function can take a string and an array of type Objects.  A typical call to String.Format will be as follows:

string myString = System.String.Format(
    "Employee #{0} had been with the company since {1}{2}",
    currentEmployee.Number,
    currentEmployee.ContractCommenceDate.ToShortDateString(),
    Environment.NewLine
    );

Notice that our array of objects is represented as a comma separated list.  Lets see what happens if we try this and create a simple console application as follows:

using System;
using System.Text;

namespace VariadicFunctions
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(
                Concat(
                    "String 1 ",
                    "String 2 ",
                    "Stirng 3 "
                    )
                );
        }

        /// <summary>
        /// Glue a lots of strings together in to the mother of all strings.
        /// </summary>
        /// <param name="myStrings">A collection of obedient strings</param>
        /// <returns>The mother of all strings</returns>
        public static String Concat(string[] myStrings)
        {
            StringBuilder sBuild = new StringBuilder();

            foreach (String str in myStrings)
            {
                sBuild.Append(str);
            }

            return sBuild.ToString();
        }
    }
}

When we compile, we get an error telling us "No overload for method 'Concat' takes '3' arguments".  That makes sense, the method is looking for a string array, not a load of separate strings.  What we need to do is turn this in to what is know as a Variadic Function.

A variadic functions is a function that takes an variable number of arguments.  Essentially, to turn our function 'Concat' in to a variadic function we just need to use the params keyword.  What this keyword does is, in simple-speak, allows us to enter our additional arguments in a comma separated list.  Simply adding this keyword in will then allow us to comma-separate our arguments:

using System;
using System.Text;

namespace VariadicFunctions
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(
                Concat(
                    "String 1 ",
                    "String 2 ",
                    "Stirng 3 "
                    )
                );
        }

        /// <summary>
        /// Glue a lots of strings together in to the mother of all strings.
        /// </summary>
        /// <param name="myStrings">A collection of obedient strings</param>
        /// <returns>The mother of all strings</returns>
        public static String Concat(params string[] myStrings)
        {
            StringBuilder sBuild = new StringBuilder();

            foreach (String str in myStrings)
            {
                sBuild.Append(str);
            }

            return sBuild.ToString();
        }
    }
}

And there we go, no build errors, we can add as many stings as we like without issue.

References: 

Keywords:

  • Variadic, params, arguments array, variable arguments, variable parameters, parameters array

Bookmark with :
Digg It! DZone StumbleUpon Technorati Reddit Del.icio.us Newsvine Furl Blinklist
posted @ Friday, September 12 2008 at 06:02 PM by Matt Nield

I was trying to parse a file which was divided into numerous parts - each one 12 lines long. For debugging, I was interested in how fast the file was being read and processed and therefore looked at the StreamReader.BaseStream.Position property. Here is an example of what I was trying to do:

class Program
{
static void Main(string[] args)
{
string filename = @"C:\windows\windowsupdate.log";
string filenameBackup = filename + ".bac";
File.Copy(filename, filenameBackup);

FileStream fs = new FileStream(filenameBackup, FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs);

int lineNumber = 0;

while (!sr.EndOfStream)
{
Console.WriteLine("Lines Read = {0}, Position = {1}", lineNumber, sr.BaseStream.Position);
string[] lines = ReadXLines(sr,5);
lineNumber += lines.Length;
}

Console.Read();
}

private static string[] ReadXLines(StreamReader sr, int linesToRead)
{
string[] lines = new string[linesToRead];

for (int lineNumber = 0; lineNumber < lines.Length; lineNumber++)
{
lines[lineNumber] = sr.ReadLine();
}

return lines;
}
}

Now, the output on my computer was this:

Lines Read = 0, Position = 1024
Lines Read = 5, Position = 1024
Lines Read = 10, Position = 1024
Lines Read = 15, Position = 2048
Lines Read = 20, Position = 2048
Lines Read = 25, Position = 3072
Lines Read = 30, Position = 3072
Lines Read = 35, Position = 4096
Lines Read = 40, Position = 5120
Lines Read = 45, Position = 5120
Lines Read = 50, Position = 6144
Lines Read = 55, Position = 7168
Lines Read = 60, Position = 7168
Lines Read = 65, Position = 8192
Lines Read = 70, Position = 8192
Lines Read = 75, Position = 9216
Lines Read = 80, Position = 9216
Lines Read = 85, Position = 10240
Lines Read = 90, Position = 10240
Lines Read = 95, Position = 11264
Lines Read = 100, Position = 11264
Lines Read = 105, Position = 12288
......

What is odd about this sequence is that the position of the FileStream is already at 1024 before anything has been read! Also, the 1024 position stays the same for 2 reads. Why is this?

The StreamReader class is a buffered reader. Therefore, it is reading the stream before anything is processed and when reading directly from StreamReader, if the amount read does not extract the entire buffer, then the position of the underlying stream doesn't change.

Unfortunately, there is nothing you can do about this. Therefore the only 2 ways you can keep track of the position is to:

  • Count how many characters are in each line (plus the Environment.Newline) and total up the position line by line.
  • Create your own implementation of the FileStream, which has a ReadLine() method. This method should continue to read the Stream until Environment.Newline is encountered. Remember, Environment.Newline is not included in the string returned.

Bookmark with :
Digg It! DZone StumbleUpon Technorati Reddit Del.icio.us Newsvine Furl Blinklist
posted @ Friday, September 05 2008 at 02:28 PM by Dominic

Since yesterday, and my post about Google Chrome, Google has updated its terms and conditions and removed the clauses.  See my previous post here: Security: How much do you trust Google?.

Privacy clauses

Section 11 has been completed rewritten.  Note that this is the only change in the terms of service, even the date has not been changed:

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.

Looks a bit different to the previous clause.  Specifically, the following has been removed:

11.1 ... 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.

Terms and conditions (still dated 15 August 2008) in full

Google Chrome Terms of Service

These Terms of Service apply to the executable code version of Google Chrome. Source code for Google Chrome is available free of charge under open source software license agreements at http://code.google.com/chromium/terms.html.

1. Your relationship with Google

1.1 Your use of Google’s products, software, services and web sites (referred to collectively as the “Services” in this document and excluding any services provided to you by Google under a separate written agreement) is subject to the terms of a legal agreement between you and Google. “Google” means Google Inc., whose principal place of business is at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. This document explains how the agreement is made up, and sets out some of the terms of that agreement.

1.2 Unless otherwise agreed in writing with Google, your agreement with Google will always include, at a minimum, the terms and conditions set out in this document. These are referred to below as the “Universal Terms”. Open source software licenses for Google Chrome source code constitute separate written agreements. To the limited extent that the open source software licenses expressly supersede these Universal Terms, the open source licenses govern your agreement with Google for the use of Google Chrome or specific included components of Google Chrome.

1.3 Your agreement with Google will also include the terms of any Legal Notices applicable to the Services, in addition to the Universal Terms. All of these are referred to below as the “Additional Terms”. Where Additional Terms apply to a Service, these will be accessible for you to read either within, or through your use of, that Service.

1.4 The Universal Terms, together with the Additional Terms, form a legally binding agreement between you and Google in relation to your use of the Services. It is important that you take the time to read them carefully. Collectively, this legal agreement is referred to below as the “Terms”.

1.5 If there is any contradiction between what the Additional Terms say and what the Universal Terms say, then the Additional Terms shall take precedence in relation to that Service.

2. Accepting the Terms

2.1 In order to use the Services, you must first agree to the Terms. You may not use the Services if you do not accept the Terms.

2.2 You can accept the Terms by:

(A) clicking to accept or agree to the Terms, where this option is made available to you by Google in the user interface for any Service; or

(B) by actually using the Services. In this case, you understand and agree that Google will treat your use of the Services as acceptance of the Terms from that point onwards.

2.3 You may not use the Services and may not accept the Terms if (a) you are not of legal age to form a binding contract with Google, or (b) you are a person barred from receiving the Services under the laws of the United States or other countries including the country in which you are resident or from which you use the Services.

2.4 Before you continue, you should print off or save a local copy of the Universal Terms for your records.

3. Language of the Terms

3.1 Where Google has provided you with a translation of the English language version of the Terms, then you agree that the translation is provided for your convenience only and that the English language versions of the Terms will govern your relationship with Google.

3.2 If there is any contradiction between what the English language version of the Terms says and what a translation says, then the English language version shall take precedence.

4. Provision of the Services by Google

4.1 Google has subsidiaries and affiliated legal entities around the world (“Subsidiaries and Affiliates”). Sometimes, these companies will be providing the Services to you on behalf of Google itself. You acknowledge and agree that Subsidiaries and Affiliates will be entitled to provide the Services to you.

4.2 Google is constantly innovating in order to provide the best possible experience for its users. You acknowledge and agree that the form and nature of the Services which Google provides may change from time to time without prior notice to you.

4.3 As part of this continuing innovation, you acknowledge and agree that Google may stop (permanently or temporarily) providing the Services (or any features within the Services) to you or to users generally at Google’s sole discretion, without prior notice to you. You may stop using the Services at any time. You do not need to specifically inform Google when you stop using the Services.

4.4 You acknowledge and agree that if Google disables access to your account, you may be prevented from accessing the Services, your account details or any files or other content which is contained in your account.

4.5 You acknowledge and agree that while Google may not currently have set a fixed upper limit on the number of transmissions you may send or receive through the Services or on the amount of storage space used for the provision of any Service, such fixed upper limits may be set by Google at any time, at Google’s discretion.

5. Use of the Services by you

5.1 In order to access certain Services, you may be required to provide information about yourself (such as identification or contact details) as part of the registration process for the Service, or as part of your continued use of the Services. You agree that any registration information you give to Google will always be accurate, correct and up to date.

5.2 You agree to use the Services only for purposes that are permitted by (a) the Terms and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United States or other relevant countries).

5.3 You agree not to access (or attempt to access) any of the Services by any means other than through the interface that is provided by Google, unless you have been specifically allowed to do so in a separate agreement with Google. You specifically agree not to access (or attempt to access) any of the Services through any automated means (including use of scripts or web crawlers) and shall ensure that you comply with the instructions set out in any robots.txt file present on the Services.

5.4 You agree that you will not engage in any activity that interferes with or disrupts the Services (or the servers and networks which are connected to the Services).

5.5 Unless you have been specifically permitted to do so in a separate agreement with Google, you agree that you will not reproduce, duplicate, copy, sell, trade or resell the Services for any purpose.

5.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any breach of your obligations under the Terms and for the consequences (including any loss or damage which Google may suffer) of any such breach.

6. Your passwords and account security

6.1 You agree and understand that you are responsible for maintaining the confidentiality of passwords associated with any account you use to access the Services.

6.2 Accordingly, you agree that you will be solely responsible to Google for all activities that occur under your account.

6.3 If you become aware of any unauthorized use of your password or of your account, you agree to notify Google immediately at http://www.google.com/support/accounts/bin/answer.py?answer=48601.

7. Privacy and your personal information

7.1 For information about Google’s data protection practices, please read Google’s privacy policy at http://www.google.com/privacy.html. This policy explains how Google treats your personal information, and protects your privacy, when you use the Services.

7.2 You agree to the use of your data in accordance with Google’s privacy policies.

8. Content in the Services

8.1 You understand that all information (such as data files, written text, computer software, music, audio files or other sounds, photographs, videos or other images) which you may have access to as part of, or through your use of, the Services are the sole responsibility of the person from which such content originated. All such information is referred to below as the “Content”.

8.2 You should be aware that Content presented to you as part of the Services, including but not limited to advertisements in the Services and sponsored Content within the Services may be protected by intellectual property rights which are owned by the sponsors or advertisers who provide that Content to Google (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this Content (either in whole or in part) unless you have been specifically told that you may do so by Google or by the owners of that Content, in a separate agreement.

8.3 Google reserves the right (but shall have no obligation) to pre-screen, review, flag, filter, modify, refuse or remove any or all Content from any Service. For some of the Services, Google may provide tools to filter out explicit sexual content. These tools include the SafeSearch preference settings (see http://www.google.com/help/customize.html#safe). In addition, there are commercially available services and software to limit access to material that you may find objectionable.

8.4 You understand that by using the Services you may be exposed to Content that you may find offensive, indecent or objectionable and that, in this respect, you use the Services at your own risk.

8.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any Content that you create, transmit or display while using the Services and for the consequences of your actions (including any loss or damage which Google may suffer) by doing so.

9. Proprietary rights

9.1 You acknowledge and agree that Google (or Google’s licensors) own all legal right, title and interest in and to the Services, including any intellectual property rights which subsist in the Services (whether those rights happen to be registered or not, and wherever in the world those rights may exist). You further acknowledge that the Services may contain information which is designated confidential by Google and that you shall not disclose such information without Google’s prior written consent.

9.2 Unless you have agreed otherwise in writing with Google, nothing in the Terms gives you a right to use any of Google’s trade names, trade marks, service marks, logos, domain names, and other distinctive brand features.

9.3 If you have been given an explicit right to use any of these brand features in a separate written agreement with Google, then you agree that your use of such features shall be in compliance with that agreement, any applicable provisions of the Terms, and Google's brand feature use guidelines as updated from time to time. These guidelines can be viewed online at http://www.google.com/permissions/guidelines.html (or such other URL as Google may provide for this purpose from time to time).

9.4 Other than the limited license set forth in Section 11, Google acknowledges and agrees that it obtains no right, title or interest from you (or your licensors) under these Terms in or to any Content that you submit, post, transmit or display on, or through, the Services, including any intellectual property rights which subsist in that Content (whether those rights happen to be registered or not, and wherever in the world those rights may exist). Unless you have agreed otherwise in writing with Google, you agree that you are responsible for protecting and enforcing those rights and that Google has no obligation to do so on your behalf.

9.5 You agree that you shall not remove, obscure, or alter any proprietary rights notices (including copyright and trade mark notices) which may be affixed to or contained within the Services.

9.6 Unless you have been expressly authorized to do so in writing by Google, you agree that in using the Services, you will not use any trade mark, service mark, trade name, logo of any company or organization in a way that is likely or intended to cause confusion about the owner or authorized user of such marks, names or logos.

10. License from Google

10.1 Google gives you a personal, worldwide, royalty-free, non-assignable and non-exclusive license to use the software provided to you by Google as part of the Services as provided to you by Google (referred to as the “Software” below). This license is for the sole purpose of enabling you to use and enjoy the benefit of the Services as provided by Google, in the manner permitted by the Terms.

10.2 You may not (and you may not permit anyone else to) copy, modify, create a derivative work of, reverse engineer, decompile or otherwise attempt to extract the source code of the Software or any part thereof, unless this is expressly permitted or required by law, or unless you have been specifically told that you may do so by Google, in writing.

10.3 Unless Google has given you specific written permission to do so, you may not assign (or grant a sub-license of) your rights to use the Software, grant a security interest in or over your rights to use the Software, or otherwise transfer any part of your rights to use the Software.

11. Content license from you

11.1 You retain copyright and any other rights you already hold in Conten