Omskrivning av URL:er

Vote:
 
Det har skett en förändring i hur URL:er hanteras, bl.a. annat så kodas de om på annat sätt än tidigare och EPiServer skriver om länkar som tidigare ej påverkades. Finns det något sätt att påverka eller komma runt detta?
#15654
Mar 25, 2008 18:58
Vote:
 
Summary in english: You asked if you can change the behaviour of EPiServer CMS, so that it does not rewrite selected URL:s to Friendly URL:s. And yes, it is possible to override this feature. And it is also possible to enhance it. Or turn it off completely if you like (in web.config). To get an overview over the different possibilities you have, I provide a code sample that can be used to move the ViewState-section to the end of the streamed HTML. By looking through this sample, you can hopefully also get ideas of how to manage you own URL:s so that they will not be modified. You will basically only need to listen to some events and descide what to do when your URL:s are to be managed. You can also get more information of this area within the SDK provided in the CTP-package. Here is the Sample. #region Copyright © 1997-2007 EPiServer AB. All Rights Reserved. /* This code may only be used according to the EPiServer License Agreement. The use of this code outside the EPiServer environment, in whole or in parts, is forbidden without prior written permission from EPiServer AB. EPiServer is a registered trademark of EPiServer AB. For more information see http://www.episerver.com/license or request a copy of the EPiServer License Agreement by sending an email to info@episerver.com */ #endregion using System; using System.Data; using System.Configuration; using System.Collections.Generic; using System.Text; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Xml; using EPiServer.Core; using EPiServer.PlugIn; using EPiServer.Web; namespace EPiServerSample.templates.Units { /// /// Move ViewState from the start of the form element, to the end of it. View state looks like this: /// input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="..." /// ViewState may be large, and cause search engines to miss significant data or rank pages lower. /// To disable it, remove this file from the project, or implement a Web.Config setting or similar mechanism /// to control it's activity. /// [PagePlugIn()] public class ViewStateMover { /// /// Called by the EPiServer framework during startup, due to the PagePlugIn attribute. This is not /// a PagePlugIn, we're just piggybacking the mechanism to ensure we get called once (and only once). /// /// public static void Initialize(int optionFlag) { HtmlRewritePipe.HtmlInit += HtmlInitEventHandler; } /// /// Init the HtmlRewrite-engines event handlers. This is called every time a HtmlRewritePipe object /// is instantiated. /// /// The sender. /// The instance containing the event data. static private void HtmlInitEventHandler(object sender, HtmlRewriteEventArgs e) { // We only want to hook up our events when it's due to the UrlRewriter instantiating // a HTML rewrite. This is not necessary - we could do it always, but this demonstrates // the technique. UrlRewriteModuleBase thisModule = e.InitContext as UrlRewriteModuleBase; if (thisModule == null) { return; } // We need an instance of ourselves, to keep track of our state ViewStateMover viewStateMover = new ViewStateMover(); HtmlRewritePipe rewritePipe = (HtmlRewritePipe)sender; // There are two major events from the HtmlRewrite-engine, which allow us to rewrite // names and values of the content. The exact definition depends on the XmlNodeType // that is being processed. rewritePipe.HtmlRewriteName += viewStateMover.HtmlRewriteNameEventHandler; rewritePipe.HtmlRewriteValue += viewStateMover.HtmlRewriteValueEventHandler; } /// /// The states of our state-machine as we find what we're looking for. /// private enum State { WaitingForForm, WaitingForViewState, BufferingInput, SkipToEndForm, SkipToEnd }; private State _state; /// /// Helper class to group the value and quote char used for attribute values /// private class AttributeValue { /// /// The Value of an attribute /// public string Value; /// /// The quote char used /// public char QuoteChar; /// /// Initialize an instance /// /// /// public AttributeValue(string value, char quoteChar) { Value = value; QuoteChar = quoteChar; } } /// /// Buffer attributes of the "input" element here /// private Dictionary _inputAttributes = new Dictionary(); /// /// Marker to determine wether in fact we've seen the ViewState /// private bool _viewStateFound = false; /// /// Handle rewrite name /// /// The sender. /// The instance containing the event data. /// /// The name event is raised before an associated value event. Check the e.NodeType and other properties to determine /// course of action. /// private void HtmlRewriteNameEventHandler(object sender, HtmlRewriteEventArgs e) { switch (_state) { case State.WaitingForForm: if (e.NodeType == XmlNodeType.Element && string.Compare(e.Name, "form", StringComparison.InvariantCultureIgnoreCase) == 0) { _state = State.WaitingForViewState; } break; case State.WaitingForViewState: if (e.NodeType == XmlNodeType.Element && string.Compare(e.Name, "input", StringComparison.InvariantCultureIgnoreCase) == 0) { _inputAttributes.Clear(); e.IsHoldingOutput = true; _state = State.BufferingInput; } break; } } /// /// Handle rewrite value /// /// The sender. /// The instance containing the event data. /// /// The value event is raised after an associated name event. Check the e.NodeType and other properties to determine /// course of action. /// private void HtmlRewriteValueEventHandler(object sender, HtmlRewriteEventArgs e) { // Remove all insignificant whitespace if (e.NodeType == XmlNodeType.Whitespace) { e.ValueBuilder.Length = 0; e.ValueBuilder.Append(" "); return; } switch (_state) { // We're buffering the contents of input element attributes, while checking for if it is a ViewState field case State.BufferingInput: switch (e.NodeType) { // Another attribute, add it to the collection and check if it's a ViewState case XmlNodeType.Attribute: _inputAttributes.Add(e.Name, new AttributeValue(e.Value, e.QuoteChar)); _viewStateFound |= string.Compare(e.Name, "name", StringComparison.InvariantCultureIgnoreCase) == 0 && e.Value == "__VIEWSTATE"; e.IsHoldingOutput = true; break; // End of the input element start tag. Determine if we're to output and continue waiting, or if it's the ViewState, // in which case we switch state, and output nothing here. case XmlNodeType.Element: if (_viewStateFound && e.IsEmptyElement) { e.IsHoldingOutput = true; _state = State.SkipToEndForm; } else { e.ValueBuilder.Length = 0; AppendInputElement(e.ValueBuilder, _inputAttributes, e.IsEmptyElement); _inputAttributes.Clear(); _state = State.WaitingForViewState; } break; } break; case State.SkipToEndForm: switch (e.NodeType) { // Check if this is the end of the form element, if so, output the ViewState, if any. case XmlNodeType.EndElement: if (string.Compare(e.Name, "form", StringComparison.InvariantCultureIgnoreCase) == 0) { string value = e.Value; e.ValueBuilder.Length = 0; e.ValueBuilder.Append("
"); AppendInputElement(e.ValueBuilder, _inputAttributes, e.IsEmptyElement); e.ValueBuilder.Append("
"); _inputAttributes = null; e.ValueBuilder.Append(value); _state = State.SkipToEnd; } break; } break; case State.SkipToEnd: break; } } /// /// Appends the input element data to the ValueBuilderResult /// /// The instance containing the event data. /// The _input attributes. private void AppendInputElement(StringBuilder sb, Dictionary _inputAttributes, bool isEmptyElement) { sb.AppendFormat(" kvp in _inputAttributes) { sb.AppendFormat(" {0}={2}{1}{2}", kvp.Key, HttpUtility.HtmlAttributeEncode(kvp.Value.Value), kvp.Value.QuoteChar); } sb.Append(isEmptyElement ? "/>" : ">"); } } }
#16062
Mar 25, 2008 19:07
Vote:
 
Thanks for the example, but it's not quite what i want. I don't want to modify the page, just prevent EPiServer from modifying some specific URL's. I've tried to hook on to these events UrlRewriteModule.RewriteValidateHtmlRewrite UrlRewriteModule.RewriteValidateToExternal UrlRewriteModule.RewriteValidateToInternal and setting e.IsValidForRewrite to false, but that doesn't seem to work. If I remove the UrlRewriteModule httpModule everything works just fine, but as i said i only want to turn it off for certain URL's.
#16063
Mar 25, 2008 19:07
Vote:
 
OK. Here is some code that could perhaps help you. It hooks into UrlRewriteModule and prevents the URL-rewritting on a Ult-by-URL-basis. using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using EPiServer.Core; using EPiServer.PlugIn; using EPiServer.Web; namespace EPiServer1 { [PagePlugIn()] public class UrlRewriteControl { public static void Initialize(int optionFlag) { UrlRewriteModule.RewriteInit += new EventHandler(UrlRewriteModule_RewriteInit); } static void UrlRewriteModule_RewriteInit(object sender, UrlRewriteEventArgs e) { ((UrlRewriteModule)sender).RewriteValidateToExternal += new EventHandler(ViewStateMover_RewriteValidateToExternal); } static void ViewStateMover_RewriteValidateToExternal(object sender, UrlRewriteEventArgs e) { if(e.Url.Path.StartsWith("/News")) // Select what URL:s should not be rewritten e.IsValidForRewrite = false; } } }
#16064
Mar 25, 2008 19:07
Vote:
 
I've tried exactly what you suggest but i still get me URL's messed up. Í have hooked up to all the events in UrlRewriteModule and set e.IsValidForRewrite = false; When debugging I can see that the eventhandler is called for the specified URL's but this doesn't seem to help. If i have UrlRewriteModule activated and try to stop it from rewriting the URL as stated above I get the following. If i remove the UrlRewriteModule from web.config i get. Note that the & is replaced by & Is there anyway we could work around this?
#16065
Mar 25, 2008 19:07
Vote:
 
Any suggestions?
#16066
Mar 25, 2008 19:07
Vote:
 
Hello, The encoding of '&' as '&' is correct - the reason this occurs when UrlRewrite is enabled is because it will always parse the outgoing HTML and when regenerating the URL it will HtmlAttributeEncode it, which is correct behavior. As far as I can determine from the sample provided, the real problem is that the URL in the first place is emitted with an undefined entity in the attribute string: '&a=...'. That this works at all is because ASP.NET silenty ignores the error. It's still incorrect HTML as far as I know. If you are using the attribute internally in your code directly, you should always do a System.Web.HttpUtility.HtmlDecode before using it to ensure that any entity encodings are resolved before applying for example System.Web.HttpUtility.ParseQueryString to get at the actual parameter values. When running as a Page, all the appropriate properties are set accordingly, thus you can use Request.RawUrl, Request.QueryStrings and Request.Params without any HtmlDecode. I guess that the situation is actually more complex than what meets the eye, so if you can please give us further details of why the correct entity encoding is problematic we can give further help. We are also considering whether we should change the meaning of the IsValidForRewrite to really, really leave the URI untouched, as that may be more intuitive and possibly necessary in some case we've not yet forseen. The solution in this case is probably for you to perform a HtmlDecode.
#16067
Mar 25, 2008 19:07
This thread is locked and should be used for reference only. Please use the Episerver CMS 7 and earlier versions forum to open new discussions.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.