2016-08-29 6 views
2

私は使用中のテキストが消費され、最終ページに書き込まれないようにするHTMLヘルパーを作ろうとしています。HtmlHelperは内部でhtml/textを消費します

カミソリ:

<div> 
    <p> 
     Before Inline 
    </p> 

    @using (Html.IncludeInlineScript("testScript")) 
    { 
     <script type="text/javascript"> 
      alert("hello world"); 
     </script> 
    } 

    <p> 
     After Inline 
    </p> 
</div> 

得られたHTML:

<div> 
    <p> 
     Before Inline 
    </p> 

     <script type="text/javascript"> 
      alert("hello world"); 
     </script> 
<!-- Top of Dispose --> 
<!-- Bottom of Dispose --> 

    <p> 
     After Inline 
    </p> 
</div> 

ヘルパー拡張メソッド:

public static ScriptWrapper IncludeInlineScript(this HtmlHelper helper, string scriptName) 
{ 
    return new ScriptWrapper(helper); 
} 

ラッパー:

public class ScriptWrapper : IDisposable 
{ 
    private HtmlHelper _helper; 
    private TextWriter _originalWriter; 
    private StringBuilder _scriptContents; 

    public ScriptWrapper(HtmlHelper helper) 
    { 
     _helper = helper; 
     _originalWriter = _helper.ViewContext.Writer; 

     _scriptContents = new StringBuilder(); 
     _helper.ViewContext.Writer = new StringWriter(_scriptContents); 
    } 

    public void Dispose() 
    { 
     _originalWriter.WriteLine("<!-- Top of Dispose -->"); 
     _helper.ViewContext.Writer.Flush(); 
     _helper.ViewContext.Writer = _originalWriter; 
     _originalWriter.WriteLine("<!-- Bottom of Dispose -->"); 
    } 
} 

ここでの問題は、ViewContext.Writerを新しいTextWriterに設定しても、元のライターに書き込んでいることです。 disposeの先頭がスクリプトの後にあるので、disposeは正しい順序で呼び出されていることは明らかです。新しいライターが設定された後のデバッグ中に<script>ブロックがストリームに存在しませんが、廃棄時には<script>が元のライターに含まれるようになりました。

ライザーエンジンはライターのローカルコピーを保持していて、別のインスタンスに設定されているという事実を無視していますか?これは私のバグのようです。

答えて

0

私はせっかちなので、誰かが回避策を求めている場合は、この作業を行う方法を見つけました。それは理想的ではありませんが、そのトリックはあります。あなたはScriptWrapperがために変更する場合:

public class ScriptWrapper : IDisposable 
{ 
    private HtmlHelper _helper; 
    private string _originalString; 
    private StringBuilder _sb; 

    public ScriptWrapper(HtmlHelper helper) 
    { 
     _helper = helper; 
     _sb = ((StringWriter) _helper.ViewContext.Writer).GetStringBuilder(); 
     _originalString = _sb.ToString(); 
     _sb.Clear(); 
    } 

    public void Dispose() 
    { 
     var contents = _sb.ToString(); 
     _sb.Clear(); 
     _sb.Append(_originalString); 
    } 
} 

あなたはusing(...)文の中何かを消費し、所望の結果を達成することができます。

しかし、私はこのような解決策をハッキングすることなくそれを行う方法があるかどうかを知りたいと思っています。

元(質問)で
0

、それはマークアップが使用してブロック内にあるので、何とかScriptWrapperマークアップ

<script type="text/javascript"> 
    alert("hello world"); 
</script> 

を消費していることを考えがちですが、あなたが見つけたとして、それがないですいかなる方法によってもScriptWrapperによって消費されています。このマークアップがあなたが作った作家に「リダイレクト」されることを期待していますが、そうではありません。代わりにあなたが作った作者は、それが起こっている作家が何であれ、ViewContext.Writerが使われているレスポンスストリームに書き込むのにも使われます。

ScriptWrapperがマークアップを消費するのではなく、Razorはビュー内の他のものと同様にマークアップとして解釈し、それを解釈してレスポンスストリームに書き出します。 Razorの観点からは、マークアップはScriptWrapperではなく、出力用に意図されています。単にそれを使用ブロックに囲んでも、マークアップを全体のビューの一部にすることはありません。

マークアップを他の場所にリダイレクトしない(これはうまくいかない)ので、応答ストリームで終わるものを編集しているので、応答は成功し、効果的に応答ストリームからマークアップが消去されます。

私は、あなたのソリューションはハックではなく、これを達成するための正しい方法であると主張します。

+0

私が作成したTextWriterが文字列ビルダーにその値を書き込んだとすれば、あなたは正しいでしょう。代わりに元のライターは、もはやViewContentに接続されていなくても価値を得ました。私はまだこれがMVC5フレームワークの欠陥だと思っています。 – VulgarBinary

関連する問題