我们一般会自定义自己的HttpHandler来处理一些特殊的业务,往往需要在方法ProcessRequest中调用其他的实现IHttpHandler的Page页或ashx一般处理文件或自定义的HttpHandler类,那么我们会用Server.Execute("path")或Server.Transfer()来实现,但有时运行时会报“为 ...执行子请求时出错。”,那么如何解决呢?
这里分几种情况来讨论。(这里测试环境为.net 4.0 IIS7 Win7)
一、自定义HttpHandler类中请求aspx、ashx、自定义HttpHandler类
首先Web.congfig中配置自定义处理程序
<system.webServer>
<handlers>
<add name="MyHttpHandler" path="*.aspx" verb="*" type="DiyControlWeb.MyHttpHandler"/>
</handlers>
</system.webServer>
1、自定义HttpHandler类使用Server.Execute跳转到Page页
public class MyHttpHandler:IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
StringWriter sw = new StringWriter();
context.Server.Execute("/SelfTextBoxControlTest.aspx",sw,false);
string dealResult = sw.ToString();
context.Response.Write(dealResult);
context.Response.End();
}
}
运行时报错:
尝试解决方案:
HttpHandler类继承Page类
代码:
public class MyHttpHandler:Page
{
public override void ProcessRequest(HttpContext context)
{
StringWriter sw = new StringWriter();
context.Server.Execute("/SelfTextBoxControlTest.aspx",false);
string dealResult = sw.ToString();
context.Response.Write(dealResult);
context.Response.End();
}
}
运行时虽然不报“执行子请求出错”,但一直循环调用ProcessRequest方法,形成死循环
解决方案:
MyHttpHandler继承IHttpHandler(继承Page也可以),通过BuildManager.CreateInstanceFromVirtualPath方法获取页面的IHttpHandler实例,再将该实例传入Execute重载方法(public void Execute(IHttpHandler handler, TextWriter writer, bool preserveForm))中
代码:
public class MyHttpHandler:IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
StringWriter sw = new StringWriter();
<strong><span style="color:#FF6666;">var handler = BuildManager.CreateInstanceFromVirtualPath("/SelfTextBoxControlTest.aspx", typeof(IHttpHandler)) as IHttpHandler;</span></strong>
context.Server.Execute(handler,sw,false);
string dealResult = sw.ToString();
context.Response.Write(dealResult);
context.Response.End();
}
}
运行通过,返回请求页面响应结果,输出到当前页面
2、自定义HttpHandler类使用Server.Execute跳转到ashx一般处理程序中
代码:
public class MyHttpHandler:IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
StringWriter sw = new StringWriter();
context.Server.Execute("/CommonHandler2.ashx", sw, false);
string dealResult = sw.ToString();
context.Response.Write(dealResult);
context.Response.End();
}
}
运行时报和aspx页面相同的错
那是不是和请求page页面一样,用BuildManager.CreateInstanceFromVirtualPath()就能解决呢?我们来试一下
代码:
public class MyHttpHandler:IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
StringWriter sw = new StringWriter();
var handler = BuildManager.CreateInstanceFromVirtualPath("/CommonHandler2.ashx", typeof(IHttpHandler)) as IHttpHandler;
context.Server.Execute(handler, sw, false);
string dealResult = sw.ToString();
context.Response.Write(dealResult);
context.Response.End();
}
}
运行后仍然报错
说明请求ashx和aspx页面不同,我们来试试将ashx文件类继承Page
代码:
<%@ WebHandler Language="C#" Class="CommonHandler2" %>
using System;
using System.Web;
using System.Web.UI;
public class CommonHandler2 :Page{
public override void ProcessRequest (HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World");
}
}
运行代码,正常执行!
在将ashx文件类继承Page类后,其实用
<span style="color:#33CC00;">context.Server.Execute("/CommonHandler2.ashx", sw, false);</span>
同样不会报错,正常执行
。
3、自定义HttpHandler类使用Server.Execute跳转到其他自定义的HttpHandler类
代码:
MyHttpHandler
public class MyHttpHandler:IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
StringWriter sw = new StringWriter();
TestHandler handler = new TestHandler();
context.Server.Execute(handler, sw, false);
string dealResult = sw.ToString();
context.Response.Write(dealResult);
context.Response.End();
}
}
TestHandler
public class TestHandler:IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.Write("TestHandler");
}
}
运行代码,报“执行子请求错误”。
解决方案:
在目标请求类TestHandler继承改为Page类,即:
TestHandler
public class TestHandler:Page
{
public override void ProcessRequest(HttpContext context)
{
context.Response.Write("TestHandler");
}
}
运行代码,正常执行!
二、Asp.Net Page页中请求其他Page页、ashx文件、自定HttpHandler类
1、Asp.Net Page页中请求其他Page页
代码:
public partial class _Default : Page
{
protected void btnTestHandler_Click(object sender, EventArgs e)
{
StringWriter sw = new StringWriter();
<span style="color:#FF0000;">Context.Server.Execute("/SelfTextBoxControlTest.aspx", sw, false);</span>
}
protected void Page_Load(object sender, EventArgs e)
{
}
}
运行代码,一切正常!说明Page页调用其他Page页,只需将目标文件路径传入Server.Execute中即可,当然,通过CreateInstanceFromVirtualPath获取文件实例再传入也行。
2、Asp.Net Page页中请求ashx文件
这种情况和上面自定义HttpHandler类请求ashx文件一样,ashx文件类也必须继承Page类才能正常被请求,否则报“执行子请求出错”
3、Asp.Net Page页中请求自定义HttpHandler类
这种情况和上面自定义HttpHandler类请求其他自定义HttpHandler类一样,被请求的自定义HttpHandler类也必须继承Page类才能正常被请求,否则报“执行子请求出错”
总结:
通常当Asp.Net运行Server.Transfer或Server.Execute程序出现“执行子请求出错”时,排除目标对象代码异常外,可得出以下结论
1、当目标对象为Page页时,用BuildManager.CreateInstanceFromVirtualPath方法获取page页的实例,再传入Server.Transfer或Server.Execute中
2、当目标对象为ashx文件或自定义HttpHandler类时,将目标对象继承的父类改为Page类
至于内部原理,暂时还没搞清楚,等以后弄明白后后续再更新博文。有知道的朋友可以给我留言,万分感谢!