Another quick note – QuickMon 2.6 has been released. The biggest change is the introduction of some parallel threading when calling collectors – using the .Net 4.0 parallel extensions. No new collectors or notifiers added yet.
Category Archives: Development - Page 6
Parallel threading and Control.BeginUpdate or EndUpdate
Yesterday I learned the hard (old) way that using BeginUpdate and EndUpdate in a multithreading environment (Windows Forms) don’t work so ‘lekker’ together. In hindsight, I should have guessed that this would be a problem but 20/20 hindvision really doesn’t help after the fact.
While making enhancements to my QuickMon tool to facilitate multithreading (using the .Net 4 parallel extensions) while calling collectors I started experiencing weird and unpredictable freezes or application hangs – app seems to be hanging but some parts of the UI still updates but the window cannot be moved, closed (in the normal way) etc. I tried various ways using mutexes, Control.Invokes, extra timers and duck tape to try and solve the problems. Only once I removed all my BeginUpdate/EndUpdates did the freezing issue disappear.
As mentioned before it all made sense afterwards. The problem is that when multiple background threads make calls back to the UI thread (yes, even using the proper Control.Invoke() method) that has a BeginUpdate in the beginning and later an EndUpdate there is no guarantee that every BeginUpdate is followed by its EndUpdate. That could mean some EndUpdates might never be reached properly.
The solution (for now) was to just disable all BeginUpdate/EndUpdates. Of course, a more proper design change would be to use some kind of buffer and a separate update UI routine that function outside the callbacks coming from the multiple threads collecting data. This unfortunately is not a small change and cannot be done in just a day or two. In a future iteration I’ll try to implement something like this for the QuickMon Windows client. The Windows service version of the tool wasn’t affected and work as is with the multi-threading change.
Hiding parts of html page on printing
If you need to create a web page on which some parts should not be visible when it is printed (or even print-previewed) you can use the following CSS:
@media print
{.notPrint
{display:none;
}
}
Then in the html you can specify something like this:
<div class=’notPrint’>This is not visible in printing</div>
This is useful if you have things like buttons and other stuff that is not applicable when printing.
DirectorySearcher and filters to search AD
If you want to do a query against AD (active directory) there are several ways to do it – but (only) one proper way like usual.
The DirectorySearcher class has a ‘filter’ property that allows you to filter the returned results – oppose to you having to test each property in code. The syntax of this filter is a bit tricky (ok a lot…)
It took me a while to figure out how to properly set up a filter to do more complex queries – like when you have multiple things to filter by including ‘and’s and ‘or’s. Anyway, I found a good reference here: Search Filter Syntax.
It explains the syntax plus give some examples. It also list some special characters plus explain how to use ‘wildcards’.
Happy searching…
IP address to table sql function
I have a requirement to do some stuff with a table that contains ip addresses like grouping per subnets etc. Doing this with straight tsql is tricky (if possible at all) so I created a sql server function that takes the ip address field and breaks it down to a set (table) of 4 values. It’s not perfect and brings another type of complexity of its own but at least you can compare the separate bits of the ip address as unique parts. Also, it doesn’t really have any error checking built in.
create FUNCTION [dbo].[ufn_IPAddressToTable]
(@IpAddress VARCHAR(15)
)
RETURNS @IpTable TABLE (part1 int, part2 int, part3 int, part4 int)
AS
BEGINDECLARE @part1 int, @part2 int, @part3 int, @part4 int
IF (not @IpAddress is null)
BEGINif (CHARINDEX(‘.’, @IpAddress) > 0)
beginset @part1 = CONVERT(int, substring(@IpAddress, 0, CHARINDEX(‘.’, @IpAddress)))
set @IpAddress = substring(@IpAddress, CHARINDEX(‘.’, @IpAddress) + 1, 100)if (CHARINDEX(‘.’, @IpAddress) > 0)
beginset @part2 = CONVERT(int, substring(@IpAddress, 0, CHARINDEX(‘.’, @IpAddress)))
set @IpAddress = substring(@IpAddress, CHARINDEX(‘.’, @IpAddress) + 1, 100)if (CHARINDEX(‘.’, @IpAddress) > 0)
beginset @part3 = CONVERT(int, substring(@IpAddress, 0, CHARINDEX(‘.’, @IpAddress)))
set @IpAddress = substring(@IpAddress, CHARINDEX(‘.’, @IpAddress) + 1, 100)
set @part4 = CONVERT(int, @IpAddress)end
end
end
if (not(@part1 is null or @part2 is null or @part3 is null or @part4 is null))insert @IpTable(part1, part2, part3, part4)
values (@part1, @part2, @part3, @part4)END
RETURNEND
As an example you can use it like this:
declare @IpAddress varchar(15)
set @IpAddress = ‘127.0.0.1’
select * from dbo.ufn_IPAddressToTable(@IpAddress)
Or if you have a table with ip addresses
with ComputerIps(Area, IpPart1, IpPart2, IpPart3)
as
(select c.Area,
(select top 1 part1 from dbo.[ufn_IPAddressToTable](c.IpAddress)) as Part1,
(select top 1 part2 from dbo.[ufn_IPAddressToTable](c.IpAddress)) as Part2,
(select top 1 part3 from dbo.[ufn_IPAddressToTable](c.IpAddress)) as Part3
from Computers c
where not (c.IpAddress is null) and LEN(c.IpAddress) > 0)
select Area, IpPart1, IpPart2, IpPart3, COUNT(*) as [Computers]
from ComputerIps
group by Area, IpPart1, IpPart2, IpPart3
order by Area, IpPart1, IpPart2, IpPart3
Another problem is that it may be slow when the source table becomes large. At least it helps a bit.
Advanced debugging in VS2010 tips
Just a quick link to an article on codeproject – Advanced Debugging in Visual Studio
Because you are never to old to learn… or too young!
Adding an user to group in AD
I was helping a colleague that has no programming background with a little tool he needs to create to add users to an AD group. The ‘tricky’ part is that he started using VB (.net) and my VB skills is a bit (or a lot) rusty…
So I set out to help him but I hit a little snag with the step of actually adding a user to the group. I got an exception ‘The server is unwilling to process the request‘ when trying to use the following type of code:
de = new DirectoryEntry(groupDn);de.Properties[“member”].Add(userDn); //<!– breaks herede.CommitChanges();
de = new DirectoryEntry(groupDn);de.Invoke(“Add”, New Object() {userDn})
DirectorySearcher and SizeLimit
Seems like each time you actually wants to use some MS technology for real you find a serious bug in it…
If you query active directory to get a list of say, all the machines on the network and the list happens to be bigger than a 1000 items there is a problem using DirectorySearcher. There is a property called SizeLimit but even if you set it to anything larger than a 1000 it always only return a 1000 items.
Fortunately (like a lot of other cases) there is a way around it. DirectorySearcher have another property for PageSize which if you set that then the size limit is ignored and you can access more than the 1000 items.
e.g.
string filter = “(objectCategory=Computer)”;
using (DirectorySearcher searcher = new DirectorySearcher(filter))
{
//searcher.SizeLimit = 2000; //ignored
searcher.PageSize = 1000;
SearchResultCollection matches = searcher.FindAll();
foreach (SearchResult match in matches)
{
DirectoryEntry de = match.GetDirectoryEntry();
…
}
}