Friday, April 18, 2008

Vista, Hibernate and Windows Update

Submit this story to DotNetKicks

My laptop lives a boring life. Every morning, I check news and e-mail before going to work. Then I put the machine in hibernate, just to be able to switch it on in half a minute. Maybe I'll go online while watching tv in the evening, and then it's back to hibernate. But in the middle of the night, my laptop lives it's own life. I started suspected something when I woke up to an empty battery every day. Strange. Annoying.

I found the problem after some days, when not hibernating, the battery was happy. But what was happening? As far as I know, hibernate means putting the machine in a power-off state - but saving the contents of RAM, enabling us to start from where we left off when we resume. Turns out this can't be quite true. Cause every night at 01:00 AM my computer would turn itself on - because I'd set Vista to check for automatic updates at that time.

I wasn't quite sure if this was real or not until today, when my colleague Petter showed up at work, telling me had discovered the same thing. His laptop woke him up at 4AM to get the newest updates.

So if you're having mysterious battery-trouble with a laptop running Vista - check your update settings.

Tuesday, March 18, 2008

How do you backup an unknown number of SQL server databases

Submit this story to DotNetKicks

How do you backup an unknown number of SQL server databases?

Consider a scenario where an application you don’t control is using your SQL server as a place to store data, and this application is creating databases on the fly.

This can be the case for several types of applications.

Now, using the built-in maintenance-plan wizard will only get you so far, since it will only apply to the databases already existing on the server at time of creation, not to databases created after the plan, so it will have to be continuously maintained.

That’s a bad solution, and if forgotten, some databases will not be backed up.

I will choose to give you two alternatives to solve this problem, the first is using a cursor to accomplish what we want, - and yes, i can already hear you mumbling about “cursor” and words like “ never”, “devils work”, “performance” and “must be some other way” and so on.. – Well, there are several ways to accomplish what we want, and a cursor is one of them, so don’t sharpen the prongs of your pitchfork just yet, i will explain later. Another way is using 2005’s new row_number() function and a in-memory table variable, and a standard execute (@sqlcommand) and this is also a very effective way.

Using a cursor for a backup task that is to run maybe once every night, or every Sunday after midnight is quite ok, the performance problem with cursors is widely agreed upon and I will not argue that they are not, but this is not a procedure that will be called by sixty thousand web users every minute, if that was the case, I would also abandon cursors, but in this case, it’s not such a bad idea.
So to the first code snippet: we will call this: DoDatabaseBackup1

create proc DoDatabaseBackup1
as
declare @DBname varchar(254)

declare @Fixedpath varchar(254)
declare @FileName varchar(254)
set @Fixedpath = 'c:\sqlbackup\'

declare getDBName cursor for
select [name] from sys.databases

where [name] NOT IN ('master','model','msdb','tempdb')


open getDBName

fetch next from getDBName into @DBname

while @@fetch_status = 0
begin
set @fileName = @Fixedpath + @DBname + '_' + convert(varchar(8),getdate(),112) + '.bak'
backup database @DBname to disk = @fileName

fetch next from getDBName into @DBname

end

close getDBName
deallocate getDBName


This procedure will loop through any user-databases there is on the server and place a backup file of each on the location of your choice, simple as that. Not big, not difficult to understand and works like a charm. Create a scheduled job under sql-server agent and you should be home free. (and the cursor performance problem is not what will take time here, the backup of each database will take considerably more out of the server…)

But, since cursor IS the work of the devil :), to solution number two:

This one is called (who would guess): DoDatabaseBackup2

The logic is more or less the same, but instead of a cursor we use a table-variable and then use this to build a sql-command-string.

create proc DoDatabaseBackup2
as
declare @sqlstr varchar(max)
declare @userdbs int
declare @counter int

declare @fixedpath varchar(254)

declare @dbnames table (dbrow int,dbname varchar(254))


set @counter=1
set @sqlstr=''

set @fixedpath='c:\sqlbackup\'

insert into @dbnames
select row_number() over(order by [name]) as dbrow,[name]
from sys.databases
where [name] not in ('master','tempdb','model','msdb')


set @userdbs=@@rowcount

if @userdbs>0
begin
while @counter<=@userdbs begin select @sqlstr=@sqlstr+(select 'backup database '+dbname+' to disk = '''+@fixedpath+dbname+'_'+Convert(char(8),getdate(),112)+'.bak'';' from @dbnames where dbrow=@counter)

set @counter=@counter+1
end
end
exec (@sqlstr)


Both of this procedures will result in the same, a backup of all userdatabases regardless of name and numbers, and you don’t even have to know anything exept that there is space available on the receiving location..

Other solutions also exist, but this will do for now….

/Leo

Friday, February 22, 2008

Where is my SQL Server Management Studio?

Submit this story to DotNetKicks

If you should stumble across this blog, I bet you have encountered the same problem I did. After you installed the Microsoft SQL Server 2005 you cannot find the SQL Server Management Studio in your Start menu, and if you try to search for the SqlWb.exe it's nowhere to be found. In my situation I had installed Visual Studio 2003, Visual Studio 2005 and Visual Studio 2008 prior to the SQL installation.

The problem is that the installation of the SQL server will interpret the installation of the SQL Express Edition as a newer version or an already installed client tool.

So the solution for you may be to uninstall the SQL Express. I had a Windows 2003 64x Server so I had to uninstall (via the Add or Remove programs) the "Microsoft SQL Server 2005" (which was the Express instance, installed by Visual Studio 2005/2008). I then reran the SQL Server 2005 installation and ensured that the Client tools were selected (click the advanced button in the installation wizard).

After this I had the Management Tools back on the machine, but now I couldn't open the Express database in my VS 2005 project so I had to install the SQL Express again by rerunning(updating) the Visual Studio 2008.

Happy sqling and programming

Tuesday, February 12, 2008

Illegal Cross Thread Operation?

Submit this story to DotNetKicks

I see many forumposts solving this problem by simply adding the CheckForIllegalCrossThreadOperations=false;

While this is a totally legit workaround, it is highly thread-unsafe, and should only be used for debugging purposes. To be able to update for instance form-components from another thread, you will need to use delegates and invoke. Sounds scary? Not really.

A delegate is simply a "blueprint" that describes how a particular function or method should look. In C++ world, delegates are similar to Function pointers, but since we don't work with pointers in C# this is the closest we get. Still, function pointer is not a correct definition, as the delegate won't point to a function unless you make it do so. Here's an example:

The function


private void UpdateStatusText(string statusText)
{
statusLabel.Text = statusText;
}


Would have the following delegate:


public delegate void UpdateStatusTextHandler(string statusText);


Both the delegate name and the parameter-name(s) are totally random, it is the return-type and parameter-types that are important.

Let's say we have an eventhandler thread_OnStatusChanged(string newStatus) that needs to update the statusLabel.Text property. If the thread is different from the one the statusLabel exists in, you will get the Illegal Cross Thread operation error if you simply try to update it.

What we first want to do is an if-check to see if it comes from a different thread.
Inside the thread_OnStatusChanged eventhandler we do the following:



if (statusLabel.InvokeRequired)
{
statusLabel.Invoke(new UpdateStatusTextHandler(UpdateStatusText), newStatus);
}



The Invoke function takes the arguments Delegate Method, as well as the optional args[] to enable you to pass the required arguments to your method.

So by doing the new UpdateStatusTextHandler(UpdateStatusText) you are simply creating a pointer to the method UpdateStatusText(string statusText)



Hopefully this will make delegates and invoking a little more understandable.

Good luck with your threads!

Wednesday, February 6, 2008

Managing Unmanaged Resources

Submit this story to DotNetKicks

Unmanaged Resources are objects that are not garbage collected, which means that they are not reclaimed by the system when the garbage collector cleans up after you.

But are Unmanaged Resources resources outside .NET framework like DLL used through interop? No, unmanaged resources can also be database connection. It is a common mistake by programmers not to close the connection when finished working with it, in misconception that the garbage collection will close it.

So how do I identify if the object is an unmanaged resource? If the object implement the IDisposable interface it have an unmanaged resource and you need to call the IDisposable.Dispose() method to clean the objects unmanaged resource.
If you use the object in a single call you can wrap it in a using statement (http://softscenario.blogspot.com/2007/10/using-using.html), and it will call the Dispose() method for you. If you keep the object for a longer time you must support the IDisposable interface in your class, and in your implementation of the Idisposable.Dispose() call the member's IDisposable method.


Remember to look for the IDisposable interface in the classes you use in your development. You will be surprised how many classes that do.

Where are my Properties.Settings saved

Submit this story to DotNetKicks

Have you ever wondered where your user settings are saved from an .NET application? You would probably think that it's saved in the [application].exe.config(located in your application folder) file, but this is only partially true. The default values you create in Visual Studio are saved in this file. But if you change these settings at runtime:

Properties.Settings.Default.myValue = "MyNewValue";
Properties.Settings.Default.Save();

they are saved to a different location. Namely the User.config file:

C:\Documents and Settings\[USER]\Local Settings\Application Data\[company]\[applicationname]\[version]

Note that if you should change the company name or AssemblyVersion attribute in your AssemblyInfo.cs your Settings will be saved in a new location.

Since you do not override the default settings in the exe.config file, you can call the reset() method to restore the settings to its original state:

Properties.Settings.Default.Reset();

Thursday, January 31, 2008

Reflecting on reflection

Submit this story to DotNetKicks

Some weeks ago I was working on a project where we receive some ten or twenty different message types from a server, and they all need to be handled when they arrive. Of course, we want to use event driven programming to make this happen on the fly, instead of polling all the time.

All of the messages have the header in common, so we already made a abstract parent class called Message, and when it came to handling all the different messages, we wanted to write as little code as possible. So we added an abstract method called HandleResponse to the code.

So the idea was to identify the incoming message type and invoke the HandleResponse using reflection on the object that we had identified this as. To do this, we made a little xml file that contains the message code (A-Z) along with the name and reference to the class linked to the message type. When the program starts, it reads the xml into a dictionary, so we can look up the key (message code) and get the class reference in return.

XDocument descriptorsXml = XDocument.Load( @".\Data\MessageDescriptors.xml");

var descQuery = from desc in descriptorsXml.Descendants("Message")

select new MessageDescriptor
{
Code = desc.Element("Code").Value,
Name = desc.Element("Name").Value,
ObjectType = desc.Element("ObjectType").Value.ToType() ,
IsServerMessage = Convert.ToBoolean( desc.Element("IsServerMessage").Value )
};
foreach (MessageDescriptor m in descQuery)
{
descriptors.Add(m.Code, m);
}

Then, we have a MessageHandlingFactory that simply gets objects in from a queue, identifies the type, and invokes the HandleResponse. If the object isn't recognized (could be a new message type, or could be that the programmer forgot to insert the description in the XML file), the MessageHandlingFactory can either throw an exception, or better yet, return a string with message that tells the user what went wrong. If everything goes as planned, it returns a string with the identified typename.


object theType = Activator.CreateInstance(t, SessionID);
EventInfo eInfo = t.GetEvent("OnWriteEvent");
Message.WriteEventHandler theHandler = new Message.WriteEventHandler(OnWriteEventHandler);

eInfo.AddEventHandler(theType, theHandler);
theType.GetType().GetMethod("HandleResponse").Invoke(theType, new object[] { message });

return "MessageHandler: " + messageType;


That's all, folks!


Update February 13, 2008: The code has now been tested in a very high throughput environment, and it performs flawlessly! There's no indication of latency even after invoking some millions of objects. And with that amount of data, everything counts. I'll not vouch for the objects that you choose to invoke, though ;)