日期:2010-11-28  浏览次数:20493 次

  在上一篇文章里,我们分析讨论了使用Atlas在进行AJAX访问Web Services所用的客户端代码。但是如果要实现这一功能,很显然还离不开服务器端的支持。在这篇文章里,我们就来讨论这一点。

  增加服务器端的支持其实就是添加/改变处理一个HTTP Request的方式。在ASP.NET中,是通过一个实现了System.Web.IHttpHandler接口的类来处理Request。我们可以在Web.config里通过配置将Request与实现IHttpHandler的类进行映射,以此告诉ASP.NET这个Request该由谁来处理。例如,在Atlas中,对于Culture的支持文件atlasglob.axd,就把该文件请求交由Microsoft.Web.Globalization.GlobalizationHandler类来处理。

<httpHandlers>
<add verb="*" path="atlasglob.axd" type="Microsoft.Web.Globalization.GlobalizationHandler" validate="false"/>
</httpHandlers>
  但是如果需要对于一个请求,使用不同的IHttpHandler来处理呢?甚者,如果需要对于已有一个请求的处理方式进行扩展呢?ASP.NET也考虑到了这一点,只需要将一个请求交给一个实现了System.Web.IHttpHandlerFactory接口的类即可。该类的功能就是根据该Request的一些“特点”,创建一个IHttpHandler实例。该类也提供了释放Hanlder的方法,提供了对于Handler实例复用的可能,减少由于构造和初始化对象的消耗,自然也减轻了GC的负担。

  在Atlas中就利用了这一点,改变了对于*.asmx请求的处理方式,对于在Query String中有mn的请求需要作特别的处理(在以后的文章中我会提到,对于“*.asmx/js”的请求,也会有另一种处理。它提供了客户端访问Web Services的代理,这超出了本篇文章的范围)。于是,如果需要使用Atlas从客户端以AJAX方式访问Web Services,则在Web.config里下面的设置绝对不可少:

<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" type="Microsoft.Web.Services.ScriptHandlerFactory" validate="false"/>
</httpHandlers>

  这个设置删除了原有*.asmx文件请求的映射,将*.asmx文件的请求交由Microsoft.Web.Services.ScriptHandlerFactory处理。这就是Atlas在服务器端的支持。

  接下来就要开始分析Atlas提供的Microsoft.Web.Atlas.dll里的代码了。这个程序集里的代码量和复杂程度均大大超过Atlas的客户端代码。因此,我只对于起关键作用的代码进行详细分析,一些辅助的方法或类的实现,只能请感兴趣的朋友们自行查看了。另外,为了大家阅读方便,我将局部变量名都改成了可读性比较高的名称,避免了“text1”,“flag1”之类的变量名,希望对大家阅读代码有所帮助。

  我们先来看一下Microsoft.Web.Services.ScriptHandlerFactory类的成员:

  ScriptHandlerFactory类成员:

1 public class ScriptHandlerFactory : IHttpHandlerFactory
2 {
3  // Methods
4  public ScriptHandlerFactory();
5  private static void CheckAtlasWebServicesEnabled();
6  public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated);
7  public virtual void ReleaseHandler(IHttpHandler handler);
8
9  // Fields
10 private IHttpHandlerFactory _restHandlerFactory;
11 private IHttpHandlerFactory _webServiceHandlerFactory;
12
13 // Nested Types
14 private class AsyncHandlerWrapper : ScriptHandlerFactory.HandlerWrapper, IHttpAsyncHandler, IHttpHandler
15 {
16  // Methods
17   internal AsyncHandlerWrapper(IHttpHandler originalHandler, IHttpHandlerFactory originalFactory);
18   public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData);
19   public void EndProcessRequest(IAsyncResult result);
20 }
21
22 private class AsyncHandlerWrapperWithSession : ScriptHandlerFactory.AsyncHandlerWrapper, IRequiresSessionState
23 {
24  // Methods
25  internal AsyncHandlerWrapperWithSession(IHttpHandler originalHandler, IHttpHandlerFactory originalFactory);
26 }
27
28 internal class HandlerWrapper : IHttpHandler
29 {
30  // Methods
31  internal HandlerWrapper(IHttpHandler originalHandler, IHttpHandlerFactory originalFactory);
32  public void ProcessRequest(HttpContext context);
33  internal void ReleaseHandler();
34
35  // Properties
36  public bool IsReusable { get; }
37
38  // Fields
39  private IHttpHandlerFactory _originalFactory;
40  protected IHttpHandler _originalHandler;
41 }
42
43 internal class HandlerWrapperWithSession : ScriptHandlerFactory.HandlerWrapper, IRequiresSessionState
44 {
45   // Methods
46   internal HandlerWrapperWithSession(IHttpHandler originalHandler, IHttpHandlerFactory originalFactory);
47  }
48 }

  可以看到,除了IHttpHandlerFactory接口的方法外,类的内部还有着“丰富”地成员。CheckAtlasWebServicesEnabled()静态方法是查看是否提供Atlas访问WebServices的服务器端支持,如果不支持,则抛出异常。要让Atlas提供对于服务器端的支持,在Web.config里需要增加如下的元素:

<microsoft.web>
<webServices enableBrowserAccess="true" />
</microsoft.web>