继续不走寻常路:ASP.NET MVC中使用Web Forms用户控件

目前我们正在用ASP.NET MVC(Razor)开发新版博客后台,在开发中遇到一个棘手的问题:如何在ASP.NET MVC中使用第三方开发的Web Forms用户控件,比如CuteEditor。

如果是商业软件,你无法用ASP.NET MVC进行重写;即使是开源软件,你也不可能花时间去重写。你只要两个选择:要么搞定这个问题?要么放弃使用ASP.NET MVC?

搞软件开发,一个吸引人的地方就是“一切皆有可能”,对于面临的技术问题,只要下定决心去解决,通常都能找到解决方法。

对于这个问题,我们的思路是:Web Forms用户控件最终输出的就是一段包含HTML代码的字符串,只要拿到这个字符串,通过控制器将字符串传给视图,就能解决问题。

有了这个思路,我们首先要解决的就是在控制器中得到用户控件的输出字符串,这不是难题,可以用三架马车(StringBuilder+StringWriter+HtmlTextWriter)搞定,代码如下:

 
  
string controlOutput = string .Empty;
BlogEditor editor
= new CuteEditorForCNBlogs();
StringBuilder sb
= new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
editor.RenderControl(htw);
controlOutput
= sb.ToString();
}
}

然后,通过ViewBag传递给视图,代码如下:

 
  
ViewBag.EditorHtml = controlOutput;

最后,在视图中显示一下就搞定(只搞定了部分Web Forms控件),代码如下:

 
  
@{
Layout = "~/Views/Admin/_AdminLayout.cshtml";
}
< div id ="editor" >
< div id ="editor_main" >
< div > 标题 </ div >
< input type ="text" id ="txtTitle" value ="" />
< div > 内容 </ div >
@Html.Raw(ViewBag.EditorHtml)
< div >< input type ="button" value ="发布" /></ div >
</ div >
</ div >

到这步,原以为大功告成...在测试CuteEditor控件时,发现革命尚需努力,CuteEditor未能正常输出。

通过错误信息发现CuteEditor调用了this.Page.Request,而实际Page的值为null。

于是,我们创建了一个Page的实例,通过Controls.Add将CuteEditor加载到Page实例中,代码如下:

 
  
Page page = new Page();
string controlOutput = string .Empty;
BlogEditor editor
= new CuteEditorForCNBlogs();
page.Controls.Add(editor);
...

增加Page实例之后,发现Page.Request为null,而且Page.Request为只读属性,无法在创建Page的实例之后进行赋值。

找遍Page的方法与属性,都没有找到为Page.Request赋值的办法。

剩下的唯一的希望就是借助Reflector深入“虎穴”,功夫不负有心人,终于发现“虎子”—— SetIntrinsics(HttpContext context):

 
  
private void SetIntrinsics(HttpContext context)
{
this .SetIntrinsics(context, false );
}
private void SetIntrinsics(HttpContext context, bool allowAsync)
{
this ._request = context.Request;
}

可是,SetIntrinsics是私有方法, 仅供内部使用,咋办?用“反射”挖地道呗。挖地道秘方如下:

 
  
Page page = new Page();
page.GetType().InvokeMember(
" SetIntrinsics " , BindingFlags.NonPublic |
BindingFlags.Instance
| BindingFlags.InvokeMethod, null , page,
new object [] { System.Web.HttpContext.Current });

地道挖好,就大功告成,ASP.NET MVC控制器中的完整代码:

 
  
public ActionResult NewPost()
{
Page page
= new Page();
page.GetType().InvokeMember(
" SetIntrinsics " , BindingFlags.NonPublic |
BindingFlags.Instance
| BindingFlags.InvokeMethod, null , page,
new object [] { System.Web.HttpContext.Current });
string controlOutput = string .Empty;
BlogEditor editor
= new CuteEditorForCNBlogs();
page.Controls.Add(editor);
StringBuilder sb
= new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
editor.RenderControl(htw);
controlOutput
= sb.ToString();
}
}
ViewBag.EditorHtml
= controlOutput;
return View( " EditPost " );
}

继续ASP.NET MVC之旅...

更新:

根据Ivony...的建议,使用Server.Execute更简单,代码如下:

 
  
public ActionResult NewPost()
{
Page page
= new Page();
string controlOutput = string .Empty;
BlogEditor editor
= new CuteEditorForCNBlogs();
page.Controls.Add(editor);
StringBuilder sb
= new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
Server.Execute(page, htw,
false );
controlOutput
= sb.ToString();
}
}
ViewBag.EditorHtml
= controlOutput;
return View( " EditPost " );
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值