How to preserve ampersand in URL's querystring when using RegisterClientScriptInclude? - asp.net

I have the need to add a javascript include to my ASP.NET page. The url of the javascript file has two key/value pairs in the query string. But the ampersand is being escaped and I don't want that.
Page.ClientScript.RegisterClientScriptInclude("myKey",
"https://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&s=1")
This results in the following HTML:
<script
src="https://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&s=1"
type="text/javascript"></script>
But what I really want is:
<script
src="https://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&s=1"
type="text/javascript"></script>
Help?

Actually the encoded ampersand is valid HTML markup. Your goal is an attempt to generate invalid markup. Unencoded ampersands are not valid.

I have run into this in the past and never found a way around it. I needed to create the URL server side and I don't like putting inline code in my aspx pages so I ended up using a Literal control and building the script tag and assigning it.
For your example:
<form id="form1" runat="server">
<asp:Literal ID="ltScriptInclude" runat="server"></asp:Literal>
Then in the Page_Load:
string url = "https://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&s=1";
ltScriptInclude.Text = string.Format(
"<script src=\"{0}\" type=\"text/javascript\"></script>",
url);
A complete recreation would be to also do a check for the registered key by wrapping the assignment in an if like:
if (IsStartupScriptRegistered("myKey"))
{
// assign
// set the key
}
But that is probably not needed since it is not being assigned anywhere else with the change of a PostBack double assigning it.
It's not the cleanest solution and it would have been nice if the RegisterClientScriptInclude had some type of param to tell it to not encode. Unfortunately I don't think there is any way around it and the above isn't too bad. Most includes for script files usually don't have the & so the vast majority would never run into this problem.

Related

Should I use both HtmlEncode and JavaScriptStringEncode if inside HTML <script> tag?

I want to render in .NET a string destined for Javascript, say:
<html>
...
<script>
alert('<%= this.MyStringHere %>');
</script>
</html>
How should I encode MyStringHere? Do I need HttpUtility.HtmlEncode(HttpUtility.JavaScriptStringEncode(unencodedString)) or is just HttpUtility.JavaScriptStringEncode(unencodedString) sufficient? Or are both wrong?
Feel free to mention alternative server tag <% solutions in your answer too, but I'm looking for the code-based solution, the example is a little contrived.
You only need to encode the script for JS use, no need to double encode using HTML encoding. Just HTML encoding will not work either because it will not encode \n etc.
<script>
alert(<%=HttpUtility.JavaScriptStringEncode(this.MyStringHere, true)%>);
alert("<%=HttpUtility.JavaScriptStringEncode(this.MyStringHere, false)%>");
</script>
Note that JavaScriptStringEncode will not add the double quotes by default - see official docs.
If you have server-side JSON package installed, you could also use that - and it will also work for arrays, dictionaries etc.. Note that it will also add quotes for strings so you do not add them yourself.
You also have to remember that you cannot use <%: text %> syntax since that does the HTML encoding. In MVC Razor views you even have to explicitly disable HTML encoding by using #Html.Raw(Json.Encode(...)).

CKEditor breaking custom .NET tags by converting single quotes to double quotes

At the client's request, we just upgraded a custom CMS system for a large site from FCKEditor 2.x to CKEditor 3.5.3.
Inside an ItemTemplate I have a custom UserControl tag in which the attributes are populated by DataBinding, like so:
<my:Viewer runat="server">
<ItemTemplate>
<my:CustomTag runat="server"
ImageUrl='<%# DataBinder.Eval(Container.DataItem, "ImageUrl") %>' />
</ItemTemplate>
</my:Viewer>
So, the point is that the above works just fine. However, when the HTML is put into the latest CKEditor, CKEditor changes the ImageUrl attribute to use double-quotes instead of single quotes. Once it's changed to double quotes, it causes a parsing error on the .aspx page. Changing: "ImageUrl" to "ImageUrl" works, but it's not ideal for our client who is going to have to update every page that exists in a very large CMS system. So, I'm asking this question hoping someone might know of a way to toggle CKEditor to use single quotes in HTML attributes by default instead of double quotes to reduce the amount of work my client is going to have to do.
I'm only looking for easy configuration-type changes, not patching the editor, etc.
This should do what you want
Taken from here
http://cksource.com/forums/viewtopic.php?f=11&t=20647&sid=f47526ecfb1f2303ad0b923ceed7aafe&start=10
To avoid CKEditor changing special chars:
switching in source view:
CKEDITOR.instances.TEXT.on( 'mode', function(ev) {
if ( ev.editor.mode == 'source' ) {
var str=ev.editor.getData();
str=str.replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, "\"");
ev.editor.textarea.setValue(str);
}
});
When save edited document:
var html=CKEDITOR.instances.TEXT.getData()
html=html.replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, "\"");
I'm going to say that the " solution that I mentioned being too much work is simply the only answer...just to put some closure on this. Or, if I can find a way, I'll withdraw the question. Thanks rqmedes for trying...I'd actually forgotten all about this question until I got your response
:)

Why does ASP.Net rewrite relative paths for runat=server anchor controls?

I have my UserControls in a ~/Controls folder in my solution:
/Controls/TheControl.ascx
If specify the following:
<a id="theId" runat="server" href="./?pg=1">link text</a>
ASP.Net seems to want to rewrite the path to point to the absolute location. For example, If the control is on site.com/products/fish/cans.aspx the link href will be rewritten to read
<a id="munged_theId" href="../../Controls/?pg=1>link text</a>
Why does Asp.Net rewrite these control paths, and is there an elegant way to fix it?
I just want the anchor control to spit out exactly what I tell it to!!! Is that so hard?
EDIT:
I've basically done what Kelsey suggested. I knew I could do it this way, but I don't like adding markup in my code when I want something relatively simple. At least it solves the problem:
Aspx page:
<asp:PlaceHolder ID="ph" runat="server"></asp:PlaceHolder>
Code-behind:
var anchor = new HtmlGenericControl("a") { InnerText = "Previous" + " " + PageSize) };
anchor.Attributes["href"] = "?pg=" + (CurrentPage - 1);
anchor.Attributes["class"] = "prev button";
ph.Controls.Clear();
ph.Controls.Add(anchor);
As you can see by the amount of code needed for what is essentially supposed to be be a simple and light-weight anchor, it's not the most optimal solution. I know I could use a Literal but I figured this was cleaner as I'm adding more than one anchor.
I would be interesting in knowing WHY ASP.Net takes over and tries to fix my URL, though.
Why do you have runat="server" and no ID defined? Do you need to access it server side? If you remove the runat="server" everything will work as expected.
For more information regardinging how ASP.NET handles paths check out this MSDN article.
Edit: You can get around the problem then by using a Literal control and then outputing the raw <a href... to it.
Eg:
<asp:Literal ID="myLiteral" runat="server" />
myLiteral.Text = "link text";
Then you can set the visible property on the Literal however you want.
I know this is a bit of an old topic, but I was running into this problem as well and in the end went with a similar solution, but was able to save a few lines of code by doing this in the ascx:
<anchor id="myAnchor" runat="server" href="xxx">link text</anchor>
Then in the code behind, I referenced it using an HtmlGenericControl and can then do this:
myAnchor.TagName = "a";
// other properties set as needed
Anyway, I thought I'd post in case anyone else stumbles in here with the same issue.
Best bet is to make everything app root relative using the magic ~/ lead-in to the url. That tends to keep stuff straight.
There isn't a great answer to your question. ASP.NET is going to treat a relative path in a UserControl as relative to the path of the user control.
What you can do is in the code behind for your user control, set the HRef property of your anchor tag based on the Request.Path property. Then you can create URLs relative to the page.
Alternative is to use a literal like Kelsey was suggestion, or I would just try and map everything app relative with ~/ like Wyatt suggested.
Even a literal doesn't work using ICallBackEventHandler and RenderControl at least... I ended up hacking the tag back client-side :/ e.g in JQuery:
$('#munged_theId').attr('href', './?pg=1');

How do I inject a script URL containing an ampersand with ASP.NET?

I have a server control that needs to programmatically inject a JavaScript reference into the page. It is to reference Microsoft's Bing map control which requires &s=1 to be appended to the script URL for use over SSL. The problem is that the .NET Framework encodes the attributes and changes the & to an & (verified with Reflector). At some point after that the & is removed altogether.
Desired script tag:
<script type="text/javascript"
src="https://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&s=1">
</script>
Attempt 1:
var clientScriptManager = this.Page.ClientScript;
if (!clientScriptManager.IsClientScriptIncludeRegistered(this.GetType(), "BingMapControl"))
{
clientScriptManager.RegisterClientScriptInclude(
this.GetType(), "BingMapControl",
"https://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&s=1");
}
Attempt 2:
HtmlGenericControl include = new HtmlGenericControl("script");
include.Attributes.Add("type", "text/javascript");
include.Attributes.Add("src",
"https://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&s=1");
this.Page.Header.Controls.Add(include);
Any ideas?
Desired script tag:
<script type="text/javascript"
src="https://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&s=1">
</script>
Actually, no. In fact, your desired script tag is:
<script type="text/javascript"
src="https://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&s=1">
</script>
You do want the & to be encoded as &. Why? Because the HTML standard says so. See, for example, Section C.12. Using Ampersands in Attribute Values (and Elsewhere) of the XHTML 1.0 standard:
In order to ensure that documents are compatible with historical HTML user agents and XML-based user agents, ampersands used in a document that are to be treated as literal characters must be expressed themselves as an entity reference (e.g. "&"). For example, when the href attribute of the a element refers to a CGI script that takes parameters, it must be expressed as http://my.site.dom/cgi-bin/myscript.pl?class=guest&name=user rather than as http://my.site.dom/cgi-bin/myscript.pl?class=guest&name=user.
Out of curiosity... is this code just an example? I generally only use RegisterClientScript and its ilk if there is some dynamic portion that needs to be set at runtime. Otherwise, you can just write it statically in an aspx, ascx, or js file.
Have you tried a Literal control? I know I've done this very thing recently. I'll have to dig up my code.
It seems like all controls added to Header are html.encode-d
Page.Header.Controls.Add
Quick solution is to add a property ScriptUrl
public string ScriptUrl
{
get
{
return "https://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&s=1";
}
}
and in aspx
<head runat="server">
<title></title>
<script type="text/javascript" src="<%= ScriptUrl %>"></script>
</head>
And that's all

RegisterClientScriptBlock without form tag

After trying to understand why client code is not rendered in a page (injected by user control) I found this link, it turns out you must have a form tag for it to work (Page.RegisterClientScriptBlock did declare this but ClientScriptManager.RegisterClientScriptBlock which I use does not say anything regarding this).
I am using Visual studio 2005.
Does anyone know if this has been solved?
Edit:
To clarify, I want my control to add javascript code to the head section of the page without having to use the
<form runat="server"
I have tried adding it using:
HtmlGenericControl x = new HtmlGenericControl("script");
x.InnerText = "alert('123');";
Page.Header.Controls.Add(x);
But this did not work for me.
As far as I know this functions the same in current versions, you can test it very simply though.
Update
per discussion in the comments, the only "workaround" that I could think of would be for your to manually insert the script into the "head" section of the page on your own, using a runat="server" declaration on the Head element.
Got it!
My mistake was not doing it in the OnPreRender method (I used the Render method).
Now all that is needed is - like Mitchel Sellers wrote, set the header to runat server and than add to it's controls:
HtmlGenericControl x = new HtmlGenericControl("script");
x.InnerText = GetScriptSection();
Page.Header.Controls.Add(x);
Thanks for pointing me to the right direction!
The MSDN Page for registerclientscriptblock here says:
The client-side script is emitted just
after the opening tag of the Page
object's <form runat= server> element.
The script block is emitted as the
object that renders the output is
defined, so you must include both tags
of the <script> element.
If you do not want to include a form, than you will basically need to build your own implementation of it.
Minor clarification for anyone seeing this:
The form tag must have the runat="server" attribute set, e.g.
<form id="theform" runat="server">
Just placing a regular HTML form tag in the page will not help.

Resources