|
Simplify Programmatic File Access
Access files in different locations using the same code, whether the files reside on a file server, a Web server, or an FTP server.
by John Cronan
December 15, 2006
Technology Toolbox: Visual Basic, C#, P/Invoke & Intertop, Win32 SDK
Network architectures often present a moving target to developers. New zones are created, firewalls inserted, and domain relationships revised, usually as a result of management policy decisions regarding risk and related benefit. One of the policy changes that cause developers headaches relates to NetBIOS file access. NetBIOS is a notorious security problem, so a lot of organizations are allowing it only in the most secure network zones. Unfortunately, production applications with dependencies on NetBIOS often restrict their options. If you take away NetBIOS you have to change those applications, and that's expensive. Because of that cost, managers can't always choose the best option in terms of application functionality and security.
When writing code, you should strive to give management options, not take them away. The more changes your code can accommodate, the more valuable it is, and the more time you can spend writing new functionality. The value of your code is directly related to its flexibility.
Sometimes writing flexible code means selecting the right third-party control or the right design pattern. Sometimes it means considering what changes your code is likely to see and design for them. But it doesn't always require writing a complicated framework.
File access is one of these cases. When reading a file in .NET, you probably write code similar to this:
Private Sub ReadFile(ByVal FileName _
As String)
Dim Reader As TextReader
Using Input As Stream = New
FileStream( _
FileName, _
FileMode.Open, FileAccess.Read)
Reader = New StreamReader(Input)
Debug.WriteLine(Reader.ReadToEnd)
End Using
End Sub
This code is inflexible in the face of network architecture changes. FileStream can only read files using a local path, mapped network drive, or UNC path. If you have to change your access protocol to HTTP or FTP, you also have to change your code.
There is a better way. The .NET Framework features underused functionality that allows you to access files using a local path, UNC path, HTTP URL, or FTP URL, all with the same application code. The technique I'll show you is not perfect, though, so I'll address its shortcomings using a design pattern called Abstract Factory first identified in the classic "Gang of Four" book Design Patterns: Elements of Reusable Object-Oriented Software.
Remember when downloading a file from the Internet was pure torture? .NET's System.Net namespace makes this once difficult task extremely easy:
Dim Request As WebRequest
Dim Response As WebResponse
Dim DataStream As Stream
Request = WebRequest.Create( _
"http://www.ftponline.com/MyFile.txt")
Response = Request.GetResponse
DataStream = Response.GetResponseStream
This code also works for local files. You can substitute "C:\MyFile.txt" for "http://www.ftponline.com/MyFile.txt" and read MyFile.txt from "C:\" using that same code. This magic happens in WebRequest's Create method. Create's return value (as declared) is WebRequest, but it doesn't return a WebRequest. Instead, it returns a subclass of WebRequest specialized for the particular URI scheme you pass it. If you pass it an HTTP URL, you get an instance of HttpWebRequest. If you pass it an FTP URL, you get an instance of FtpWebRequest. If you pass it a FILE URL, you get an instance of FileWebRequest. The lesson here is that you can achieve a good degree of protocol-independence in your applications if you ignore the derived classes and code against the members of the base class, WebRequest (see Figure 1).
Build on Abstract Factory
The solution described in this article relies on the venerable Abstract Factory design pattern. If you are new to design patterns, the Abstract Factory is a great place to start because you've probably seen it before—and you will almost certainly see it again—even if you didn't know it had a name.
The .NET Framework uses the Abstract Factory extensively. XmlReader and XmlWriter also use it, as do the classes in the System.Security.Cryptography namespace. There are almost as many variations on the Abstract Factory design pattern as there are implementations, but the common elements are the abstract base class (WebRequest) called the Abstract Product, the specialized subclasses called Concrete Products, and the application code that consumes Product Objects called the Client.
Back to top
|