开发者

Dynamic Razor code execution - how?

In this post I wondered about cleaner code when internationalising an app. that leads to this second query... supposing I wanted to call a function like this:

@Html.RenderWithTags("Help",
    new Dictionary<string, string>() { "HelpPage", "@Html.ActionLink(...)" }
)

such that I look up a string in my local resource file containing embedded "tags" e.g. resource name "Help" contains:

We suggest you read our [HelpPage] before proceeding

and then my .RenderWithTags() method will expand the tags but dy开发者_如何学JAVAnamically executing the code in the dictionary passed e.g. replace [HelpPage] with whatever @Html.ActionLink(...) produces.

I know I can use Microsoft.CSharp.CSharpCodeProvider().CreateCompiler() to compile C# code on the fly, but what about Razor code?


This will be rather difficult to do.

Instead, you should put delegates in your dictionary.
For example:

new Dictionary<string, Func<string>>() { 
    { "HelpPage", () => Html.ActionLink(...).ToString() }
}

If you're creating the dictionary in a Razor page, you could also use inline helpers:

new Dictionary<string, Func<Something, HelperResult>>() { 
    { "HelpPage", @Html.ActionLink(...) }
}

This will allow to use arbitrary Razor markup in the values.

However, I would probably recommend that you create a single global dictionary in code, so that you don't need to repeat definitions across pages. (Depending on how you use it)


in the end, the solution turned out pretty slick. would not have been possible without SLaks, I'm much obliged for the help (though I didn't end up using inline helpers (but thanks for the intro (they're very cool))). Now my page contains this:

@{
    Dictionary<string, MvcHtmlString> tokenMap = new Dictionary<string, MvcHtmlString>() {
        {"HelpPage", Html.ActionLink("help page", "Help", "Home") }
    };
}

and somewhere below I have:

@this.Resource("Epilogue", tokenMap)

To accomplish this simplicity:

public static class PageExtensions
{
    public static MvcHtmlString Resource(this WebViewPage page, string key)
    {
        HttpContextBase http = page.ViewContext.HttpContext;
        string ret = (string) http.GetLocalResourceObject(page.VirtualPath, key);
        return MvcHtmlString.Create(ret);
    }

    public static MvcHtmlString Resource(
        this WebViewPage page, string key, 
        Dictionary<string, MvcHtmlString> tokenMap
    ) {
        HttpContextBase http = page.ViewContext.HttpContext;
        string text = (string) http.GetLocalResourceObject(page.VirtualPath, key);
        return new TagReplacer(text, tokenMap).ToMvcHtmlString();
    }
}

...and:

public class TagReplacer
{
    Dictionary<string, MvcHtmlString> tokenmap;
    public string Value { get; set; } 

    public TagReplacer(string text, Dictionary<string, MvcHtmlString> tokenMap)
    {
        tokenmap = tokenMap;

        Regex re = new Regex(@"\[.*?\]", RegexOptions.IgnoreCase);
        Value = re.Replace(text, new MatchEvaluator(this.Replacer));
    }

    public string Replacer(Match m)
    {
        return tokenmap[m.Value.RemoveSet("[]")].ToString();
    }

    public MvcHtmlString ToMvcHtmlString()
    {
        return MvcHtmlString.Create(Value);
    }
}

...with a little extra help:

public static class ObjectExtensions
{
    public static string ReplaceSet(this string text, string set, string x)
    {
        for (int i = 0; i < set.Length; i++)
        {
            text = text.Replace(set[i].ToString(), x);
        }
        return text;
    }
    public static string RemoveSet(this string text, string set)
    {
        return text.ReplaceSet(set, "");
    }
}

comments or feedback on how it could have been better most welcome!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜