Archive of articles classified as' ".NET"

Back home

Configuring the ReportViewer control at run time

9/07/2007

I’ve been using the ReportViewer .NET control recently for a project at work. I’m using a collection of data objects as a data source, and while the ReportViewer itself works great, the documentation doesn’t really go beyond putting things together in the Visual Studio designer. It’s actually just as easy to do the configuration in code at run time, which is useful if you need to choose from multiple reports or types of data. Just add the ReportViewer control in the designer, but use the following code example instead of choosing a report and bindings context.

string dataSetName = "MyApplication_ModelObject";
string resourcePath = "MyApplication.SomeReport.rdlc"
List dataSource = ObjectProvider.GetObjects();

reportViewer.LocalReport.ReportEmbeddedResource = resourcePath;
reportViewer.LocalReport.DataSources.Add( new ReportDataSource( dataSetName, dataSource ) );
this.reportViewer.RefreshReport();

Note that the ReportEmbeddedResource string must include the full namespace as well as the file name. If you’re not sure what data set name to use, just open your report in the XML viewer.

No Comments

Auto-incrementing build numbers in Visual Studio

13/03/2007

One neat feature in Visual Studio I came across today is auto-incrementing build numbers. You can use this to avoid having to configure or write an external tool or version control system just (although you should be using the latter anyway).

To enable it, just open AssemblyInfo.cs in your project, and change the AssemblyVersion setting to [assembly: AssemblyVersion( "1.0.*" )];. Remove the [assembly: AssemblyFileVersion( "1.0.0.0" )]; line entirely; it doesn’t support auto incrementing, and you usually don’t need it in the first place.

The next time you build your project, Visual Studio will put its own values in for the build number and revision number. It’s not too important how it generates these; but if you’re wondering, it uses the number of days since Jan. 1st 2000 as the build number, and the number of seconds since midnight number of seconds since midnight divided by 2 as the revision.

3 Comments

Windows Vista Developer Launch Event

13/02/2007

I took the afternoon off work today to attend the Windows Vista Developer Launch Event (free coffee and a copy of MS Office 2007, how could I miss it?). It was an interesting time; the MS technology evangelist gave a four hour talk about the new developer features of Vista and .NET 3.0, and also Office 2007 development (which actually looks pretty neat, it seems like you can pretty much develop a complete .NET application inside an Office product now). I still don’t think .NET 3.0 is too exciting for the average developer, but it did raise my interest in it a bit.

Anyway, one of the biggest talking points was on the Windows Presentation Foundation, a new technology for creating user interfaces in .NET applications and webpages. WPF is more like Flash than a traditional UI library. It’s easy for non-developers to design their own widgets, either from right scratch or mixing and matching with the default look. Like Flash, there’s lots of animation, embedded media, and vector graphics. The end result is turned into an XML document that the developer can drop into his .NET application.

What I’m getting at though, is that no where during this talk did anyone mention any sort of style or interface guidelines. Rather, the designer is pretty much given carte blanche to do as they please. One of the examples she gave was a “fish button;” a button that looked, well, like a fish. That kind of thing scares me. If every developer starts using WPF there’s really no telling what Windows applications will look like. Maybe I’m being a bit paranoid, but without a good interface guideline I can easy imagine a program full of fish buttons, and the developer wouldn’t even know he did something wrong.

As a side note, those of you who don’t care much for Vista will be happy to note that the presenter’s laptop crashed, a lot. I think there were three reboots before the talk was done, and at one point the Microsoft evangelist went so far as to say “you know, I have three gigs of RAM in this laptop, but sometimes it’s still not enough for Vista.” Vista was pretty, though.

3 Comments

Windows PowerShell

21/11/2006

Microsoft released Windows PowerShell 1.0 a week or two ago, and I’ve heard a lot of positive things about it so far. The easiest way to describe PowerShell is to imagine a Unix command line shell, but with all kinds of design hints and functionality from the .NET programming language and Windows administration tools.

I was skeptical at first; I don’t use the command line much at work, and when I do I always have a *nix terminal nearby. The PowerShell “cmdlets” have different names than their DOS or Unix counterparts, so there’s a bit of a learning curve, even though PowerShell uses a pretty standardized naming scheme ((You can, and will probably want to, create aliases for common commands. This is why “ls” works by default.)). Spending some time with it changed my opinion though. The fact that you can run WMI queries right from the command line (normally you would write a .NET or vbscript application to run them) is enough to make me want to learn more. The scripting support seems nice as well, since it supports C# language concepts like foreach and doesn’t rely on text formatting tools to pipe data from one command to another (data is piped in the form of .NET style objects).

The only question now is if PowerShell will be the de-facto shell in future releases of Windows, or if it’ll silently gather dust until it’s forgotten altogether. If you read the PowerShell blog the development team seems pretty excited about integration with all the Microsoft server technologies like IIS and Active Directory, but I really think it could go either way, especially since it was one of the early features cut from Windows Vista.

No Comments

Memory leaks in the .NET 2.0 Ping class

14/11/2006

As an IT developer, the .NET 2.0 System.Net.NetworkInformation.Ping class is extremely useful. Many times I’ll need to see if a server is reachable, or whether something exists at an IP address before sending another network request (say, a WMI query) with a long timeout delay. Although the Ping class works great (and is much easier than writing your own ping networking code, as in .NET 1.1), it can easily lead to a memory leak in your application. I remember when I first started with C#, there was the feeling that “everything is garbage collected, so that means I don’t have to worry about memory management.” I soon learned that wasn’t true at all, especially with Ping.

Let me post some sample code, illustrating the correct way to send an asynchronous ping. I’ll explain it further below.


private void Refresh( Object sender, EventArgs args )
{
    Ping ping = null;

    try
    {
        ping = new Ping();
        ping.PingCompleted += PingComplete;
        ping.SendAsync( defaultHost, null );
    }
    catch ( Exception )
    {
        ( (IDisposable)ping ).Dispose();
        this.isAlive = false;
    }
}

private void PingComplete( Object sender, PingCompletedEventArgs args )
{
    this.isAlive = ( args.Error == null && args.Reply.Status == IPStatus.Success );
    ( (IDisposable)sender ).Dispose();
}

You can see the Ping class implements the IDisposable interface. IDisposable, if you’re new to .NET, simply means you must call Dispose() before your object can be garbage collected. What makes the Ping class difficult compared to other IDisposable classes is that calling Ping.Dispose() doesn’t actually do anything. It might not be apparent at first, but if you’re working on a monitoring application that sends a new ping every minute (or less), you’ll notice your application’s memory usage creeping up to the hundred of megabytes before long.

The reason behind this is due to some tricky issues with inheritance and interfaces. You see, Ping inherits from System.ComponentModel.Component, which also implements Dispose(). Instead of overriding the inherited Dispose() method to actually dispose of the object, the Ping class explicitly implements the IDisposable Dispose() method. This means you must explicitly call IDisposable.Dispose(), or you’ll end up with the inherited Dispose() method which doesn’t do anything useful at all in this case. You can do this by casting the Ping object to IDisposable, hence the ( (IDisposable)ping ).Dispose() in the example above.

If this seems like a strange design decision, you’re not alone. I’d love to know why Ping implements IDisposable in this way, so feel free to post a comment if you know the answer.

4 Comments

.NET 3.0 and C# 3.0

10/11/2006

.NET 3.0 was released earlier this week, to very little fanfare. I haven’t done much to prepare for it, and from what I’ve read so far there’s not much reason to unless you’re already building applications for Vista. The Windows Presentation Framework looks neat, but not something I’d use at work, where I do nearly all of my .NET development.

What really caught my eye as I was reading was LINQ, one of the upcoming features in C# 3.0 (which is not included in WinFX 3.0 .NET 3.0, and won’t be released for a while; confused yet?). Here’s a little code sample from the website which illustrates what it’s all about.


using System;
using System.Query;
using System.Collections.Generic;

class app {
  static void Main() {
    string[] names = { "Burke", "Connor", "Frank",
                       "Everett", "Albert", "George",
                       "Harris", "David" };

    IEnumerable expr = from s in names
                               where s.Length == 5
                               orderby s
                               select s.ToUpper();

    foreach (string item in expr)
      Console.WriteLine(item);
  }
}

This is just a simple data query, but what’s exciting is that it’s built into the language itself, and you can use it on any object which implements the IEnumerable interface. Here it’s an array, but it could just have easily been an MS SQL database or an XML file. Data handling has always been one of .NET’s strengths compared to other languages and platforms, and with stuff like LINQ in the works I don’t think that’s going to change any time soon.

4 Comments

Using .NET and WebDAV to access an Exchange server

26/10/2006

If your company runs on Exchange (and who doesn’t), there will come a day when you’ll need to gather or modify data from an external application or a web page you’re building. There are many tools for doing this, from expensive third-party libraries to dead technologies buried in MSDN. The method I found best was a mix of C#, .NET and WebDAV, all of which are modern, flexible, and recommended by Microsoft. WebDAV (basically an HTTP request that can write as well as read) is used in many applications, including Microsoft’s own Entourage. It’s reliable and easy to use, but there are plenty of potential problems if you’re starting from scratch. Here’s a short tutorial that should give you all the basics for building Exchange support into your own application.

Getting Started

Because WebDAV is built on standard HTTP requests, the .NET library classes can handle many of the gritty details. We need to start by authenticating with a set of login credentials to get an authorization cookie, request the data we need, and extract it into a format we understand. To keep things simple, I’m only going to create one class, WebDAVRequest. I’m going to stick a few variables in here, to define things like the username and server address. Remember to URL encode the path if it contains any non-alphanumeric characters.


using System;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Security.Authentication;
using System.Text.RegularExpressions;

namespace DowntownSoftwareHouse.ExchangeExample
{
    public class WebDAVRequest
    {
        private static string server = "https://mail.mycompany.com";
        private static string path = "/public/Calendars/Board%20Room";
        private static string username = "user"
        private static string password = "password";
        private CookieContainer authCookies = null;
    }
}

Authentication

We’re going to be using forms based authentication in this example. The code you need to write does pretty much the same thing as when you log into your OWA server using a web browser; the local client checks the server’s certificate, attempts to authenticate using your credentials, and stores a cookie for later requests. Put these methods into the class we just wrote.


///

/// Add code here to check the server certificate, if you think it's necessary. Note that this
/// will only be called once when the application is first started.
/// 

protected bool CheckCert( Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors )
{
    return true;
}

///

/// Default WebDAVRequest constructor. Set the certificate callback here.
/// 

public WebDAVRequest()
{
    ServicePointManager.ServerCertificateValidationCallback += CheckCert;
}

The CheckCert event handler is called once when you first connect to the Exchange server. You’ll see that I’m cheating here; this code doesn’t actually do anything except allow us to move on to the next step. Whether or not you verify the certificate’s authenticity depends on the security of your network, and I’ll leave that decision up to you. For now, let’s move on.


///

/// Authenticate against the Exchange server and store the authorization cookie so we can use
/// it for future WebDAV requests.
/// 

public void Authenticate()
{
    string authURI = server + "/exchweb/bin/auth/owaauth.dll";

    // Create the web request body:

    string body = string.Format( "destination={0}&username={1}&password={2}", server + path, username, password );
    byte[] bytes = Encoding.UTF8.GetBytes( body );

    // Create the web request:

    HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create( authURI );
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    request.CookieContainer = new CookieContainer();
    request.ContentLength = bytes.Length;

    // Create the web request content stream:

    using ( Stream stream = request.GetRequestStream() )
    {
        stream.Write( bytes, 0, bytes.Length );
        stream.Close();
    }

    // Get the response & store the authentication cookies:

    HttpWebResponse response = (HttpWebResponse)request.GetResponse();

    if ( response.Cookies.Count < 2 )
        throw new AuthenticationException( "Login failed. Is the login / password correct?" );

    cookies = new CookieContainer();
    foreach ( Cookie myCookie in response.Cookies )
    {
        cookies.Add( myCookie );
    }

    response.Close();
}

Things are getting a bit trickier now. This might be a little unfamiliar if you haven't worked with HTTP data streams in the past, but .NET encapsulates most of it. All we're doing is sending an HTTP request (which contains our login credentials, as well as the URL to the resource we're requesting access to) to the Exchange OWA server's authorization .dll, and reading back the response. If everything goes okay, we'll get a few cookies which will be used later to access the resource we need. Note that we have to move these from a CookieCollection to a CookieContainer; for reasons I don't know .NET doesn't let you intermix the containers for requests and responses.

Don't forget to close the response stream; you'll get errors the next time you make a request if you don't.

Gathering Data

At this point, we're finally ready for whatever it is we need to do with Exchange. In this example, I'm going to poke around in the public folders and gather information for the day's calendar appointments. I'll also use a regular expression to find the organizer's full name; the full string contains their name and email address, which might not be suitable for what you're trying to display.


///

/// Find today's appointments in the public folder calendar and print the results.
/// 

public void RunQuery()
{
    string uri = server + path;
    HttpWebRequest request;
    WebResponse response;
    byte[] bytes;

    string start = DateTime.Today.ToString( "yyyy/MM/dd" );
    string end = DateTime.Today.ToString( "yyyy/MM/dd" );

    // Note that deep traversals don't work on public folders. In other words, if you
    // need to dig deeper you'll need to split your query into multiple requests.

    string format =
        @"
            
                
                    SELECT
                        ""urn:schemas:calendar:dtstart"", ""urn:schemas:calendar:dtend"",
                        ""urn:schemas:httpmail:subject"", ""urn:schemas:calendar:organizer"",
                        ""DAV:parentname""
                    FROM
                        Scope('SHALLOW TRAVERSAL OF ""{0}""')
                    WHERE
                        NOT ""urn:schemas:calendar:instancetype"" = 1
                        AND ""DAV:contentclass"" = 'urn:content-classes:appointment'
                        AND ""urn:schemas:calendar:dtstart"" > '{1}'
                        AND ""urn:schemas:calendar:dtend"" < '{2}'
                    
            ";

    bytes = Encoding.UTF8.GetBytes( String.Format( format, uri, start, end ) );

    // Use the authorization cookies we stored in the authentication method.

    request = (HttpWebRequest)HttpWebRequest.Create( uri );
    request.CookieContainer = authCookies;
    request.Method = "SEARCH";
    request.ContentLength = bytes.Length;
    request.ContentType = "text/xml";

    using ( Stream requestStream = request.GetRequestStream() )
    {
        requestStream.Write( bytes, 0, bytes.Length );
        requestStream.Close();
    }

    response = (HttpWebResponse)request.GetResponse();

    using ( Stream responseStream = response.GetResponseStream() )
    {
        // Parse the XML response to find the data we need.

        XmlDocument document = new XmlDocument();
        document.Load( responseStream );

        XmlNodeList subjectNodes = document.GetElementsByTagName( "e:subject" );
        XmlNodeList locationNodes = document.GetElementsByTagName( "a:parentname" );
        XmlNodeList startTimeNodes = document.GetElementsByTagName( "d:dtstart" );
        XmlNodeList endTimeNodes = document.GetElementsByTagName( "d:dtend" );
        XmlNodeList organizerNodes = document.GetElementsByTagName( "d:organizer" );

        for ( int index = 0; index < subjectNodes.Count; index++ )
        {
            string subject = subjectNodes[index].InnerText;
            string organizer = organizerNodes[index].InnerText;
            string location = ParentName( locationNodes[index].InnerText );
            DateTime startTime = DateTime.Parse( startTimeNodes[index].InnerText );
            DateTime endTime = DateTime.Parse( endTimeNodes[index].InnerText );

            // Use a regex to get just the user's first and last names. Note that
            // some appointments may not have a valid user name.

            string pattern = @"""(?.*?)""";
            Regex regex = new Regex( pattern, RegexOptions.None );
            Match matchedText = regex.Match( organizer );

            if ( matchedText.Success && matchedText.Groups["name"] != null )
                organizer = matchedText.Groups["name"].Value;

            // Print the results to the console.

            Console.WriteLine( "{0} - {1}: {2}", startTime.ToShortTimeString(), endTime.ToShortTimeString(), subject );
            Console.WriteLine( "{0} ({1})", location, organizer );
            Console.WriteLine();
        }

    }

    response.Close();
}

Just as before, we're making an HTTP request and reading back the response. The body of the request is XML markup that contains the Exchange data store query. The query itself is similar (both in structure and power) to SQL, so you should feel right at home if you've worked with databases before. It's possible to use a deep traversal or specify multiple folders in the FROM clause, as long as you're not looking in the public folders. If you are, you'll need to make multiple WebDAV requests to get the data you need.

The response is also XML, and since .NET has excellent XML support, we don't have to do much work to parse it. As I mentioned before, I used a regular expression to change one of the attributes, but that part is really optional. The format of both the request query and response is complex (to say the least), but everything you need should be in MSDN. I've included a few links at the end of the article to get you started.

Finishing Up

All that's left now is to run the query! I'll also do a little error handling here, and catch the exceptions I'm likely to run into.


static void Main( string[] args )
{
    try
    {
        WebDAVRequest request = new WebDAVRequest();
        request.Authenticate();
        request.RunQuery();
    }
    catch ( SecurityException e )
    {
        Console.WriteLine( "Security Exception" );
        Console.WriteLine( "   Msg: " + e.Message );
        Console.WriteLine( "   Note: The application may not be trusted if run from a network share." );
    }
    catch ( AuthenticationException e )
    {
        Console.WriteLine( "Authentication Exception, are you using a valid login?" );
        Console.WriteLine( "   Msg: " + e.Message );
        Console.WriteLine( "   Note: You must use a valid login / password for authentication." );
    }
    catch ( WebException e )
    {
        Console.WriteLine( "Web Exception" );
        Console.WriteLine( "   Status: " + e.Status );
        Console.WriteLine( "   Reponse: " + e.Response );
        Console.WriteLine( "   Msg: " + e.Message );
    }
    catch ( Exception e )
    {
        Console.WriteLine( "Unknown Exception" );
        Console.WriteLine( "   Msg: " + e.Message );
    }
}

How you integrate this in your own application is up to you, and ultimately depends what it is you're trying to accomplish. One of the things I like about .NET is how flexible and reusable it often is. In my case, I put the Exchange handling code and related classes in its own class library, which is imported into the ASP .NET webapp that displays the data to the user. When it's time to update the library, or create a different ASP .NET project that uses the code, all I have to do is copy a single .dll into the project.

Here are a few URLs you might need as you go.

Searching Calendar Folders with WebDAV
Exchange Store Key Tasks
Exchange Programming Technologies

38 Comments

Free Design Resources

18/10/2006

For a lot of programmers, no matter what language or technology you’re working with the hardest part of developing an application isn’t just writing code, but making the end result look nice as well. Those of us who prefer an IDE to Photoshop are pretty much reliant on what we can find on the internet, and a lot of what’s out there is only available for a fee, or includes restrictive licenses. Good design work is worth paying for, but for those independent developers without any real budgets, there are a few free alternatives. Here are a few I’ve used in the past.

FAMFAMFAM Icons
Over 1,000 very nice looking 16×16 px icons. They work great for websites, but are just as good for menu and toolbar icons in .NET programs. Cocoa applications use 32×32 px toolbar icons (or even higher, with resolution independence on its way), but you can still use them to spruce up a boring NSTableView.

Squidfingers Patterns
Dozens of simple, elegant looking patterns that make a great backgrounds for any website or application. I’ve noticed one or two other OSX software websites using them in the past.

Matt Ball’s Royalty Free Icons
I don’t know much about this designer, other than the fact that he posted some really nice 32×32 px OSX-ish toolbar icons on CocoaDev last year. The icon set includes many generic icons common to OSX applications, so you can quickly prototype a nice looking UI without resorting to stealing from someone else’s Contents/Resources directory.

No Comments

Friday Project

22/09/2006

I started a new project at work this morning. It’s a client-server helpdesk application, that allows users to fill out a request form on our intranet site, which puts an entry in our database and notifies me and my boss at our desks via a system tray application. I know there’s a lot of free (and expensive) helpdesk applications out there already, but honestly I’ve never seen one that’s as transparent, easy to use and maintain, and (dare I say it) stylish as what I’m planning. I’m using ASP / C# / .NET 2.0 / MS-SQL, all of which work really well for a project like this. A lot of the code is similar to tools I’ve written in the past, so I had a good portion of it finished by the time I left today. I’m really excited about how it’s going to turn out, and I think it’s going to simply things a lot for us.

I haven’t forgotten about Cocoa; in fact, I’ll probably rewrite the notification client as a neat little Growl integrated OSX app once I’m done with the Windows side of things. All part of my eventual plan to get my boss to buy a few more Macs for us to play with at the office.

No Comments