首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > ASP >

ASP.NET 治理网站(虚拟目录)

2014-01-15 
ASP.NET 管理网站(虚拟目录)?????? 网站名称中可以填写有意义的内容,不过,它只用于在 IIS 里标识网站,但并

ASP.NET 管理网站(虚拟目录)

?????? 网站名称中可以填写有意义的内容,不过,它只用于在 IIS 里标识网站,但并不影响网站的内容。物理路径指定了 IIS 7 到哪里寻找服务新网站请求的内容。我们创建了一个新目录 C:\FileCopySite。“连接为”和“测试设置”按钮可以指定用于访问网站内容的不同用户身份。

?????? “绑定”一节可以指定 IIS 7 如何监听来自客户端的请求。IIS 7 支持一系列的网络协议,“类型”下拉列表有众多选项,但我们只关注 HTTP,因为它是最广泛被使用的。IP 地址我们采用默认的“全部未分配”,也就是说 IIS 监听处理其他网站在同一 TCP 端口上已经被服务的网络接口之外的全部网络接口。“端口”值指定 IIS 7 要监听客户端请求的 TCP 端口号,一般而言每个网站必须仅由唯一的端口提供服务,因此我们选择了 81,这样不会和默认网站的 80 端口相冲突。

?????? 勾选了“立即启动网站”,它表示在我们单击“确定”之后,IIS 就创建网站并开始监听请求。现在单击确定。

?

创建虚拟目录

?????? 在之前的部署网站系列文章里,我们把内容放到了 IIS 7 寻找内容的默认目录里。但我们也可以不这样做,而是把内容放到其他地方,然后通过虚拟目录来引用它。为了演示,我们在服务器上创建一个新目录,并把网站的内容复制到了那里,新目录路径如下:

C:\WebSiteDeployment\VirtualDirectory

?????? 为了把新目录关联到 IIS ,右击“默认网站”,选择“添加虚拟目录”,会打开如下对话框:

?????? ASP.NET 治理网站(虚拟目录)

?????? 我们希望网站的 URL 是这样的:/virtual">/virtual">/virtual">http://<servername>/virtual,因此在别名里输入了 virtual。单击“确定”创建虚拟目录。为了测试它,浏览器现在访问 URL http://localhost/virtual,你会看到自己的简单网站,但这一回内容是以新目录作为源的,并且通过自定义的 URL 来进行访问。

?????? 甚至可以有多个虚拟目录指向一个实际物理路径,访问同一资源时,显示的 URL 是不同的。

ASP.NET 治理网站(虚拟目录) ASP.NET 治理网站(虚拟目录)

?

??????

使用 VirtualPathProvider

?????? VirtualPathProvider 类提供了虚拟目录之外的另一个选择,不再由文件系统提供网站内容,内容可以通过编程生成或者取自数据库。

?????? 下面我将通过一个从 SQL Server 表读取 ASPX 文件的简单示例来理解 VirtualPathProvider 类。我们在本地 SQL Server 上有一个如下图所示的数据库表,里面保存了 3 个页面:

?????? ASP.NET 治理网站(虚拟目录)

?????? 你可以看到表里有一个文件名(同时还是主键)和真是内容。内容可以是 ASP.NET 能够理解的任意类型的代码。

?

??????

?????? VirtualPathProvider 类被定义在 System.Web.Hosting 命名空间里。在 App_Code 目录里新增一个类并继承 VirtualPathProvider,至少要实现以下方法:

using System;
using System.Data.SqlClient;
using System.IO;
using System.Text;
using System.Web.Hosting;
?
// VirtualPathProvider: 使 Web 应用程序可以从虚拟文件系统中检索资源
public class DBPathProvider : VirtualPathProvider
{
    public static void AppInitialize()
    {
        // HostingEnvironment: 在托管应用程序的应用程序域内向托管应用程
        // 序提供应用程序管理功能和应用程序服务
        // RegisterVirtualPathProvider(): 在 ASP.NET 编译系统中注册新
        // 的 VirtualPathProvider 实例
        HostingEnvironment.RegisterVirtualPathProvider(new DBPathProvider());
    }
?
    // VirtualPathProvider.FileExists(): 获取一个值,该值指示文件是否
    // 存在于虚拟文件系统中
    public override bool FileExists(string virtualPath)
    {
        throw new Exception("The method or operation is not implemented.");
    }
?
    // VirtualPathProvider.GetFile(): 从虚拟文件系统中获取一个虚拟文件
    public override VirtualFile GetFile(string virtualPath)
    {
        throw new Exception("The method or operation is not implemented.");
    }
}

?????? 提供程序必须实现一个静态的 AppInitialize 方法,这个方法应创建自定义类的实例并把它注册为 Framework 的提供程序;FileExists 方法用于检查某个路径是否可以由提供程序提供;GetFile 方法用于获取某个路径的内容,返回抽象类 VirtualFile 的实例。

?

?????? Framework 没有提供 VirtualFile 类的具体实现,我们必须自己扩展 VirtualFile 类来支持自己的提供程序。下面是我们的提供程序的 VirtualFile 类的实现,它被放在同一个代码文件中:

public class DBVirtualFile : VirtualFile
{
    private string _FileContent;
?
    public DBVirtualFile(string virtualPath, string fileContent)
        : base(virtualPath)
    {
        _FileContent = fileContent;
    }
?
    public override Stream Open()
    {
        Stream stream = new MemoryStream();
        StreamWriter write = new StreamWriter(stream,Encoding.Unicode);
        write.Write(_FileContent);
        write.Flush();
        stream.Seek(0, SeekOrigin.Begin);
        return stream;
    }
}

?????? 这个类的构造函数获取虚拟路径以及文件的内容。在 Open 方法里,真实内容的字符串被保存到了 MemoryStream,然后返回这个流。ASP.NET 使用这个流读取内容,就好像它在读取文件系统一样(感谢基于 Stream 类的字节抽象)。

?

?????? 下一步是继续完成 VirtualPathProvider 类。它需要读取来自数据库文件的真实数据。如果文件在数据库里不存在,提供程序就把请求转送给它的前一个提供程序(由框架在静态方法 AppInitialize 里注册时选定)。给 DBPathProvider 类增加一个从数据库获取内容的方法

private string GetFileFromDB(string virtualPath)
{
    string contents;
    string fileName = virtualPath.Substring(virtualPath.IndexOf('/', 1), +1);
?
    // Read the file from the database.
    SqlConnection conn = new SqlConnection();
    conn.ConnectionString = @"Data Source=.\SqlExpress;Initial Catalog=AspNetContents;
        Integrated Security=true";
    conn.Open();
?
    try
    {
        SqlCommand cmd = new SqlCommand("select FileContents from AspContent "
            + "where FileName=@fn", conn);
        cmd.Parameters.AddWithValue("@fn", fileName);
        contents = cmd.ExecuteScalar() as string;
        if (contents == null)
        {
            contents = string.Empty;
        }
    }
    catch
    {
        contents = string.Empty;
    }
    finally
    {
        conn.Close();
    }
    return contents;
}

?

?????? GetFileFromDB 函数从虚拟路径获取文件名并从数据库读取该文件名对应的内容。此方法将同时被 FileExists() 和 GetFile() 使用

// VirtualPathProvider.FileExists(): 获取一个值,该值指示文件是否
// 存在于虚拟文件系统中
public override bool FileExists(string virtualPath)
{
    string contents = this.GetFileFromDB(virtualPath);
    if (contents.Equals(string.Empty))
    {
        return false;
    }
    else
    {
        return true;
    }
}
?
// VirtualPathProvider.GetFile(): 从虚拟文件系统中获取一个虚拟文件
public override VirtualFile GetFile(string virtualPath)
{
    string contents = this.GetFileFromDB(virtualPath);
    if (contents.Equals(string.Empty))
    {
        // VirtualPathProvider.Previous: 获取对编译系统中以前注册的 
        // System.Web.Hosting.VirtualPathProvider 对象的引用
        return Previous.GetFile(virtualPath);
    }
    else
    {
        return new DBVirtualFile(virtualPath, contents);
    }
}

?????? 你还可以在自己的提供程序里实现一些额外的方法,它们对更复杂的模型会很有用。比如,验证目录是否存在(DirectoryExists)、计算文件散列值(GetFileHash),以及执行缓存验证(GetCacheDependency)等等

?

?????? 现在输入以下3个请求URL可以看见数据库中这 3 个简单网页的效果:

?????? ASP.NET 治理网站(虚拟目录)

?????? 现在你不使用网站的文件系统,也可也动态的生成网页了,将网站部署到服务器即可。

?

?????? 示例完整代码如下:

using System;
using System.Data.SqlClient;
using System.IO;
using System.Text;
using System.Web.Hosting;
?
// VirtualPathProvider: 使 Web 应用程序可以从虚拟文件系统中检索资源
public class DBPathProvider : VirtualPathProvider
{
    public static void AppInitialize()
    {
        // HostingEnvironment: 在托管应用程序的应用程序域内向托管应用程
        // 序提供应用程序管理功能和应用程序服务
        // RegisterVirtualPathProvider(): 在 ASP.NET 编译系统中注册新
        // 的 VirtualPathProvider 实例
        HostingEnvironment.RegisterVirtualPathProvider(new DBPathProvider());
    }
?
    // VirtualPathProvider.FileExists(): 获取一个值,该值指示文件是否
    // 存在于虚拟文件系统中
    public override bool FileExists(string virtualPath)
    {
        string contents = this.GetFileFromDB(virtualPath);
        if (contents.Equals(string.Empty))
        {
            return false;
        }
        else
        {
            return true;
        }
    }
?
    // VirtualPathProvider.GetFile(): 从虚拟文件系统中获取一个虚拟文件
    public override VirtualFile GetFile(string virtualPath)
    {
        string contents = this.GetFileFromDB(virtualPath);
        if (contents.Equals(string.Empty))
        {
            // VirtualPathProvider.Previous: 获取对编译系统中以前注册的 
            // System.Web.Hosting.VirtualPathProvider 对象的引用
            return Previous.GetFile(virtualPath);
        }
        else
        {
            return new DBVirtualFile(virtualPath, contents);
        }
    }
?
    private string GetFileFromDB(string virtualPath)
    {
        string contents;
        string fileName = virtualPath.Substring(virtualPath.IndexOf('/', 1) + 1);
?
        // Read the file from the database.
        SqlConnection conn = new SqlConnection();
        conn.ConnectionString = @"Data Source=.\SqlExpress;Initial Catalog=AspNetContents;
            Integrated Security=true";
        conn.Open();
        try
        {
            SqlCommand cmd = new SqlCommand("select FileContents from AspContent "
                + "where FileName=@fn", conn);
            cmd.Parameters.AddWithValue("@fn", fileName);
            contents = cmd.ExecuteScalar() as string;
            if (contents == null)
            {
                contents = string.Empty;
            }
        }
        catch
        {
            contents = string.Empty;
        }
        finally
        {
            conn.Close();
        }
        return contents;
    }
}
?
public class DBVirtualFile : VirtualFile
{
    private string _FileContent;
?
    public DBVirtualFile(string virtualPath, string fileContent)
        : base(virtualPath)
    {
        _FileContent = fileContent;
    }
?
    public override Stream Open()
    {
        Stream stream = new MemoryStream();
        StreamWriter write = new StreamWriter(stream, Encoding.Unicode);
        write.Write(_FileContent);
        write.Flush();
        stream.Seek(0, SeekOrigin.Begin);
        return stream;
    }
}

?????? 总结一下整篇代码的工作顺序与原理。

    AppInitialize() 被 Framework 调用。我们向 ASP.NET 编译系统注册了自定义的 DBPathProvider 类,使得这个 Web 应用程序可以从虚拟文件系统中检索资源。FileExists(string virtualPath) 被调用。它告诉系统是否存在请求路径,如果存在,则通知程序继续查找内容(事件激发系统继续调用 GetFile 方法)GetFile(string virtualPath) 被调用。如果获取不到文件内容,则将请求交由编译系统以前注册的提供程序处理(回复到 ASP.NET 网页请求的默认处理流程)。如果成功获取数据库中对应文件名的网页内容,则创建 VirtualFile 类的实例(我们的扩展类 DBVirtualFile 实现了它),同时传入路径和网页内容至 DBVirtualFile 的构造函数Open() 被调用。它将字符串表现形式的网页内容读取到内存流中并返回这个流。ASP.NET 使用这个流读取内容,就好像它在读取文件一样!

?????? 上述方法的调用均由 .NET 内部事件机制做驱动,并无显式的调用逻辑和顺序。

?

原文:http://www.cnblogs.com/SkySoot/archive/2013/04/02/2995533.html

热点排行