asp.net - Webforms 路由 - 不同页面的相同签名?

标签 asp.net webforms routes url-routing

我正在一个已建立的网站上工作。虽然很小(就页面而言),但有一些大钱的登陆页面以及通常的库存页面。

由于网站相对较小,页面结构比较扁平。

https://example.com/contact
https://example.com/big-money-page

我们计划引入更多具有不同页面设计的页面。这意味着我们将使用母版页和/或 aspx 模板化页面并创建我们自己的数据库驱动的 CMS。

这是我看到的问题是 url 路由:

模板类型 1

Route url: /{Name} - e.g. /big-money-page
Physica path: ~/template1.aspx

模板类型 2

Route url: /{Name} - e.g. /new-supporting-page
Physical path: ~/template2.aspx

我希望在不破坏现有资金页面的情况下完成这项工作,并且如果可能的话,保持熟悉的网站结构,对于访问者来说,模板1和模板2是相似的页面,并且自然不会驻留在不同的文件夹中 - 它们只是设计不同。

此外,固定的深层路由文件夹结构使得将来很难进行更改。

我使用 WF 路由已经有一段时间了,但总是以简单的方式使用。有人知道我如何才能使这些改变发挥作用并产生有限的后果吗?

更新 ---------------------------------------------------------- ----------------------

好吧,在没有任何反馈的情况下,我提出了一个想法。如果您能就可行性和任何可以想到的缺点提供反馈,我将不胜感激。

我的想法是有一个虚拟路线/页面。

路由的格式为http://example.com/{name}

虚拟页面使用占位符{name}从数据库中检索目标页面的数据。

然后,我们使用从数据库检索的数据,server.transfer 到正确的目标页面。

我认为这会起作用,但我担心我不知道的事情:

  • server.transfer 的浏览器兼容性
  • 性能开销
  • 对输出缓存的影响
  • 其他我没想过的事情

当然,这不是一个理想的解决方案,但我也愿意接受任何其他想法。

最佳答案

在 WebForm 项目中,可以使用自定义 HTTPModule 来实现该任务。实现包括几个步骤。简化版本如下:
1. SQL

create table dbo.UrlMap (
  publicUrl varchar(255) not null primary key,
  PhysUrl varchar(255) not null
)

用一些数据填充表格,例如

publicUrl        PhysUrl 
big-money-page   template1.aspx?id=1
huge-money-page  template1.aspx?id=2
no-money-page    template2.aspx?id=3
other-page       template1.aspx?id=4

<强>2。在App_code文件夹中创建一个类

using System;
using System.Web;

/// <summary>
/// Implements IHttpModule  with custom URLs
/// </summary>
public class UrlMap:IHttpModule
{
    /// <summary>
    /// Initialize the module 
    /// </summary>
    /// <param name="context"></param>
    void IHttpModule.Init(HttpApplication context)
    {
        context.BeginRequest += Context_BeginRequest;
        context.PostMapRequestHandler += Context_PostMapRequestHandler;
    }

    private void Context_BeginRequest(object sender, EventArgs e)
    {
        var app = (HttpApplication)sender;
        Url2PhysPath(app.Request.Path, app);
    }

    private void Context_PostMapRequestHandler(object sender, EventArgs e)
    {
        var app = (HttpApplication)sender;
        var pg = app.Context.Handler as System.Web.UI.Page;
        if (pg != null)
        {
            pg.PreRenderComplete += Pg_PreRenderComplete;
        }
    }

    private void Pg_PreRenderComplete(object sender, EventArgs e)
    {
        ProcessPageTree((System.Web.UI.Control)sender);
    }

    /// <summary>
    /// Replaces physical URLs on the page with "beutified" version
    /// </summary>
    /// <param name="control"></param>
    private void ProcessPageTree(System.Web.UI.Control control)
    {
        var form = control as System.Web.UI.HtmlControls.HtmlForm;
        if (form != null)
        {
            form.Action = BeautifyUrl(form.Page.Request.Url.PathAndQuery);
        }
        //other types in a similar way
        if (control.HasControls())
        {
            foreach(System.Web.UI.Control c in control.Controls)
            {
                ProcessPageTree(c);
            }
        }
    }
    /// <summary>
    /// Helper function. Can be inlined. 
    /// Searches "beautified" url in a DB and rewrites path
    /// </summary>
    /// <param name="url"></param>
    /// <param name="app"></param>
    private static void Url2PhysPath(string url, HttpApplication app)
    {
        using (var cnn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["SiteCnn"].ConnectionString))
        {
            var cmd = new System.Data.SqlClient.SqlCommand("select physPath from dbo.urlMap where publicUrl=@url", cnn);
            cmd.CommandType = System.Data.CommandType.Text;
            cmd.Parameters.Add("@url", System.Data.SqlDbType.VarChar, 255).Value = url;
            cnn.Open();
            string physPath = null;
            using(var r = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection))
            {
                if (r.Read())
                {
                    physPath = (string)r["physPath"];
                }
                r.Close();
            }
            if (!string.IsNullOrEmpty(physPath))
            {
                app.Context.RewritePath("/" + physPath);
            }
        }
    }

    /// <summary>
    /// Helper function 
    /// </summary>
    /// <param name="physUrl"></param>
    /// <returns>returns original url when nothing is found</returns>
    private static string BeautifyUrl(string physUrl)
    {
        using (var cnn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["SiteCnn"].ConnectionString))
        {
            var cmd = new System.Data.SqlClient.SqlCommand("select publicUrl from dbo.urlMap where physPath=@url", cnn);
            cmd.CommandType = System.Data.CommandType.Text;
            cmd.Parameters.Add("@url", System.Data.SqlDbType.VarChar, 255).Value = physUrl;
            cnn.Open();
            string pubUrl = physUrl;//to return original url when nothing is found
            using(var r = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection))
            {
                if (r.Read())
                {
                    pubUrl = (string)r["publicUrl"];
                }
                r.Close();
            }
            return pubUrl;
        }

    }
    /// <summary>
    /// Required by interface
    /// </summary>
    void IHttpModule.Dispose()
    {
     //   throw new NotImplementedException();
    }
}

<强>3。修改Web.config
注册模块。将以下行添加到 configuration \ system.webServer \ modules

  <add name="UrlRewriter" type="UrlMap" preCondition="managedHandler"/>

跟进
server.transfer 的浏览器兼容性不是问题。浏览器仅接收 HTML
性能开销不多
对输出缓存的影响 缓存得比 template.aspx?id=123 更好
其他我没想过的事情两者publicUrlphysUrl必须是唯一的。实际上,您可以在静态 Dictionary<string, string> 中缓存直接和反向键查找。变量。

关于asp.net - Webforms 路由 - 不同页面的相同签名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45479355/

相关文章:

asp.net - 我的特定 web.x.config 文件未使用

c# - 如何防止暴露任何其他接口(interface)方法?

Asp.net默认主题css菜单问题

c# - 在全局命名空间中找不到 "Telerik"

rest - HereMaps - 这些凭据不授权访问。无法获得公共(public)交通 API 的有效响应

asp.net - 身份3 SignInManager.PasswordSignInAsync()不返回任何结果

c# - 在此 ASP.NET webforms 页面中以何种顺序执行哪些方法

asp.net - 如何在 ASP.NET 中构建灵活的 Web 表单

codeigniter - 如何在 CodeIgniter 4 的路由中调用子文件夹 Controller 方法

playframework - Play Framework 2.1 模板上的动态路由