Differences between different .net framework HtmlEncode methods - asp.net

What differences, if any are there between:
System.Web.HttpUtility.HtmlEncode
System.Web.HttpServerUtility.HtmlEncode
System.Net.WebUtility.HtmlEncode
Both HttpUtility.HtmlEncode and HttpServerUtility.HtmlEncode say:
To encode or decode values outside of a web application, use the WebUtility class.
Which implies that there is a difference, but doesn't come out say so directly or say what the difference is, if there is one.

If you dig though the source code you can follow easily enough.
System.Web.HttpUtility.HtmlEncode
/// <devdoc>
/// <para>
/// HTML encodes a string and returns the encoded string.
/// </para>
/// </devdoc>
public static String HtmlEncode(String s) {
return HttpEncoder.Current.HtmlEncode(s);
}
System.Web.HttpServerUtility.HtmlEncode
/// <devdoc>
/// <para>
/// HTML
/// encodes a given string and
/// returns the encoded string.
/// </para>
/// </devdoc>
public string HtmlEncode(string s) {
return HttpUtility.HtmlEncode(s);
}
System.Net.WebUtility.HtmlEncode
public static string HtmlEncode(string value) {
if (String.IsNullOrEmpty(value)) {
return value;
}
// Don't create string writer if we don't have nothing to encode
int index = IndexOfHtmlEncodingChars(value, 0);
if (index == -1) {
return value;
}
StringWriter writer = new StringWriter(CultureInfo.InvariantCulture);
HtmlEncode(value, writer);
return writer.ToString();
}
So System.Web.HttpServerUtility.HtmlEncode actually uses System.Web.HttpUtility.HtmlEncode. If you drill into HttpEncoder.Current.HtmlEncode(s); this has the following code:
protected internal virtual void HtmlDecode(string value, TextWriter output) {
WebUtility.HtmlDecode(value, output);
}
Tl;Dr
So they all, ultimately, use System.Net.WebUtility.HtmlEncode. I guess the System.Web version are only there for backwards compatibillity. Hence the advice of using the System.Net version.

Related

Custom Control with Template that allows child control HTML Response to be manipulated

I'm trying to create an ASP.NET Custom Control that has uses ITemplate to allow the developer to place their own inner ASP/HTML controls in it. The purpose of the control is to parse the rendered HTML of the template contents and search/replace certain placeholder text that might appear (such as [Location], [Division], [FirstName]) with context specific values.
I'm struggling on how to "capture" the generated HTML and "replace" aspects of it as required prior to going out to the response object.
My thoughts are on the lines of using RenderContents(HtmlTextWriter output) to replace output with my own stream and get the controls to write to that. I can then do what I need to do with the rendered content before sending out to output.
However, I am unsure if this is the right method.
Here is a snippet of what I have:
/// <summary>
/// This custom control allows replacement fields to be picked up
/// </summary>
[DefaultProperty("Text")]
[ToolboxData("<{0}:ReplaceableText runat=\"server\" Text=\"[Text]\"></{0}:ReplaceableText>")]
public partial class ReplaceableText : WebControl
{
public ReplaceableText()
{
TokenReplacer = new TokenReplacer();
}
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[TemplateInstance(TemplateInstance.Single)]
public ITemplate Content { get; set; }
/// <summary>
/// The component the performs the replacement
/// </summary>
/// <remarks>
/// An alternative TokenReplacer component could be installed by the caller if required.
/// More typically, you will use the AddResolver(s) methods to apply callbacks to do the
/// actual replacement.
/// </remarks>
public ITokenReplacer TokenReplacer { get; set; }
public bool HasTokenReplacer { get { return (TokenReplacer != null && !DesignMode); } }
protected override void RenderContents(HtmlTextWriter output)
{
System.Diagnostics.Debug.WriteLine("RenderContents() enter");
if (HasTokenReplacer)
{
using (var memStream = new MemoryStream())
{
using (var sw = new StreamWriter(memStream))
{
using (var htw = new HtmlTextWriter(sw))
{
base.RenderContents(htw);
}
}
// !! memStream is still empty (0 bytes) !!
var text = Encoding.UTF8.GetString(memStream.GetBuffer());
var text2 = TokenReplacer.Convert(text);
output.Write(text2);
}
}
else
{
base.RenderContents(output);
}
output.Write(ConvertedText);
System.Diagnostics.Debug.WriteLine("RenderContents() exit");
}
protected override void CreateChildControls()
{
if (Content != null)
{
Controls.Clear();
Content.InstantiateIn(this); // !!! I need this to write to my own alternative temporary stream
}
base.CreateChildControls();
}
Unfortunately, I don't seem to get any mark-up deposited into my Memory Stream.
Silly sausage that I am, I hadn't put any controls into my Contents ITemplate.
This solution does appear to work well, just make sure you check that Controls.Count > 0 if you find your MemoryStream ends up with 0 bytes.

Get value from language specific resource file without changing the site language

I have several resource files, e.g.
default.aspx.resx, default.aspx.nl.resx, default.aspx.en.resx
Now when I'm on the Dutch domain the default.aspx.nl.resx is loaded.
But now I want to access the value from default.aspx.en.resx and get the English value belonging to name "title".
I can now achieve this by changing the current culture server-side, access the value and then change it back, like so:
Dim culture As CultureInfo = New CultureInfo("en")
Threading.Thread.CurrentThread.CurrentCulture = culture
Threading.Thread.CurrentThread.CurrentUICulture = culture
Dim title as String = GetLocalResourceObject("title")
culture = New CultureInfo("nl")
Threading.Thread.CurrentThread.CurrentCulture = culture
Threading.Thread.CurrentThread.CurrentUICulture = culture
But is there a better/faster way? Preferably without have to change the culture for the current thread, so I can just define which resource file I want to access and in which language?
You can add in parameter your targe culture
GetLocalResourceObject("title","YourCulture");
link : http://msdn.microsoft.com/fr-fr/library/ms149953.aspx
Edit: (Sorry I didn't know that you wanted another method different from this, but this was the only way that I managed to do:)
I managed to do this by doing:
var userLanguage = "en-US";
System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(userLanguage);
System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo(userLanguage);
HttpContext.GetGlobalResourceObject("MyAppResource", "KeyThatIWantToGet");
Where MyAppResource is how your .resx file is named and KeyThatIWantToGet explains itself.
When not using the HttpContext (general .NET applications) I use the following helper:
/// <summary>
/// Disposable class that lets us assume a specific culture while executing
/// a certain block of code. You'd typically use it like this:
///
/// using (new CultureContext("de"))
/// {
/// // Will return the German translation of "Please click here"
/// string text = SharedResource.Please_click_here;
/// }
/// </summary>
public class CultureContext : IDisposable
{
private readonly CultureInfo _previousCulture;
private readonly CultureInfo _previousUiCulture;
public CultureContext(CultureInfo culture)
{
// Save off the previous culture (we'll restore this on disposal)
_previousCulture = Thread.CurrentThread.CurrentCulture;
_previousUiCulture = Thread.CurrentThread.CurrentUICulture;
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
}
public CultureContext(string cultureCode)
: this(new CultureInfo(cultureCode))
{
}
/// <summary>
/// Syntactic sugar so that we can switch to a culture context as follows:
///
/// using (CultureContext.For("de"))
/// {
/// // Will return the German translation of "Please click here"
/// string text = SharedResource.Please_click_here;
/// }
/// </summary>
public static CultureContext For(string cultureCode)
{
return new CultureContext(cultureCode);
}
public void Dispose()
{
// Restore the culture settings that were in place before switching
// to this context
Thread.CurrentThread.CurrentCulture = _previousCulture;
Thread.CurrentThread.CurrentUICulture = _previousUiCulture;
}
}

Revalidate Model When Using WebAPI (TryValidateModel equivalent)

Using vanilla MVC I can revalidate my model with TryValidateModel. The TryValidateModel method doesn't seem to be applicable to WebAPI. How can I revalidate my model when using WebAPI?
I know it has been a while since this has been asked, but the problem is still valid. Thus i thought i should share my solution to this problem.
I decided to implement the TryValidateModel(object model) myself, based on the implementation in the System.Web.Mvc.Controller.cs
The problem is that the mvc's TryValidateModel internally used their own HttpContext and ModelState. If you go and compaire the two, they are very similar....
The be able to use our own HttpContext there exists a HttpContextWrapper that can be used for that.
And Since we have to clear our model state, it doesn't really matter that we use a different type of ModelState , as long as we get the desired result, thus i create a new ModelState object from the correct type...
I did add the error to the ModelState of the controller and not to the model state to the newly created ModelState , This seems to work just fine for me :)
Here is my code, that i just added to the controller...
do not forget to import the library...
using System.Web.ModelBinding;
protected internal bool TryValidateModel(object model)
{
return TryValidateModel(model, null /* prefix */);
}
protected internal bool TryValidateModel(object model, string prefix)
{
if (model == null)
{
throw new ArgumentNullException("model");
}
ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType());
var t = new ModelBindingExecutionContext(new HttpContextWrapper(HttpContext.Current), new System.Web.ModelBinding.ModelStateDictionary());
foreach (ModelValidationResult validationResult in ModelValidator.GetModelValidator(metadata, t).Validate(null))
{
ModelState.AddModelError(validationResult.MemberName, validationResult.Message);
}
return ModelState.IsValid;
}
I don't know when was it added but now there is Validate method on api controller.
ApiController.Validate Method (TEntity)
https://msdn.microsoft.com/en-us/library/dn573258%28v=vs.118%29.aspx
Based from rik-vanmechelen original answer, here is my version that relies on the services container exposed by Web API.
/// <summary>
/// Tries to validate the model.
/// </summary>
/// <param name="model">The model.</param>
/// <returns>Whether the model is valid or not.</returns>
protected internal bool TryValidateModel(object model)
{
if (model == null)
{
throw new ArgumentNullException("model");
}
var metadataProvider = Configuration.Services.GetService<System.Web.Http.Metadata.ModelMetadataProvider>();
var validatorProviders = Configuration.Services.GetServices<System.Web.Http.Validation.ModelValidatorProvider>();
var metadata = metadataProvider.GetMetadataForType(() => model, model.GetType());
ModelState.Clear();
var modelValidators = metadata.GetValidators(validatorProviders);
foreach (var validationResult in modelValidators.SelectMany(v => v.Validate(metadata, null)))
{
ModelState.AddModelError(validationResult.MemberName, validationResult.Message);
}
return ModelState.IsValid;
}
This uses the following simple extension methods to access the services :
/// <summary>
/// Services container extension methods.
/// </summary>
public static class ServicesContainerExtensions
{
/// <summary>
/// Gets the service.
/// </summary>
/// <typeparam name="TService">The type of the service.</typeparam>
/// <param name="services">The services.</param>
/// <returns>The service.</returns>
/// <exception cref="System.ArgumentNullException">services</exception>
public static TService GetService<TService>(this ServicesContainer services)
{
if (services == null)
{
throw new ArgumentNullException("services");
}
return (TService)((object)services.GetService(typeof(TService)));
}
/// <summary>
/// Gets the services.
/// </summary>
/// <typeparam name="TService">The type of the service.</typeparam>
/// <param name="services">The services.</param>
/// <returns>The services.</returns>
/// <exception cref="System.ArgumentNullException">services</exception>
public static IEnumerable<TService> GetServices<TService>(this ServicesContainer services)
{
if (services == null)
{
throw new ArgumentNullException("services");
}
return services.GetServices(typeof(TService)).Cast<TService>();
}
}
The advantage of using this method is that it reuses the MetadataProvider and ValidatorProvider(s) you have configured for your Web API application while the previous answer is retrieving the one configured in ASP.NET MVC.
ASP.NET MVC and WebAPI run through different pipelines.
Turns out TryValidateModel is not supported in WebAPI. There's a feature request over on CodePlex.

ASP.NET MVC - Session is null

I have an MVC3 application on .net4 that its session working in the dev Environment, but not in the production.
In the production I logged the sessionID and the it is the same in the moment I Set and Get from the session.
When I try to get the session I am getting Null Exception.
This is how I access the session:
public static class HandlersHttpStorage
{
public static string TestSession
{
get
{
return HttpContext.Current.Session["time"];//This is null
}
set
{
HttpContext.Current.Session.Add("time", value);//DateTime.Now.ToString()
}
}
}
What's makes me worried is that the behavior in the production is different than the development, even though the web.config is the same.
Solution 1:
Link: HttpContext.Current.Session is null when routing requests
Got it. Quite stupid, actually. It worked after I removed & added the SessionStateModule like so:
<configuration>
...
<system.webServer>
...
<modules>
<remove name="Session" />
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>
...
</modules>
</system.webServer>
</configuration>
Simply adding it won't work since "Session" should have already been defined in the machine.config.
Now, I wonder if that is the usual thing to do. It surely doesn't seem so since it seems so crude...
Solution 2:
Link: HttpContext.Current.Session null item
sessionKey may be changing, you probably only need to do:
HttpContext.Current.Session["CurrentUser"]
Or the session may be expiring, check the timeout:
http://msdn.microsoft.com/en-us/library/h6bb9cz9(VS.71).aspx
Or you may be setting the session value from somewhere else, normally i control access to Session/Context object through one property
static readonly string SESSION_CurrentUser = "CurrentUser";
public static SiteUser Create() {
SiteUser.Current = new SiteUser();
return SiteUser.Current;
}
public static SiteUser Current {
get {
if (HttpContext.Current.Session == null || HttpContext.Current.Session[SESSION_CurrentUser] == null) {
throw new SiteUserAutorizationExeption();
}
return HttpContext.Current.Session[SESSION_CurrentUser] as SiteUser;
}
set {
if (!HttpContext.Current.Session == null) {
HttpContext.Current.Session[SESSION_CurrentUser] = value;
}
}
}
Another possible cause/solution is that IE doesn't save cookies if the domain name has an underscore (because strictly speaking domain names can't have underscores, so you'll probably only encounter this in development), e.g. http://my_dev_server/DoesntWork. Chrome or Firefox should work in this scenario, and if you change the domain name you're using to not have an underscore problem solved.
Ref:
http://blog.smartbear.com/software-quality/internet-explorer-eats-cookies-with-underscores-in-the-hostname/
http://social.msdn.microsoft.com/Forums/ie/en-US/8e876e9e-b223-4f84-a5d1-1eda2c2bbdf4/ie7-cookie-issue-when-domain-name-has-underscore-character-in-it?forum=iewebdevelopment
For me, I found that HttpContext.Current was null, so I created it:
System.Web.HttpContext c = System.Web.HttpContext.Current;
And I passed that into my function that was in my other class, like this:
string myString = "Something to save";
SessionExtensions.SetDataToSession<string>(c, "MyKey1", myString);
I had actually wanted my function to be a real extension method off of Session like the one below, but what I found was this HttpSessionStateBase session was null, it would give the NullReferenceException when I tried to add anything to Session using it. So this:
public static class SessionExtensions
{
/// <summary>
/// Get value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="session"></param>
/// <param name="key"></param>
/// <returns></returns>
public static T GetDataFromSession<T>(this HttpSessionStateBase session, string key)
{
return (T)session[key];
}
/// <summary>
/// Set value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="session"></param>
/// <param name="key"></param>
/// <param name="value"></param>
public static void SetDataToSession<T>(this HttpSessionStateBase session, string key, object value)
{
session[key] = value;
}
}
That Microsoft had here: https://code.msdn.microsoft.com/How-to-create-and-access-447ada98 became this, instead:
public static class SessionExtensions
{
/// <summary>
/// Get value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="session"></param>
/// <param name="key"></param>
/// <returns></returns>
public static T GetDataFromSession<T>(HttpContext context, string key)
{
if (context != null && context.Session != null)
{
context.Session.Abandon();
}
return (T)context.Session[key];
}
/// <summary>
/// Set value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="session"></param>
/// <param name="key"></param>
/// <param name="value"></param>
public static void SetDataToSession<T>(HttpContext context, string key, object value)
{
context.Session[key] = value;
}
}
And I was able to retrieve my data like this:
System.Web.HttpContext c = System.Web.HttpContext.Current;
string myString = SessionExtensions.GetDataFromSession<string>(c, "MyKey1");
And, of course, since HttpContext.Current and Session now exists, I was able to even simplify that to be:
string myString = Session["MyKey1"].ToString();
If this had been object, you would put the object's type in place of <string> in the SetDataToSession()
function:
List<string> myStringList = new List<string>();
myStringList.Add("Something to save");
SessionExtensions.SetDataToSession<List<string>>(c, "MyKey1", myStringList);
And to retrieve it:
System.Web.HttpContext c = System.Web.HttpContext.Current;
List<string> myStringList = SessionExtensions.GetDataFromSession<List<string>>(c, "MyKey1");
or simply:
List<string> myStringList = (List<string>)Session["MyKey1"];

Similar method to ResolveUrl for using from a static class?

I'm building a WebPart for Microsoft SharePoint 2010.
Which method could I use from a static class that does the same than ResolveUrl?
Take a look at this:
http://msdn.microsoft.com/en-us/library/system.web.virtualpathutility.aspx
You could make use of the ToAbsolute or ToAppRelative methods in order to simulate the functionality
http://www.west-wind.com/weblog/posts/2007/Sep/18/ResolveUrl-without-Page (in the comments)
/// <summary>
/// Returns a site relative HTTP path from a partial path starting out with a ~.
/// Same syntax that ASP.Net internally supports but this method can be used
/// outside of the Page framework.
///
/// Works like Control.ResolveUrl including support for ~ syntax
/// but returns an absolute URL.
/// </summary>
/// <param name="originalUrl">Any Url including those starting with ~</param>
/// <returns>relative url</returns>
public static string ResolveUrl(string originalUrl)
{
if (string.IsNullOrEmpty(originalUrl))
return originalUrl;
// *** Absolute path - just return
if (IsAbsolutePath(originalUrl))
return originalUrl;
// *** We don't start with the '~' -> we don't process the Url
if (!originalUrl.StartsWith("~"))
return originalUrl;
// *** Fix up path for ~ root app dir directory
// VirtualPathUtility blows up if there is a
// query string, so we have to account for this.
int queryStringStartIndex = originalUrl.IndexOf('?');
if (queryStringStartIndex != -1)
{
string queryString = originalUrl.Substring(queryStringStartIndex);
string baseUrl = originalUrl.Substring(0, queryStringStartIndex);
return string.Concat(
VirtualPathUtility.ToAbsolute(baseUrl),
queryString);
}
else
{
return VirtualPathUtility.ToAbsolute(originalUrl);
}
}
/// <summary>
/// This method returns a fully qualified absolute server Url which includes
/// the protocol, server, port in addition to the server relative Url.
///
/// Works like Control.ResolveUrl including support for ~ syntax
/// but returns an absolute URL.
/// </summary>
/// <param name="ServerUrl">Any Url, either App relative or fully qualified</param>
/// <param name="forceHttps">if true forces the url to use https</param>
/// <returns></returns>
public static string ResolveServerUrl(string serverUrl, bool forceHttps)
{
if (string.IsNullOrEmpty(serverUrl))
return serverUrl;
// *** Is it already an absolute Url?
if(IsAbsolutePath(serverUrl))
return serverUrl;
string newServerUrl = ResolveUrl(serverUrl);
Uri result = new Uri(HttpContext.Current.Request.Url, newServerUrl);
if (!forceHttps)
return result.ToString();
else
return ForceUriToHttps(result).ToString();
}
/// <summary>
/// This method returns a fully qualified absolute server Url which includes
/// the protocol, server, port in addition to the server relative Url.
///
/// It work like Page.ResolveUrl, but adds these to the beginning.
/// This method is useful for generating Urls for AJAX methods
/// </summary>
/// <param name="ServerUrl">Any Url, either App relative or fully qualified</param>
/// <returns></returns>
public static string ResolveServerUrl(string serverUrl)
{
return ResolveServerUrl(serverUrl, false);
}
/// <summary>
/// Forces the Uri to use https
/// </summary>
private static Uri ForceUriToHttps(Uri uri)
{
// ** Re-write Url using builder.
UriBuilder builder = new UriBuilder(uri);
builder.Scheme = Uri.UriSchemeHttps;
builder.Port = 443;
return builder.Uri;
}
private static bool IsAbsolutePath(string originalUrl)
{
// *** Absolute path - just return
int IndexOfSlashes = originalUrl.IndexOf("://");
int IndexOfQuestionMarks = originalUrl.IndexOf("?");
if (IndexOfSlashes > -1 &&
(IndexOfQuestionMarks < 0 ||
(IndexOfQuestionMarks > -1 && IndexOfQuestionMarks > IndexOfSlashes)
)
)
return true;
return false;
}

Resources