04 September, 2012

Add and remove values in User Profile criteria


I was asked by a customer to add "Country" to User Profile criteria as it was not in the dropdown list.

User Profile dropdown list














I haven't used Visitor Groups before and was a bit surprised that that the values in the dropdown list were shorter than expected. I thought the list was populated from Personalization in EPiServer and could be configured in SqlProfile in web.config. 

profile section i web.config














Just to be sure I added a value to SqlProfile and it appeared in the dropdown list after a reload. So my first thought was right, but what had happened with the removed values? I now suspected that EPiServer for some reason or another had chosen to filter the list. Loading up episerver.dll in dotPeek revealed the truth. In the initializing code the class added an ignore list and the missing values where added to the ignore list. The next question was how to enable those values. After contact with EPiServer support they provided me with an easy way to control the ignore list.

The way to do it is to call the criterion in global.asax.cs, I used application_start. Here are some examples:

1. To remove all values in the list, e.g. show all values:
protected void Application_Start(Object sender, EventArgs e)
{          EPiServer.Personalization.VisitorGroups.Criteria.UserProfileCriterion.IgnoreUserProfileProperties.Clear();
        }

2. To remove a specific value, e.g. show "Country":
protected void Application_Start(Object sender, EventArgs e)
{            EPiServer.Personalization.VisitorGroups.Criteria.UserProfileCriterion.IgnoreUserProfileProperties.Remove("Country");
        }

3. To add a specific value, e.g. hide "FirstName":
protected void Application_Start(Object sender, EventArgs e)
{            EPiServer.Personalization.VisitorGroups.Criteria.UserProfileCriterion.IgnoreUserProfileProperties.Add("FirstName");
        }
This should be useful for hiding the values that make no sense for creating Visitor Groups, just as EPiServer did with their default values. Although I think they probably removed some useful values, like "Country".

The complete list of default properties are:

    IgnoreUserProfileProperties.Add("SubscriptionInfo");
    IgnoreUserProfileProperties.Add("CustomExplorerTreePanel");
    IgnoreUserProfileProperties.Add("FileManagerFavourites");
    IgnoreUserProfileProperties.Add("EditTreeSettings");
    IgnoreUserProfileProperties.Add("ClientToolsActivationKey");
    IgnoreUserProfileProperties.Add("FrameworkName");
    IgnoreUserProfileProperties.Add("ZipCode");
    IgnoreUserProfileProperties.Add("Locality");
    IgnoreUserProfileProperties.Add("Language");
    IgnoreUserProfileProperties.Add("Country");

22 August, 2012

.Net and HTML 4.01


It's not that easy to make .Net produce valid HTML 4.01.

One of the problems is that even if you write <br> in your webform .Net will "correct" it to <br /> before the html-stream is sent to the webserver. (it's the same with all "not closed" html-tags)

Another problem is that .Net adds tags for Viewstate that has ID's that not conform to the HTML 4.01 standard.(__VIEWSTATE and __EVENTVALIDATION)

This was an terrible issue for me since I have a customer that requires HTML 4.01 that validates to the W3C validator.

After some massive googling I found an article with a suggestion on how to manipulate the html-stream before it reaches the webserver. The article is written by Rick Strahl and can be found here: Capturing and Transforming ASP.NET Output with Response.Filter

This is done by creating a response filter.
The code for the filter can be found here

I implemented it in the code behind of my master page like this:


protected override void OnInit(System.EventArgs e)
{
    base.OnInit(e);
    //To remove warning about Byte Order Mark
    Response.ContentEncoding = new System.Text.UTF8Encoding(false);

    ResponseFilterStream filter = new ResponseFilterStream(Response.Filter);
    filter.TransformString += filter_TransformString;
    Response.Filter = filter; 
}

string filter_TransformString(string output)
{
    return MakeHTML4_01(output);
}

/// <summary>
/// Tries to adjust output to conform to HTML4.01 standard
/// </summary>
/// <param name="output">The output adjusted to conform to HTML4.01 standard</param>
/// <returns></returns>
private string MakeHTML4_01(string output)
{
    output = output.Replace("id=\"__VIEWSTATE\"""id=\"VIEWSTATE\"");
    output = output.Replace("id=\"__EVENTVALIDATION\"""id=\"EVENTVALIDATION\"");
    return output.Replace("/>"">");
}


(Off course it would be faster to use regexp to do the replacements, but I wanted the example to be clean.)