Downloading Web Content


In many cases, you may want to deploy your application remotely via the Web. You can use Internet Explorer to download and run .NET applications, simply by creating HTML that describes which assemblies to download, where each assembly is located, and what custom configuration settings apply to the application.

As you might expect, Internet Explorer leverages many of the concepts used by the .NET Framework ”particularly the use of assemblies and application configuration files. Deploying an application via Internet Explorer can be as simple as building your application and uploading it to your Web server of choice! The executable can then be referenced via a standard URL, and Internet Explorer will detect the fact that it is a .NET application and respond appropriately.

Let's demonstrate this approach with a simple example: a trivial "Hello World" application that creates a message box. To demonstrate that the assembly truly is considered remote, the message box displays the code base of the assembly ”that is, the location from which the assembly was downloaded. Listing 6.6 shows the source code, which is located in RemoteHelloWorld.cs .

Listing 6.6 RemoteHelloWorld.cs source code
 using System.Reflection; using System.Windows.Forms; class Demo {   public static void Main()   {     Assembly ass = Assembly.GetExecutingAssembly();     string msg = "Hello, my codebase is " + ass.CodeBase;     MessageBox.Show(msg);   } } 

Let's build this application using the C# compiler, and then build a standard Windows application, resulting in RemoteHelloWorld.exe . The next step is to upload this file to some Web server. Any Web server will do; nothing here replies in ASP or ASP.NET. This approach assumes that you can use FTP or some other facility for transferring this file from your development machine to the Web server.

With the application in place, you need simply reference the executable from Internet Explorer. The simplest way to do so is to type the complete URL to the file in the Internet Explorer address bar. [2] If all goes according to plan, Internet Explorer should automatically download and execute the .NET code.

[2] The security system's configuration on your machine could prohibit the downloaded code from executing. To resolve this issue, you may need to either allow code downloaded from the Internet to execute or make the site you reference trusted and ensure that code from trusted sites can execute. In this chapter, we assume that such settings have been specified.

As shown in Figure 6.1, .NET knows the location from which the application was loaded and has set the CodeBase property of the assembly appropriately.

Figure 6.1. Remote application running under Internet Explorer

graphics/06fig01.gif

This example also demonstrates how the .NET security system works. You probably noticed that, unlike with other executable files that you reference on the Web, Internet Explorer did not ask your permission to download and run the file. As the file is a .NET application, Internet Explorer defers to .NET for security settings, including exactly which tasks remote applications are allowed to perform. The example application is quite benign : It references the CodeBase property of a user -defined assembly and displays a message box. The default .NET security configuration normally permits these operations, so the application downloads and runs without incident. If you experienced trouble executing the application, you might find that your local security policies are tighter than the default and so prevent the application from running, in which case you will generally receive a security exception message. Indeed, if you modify the application to do anything more sophisticated (such as opening a file on the local computer), you will find that .NET will halt the operation.

Referencing Assemblies with the codeBase Element

Configuration files also allow you to specify an alternative code base for your assemblies ”that is, a location that .NET will search for your assembly. This option allows you to override the default .NET assembly search algorithm so your application can automatically download referenced assemblies from any location that you choose.

To achieve this goal, you can add a codeBase element to any of the .NET supported configuration files. In this way, you can provide this behavior for only a single application by using the application configuration file or for the entire machine by using the machine configuration file. The codeBase element specifies the identity of the assembly as well as the URL from which the assembly can be downloaded. If the referenced assembly has a strong name (see Chapter 5), then the URL can be any valid URL. If the referenced assembly is a private assembly (that is, the assembly has no strong name ), then the URL must be a path relative to, and a child of, the application's directory.

For complete details on the codeBase element, consult the .NET documentation. This section provides a short example that demonstrates downloading content. As in some of the previous examples, two assemblies are created here: the assembly to be downloaded from a remote Web server and an application that uses this assembly.

The remote assembly is quite trivial ”just a single method that displays a message box. As in the previous example, the program displays the codeBase property of the assembly to prove it really comes from the remote location. Listing 6.7 shows the source code, which is located in RemoteAssembly.cs .

Listing 6.7 Source code for RemoteAssembly\RemoteAssembly.cs
 using System.Reflection; using System.Windows.Forms; public class Demo {   public static void DisplayCodeBase()   {     Assembly ass = Assembly.GetExecutingAssembly();     string msg = "Hello, my codebase is " + ass.CodeBase;     MessageBox.Show(msg);   } } 

As mentioned earlier, any assembly downloaded from a remote code base must have a strong name. Chapter 5 described ways to give strong names to assemblies, and the same pattern is followed here: Create a key with the strong name utility ( sn.exe ) and create the final assembly with the Assembly Linker tool ( al.exe ). These commands are shown in the makefile (see Listing 6.8).

Listing 6.8 Contents of RemoteAssembly\makefile
 all: RemoteAssembly.dll RemoteAssembly.key:     sn -k RemoteAssembly.key RemoteAssembly.dll: RemoteAssembly.cs RemoteAssembly.key     csc /t:module RemoteAssembly.cs     al /v:1.0.0.0 /keyfile:RemoteAssembly.key \        /out:RemoteAssembly.dll RemoteAssembly.netmodule clean:     -del *.netmodule     -del *.dll 

To build this assembly, simply execute nmake in the example directory.

The next step is to transfer this assembly to the remote Web server. As you will recall from Chapter 5, this process creates an assembly consisting of two files: RemoteAssembly.dll is the module containing the assembly manifest, and RemoteAssembly.netmodule is a module referenced by the main assembly module. You must transfer these two files to your Web server using whatever technique you prefer.

Finally, you can create the application that downloads and uses this assembly. This application is truly trivial: It simply calls the static method defined in the remote assembly. Listing 6.9 shows the source code, which is located in UseRemoteAssembly.cs .

Listing 6.9 Source code for UseRemoteAssembly\UseRemoteAssembly.cs
 class UseRemoteAssembly {   public static void Main()   {     Demo.DisplayCodeBase();   } } 

To build the application, let's use a makefile , which is shown in Listing 6.10. Note that you must reference the remote assembly to successfully build the application. Referencing external assemblies at build time is discussed in Chapter 5.

Listing 6.10 Contents of RemoteAssembly\makefile
 all: UseRemoteAssembly.exe UseRemoteAssembly.exe: UseRemoteAssembly.cs     csc UseRemoteAssembly.cs \         /reference:..\RemoteAssembly\RemoteAssembly.dll clean:     -del *.exe 

If you attempt to execute the application as it stands, it fails with an error message similar to the following:

 Unhandled Exception: System.IO.FileNotFoundException:  File or assembly name RemoteAssembly, or one of its dependencies, was not found. 

As expected, .NET cannot find the RemoteAssembly assembly. Depending on the .NET configuration, debugging information may also be printed that shows where .NET searched for the assemblies. Note that the global assembly cache (GAC) is always used in preference to any locations specified in the configuration files; if a matching assembly is found in the GAC, it is always used.

Next, you can create the application configuration file that specifies the location from which this assembly can be downloaded. Much like in the version binding example in Chapter 5, the codeBase element is a child of the assemblyIdentity element, which specifies the assembly name and public key token. Listing 6.11 shows the complete application configuration file, which is found in UseRemoteAssembly.exe.config .

Listing 6.11 UseRemoteAssembly.exe.config application configuration file
 <configuration>   <runtime>     <assemblyBinding       xmlns="urn:schemas-microsoftcom:asm.v1">       <dependentAssembly>         <assemblyIdentity             name="RemoteAssembly"             publicKeyToken="c15b091d4324f090"             culture=""/>         <codeBase             version="1.0.0.0"             href=             "http://www.project42.net/RemoteAssembly.dll"/>       </dependentAssembly>     </assemblyBinding>   </runtime> </configuration> 

The configuration file shows the public key token of the remote assembly (extracted by executing sn “T RemoteAssembly.dll ) and the URL from which this assembly can be downloaded. The configuration file also assumes that you previously uploaded the two remote assembly files to http://www.project42.net/ ; obviously, you will need to modify this URL to specify your own location.

Once this configuration file is in place, you can execute the application without incident. Figure 6.2 shows this application in action and confirms that the code base for the assembly is, indeed, on the HTTP server specified.

Figure 6.2. Application using the remote assembly

graphics/06fig02.gif

The Download Cache Revisited

As discussed briefly in Chapter 5, a download cache controls all content downloaded from the Web. It is responsible for downloading the appropriate assemblies and keeping them isolated from other assemblies that may be downloaded by other users or applications. This isolation is critical when you consider that assemblies downloaded from the Web need not be signed (recall the first RemoteHelloWorld example in this chapter) and, therefore, do not have strong names. This can lead to the situation in which two different applications use MyApp.exe as the name of the assembly, but are completely unrelated files. .NET must ensure that each application has its own discrete copy of MyApp.exe .

The gacutil tool (as described in Chapter 5) supports a /ldl option that lists the contents of the download cache. You can use this tool to verify that the assembly created by the example code is, indeed, present in the download cache, as shown in Listing 6.12.

Listing 6.12 Using gacutil to list the contents of the download cache
 Microsoft (R) .NET Global Assembly Cache Utility.  Version 1.0.3705.0 Copyright (C) Microsoft Corporation 1998-2001. All rights reserved. The cache of downloaded files contains the following entries:         RemoteAssembly, Version=1.0.0.0, Culture=neutral,             PublicKeyToken=c15b091d4324f090, Custom=null         RemoteHelloWorld, Version=0.0.0.0, Culture=neutral,             PublicKeyToken=null, Custom=null Number of items = 2 

The machine running Listing 6.12 has two entries: RemoteAssembly has a strong name, while RemoteHelloWorld does not.

Web Controls

Another popular way to create and deploy applications using .NET is to embed Web controls in an ASP.NET Web page. Web controls, also known as ASP.NET server controls, are special in that they combine server-side and client-side functionality into a single control. When ASP.NET is asked to render a page containing such a control, it generates some extra HTML or JScript for the client that delivers local events to the server. This approach allows your control to be hosted in an ASP.NET page executing at the server, but to handle events just as if the control resided locally on the client.

ASP.NET routes these events using standard HTML and ECMAScript (JScript). It does not use Internet Explorer's DHTML extensions, which means that the code should work in all modern browsers.

For an overview of how this system works, let's consider a simple example. To create a simple control, you just create a class deriving from System.Web.UI.Control and implement the INamingContainer interface. One method that you can override is CreateChildControls , which gives you the opportunity to create your own controls or other HTML elements to build your control.

The code fragment in Listing 6.13 shows such a class. It defines the class MyControl and implements the CreateChildControls method, which creates two additional buttons and a label as children. Clicking on either of the two buttons changes the text in the label.

Listing 6.13 C# code fragment a defining Web control
 using System; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace Project42 {   public class MyControl : Control,                            INamingContainer   {     private Button firstButton = new Button();     private Button secondButton = new Button();     private Label outputLabel = new Label();     protected override void CreateChildControls()     {       firstButton.Text = "Hello";       firstButton.Click +=               new EventHandler(this.FirstButtonClick);       this.Controls.Add(firstButton);       secondButton.Text = "Goodbye";       secondButton.Click +=               new EventHandler(this.SecondButtonClick);       this.Controls.Add(secondButton);       outputLabel.Text="Press a button!";       this.Controls.Add(outputLabel);     }     private void FirstButtonClick(object sender,                                   System.EventArgs e)     {        outputLabel.Text = "Hello";     }     private void SecondButtonClick(object sender,                                    System.EventArgs e)     {        outputLabel.Text = "Goodbye";     }   } } 

Before an ASP.NET Web page can use a control, it must be compiled and stored in a well-known place: a directory called bin that is located in a directory off the parent directory holding the ASP.NET Web page that will access the control. The following makefile compiles the control's source code and stores the resulting DLL in the bin directory:

 all: MyWebControl.dll  MyWebControl.dll: MyWebControl.cs    csc /t:library /out:..\bin\MyWebControl.dll \        /debug MyWebControl.cs clean:    del *.dll 

To display this control on a Web page, an ASP.NET ( .aspx ) file will be created that references the control. This ASP.NET page must contain an @Register directive to indicate where to find the custom control. This control is then added to the HTML body, which includes runat =server directives to indicate that all event processing happens on the server side. Such an ASP.NET page is shown in Listing 6.14.

Listing 6.14 ASP.NET page using a custom Web control
 <%@ Register TagPrefix="MyWebControl"     Namespace="Project42"     Assembly="MyWebControl" %> <html>    <body>       <form method="POST" action="TestControl.aspx"         runat=server>         <MyWebControl:MyControl id="MyControl"           runat=server/>       </form>    </body> </html> 

The ASP.NET Web page must be located on an ASP.NET-enabled Web server. If you were to merely open the page with a browser on a local hard disk, then the control would not display correctly. After the files are installed on a Web site, Figure 6.3 shows the output generated when accessing the page.

Figure 6.3. Output generated when accessing the ASP.NET Web page

graphics/06fig03.gif

As mentioned earlier, ASP.NET performs its control magic by generating some extra HTML for the client. To see this magic in operation, you can view the page in your favorite Web browser. For the ASP.NET page in Listing 6.14, ASP.NET will generate the page for the client as shown in Listing 6.15.

Listing 6.15 HTML generated for an ASP page
 <html>   <body>     <form name="_ctl0" method="POST"           action="MyWebControl.aspx" id="_ctl0">     <input type="hidden" name="__VIEWSTATE"            value="dDwxNzI1ODgyMzE0Ozs+IFybHNgVDzLdmHT2..."     />     <input type="submit" ame="MyControl:_ctl0"            value="Hello" />     <input type="submit" name="MyControl:_ctl1"            value="Goodbye" />     <span>Press a button!</span>   </form> </body> </html> 

The HTML generated in this way should work on any browser. It defines a standard HTML form with three controls. One control is a special hidden control used by the ASP.NET server to maintain the correct state between the server and the client. The other two controls are the children controls added in the C# code given in Listing 6.13. The buttons created by the HTML will produce a standard POST event to the nominated page whenever the user presses one of them. The ASP.NET server will respond to this event by generating the appropriate Click event for the control.

For more information on Web controls, consult the ASP.NET documentation or another ASP.NET reference.



Programming in the .NET Environment
Programming in the .NET Environment
ISBN: 0201770180
EAN: 2147483647
Year: 2002
Pages: 146

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net