正如我提到here,我正在尝试从WinForms中的ASPX页面生成HTML。
我正在尝试将ASPX页面直接编译到EXE中;我希望能够写出这样的东西:
var page = new ASP.MyPageName();
var stringWriter = new StringWriter();
using(var htmlWriter = new HtmlTextWriter(stringWriter))
page.RenderControl(htmlWriter);
我添加了一个ASPX页面,将Build Action设置为Compile,并输入以下Page
声明:
<%@ Page Language="C#" ClassName="MyPageName" %>
代码编译,我在ASPX中定义的属性可以从调用代码中使用,但StringWriter仍然为空。我试着打电话给htmlWriter.Flush
,但没有帮助。
page
实例的Controls
集合为空,可能不应该是
我查看了Reflector中的EXE,我无法在任何地方找到页面内容。因此,我假设页面未正确编译。
这样做的正确方法是什么?
答案 0 :(得分:3)
我最终使用ApplicationHost.CreateApplicationHost在ASP.Net AppDomain中运行整个应用程序。这比我伪造ASP.Net AppDomain更简单,更可靠。
注意:为此,您必须在ASP.Net文件夹的Bin目录中放置EXE文件的副本(或包含传递给CreateApplicationHost的类型的任何程序集)。这可以在构建后步骤中完成。然后,您可以处理AssemblyResolve
以在原始目录中找到其他程序集。
或者,您可以将程序本身和所有DLL放在ASP.Net的Bin
目录中。
注意:WinForms的“设置”功能在ASP.Net AppDomain中不起作用。
答案 1 :(得分:2)
我相信你想要使用的是SimpleWorkerRequest。
不幸的是,它需要资源(我相信)存在于磁盘上。从您的描述中听起来您更喜欢整个应用程序驻留在您的DLL中。如果是这种情况,您很可能需要实施自己的HttpWorkerRequest。
答案 2 :(得分:2)
这不能可靠地工作,我已经放弃了。
我最终将文件复制到输出文件夹并在同一个AppDomain中初始化ASP.Net,使用以下代码:(我测试了它;它有时可以工作)
static class PageBuilder {
public static readonly string PageDirectory = Path.Combine(Path.GetDirectoryName(typeof(PageBuilder).Assembly.Location), "EmailPages");
static bool inited;
public static void InitDomain() {
if (inited) return;
var domain = AppDomain.CurrentDomain;
domain.SetData(".appDomain", "*");
domain.SetData(".appPath", PageDirectory);
domain.SetData(".appVPath", "/");
domain.SetData(".domainId", "MyProduct Domain");
domain.SetData(".appId", "MyProduct App");
domain.SetData(".hostingVirtualPath", "/");
var hostEnv = new HostingEnvironment();//The ctor registers the instance
//Ordinarily, the following method is called from app manager right after app domain (and hosting env) is created
//Since CreateAppDomainWithHostingEnvironment is never called here, I need to call Initialize myself.
//Here is the signaature of the method.
//internal void Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters) {
var cmp = Activator.CreateInstance(typeof(HttpRuntime).Assembly.GetType("System.Web.Hosting.SimpleConfigMapPathFactory"));
typeof(HostingEnvironment).GetMethod("Initialize", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(hostEnv, new[] { ApplicationManager.GetApplicationManager(), null, cmp, null });
//This must be done after initializing the HostingEnvironment or it will initialize the config system.
SetDefaultCompilerVersion("v3.5");
inited = true;
}
static void SetDefaultCompilerVersion(string version) {
var info = CodeDomProvider.GetCompilerInfo("c#");
var options = (IDictionary<string, string>)typeof(CompilerInfo).GetProperty("ProviderOptions", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(info, null);
options["CompilerVersion"] = version;
}
public static TPage CreatePage<TPage>(string virtualPath) where TPage : Page {
return BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(TPage)) as TPage;
}
//In a base class that inherits Page:
internal string RenderPage() {
var request = new SimpleWorkerRequest("", null, null);
ProcessRequest(new HttpContext(request));
using (var writer = new StringWriter(CultureInfo.InvariantCulture)) {
using (var htmlWriter = new HtmlTextWriter(writer))
RenderControl(htmlWriter);
return writer.ToString();
}
}
程序启动时必须正确调用 InitDomain
;否则,它会抛出有关已初始化的配置系统的异常。
如果不调用ProcessRequest
,则网页的Controls
集合为空。
更新:在调用ProcessRequest
期间呈现页面,因此必须在操作Page
实例后完成。
如果程序有.config
文件,则此代码无效;我创建了一个方法来设置默认的C#编译器版本而没有使用反射的.config
文件。
答案 3 :(得分:1)
答案 4 :(得分:1)
您很可能使用了错误的网页类。你需要在代码背后使用不是实际的名字好的类。在编译期间,ASP.NET生成页面类,它继承自代码中定义的类,并且在此类中发生所有控件的初始化。因此,您应该使用生成的类(使用Reflector检查其名称)。
答案 5 :(得分:1)
如果您正在寻找此答案的MVC版本,请参阅: Is there a way to process an MVC view (aspx file) from a non-web application?
代码使用单独的AppDomain,但据我所知,这是必需的,因为从ASPX文件生成的所有代码都依赖于HttpContext和HostingEnvironment.VirtualPathProvider。
public class AspHost : MarshalByRefObject
{
public string _VirtualDir;
public string _PhysicalDir;
public string AspxToString(string aspx)
{
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter tw = new HtmlTextWriter(sw))
{
var workerRequest = new SimpleWorkerRequest(aspx, "", tw);
HttpContext.Current = new HttpContext(workerRequest);
object view = BuildManager.CreateInstanceFromVirtualPath(aspx, typeof(object));
Page viewPage = view as Page;
if (viewPage == null)
{
UserControl viewUserControl = view as UserControl;
if (viewUserControl != null)
{
viewPage = new Page();
viewPage.Controls.Add(viewUserControl);
}
}
if (viewPage != null)
{
HttpContext.Current.Server.Execute(viewPage, tw, true);
return sb.ToString();
}
throw new InvalidOperationException();
}
}
}
public static AspHost SetupFakeHttpContext(string physicalDir, string virtualDir)
{
return (AspHost)ApplicationHost.CreateApplicationHost(
typeof(AspHost), virtualDir, physicalDir);
}
}
然后,渲染文件:
var host = AspHost.SetupFakeHttpContext("Path/To/Your/AspNetApplication", "/");
String rendered = host.AspxToString("~/Views/MyView.aspx");
答案 6 :(得分:0)
您可以使用ClienBuildManager类来编译ASPX文件。