开发者

asp.net mvc 3 regular expression returning encoded html?

开发者 https://www.devze.com 2023-01-27 00:43 出处:网络
public static string MakeAnchor(string text) { string pattern = @\"((?<Protocol>\\w+):\\/\\/(?<Domain>[\\w@][\\w.:@]+)\\/?[\\w\\.?=%&=\\-@/$,]*)\";
public static string MakeAnchor(string text) 
{
    string pattern = @"((?<Protocol>\w+):\/\/(?<Domain>[\w@][\w.:@]+)\/?[\w\.?=%&=\-@/$,]*)";
    R开发者_运维知识库egex r = new Regex(pattern, RegexOptions.Multiline);
    var anchor = r.Replace(text, "<a href=\"$1\" target=\"_blank\">$1</a>");
    return anchor;
}

This method returns &lt;a href=&quot;http://google.com/&quot; target=&quot;_blank&quot;&gt;http://google.com/&lt;/a&gt; if I pass it some text containing http://google.com/

instead of &lt;a href=&quot;http://google.com/&quot; target=&quot;_blank&quot;&gt;http://google.com/&lt;/a&gt;

I'm using razor views with MVC 3. I'm stumped. Is there some sort of new view encoding in MVC 3 that I'm unaware of?


If you use @: (in Razor) or <%: (in the WebForm View Engine) the text will be automatically html encoded. Try @= or <%=


Make your method return an IHtmlString to indicate to the framework that your output is already encoded.

The simplest implementation of that is return new HtmlString(anchor);

IHtmlString is implemented in .NET 4, so if you're in .NET 3.5, you'll have to use the @= or <%= syntax (as @Andrew mentions) to avoid encoding.


I found this blog post (http://www.akngo.com/) that shows how to "wrap" Htmlstring for convenience sake. Usage is RawView.SomeString

I have been using the Razor engine for a few days now, and I am liking it a lot. I noticed one big problem right from the start, all strings are HTML encoded. For our uses, this becomes quite an annoying “feature” when we deal with JSON strings. For example, given a simple JSON string, ["1", "2", "3", "4"]

The actual HTML encoded output of this became, ["1", "2", "3", "4"]

The quotes have been escaped, which is not the desired output. If we need to send HTML back out, or XML, we would have to then individually escape those. Overall, I find this quite annoying as we would have to wrap it inside of an HtmlString as shown in this StackOverflow post.

In our scenario, we are generating JSON/XML from C#, so most of the time, our serialized data is inside of the ViewModel. Which would result in us doing things like, @(new HtmlString(View.Foo)) @(new HtmlString(View.Bar))

As you can see, this can become quite cumbersome. So I decided to plagiarized part of MVC to create a RawView. In the end, the usage will be, @RawView.Foo @RawView.Bar

I also went ahead to allow the usage of the index operator as well in case there’s a need to loop over it with a list of keys. // Assuming we have Foo, Bar, and Baz in our ViewModel @{ List keys = new List { "Foo", "Bar", "Baz" }; foreach (var key in keys) { @RawView[key] } }

To achieve this, I would need to duplicate DynamicViewDataDictionary. Naturally, I named it DynamicRawViewDataDictionary, public class DynamicRawViewDataDictionary : DynamicObject { private readonly Func viewThunk; public DynamicRawViewDataDictionary(Func viewThunk) { this.viewThunk = viewThunk; }

    private ViewDataDictionary ViewData
    {
        get
        {
            ViewDataDictionary viewData = this.viewThunk();
            return viewData;
        }
    }

    public object this[string key]
    {
        set { setData(key, value); }
        get { return getData(key); }
    }

    public override IEnumerable<string>

GetDynamicMemberNames() { return ViewData.Keys; }

    public override bool TryGetMember(GetMemberBinder binder,

out object result) { result = getData(binder.Name); return true; }

    public override bool TrySetMember(SetMemberBinder binder,

object value) { setData(binder.Name, value); return true; }

    private object getData(string key)
    {
        object value = ViewData[key];
        if (value is string)
        {
            return new HtmlString(value.ToString());
        }

        return value;
    }

    private void setData(string key, object value)
    {
        ViewData[key] = value;
    }
}

The reason for the duplication is because the DynamicViewDataDictionary is an internal sealed class. There was no way I could get around this restriction other than copying and pasting. The obvious change I made to this class is the getData method. I checked to see if the object is a string, if it is, I wrapped it with an HtmlString().

Now I need to use this inside of a WebViewPage, since all views , I have to have a customized version of a WebViewPage as well. Good thing that MS didn’t make this class internal sealed, so I can easily inherit from it. I needed to make a generic and a non-generic version, I just plopped both of this inside of one file. public abstract class CustomWebViewPage : WebViewPage { private DynamicRawViewDataDictionary _rawData; public dynamic RawView { get { if (_rawData == null) { _rawData = new DynamicRawViewDataDictionary(() => ViewData); } return _rawData; } } }

public abstract class CustomWebViewPage : WebViewPage
{
    private DynamicRawViewDataDictionary _rawData;
    public dynamic RawView
    {
        get
        {
            if (_rawData == null)
            {
                _rawData = new DynamicRawViewDataDictionary(() =>

ViewData); } return _rawData; } } }

For the final touch to actually make this work, at the top of the cshtml file, you should have something like, @inherits Namespace.To.CustomWebViewPage

//or @inherits Namespace.To.CustomWebViewPage

Now that the cshtml file inherits from the new CustomWebViewPage, it should have access to RawView, which will wrap all strings with an HtmlString.

Once you have this in place, you’ll still need to make sure that all of your new views inherits from CustomWebViewPage. I highly recommend using custom code templates in your MVC project to generate the view. This will help with automating a lot of the mundane tasks.


Htmlstring is the answer.

@(new HtmlString(SomeString))
0

精彩评论

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