Chapter 4. Accessing the Internet

In This Chapter

  • Taking a tour of the System.Net namespace

  • Using built-in tools to access the network

  • Making the network tools work for you

In my opinion, the reason that Microsoft had to create the .NET Framework in the first place was the lack of Internet interoperability within the existing infrastructure. COM just couldn't handle the Internet. The Internet works differently than most platforms, such as PCs. The Internet is based on protocols — carefully defined and agreed upon ways to get things like mail and file transfers working. Microsoft's environment before 2002 distinctly didn't handle those as well.

As you can see throughout this book, the .NET Framework is designed from the ground up to take the Internet and networking in general into consideration. Not surprisingly, that is nowhere more clear than it is in the System.Net namespace. The Internet takes first chair here, with Web tools taking up nine of the classes in the namespace.

In this fourth version of the framework, even more Internet functionality is baked in. Although in version one the focus was on tools used to build other tools (low-level functions), now it contains features that are useful to you, such as Web, mail, and File Transfer Protocol (FTP). Secure Sockets Layer — the Internet's transport security — is much easier to use in this version, as are FTP and mail, which previously required other, harder-to-use classes.

System.Net is a big, meaty namespace, and finding your way around it can be difficult. My goal for this chapter is to take things that you do often and show the basics, and then give you the tools to research the more complex features of the classes.

Networking is a big part of the .NET Framework, and all the functionality is in this namespace — a whole book can be (and has been) written on the subject. For the purposes of this introduction to networking with C#, I show you these features:

  • Getting a file from the network

  • Sending e-mail

  • Logging transfers

  • Checking the status of the network around your running application

Keep in mind that I am not saying that sockets and IPv6 and other advanced Internet protocols aren't important. This chapter talks about the parts of the namespace that you will use every day. As always, there is more to learn about System.Net.

Getting to Know System.Net

The System.Net namespace is full of classes that are confusing if viewed in the documentation but make a lot of sense when used in an application. The namespace removes all the complexity of dealing with the various protocols used on the Internet.

There are more than 2,000 RFCs for Internet protocols (an RFC is a Request For Comments, a document that is sent to a standards body for review by peers before it becomes a standard), and if you have to learn all of them separately, you will never complete your project. The System.Net namespace is about making it less painful.

System.Net is not just for Web projects. Like everything else in the base class library, you can use System.Net with all kinds of projects. You can

  • Get information from Web pages on the Internet and use them on your programs.

  • Move files via the Internet using FTPs.

  • Send e-mail easily.

  • Use more advanced network structures.

  • Secure communications over the Internet using the SSL protocol.

If you need to check on the connectivity of a computer from a Windows application, you can use System.Net. If you need to build a class that will download a file from a Web site, System.Net is the namespace you need. Just because most classes relate to the Internet doesn't mean that only Web applications can use it. That's the magic of System.Net. Any application can be a connected application. While some parts of the namespace function to make the development of Web applications easier, the namespace in general is designed to make any application work with the Web.

How Net Classes Fit into the Framework

The System.Net namespace contains 62 classes and six smaller namespaces. Even as I write this, I am overwhelmed. However, if you look closely, you can see patterns.

Note

If you need help using classes, you can find more information in Book II.

The classes are well named, and you will note that a few protocols get a number of classes each. After you translate, you can narrow down what you need based on the way the protocol is named:

  • Authentication and Authorization: These classes provide security.

  • Cookie: This class manages cookies from Web browsers and usually is used in ASP.NET pages.

  • DNS (Domain Name Services): These classes help to resolve domain names into IP addresses.

  • Download: This class is used to get files from servers.

  • EndPoint: This class helps to define a network node.

  • FileWeb: This brilliant set of classes describes network file servers as local classes.

  • FtpWeb: This class is a simple File Transfer Protocol implementation.

  • Http (HyperText Transfer Protocol): This class is the Web protocol.

  • IP (Internet Protocol): This class helps to define network endpoints that are specifically Internet related.

  • IrDA: This class is an infrared endpoint. Infrared ports are networks too!

  • NetworkCredential: This class is another security implementation.

  • Service: This class helps manage network connections.

  • Socket: This class deals with the most primitive of network connections.

  • Upload: This set of classes helps you upload information to the Internet.

  • Web: These classes help with the World Wide Web — largely implementations of the http classes that are more task oriented.

This list is extensive because the classes build on each other. The EndPoint classes are used by the socket classes to define certain network specifics, and the IP classes make them specific to the Internet. The Web classes are specific to the World Wide Web. You will rarely use highest-level classes, but it's often tough to see what is needed when.

Most of the functions that you use every day, though, are encapsulated within seven mostly new namespaces under the System.Net namespace:

  • Cache: This function has a lot of enumerators that manage the browser and network caching functions built into the namespace.

  • Configuration: This function grants access to the properties that you need to set to make many of the other System.Net classes work.

  • Mail: This function takes over for System.Web.Mail to facilitate the sending of Internet e-mail.

  • Mime: This function bundles file attachments with the Mail namespace.

  • NetworkInformation: This function gets details about the network around your application.

  • Security: This function implements the network security managed by many classes of System.Net.

  • Sockets: This function utilizes the most basic network connections available to Windows.

Using the System.Net Namespace

The System.Net namespace is code-oriented, which means that few implementations are specifically for user interfaces. Most everything that you do with these classes is behind the scenes. You have few drag-and-drop user controls — the System.Net namespace is used in the Code View.

To demonstrate this, in the rest of this chapter, I go over building a Windows Forms application that has the following requirements:

  • Check the network status.

  • Get a specific file from the Internet.

  • E-mail it to a specific e-mail address.

  • Log the whole transaction.

This is not an insignificant set of requirements. In fact, even in the 1.0 and 1.1 versions of C#, this would be difficult. One of the main goals of the System.Net namespace in this version is to make common tasks much easier. You can start by loading the sample code or by starting a new project and following the steps in the following sections.

Checking the network status

First, you need to inform the user about network connectivity by following these steps:

  1. Create a new Windows Forms Application project in Visual Studio.

    I called mine NetworkTools.

  2. Add a StatusStrip control to the form by dragging it from the Toolbox.

  3. Select the SmartTag that appears and add a StatusLabel.

  4. Double-click the form to get the Form_Load event handler and move to Code View.

  5. Reference the System.Net namespace by adding the line using System.NET.NetworkInformation; to the top of the code.

  6. Add the code in bold from the following listing to test whether the network is available and display it on the status bar:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Net.NetworkInformation;
    
    namespace NetworkTools
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                if (NetworkInterface.GetIsNetworkAvailable())
                {
                    toolStripStatusLabel1.Text = "Connected";
                }
                else
                {
                    toolStripStatusLabel1.Text = "Disconnected";
                }
    
            }
        }
    }

That's all there is to it. The NetworkInformation class contains a bunch of information about the status of the network, current IP addresses, the gateway being used by the current machine, and more.

Tip

Keep in mind that the NetworkInformation class will work only on a local machine. If you use this class in an ASP.NET Web Forms application, you will get information about the server.

Downloading a file from the Internet

You can get a file from the Internet in one of several ways, and one of the most common is by using FTP. The lightweight FTP protocol is favored because it's secure and supported on many systems.

To build an application that uses FTP, follow these steps:

  1. Drag a button onto the form from the Toolbox.

  2. Double-click the button to get the Click event handler.

  3. Add the required imports, System.Net, System.Net.Mail, and System.IO to the top of the code.

  4. Create a new subroutine called Download File that accepts a remote filename and a local filename as strings.

  5. In the new subroutine, create a new FileStream (called localFileStream) and FTPWebRequest (called ftpRequest), as shown in Listing 4-1.

    The FileStream references a local file and accepts the local file that is passed into the subroutine. The FtpWebRequest is the same thing for the remote file.

  6. Set the Method parameter of the FtpWebRequest to WebRequestMethods.Ftp.Downloadfile.

  7. Set the Credentials property of the FtpWebRequest to a new NetworkCredential with anonymous information, like I did in Listing 4-1.

  8. Create a new WebResponse object from the ftpRequest method. This gets the statement back from the FTP server about how your request will be handled.

  9. Get the Stream from the Response object.

  10. Read the file into a 1024-byte buffer, one block at a time, using a While loop, as shown at the end of Listing 4-1.

  11. Call the DownloadFile method from the Button1_Click event handler, like I show in this chunk of code:

    private void button1_Click(object sender, EventArgs e)
        DownloadFile(@"ftp://ftp.csharpfordummies.net/sampleFile.bmp", @"c:
        sampleFile.bmp");
    End Sub

Example 4-1. The DownloadFile Method

private void DownLoadFile(string remoteFile, string localFile)
    {
       FileStream localFileStream = new FileStream(localFile, FileMode.
OpenOrCreate);
       FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.
Create(remoteFile);
       ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile;
       ftpRequest.Credentials = new NetworkCredential("Anonymous", "bill@
sempf.net");
       WebResponse ftpResponse = ftpRequest.GetResponse();
       Stream ftpResponseStream = ftpResponse.GetResponseStream();
       byte[] buffer = new byte[1024];
       int bytesRead = ftpResponseStream.Read(buffer, 0, 1024);
       while (bytesRead > 0)
       {
           localFileStream.Write(buffer, 0, bytesRead);
           bytesRead = ftpResponseStream.Read(buffer, 0, 1024);
       }
       localFileStream.Close();
       ftpResponseStream.Close();
    }

This FTP example is watered down, but it makes my point. The WebRequest and WebResponse classes in the System.Net namespace are fully utilized to create the more complete FtpWebRequest, for instance. Properties like the Method of download and Credentials make it an easy call.

In fact, the toughest part of this process is dealing with a FileStream object, which is still the best way to move files and not specific to the System.Net namespace. Streams are discussed in Chapter 3 of this mini-book, which covers the System.IO namespace, but they have significance to the network classes too. Streams represent a flow of data of some kind, and a flow of information from the Internet qualifies.

That's what you are doing when you get a Web page or a file from the Internet — gathering a flow of data. If you think about it, it makes sense that this is a flow, because the status bar in an application shows a percentage of completion. Just like pouring water into a glass, the flow of data is a stream, so the concept is named Stream.

This concept holds true for getting a file from the World Wide Web, as well. HTTP, the Web protocol, is just another protocol that defines how a document is moved from a server on the Internet to your local machine. In fact, the code looks strikingly similar to the FTP example, as you can see in the following bit of code. The same stream is recovered; only the formatting is different.

private void DownLoadWebFile(string remoteFile, string localFile)
{
    FileStream localFileStream = new FileStream(localFile, FileMode.
    OpenOrCreate);
    WebRequest webRequest = WebRequest.Create(remoteFile);
    webRequest.Method = WebRequestMethods.Http.Get;
    WebResponse webResponse = webRequest.GetResponse();
    Stream webResponseStream = webResponse.GetResponseStream();
    byte[] buffer = new byte[1024];
    int bytesRead = webResponseStream.Read(buffer, 0, 1024);
    while (bytesRead > 0)
    {
        localFileStream.Write(buffer, 0, bytesRead);
        bytesRead = webResponseStream.Read(buffer, 0, 1024);
    }
    localFileStream.Close();
    webResponseStream.Close();
}

Note

You need to pass in a Web address, so your subroutine call looks like this:

DownloadWebFile(@"http://www.csharpfordummies.net/sampleFile.bmp", @"c:
    sampleFile.bmp");

Note the changes, marked as bold. webRequest is now a WebRequest rather than an FtpWebRequest. Also, the Method property of webRequest has been changed to WebRequestMethods.Http.Get. Finally, the Credentials property has been removed because the credentials are no longer required.

E-mailing a status report

E-mail is a common requirement of networked systems. If you are working in an enterprise environment, you are going to write a larger scale application to handle all e-mail requirements, rather than make each individual application e-mail-aware.

However, if you are writing a standalone product, it might require e-mail support. Because I happen to be writing a standalone application, that is exactly what I'm going to do.

E-mail is a server-based operation, so if you don't have an e-mail server that you can use to send from, this might be hard. Many ISPs no longer allow relaying, which is sending an outgoing message without first having an account and logging in. Therefore, you might have trouble running this part of the sample.

If you are in a corporate environment, however, you can usually talk to your e-mail administrator and get permission to use the e-mail server. Because outgoing requests are usually only harnessed inside the firewall, relaying is often available. To build your e-mail function, follow these steps:

  1. Add a text box to the default form in Design View, and then change to Code View.

    At the top of Code View, make sure that you have referenced the System.Net.Mail namespace.

  2. Create a new subroutine called SendEmail.

    It should accept the from e-mail address, the to e-mail address, the subject of the e-mail, and the body of the e-mail.

  3. Declare a new MailMessage and pass in the fromAddress, toAddress, subject, and body parameters, like this:

    MailMessage message = New MailMessage(fromAddress,
       toAddress, subject, body);
  4. Declare a new SmtpClient and pass in the address of your mail server.

    This can be an IP address, machine name, or URL.

  5. Use the Send method of the SmtpClient object you created to send the MailMessage, which is passed in as a parameter.

  6. When you're finished, make sure that you set the values of the MailMessage and SmtpClient to Nothing, because they do take up resources.

Listing 4-2 shows the completed subroutine.

Example 4-2. The SendEmail Subroutine

private void SendEmail(string fromAddress, string toAddress, string subject,
    string body)
{
    MailMessage message = new MailMessage(fromAddress, toAddress, subject, body);
    SmtpClient mailClient = new SmtpClient("localhost");
    mailClient.Send(message);
    message = null;
    mailClient = null;
}

Notice that I used localhost as the e-mail server name. If you have an e-mail server software installed locally, even IIS 6.0 with SMTP, this will work. Most of the time, you will have to put another e-mail server name in the SmtpClient constructor. The e-mail server name can often be found in your Outlook preferences.

After you have written your method, you need to call it after the file is downloaded in the Button1_Click event handler. Change the code of that subroutine to the following to call that method:

private void button1_Click(object sender, EventArgs e)
{
    DownloadFile(@"ftp://ftp.csharpfordummies.net/sampleFile.bmp", @"c:
    sampleFile.bmp");
    SendEmail(textBox1.Text, textBox1.Text, "FTP Successful", "FTP Successfully
    downloaded");
}

Notice that I sent in the value of the text box twice: once for the to address, and once for the from address. This isn't always necessary, because you may have a situation where you want the e-mail to come only from a Webmaster address or to go only to your address.

You should have enough code in place to run the application now. Press F5 to launch the application in debug mode and give it a try.

When you click the button, the application should download the file to the local drive and then e-mail you to inform you that the download is complete. A host of things can go wrong with network applications, though, and you should be aware of them. Here are a few:

  • For most network activity, the machine running the software must be connected to a network. This isn't a problem for you as the developer, but you need to be conscious of the end users, who may need connectivity to have access to the features they want to use. Use of the network status code can help inform users about the availability of those features.

  • Firewalls and other network appliances sometimes block network traffic from legitimate applications. Some examples of this include:

    • FTP is often blocked from corporate networks.

    • Network analysis features of .NET are often blocked on corporate servers. If the server is available to the public, these openings can cause holes for hackers to crawl through.

    • Speaking of hackers, make sure that if you use incoming network features in your application, you have adequately secured your application. More on this can be found in the excellent book Writing Secure Code, Second Edition, by Michael Howard and David C. LeBlanc (published by Microsoft Press).

    • E-mail is especially fragile. Often, Internet service providers will block e-mail from an address that is not registered on a mail server. This means that if you are using your localhost server (like in the example in Listing 4-2), your ISP might block the e-mail.

  • Network traffic is notoriously hard to debug. For instance, if the sample application works, but you never receive an e-mail from the SmtpServer you coded, what went wrong? You may never know. XML Web services (covered in Book VII) have a similar problem — it's spectacularly tough to see the actual code in the SOAP envelope (markup added around requests for Web services) to tell what went wrong.

Logging network activity

This brings you to the next topic, which is network logging. Because network activity problems are so hard to debug and reproduce, Microsoft has built in several tools for the management of tracing network activity.

What's more, like the ASP.NET tracing available, the System.Net namespace tracing is completely managed using the configuration files. To be able to use the functions, therefore, you don't need to change and recompile your code. In fact, with a little management, you can even show debug information to the user by managing the config files your application uses.

Each kind of application has a different kind of configuration file. For Windows Forms applications, which you are using here, the file is called app.config and is stored in the development project directory. When you compile, the name of the file is changed to the name of the application, and it's copied into the bin directory for running.

If you open your app.config file now, you see that it already contains some diagnostic information, as shown in Listing 4-3. You will add some information to it.

Example 4-3. The Default app.config File

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.diagnostics>
        <sources>
            <!-- This section defines the logging configuration for
    My.Application.Log in Windows Forms projects.-->
            <source name="Microsoft.VisualBasic.Logging.Log.WindowsFormsSource"
    switchName="DefaultSwitch">
                <listeners>
                    <add name="FileLog"/>
                    <!-- Uncomment the below section to write to the Application
    Event Log -->
                    <!--<add name="EventLog"/>-->
                </listeners>
            </source>
        </sources>
        <switches>
            <add name="DefaultSwitch" value="Information" />
        </switches>
<sharedListeners>
            <add name="FileLog"
                 type="Microsoft.VisualBasic.Logging.FileLogTraceListener,
    Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f
    5f7f11d50a3a, processorArchitecture=MSIL"
                 initializeData="FileLogWriter"/>
            <!-- Uncomment the below section and replace APPLICATION_NAME with
    the name of your application to write to the Application Event Log -->
            <!--<add name="EventLog" type="System.Diagnostics.
    EventLogTraceListener" initializeData="APPLICATION_NAME"/> -->
        </sharedListeners>
    </system.diagnostics>
</configuration>

First, you need to add a new source for the System.Net namespace. Next, you add a switch to the Switches section for the source you added. Finally, you add a SharedListener to that section and set the file to flush the tracing information automatically.

The finished app.config file, with the adds in bold, is shown in Listing 4-4. It's also in the sample code on this book's companion Web site.

Example 4-4. The Finished app.config File

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.diagnostics>
        <sources>
            <source name="Microsoft.VisualBasic.Logging.Log.WindowsFormsSource"
    switchName="DefaultSwitch">
                <listeners>
                    <add name="FileLog"/>
                </listeners>
            </source>
            <source name="System.Net">
                <listeners>
                    <add name="System.Net"/>
                </listeners>
            </source>
        </sources>
        <switches>
            <add name="DefaultSwitch" value="Information" />
            <add name="System.Net" value="Verbose" />
        </switches>
        <sharedListeners>
            <add name="FileLog"
                 type="Microsoft.VisualBasic.Logging.FileLogTraceListener,
    Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f
    5f7f11d50a3a, processorArchitecture=MSIL"
                 initializeData="FileLogWriter"/>
            <add name="System.Net"
                 type="System.Diagnostics.TextWriterTraceListener"
                 initializeData="my.log"/>
        </sharedListeners>
        <trace autoflush="true" />
    </system.diagnostics>
</configuration>

Run the application again and watch the Output window. Advanced logging information is shown there because of your changes to the configuration file. Additionally, a log file was written. In the development environment, this is in the bin/debug directory of your project. You might have to click the Show All Files button at the top of the Solution Explorer to see it.

In that folder, you should see the file named my.log, where the SharedListener you added to the app.config file directed the logging information. My copy of that file is shown in Listing 4-5 — your mileage may vary.

Example 4-5. The Log Information

System.Net Information: 0 : WebRequest::Create(ftp://ftp.csharpfordummies.net/
    sample.bmp)
System.Net Information: 0 : Exiting WebRequest::Create() ->
    FtpWebRequest#37460558
System.Net Information: 0 : FtpWebRequest#37460558::GetResponse()
System.Net Information: 0 : Exiting FtpWebRequest#37460558::GetResponse()
System.Net Information: 0 : Associating Message#59487907 with
    HeaderCollection#23085090
System.Net Information: 0 : HeaderCollection#23085090::Set(mime-version=1.0)
System.Net Information: 0 : Associating MailMessage#6964596 with Message#59487907
System.Net Information: 0 : SmtpClient::.ctor(host=24.123.157.3)
System.Net Information: 0 : Associating SmtpClient#17113003 with
    SmtpTransport#30544512
System.Net Information: 0 : Exiting SmtpClient::.ctor()          ->
    SmtpClient#17113003
System.Net Information: 0 : SmtpClient#17113003::Send(MailMessage#6964596)
System.Net Information: 0 : SmtpClient#17113003::Send(DeliveryMethod=Network)
System.Net Information: 0 : Associating SmtpClient#17113003 with
    MailMessage#6964596
System.Net Information: 0 : Associating SmtpTransport#30544512 with
    SmtpConnection#44365459
System.Net Information: 0 : Associating SmtpConnection#44365459 with
    ServicePoint#7044526
System.Net Information: 0 : Associating SmtpConnection#44365459 with
    SmtpPooledStream#20390146
System.Net Information: 0 : HeaderCollection#30689639::Set(content-transfer-
    encoding=base64)
System.Net Information: 0 : HeaderCollection#30689639::Set(content-transfer-
    encoding=quoted-printable)
System.Net Information: 0 : HeaderCollection#23085090::Remove(x-receiver)
System.Net Information: 0 : HeaderCollection#23085090::Set([email protected])
System.Net Information: 0 : HeaderCollection#23085090::Set([email protected])
System.Net Information: 0 : HeaderCollection#23085090::Set(date=1 Apr 2010
    16:32:32 −0500)
System.Net Information: 0 : HeaderCollection#23085090::Set(subject=FTP
    Successful)
System.Net Information: 0 : HeaderCollection#23085090::Get(mime-version)
System.Net Information: 0 : HeaderCollection#23085090::Get(from)
System.Net Information: 0 : HeaderCollection#23085090::Get(to)
System.Net Information: 0 : HeaderCollection#23085090::Get(date)
System.Net Information: 0 : HeaderCollection#23085090::Get(subject)
System.Net Information: 0 : HeaderCollection#30689639::Get(content-type)
System.Net Information: 0 : HeaderCollection#30689639::Get(content-transfer-
    encoding)
System.Net Information: 0 : Exiting SmtpClient#17113003::Send()

Reading this file, you can see that the reference numbers that match the requests on the server all appear, dramatically improving the ease of debugging. Also, because everything is in order of action, finding out exactly where the error occurred in the process is much easier.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.123.208