科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件深入Atlas系列之服务器端支持(下)

深入Atlas系列之服务器端支持(下)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

我们知道,处理Web Services方法请求的Handler是RestHandler

作者:老赵 来源:博客园 2007年11月3日

关键字: Atlas 服务器端 支持

  • 评论
  • 分享微博
  • 分享邮件
 在上一篇文章里,我们分析了一部分服务器端的代码。到现在为止,我们已经获得处理Web Services方法请求的Handler,马上就要开始Process Request了。

  我们知道,处理Web Services方法请求的Handler是RestHandler,所以我们来看一下它的ProcessHandler方法:

  ProcessRequest获得调用结果代码分析:

1 public void ProcessRequest(HttpContext context)
2 {
3 // 根据Web Services的Cache设置来配置Cache策略
4 this.InitializeCachePolicy(context);
5
6 try
7 {
8 string contentType;
9
10 // 从body的JSON字符串中得到输入的参数。
11 IDictionary<string, object> inputParams = this.GetRawParams(context);
12
13 // this._webServiceMethodData.Ower.Type即获得了即将调用的那个
14 // Web Service类,通过Activator.CreateInstance方法构造实例。
15 object serviceObj = Activator.CreateInstance(this._webServiceMethodData.Owner.Type);
16
17 // 这是一段很有技巧的代码,我们目前不去分析它。
18 DataService service = serviceObj as DataService;
19 if (service != null)
20 {
21 service.IsCalledRemotely = true;
22 }
23
24 // Call这个Web Service方法来得到结果
25 object resultObj = this._webServiceMethodData.CallMethodFromRawParams(serviceObj, inputParams);
26
27 ……
28 }
29 catch (Exception e)
30 {
31 ……
32 }
33 }

  首先调用InitializeCachePolicy方法来处理缓存策略,代码很短也很简单,因此不多解释了。其次查看serviceObj是否是DataService类型,如果是的话则将IsCalledRemotely设为ture,这是比较有技巧的做法,我们目前不去分析它。接着通过GetRawParams方法方法获得以Dictionary方式存放的参数,我们需要看一下它的框架,可以了解它获得参数的方法。

  GetRawParams(HttpContext) :

1 private IDictionary<string, object> GetRawParams(HttpContext context)
2 {
3 // 如果是Cross Domain Access,则抛出异常
4 if (!this._webServiceMethodData.SafeForCrossDomain && ChildRequest.IsCrossDomainRequest(context))
5 {
6 throw new InvalidOperationException(
7 string.Format(
8 CultureInfo.CurrentCulture,
9 AtlasWeb.InvalidCrossDomainRequest,
10 new object[] { this._webServiceMethodData.MethodInfo.Name }));
11 }
12
13 // 如果使用HTTP POST方法
14 if (context.Request.HttpMethod == "POST")
15 {
16 // 则通过Body中的JSON代码获得参数
17 return this.GetRawParamsFromPostRequest(context);
18 }
19
20 // 由于使用了HTTP GET方法,需要看一下Web Services方法是否允许GET操作
21 if (!this._webServiceMethodData.GetVerbEnabled)
22 {
23 throw new InvalidOperationException(
24 string.Format(
25 CultureInfo.CurrentCulture,
26 AtlasWeb.InvalidGetRequest,
27 new object[] { this._webServiceMethodData.MethodInfo.Name }));
28 }
29
30 // 从Query String中获得参数
31 return this.GetRawParamsFromGetRequest(context);
32 }

  一个Web Service方法,可以使用Microsoft.Web.Services.WebOperationAttribute来标记是否使用能够通过GET方法访问。下面的代码让该Web Service方法允许使用GET方法来访问:

  [WebOperation(true)]

  获得的Dictionary数据结构以Key - Value的方式对应的参数名和表示参数值的字符串,如果是复杂类型的话会产生许多层的Dictionary或List,大家应该能够想象出来它是什么样子,因为这和大名鼎鼎的JSON非常相似!获得参数之后,会将其传入WebServiceMethodData的CallMethodFromRawParams方法,以获得方法执行的结果。

  WebServiceMethodData.CallMethodFromRawParams方法代码如下:

  CallMethodFromRawParams方法分析

1 internal object CallMethodFromRawParams(object target, IDictionary<string, object> parameters)
2 {
3 // 获得强类型的参数字典
4 parameters = this.StrongTypeParameters(parameters);
5 return this.CallMethod(target, parameters);
6 }

  首先通过StrongTypeParameters方法来获得一个强类型的参数字典,它不会有多层的Dictionary或List。此方法非常的复杂,在这里就先不进行分析了,有兴趣的朋友可以先看一下相关代码,我会在今后的文章中分析这些代码的细节,它们还是写得非常优秀的。得到强类型的参数后,就会使用CallMethod来调用方法得到结果了。在这里面只是使用了简单的Reflection,相信大家也能够想象得到个中实现。

  接下来就要输出结果了,代码如下:

  ProcessRequest输出结果代码分析 :

1 public void ProcessRequest(HttpContext context)
2 {
3 ……
4
5 try
6 {
7 ……
8
9 // 如果这个Web Service方法被要求使用XML作为Response
10 if (this._webServiceMethodData.UseXmlResponse)
11 {
12 // 如果result是String,那么直接输出
13 if (resultObj is string)
14 {
15 body = (string) resultObj;
16 }
17 else if (resultObj is XmlNode)
18 {
19 // 如果是一段XML,则输出它的OuterXml
20 body = ((XmlNode) resultObj).OuterXml;
21 }
22 else // 如果只是一个普通的对象
23 {
24 try
25 {
26 // 使用XmlSerializer来序列化对象
27 body = ServicesUtilities.XmlSerializeObjectToString(resultObj);
28 }
29 catch (Exception e)
30 {
31 throw new InvalidOperationException(
32 string.Format(
33 CultureInfo.CurrentCulture,
34 AtlasWeb.InvalidXmlReturnType,
35 new object[] {
36 this._webServiceMethodData.MethodInfo.Name,
37 resultObj.GetType().FullName,
38 e.Message
39 }
40 )
41 );
42 }
43 }
44
45 // contentType为"text/xml"
46 contentType = "text/xml";
47 }
48 else // 如果不以Xml输出
49 {
50 // 那么以JSON方式输出
51 body = JavaScriptObjectSerializer.Serialize(resultObj, this._webServiceMethodData.Owner);
52 // contentType为"application/json"
53 contentType = "application/json";
54 }
55
56 // 设置ContentType
57 context.Response.ContentType = contentType;
58 // 输出body
59 if (body != null)
60 {
61 context.Response.Write(body);
62 }
63 }
64 catch (Exception e)
65 {
66 ……
67 }
68 }

  要设置该Web Services方法的输出方式为XML(UseXmlResponse == true),则也是需要使用Microsoft.Web.Services.WebOperationAttribute来标记方法,如下:

[WebOperation(false, ResponseFormatMode.Xml)]

  后面会有一个例子来演示这一点。如果该方法被标记使用XML方式输出,则会判断结果类型。如果是字符串则直接输出;如果是Xml类型的结果,则输出它的OuterXml;最后则会尝试使用XmlSerializer来序列化这个对象。

  在默认情况下,该对象会被JSON序列化输出,这就是我们最常见的做法。

  最后,对于异常情况,也需要进行输出。代码如下:

  ProcessRequest输出异常代码分析 :

1 public void ProcessRequest(HttpContext context)
2 {
3 ……
4
5 try
6 {
7 ……
8 }
9 catch (Exception e)
10 {
11 // 输出异常信息
12 context.Response.ClearHeaders();
13 context.Response.Clear();
14 // Status Code设为500
15 context.Response.StatusCode = 500;
16 context.Response.StatusDescription = HttpWorkerRequest.GetStatusDescription(500);
17 using (StreamWriter writer = new StreamWriter(context.Response.OutputStream, new UTF8Encoding(false)))
18 {
19 // 以JSON方式输出异常信息
20 RestHandler.WriteExceptionJsonString(context, writer, e);
21 return;
22 }
23 }
24 }

  代码使用RestHandler.WriteExceptionJsonString来分别输出异常的Message,StackTrace和异常的FullName。在代码里可以使用这一点。

  到现在为止,可以说Atlas在服务器端对于Web Services的支持代码已经分析完了。我们通过两个实例来详细理解这一点。
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章