posts - 33, comments - 51, trackbacks - 0, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

公告

2008年3月12日

In my last post I described how Routing no longer has any dependency on MVC. The natural question I’ve been asked upon hearing that is “Can I use it with Web Forms?” to which I answer “You sure can, but very carefully.”

Being on the inside, I’ve had a working example of this for a while now based on early access to the bits. Even so, Chris Cavanagh impressively beats me to the punch in blogging his own implementation of routing for Web Forms. Nice!

One of the obvious uses for the new routing mechanism is as a “clean” alternative to URL rewriting (and possibly custom VirtualPathProviders for simple scenarios) for traditional / postback-based ASP.NET sites.  After a little experimentation I found some minimal steps that work pretty well:

  • Create a custom IRouteHandler that instantiates your pages
  • Register new Routes associated with your IRouteHandler
  • That’s it!

He took advantage of the extensibility model by implementing the IRouteHandler interface with his own WebFormRouteHandler class (not surprisingly my implementation uses the same name) ;)

There is one subtle potential security issue to be aware of when using routing with URL Authorization. Let me give an example.

Suppose you have a website and you wish to block unauthenticated access to the admin folder. With a standard site, one way to do so would be to drop the following web.config file in the admin folder...

<?xml version="1.0"?>
<configuration>
<system.web>
<authorization>
<deny users="*" />
</authorization>
</system.web>
</configuration>

Ok, I am a bit draconian. I decided to block access to the admin directory for all users. Attempt to navigate to the admin directory and you get an access denied error. However, suppose you use a naive implementation of WebFormRouteHandler to map the URL fizzbucket to the admin dir like so...

RouteTable.Routes.Add(new Route("fizzbucket"
, new WebFormRouteHandler("~/admin/secretpage.aspx"));

Now, a request for the URL /fizzbucket will display secretpage.aspx in the admin directory. This might be what you want all along. Then again, it might not be.

In general, I believe that users of routing and Web Form will want to secure the physical directory structure in which Web Forms are placed using UrlAuthorization. One way to do this is to call UrlAuthorizationModule.CheckUrlAccessForPrincipal on the actual physical virtual path for the Web Form.

This is one key difference between Routing and URL Rewriting, routing doesn’t actually rewrite the URL. Another key difference is that routing provides a mean to generate URLs as well and is thus bidirectional.

The following code is my implementation of WebFormRouteHandler which addresses this security issue. This class has a boolean property on it that allows you to not apply URL authorization to the physical path if you’d like (in following the principal of secure by default the default value for this property is true which means it will always apply URL authorization).

public class WebFormRouteHandler : IRouteHandler
{
public WebFormRouteHandler(string virtualPath) : this(virtualPath, true)
{
}
public WebFormRouteHandler(string virtualPath, bool checkPhysicalUrlAccess)
{
this.VirtualPath = virtualPath;
this.CheckPhysicalUrlAccess = checkPhysicalUrlAccess;
}
public string VirtualPath { get; private set; }
public bool CheckPhysicalUrlAccess { get; set; }
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
if (this.CheckPhysicalUrlAccess
&& !UrlAuthorizationModule.CheckUrlAccessForPrincipa(this.VirtualPath
,  requestContext.HttpContext.User
, requestContext.HttpContext.Request.HttpMethod))
throw new SecurityException();
var page = BuildManager
.CreateInstanceFromVirtualPath(this.VirtualPath
, typeof(Page)) as IHttpHandler;
if (page != null)
{
var routablePage = page as IRoutablePage;
if (routablePage != null)
routablePage.RequestContext = requestContext;
}
return page;
}
}

You’ll notice the code here checks to see if the page implements an IRoutablePage interface. If your Web Form Page implements this interface, the WebFromRouteHandler class can pass it the RequestContext. In the MVC world, you generally get the RequestContext via the ControllerContext property of Controller, which itself inherits from RequestContext.

The RequestContext is important for calling into API methods for URL generation. Along with the IRoutablePage, I provide a RoutablePage abstract base class that inherits from Page. The code for this interface and the abstract base class that implements it is in the download at the end of this post.

One other thing I did for fun was to play around with fluent interfaces and extension methods for defining simple routes for Web Forms. Since routes with Web Forms tend to be simple, I thought this syntax would work nicely.

public static void RegisterRoutes(RouteCollection routes)
{
//first one is a named route.
routes.Map("General", "haha/{filename}.aspx").To("~/forms/haha.aspx");
routes.Map("backdoor").To("~/admin/secret.aspx");
}

The general idea is that the route url on the left maps to the webform virtual path to the right.

I’ve packaged all this up into a solution you can download and try out. The solution contains three projects:

  • WebFormRouting - The class library with the WebFormRouteHandler and helpers...
  • WebFormRoutingDemoWebApp - A website that demonstrates how to use WebFormRouting and also shows off url generation.
  • WebFormRoutingTests - a few non comprehensive unit tests of the WebFormRouting library.

WARNING: This is prototype code I put together for educational purposes. Use it at your own risk. It is by no means comprehensive, but is a useful start to understanding how to use routing with Web Forms should you wish. Download the demo here.

posted @ 2008-03-12 20:54 阿布 阅读(449) 评论(0) 编辑

微软发布了一个Visual Studio 10未来特性的演示,这些特性将作为VS 2008的扩展发布。这些特性被统一称为Visual Studio 2008的PowerCommands ,其中还包括了这些特性的源代码。

复制与粘贴命令

这些命令可以简化在项目与剪贴板之间的信息移动。它们包括:

  • 复制和粘贴类(Copy and Paste Class)——这或许有些名不副实,因为它可以在一个特定的项目文件中复制所有的类。如果项目文件中有子文件(例如page.aspx和page.aspx.cs),那么它们也会被复制。
  • 复制与粘贴引用(Copy and Paste References)——在生成相似的项目时,这一功能将非常有用。
  • 作为项目引用复制(Copy As Project Reference)——它将上面两者结合起来,比“添加引用”对话框更加快捷。

项目

  • 折叠项目(Collapse Projects)——仅仅作为折叠项目树的快捷方式。
  • 编辑项目文件(Edit Project File)——它将为选中的项目打开MSBuild。警告,这一操作会导致项目被卸载。

重构

  • 这些新增的重构功能仅仅针对于C#是可用的。VB则从第三方供应商得到对重构的支持。
  • 提取静态变量(Extract Constant)——它可以将一个字符串转换为静态的。VB则通过免费版的Refacto来r实现。
  • 移除和排序Usings(Remove and Sort Usings)——它将为一个项目中所有文件的“using”语句进行排序,并移除其中没有使用的“using”语句。VB通过付费版的Refactor实现。
    注意:在文档中,错误地将这一特性描述为与VB中的移除不用的引用(Remove Unused Reference)相同。实际上不是这样,C#仍然没有办法自动移除实际没有使用的对DLL的引用。

其他

  • 以文件夹方式打开(Open Containing Folder)——它会打开资源管理器(Explorer),这与右键点击文件,选择Explorer标签打开文件一样。
  • 以命令提示符方式打开(Open Command Prompt)——它会打开Visual Studio command prompt。
  • 卸载/重新加载项目——在处理未集成的源代码控制时,这些命令会非常有用。或许受到性能的影响,当前可能不需要“卸载项目”命令。

完整列表请参见i安装和源代码包附带的readme文件。

查看英文原文:Proposed VS 10 Features Released as a VS 2008 Add-On

来源: http://www.infoq.com/cn/news/2008/03/PowerCommands

posted @ 2008-03-12 13:23 阿布 阅读(454) 评论(2) 编辑