zoukankan      html  css  js  c++  java
  • 继续不走寻常路: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");
    }

  • 相关阅读:
    BEC listen and translation exercise 44
    中译英12
    BEC listen and translation exercise 43
    中译英11
    BEC listen and translation exercise 42
    中译英10
    BEC listen and translation exercise 41
    中译英9
    BEC listen and translation exercise 40
    中译英8
  • 原文地址:https://www.cnblogs.com/dudu/p/asp_net_mvc_user_control.html
Copyright © 2011-2022 走看看