Executing ASPX pages without a web server

本文介绍了一种不依赖Web服务器独立执行ASPX页面的方法。通过创建一个包含特定逻辑的应用程序域,可以在控制台应用程序中运行ASP.NET页面并显示结果。

Executing ASPX pages without a web server

 

For the last couple of days, I?ve been writing about creating a standalone ASPX execution environment?a Windows Forms application that executes an ASP.NET page and displays the results in a Web Browser control.

Because of the way the ASP libraries are written, this effectively requires either a couple of communicating but distinct assemblies or a strongly-named assembly in the Global Assembly Cache. In my project, I wrote two distinct assemblies, which worked. But I wondered if I could overcome this requirement, with the hope that I would learn a thing or two in the process. It took some code spelunking (and a venture beyond what is documented), but I succeeded on both fronts.

The article that got me started on this project was Ted Neward?s "Hosting ASP.NET: Running an All-Managed HTTP Server," which I can?t recommend highly enough. Neward opted for the two assembly approach (or more exactly, the same assembly copied into two different directories). My code still retains a class from his example. But while he uses an ASP.NET function to spin up the app domain that the ASPX page runs in, I create mine from scratch.

Here?s a little console app I created:


 
using System; using System.Web; using System.Web.Hosting; using System.IO; using System.Runtime.Remoting; using System.Globalization; namespace AspHostTest { public class MyExeHost : MarshalByRefObject { public void ProcessRequest(String page) { HttpWorkerRequest hwr = new SimpleWorkerRequest(page, null, Console.Out); HttpRuntime.ProcessRequest(hwr); } } class MyAspHost { public static object CreateApplicationHost(Type hostType, string virtualDir, string physicalDir) { if (!(physicalDir.EndsWith("//"))) physicalDir = physicalDir + "//"; string aspDir = HttpRuntime.AspInstallDirectory; string domainId = DateTime.Now.ToString(DateTimeFormatInfo.InvariantInfo).GetHashCode().ToString("x"); string appName = (virtualDir + physicalDir).GetHashCode().ToString("x"); AppDomainSetup setup = new AppDomainSetup(); setup.ApplicationName = appName; setup.ConfigurationFile = "web.config"; // not necessary execept for debugging AppDomain ad = AppDomain.CreateDomain(domainId, null, setup); ad.SetData(".appDomain", "*"); ad.SetData(".appPath", physicalDir); ad.SetData(".appVPath", virtualDir); ad.SetData(".domainId", domainId); ad.SetData(".hostingVirtualPath", virtualDir); ad.SetData(".hostingInstallDir", aspDir); ObjectHandle oh = ad.CreateInstance(hostType.Module.Assembly.FullName, hostType.FullName); return oh.Unwrap(); } static void Main(string[] args) { MyExeHost myHost = (MyExeHost)CreateApplicationHost(typeof(MyExeHost),"/",Directory.GetCurrentDirectory()); myHost.ProcessRequest("app.aspx"); } } }

To compile it, open a Visual Studio .NET command prompt (or any other command prompt session with the C# compiler in the path) and run this command:


 
csc /t:exe /r:System.Web.dll AppHostTest.cs

Put the exe file in a directory with an ASPX file named app.aspx. Here?s the simple file I?ve used in my tests:


 
<html><body><h1>Hello, world.</h1> <b>Today is <%= DateTime.Now %>.</b> </body></html>

When you run AppHostTest.exe, you?ll see the raw html that the executed ASPX file creates.

In addition to running this program, you can use VS.NET to debug right into the ASP.NET page. For this to work, you?ll have to instruct the ASP.NET classes to compile your code with debug symbols. You can do this by creating a file called web.config in the same directory. All this file needs to contain is the following XML:


 
<configuration> <system.web> <compilation debug="true"/> </system.web> </configuration>

To load the debugger, run this command from the same directory:


 
devenv /debugexe AspHostText.exe

 

Load the ASPX file with the Open/File? menu choice, set a breakpoint on a line of code, press F5, and you should see the debugger stop at that line.

Okay. That was fun, but what exactly is going on in the code?

What we?ve done is to create two classes. MyAspHost includes the Main method that runs the show and a static method I?ve called CreateApplicationHost. This latter method serves the same purpose (and takes the same parameters) as a static method of the same name in the System.Web.Hosting.ApplicationHost class. The ASP.NET method does more, and calls a lot of protected functions in the process.

My method does the minimum that is required to get a simple ASPX page to execute, which is to create an app domain, create an object in the app domain, and return a reference to this object to the calling program (in the default app domain). That's essentially what the ASP.NET classes do, but I've left out what isn't absolutely necessary. (The domain ID and application name could be given simpler names, but I chose to use the same algorithm that ApplicationHost.CreateApplicationHost uses.)

The other class in the file is the one that gets instantiated in the new app domain. All it does is create a System.Web.Hosting.SimpleWorkerRequest specifying the page to run and the output System.IO.TextWriter, then hand this request to a static method in the System.Web.HttpRuntime class, which does all the rest.

Next week I?ll write about the documented way to do this same thing, but I should mention the difference between this code and the Kosher code. The salient difference (apart from all the other things I left out) is that the ASP.NET code sets up a PrivateBinPath for the new app domain so it looks for the assembly it creates in a bin directory below the virtual root is uses. This explains the need for the second assembly?ASP.NET forces the Fusion assembly resolver to look for this assembly in a separate place. That?s what allows my code to be so simple; I allow Fusion to look for the new assemblies in the same directory as the executable.

 

转载于:https://www.cnblogs.com/dhz123/archive/2007/10/16/2194319.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值