Importance of understanding ASP.NET

These days I’m pretty annoyed by my own programming work. I’ve reviewed my own work more then once and found out that I’m definitelly not as productive as I would expect from myself. And, maybe more important, I don’t deliver the quality I expect I should be able to do so.

Looking futher at it, I’ve foudn out that my knowledge of ASP.NET is far below the required level of good webdeveloper. But uhmm.. Alex we tought you were the guru? Well, thatterm is way overkill. I actually think my brother and sister programmers in the world do agree with me as I say that about 90% of them doesn’t have the required knowledge for the job they are doing. They might be skilled enough, but the exact knowledge is missing. 

So I’ve given myself 5 improvements tasks which should be ready by the end of August:

  1. For general code tasks, make guidelines. This includes
    • Dividing classes in regions
    • Splitting of class-files / allowing of more stuff within a class of a file
    • Enums vs classes
    • Usage of helpers
    • Defining what is self explaining and what should be comemted(for example, the ‘e’ in events is pretty self explaining)
    • Find out in which case you should use Html- and WebControls
  2. Get through the whole process of databinding. This includes stuff like creating inherited controls from repeaters and gridviews.
  3. Make the whole process of retrieving data out of Sitecore(or any other system) to the final display-steps visible for myself any other developer
  4. Become more familiar with stuff like ASP.NET theming and skinning
  5. Make a transparatn solution for databinding within Sitecore wether my data is displayed by XSLT of C#

I know, I might be a bit to critical to myself. But sometimes you’ve to stop innovating and stabalize your roots. Results on the above quests will be published here.

Sitecore seems to listen to feedback

Just foudn out that Sitecore really listens to feedback :). A while ago I sent the developer my own URLUtil as Item.Path.GetFriendlyUrl() seemed to create broken links for more advanced site-configs.
So I spent a whole day on writing this util and look, the latest build(earlier build might have it too) has the following overloads:

  1. GetFriendlyUrl() //Default, no interface changes 
  2. GetFriendlyUrl(bool shorten) //Default, no interface changes
  3. GetFriendlyUrl(string sitename) //Resolve url by site
  4. GetFriendlyUrl(string startPath, string virtualFolder) //Same a above but now you can control your own startath and virtual folder

Goo to see that Sitecore actually listens to this kind of feedback. Altough I remember I had a very strong case, I didn’ t expect them to accelarate this quick without breaking any interfaces at all :).
Note: haven’t tested  it fully, but it seems to work :).

SQL 2000 and 2005 are causing problems with 5.3.1

For 2 days I’ve got this extreme ugly dialog when deleting items after an upgrade from 5.3.0 to 5.3.1:

scerror

Today I’ve found out what was the problem. We are running on SQL 2000 here at the customer. First I’ve tested my upgrade on my local machine on SQL 2005 Express. And in that way I introduced the pain :(. Sitecore delivers databases for SQL Server 2005 with the field called ‘Blob’ with as datatype nvarchar(max) in the tables ‘VersionedFields’, ‘UnversionedFields’ and ‘SharedFields’.
Sitecore 5.3.0 on SQL 2000 uses ntext instead. Comparing ntext’s results in the above message. Alter your tables to nvarchar(max-length-sql2000=4000) and your problem will be resolved. 🙂 Altough I’m not really sure this is the 100% best solution, it works :).
For more information about this kind of length and type issues, take a look here.

Field Security vs Security

On the SDN5-forum, Kerry Bellerose posted an extremely usefull reply where he explains what the difference is between Field Security and Security. He also explains why they have chosen to implement it that way:

The difference in setting field security from item security reflects the fact that field security is actually different from item security.
In general, users who are given read/write access to an item, automatically have read/write access to all the fields in that item.
This covers the great majority of items and fields, so it’s nice that things work this way.
On the other hand, when business rules suggest that only a limited set of people who have read/write access to an item should also have read/write access to a given field, Sitecore’s approach is designed to limit the number of security configuration changes required.
For example, lets say we have a field called Foo that Authors should not even see (even if they have read/write access to an item), the Sales People should see, but should not be change, and that Managers should be able to see and change.
When we define the field Foo, the field inherits the Read / Write access rights assigned to the user, be it Author, Sales Person, or Manager.
When we begin assigning field security to Foo for any role, however, this breaks the inheritance of access rights from item to field.  In other words, as soon as we assign field security to Foo for any given users or roles, read and write access defaults to denied for all other users and roles.
This may seem complex until you understand it, but you do understand it you can see that the following is true:

  • Generally you can ignore field security and focus on item security (assuming that having access to an item also gives the same access to fields).
  • When a limited group of users/roles should have access to a specific field, you only need to grant access to those users/roles, you never need to deny read/write access to a field (because as soon as you explicitly Allow access for anyone, everyone else defaults to Denied access).

So in our example above, to meet our business requirements, we would do the following:

  • Allow Read access on Foo for Sales People
  • Allow Read and Write access on Foo to Managers

This would implicitly deny read and write access to authors and deny write access to Sales People.
I hope this clears things up!

 Kerry Bellerose,
Solution Architect, Sitecore Corp.
Blog: kerrybellerose.blogspot.com
Web: www.sitecore.net

Thank you Kerry! For the full thread take a look here.

Web.config tweaks in latest build

This might take a lot of work away :). Here’s the web.config changelog between 5.3.1 build 070515 and 070628:

Changes:

  • All tags are not shortened. For example:  <sc include …></sc:include> is now <sc.include … />
    Which means that the file is around 510 lines shorter
  • Physical paths in scheduling and log4net sections are now replaced by $(dataFolder)
  • Physical paths in the settings ‘Licensefile’, ‘LogFile’and ‘PackagePath’ are now replaced by $(dataFolder)
  • Sites can have an additional attribute:
    disableXmlControls: If set to true, loading Xml Controls as pages will be disabled.
  • The setting ‘HtmlEditor.SupportWebControls’ is introduced(as described in the changelog:
          <!–  HTML EDITOR SUPPORT WEB CONTROLS
                Indicates if the Html Editor supports web controls. If true, Web Controls are shown as yellow boxes.
                Default value: true
          –>
          <setting name=”HtmlEditor.SupportWebControls” value=”true” />

Strange stuff:
Take a look at the default values ;-)… Will report it to Sitecore Support later on today.

      <!–  COUNTERS INSTANCE NAME
            Indicates the instance name to assign to counters.
            Default value: [empty string]
      –>
      <setting name=”Counters.InstanceName” value=”Default” />
      <!–  RESET COUNTERS
            Indicates if performance counters will be reset on Sitecore startup.
            Default value: false
      –>
      <setting name=”Counters.ResetOnStartup” value=”true” />

Thank you WinMerge for helping me :).

Update: The other config-files are 100% identical. I’m talking about the /App_Config/-files

Another Sitecore build, the June(06) version

Yesterday, Sitecore released a new version of their main product. It’s th build of the 28 of june(5.3.1 build 07(y)06(m)28(d)).
A quite huge chnagelog has posted again. So far I’ve seen by now you can upgrade painless to this version. Altough I haven’t got a change to compare stuff like the web.config. Here’s a cropped list of fixed bugs/enhancements:

  • Workflow auto-publish action of media item does not publish media/blob content.
  • Access to items in different languages is inconsistent. User rights are denied at random for users when accessing items in new content languages created in Sitecore, while access to items in the primary (en) language is always maintained.
  • Virtual user login in Page_Load event of loginPage doesn’t work.
  • AJAX works fine in WebEdit mode even if a content marker is placed on the layout.
  • Any event of any ASP.NET control does not work on login page that is specified in the loginPage parameter for

    <site name = “website” ! />

  • Publishing of media items takes too long if the replacer mode is on in the web.config file and there are a lot of replacements. The replacer now skips the blob fields.
  • AJAX works fine on the Sitecore front-end now.
  • Confirmation window “This operation may take a long time to complete !” appears when a master with a lot of references is being renamed.

As you might noticed, this is the third release in 3 months. At this moment, we’ve got over 6 Sitecore project running and another 25 which are maintained by our support team. You can imagine what kind of pain there is when we haev to upgrade every time.
Last week we’ve spent a lot of time on a dramatic merge from 3 different branches. It wasn’t all because of the new release of Sitecore, that was just another problem :(. But as the product Sitecore grows and the solution become bigger and bigger, upgradign becomes more and more a problem. So we’ve asked Sitecore last week to think better about release management strategy. I was kinda happy when Lars told me that someone is actually working on a better release management and also on better tools to support the partners. You should think about tools like ‘upgrade packagers’, ‘sttings comparers’, etc.
When you’ve got problems with upgrading between version as well and when you can describe the pain, please don’t hestitate to do this! Just create a support-ticket and they will redirect you message to the right person inside Sitecore. The more response, the faster Sitecore’s reaction. Thank you!

Sick of tagging

One thing I definitelly hate about the concept web 2.0 is tagging. I hate those unused links at the bottom of blogs, articles, etc. Why? Why do not use tags as an internal thing, but do not publish those incredible irritating  are unstructured mess below or on the right side of a piece of content… It’s disturbing and nobody clicks on uncategorized messy words. Well… they might be interesting when well selecting and displayed in a well-designed way, but all of you know better. These days tags are a total mess!

Just had to share this with the world… Sorry tag-addicts! I’m just sick of them! 😛

Enable downloading from the Media Library

This post applies to Sitecore 5.3.1:

Two weeks ago I had to create a simple page which allowed users to download any file from the Media Library. And as the customer might provide images, pdfs, etc, and you don’t know which viewer the visitor uses, you want to force them to download the file. I’ve created a pipeline processor who handles this for you, just by adding dl=true to your url. But wait hey… you can define this in your web.config?! Yeah that’s true, but this would mean you have to download every type of file, I’m sure our customer doesn’t want that. So here’s my processor:

    1     public class DownloadProcessor

    2     {

    3         public void Process(GetMediaStreamPipelineArgs args)

    4         {

    5             if(GetBoolFromQueryString(“dl”, false))

    6             {

    7                 WriteCacheHeaders(args);

    8             }

    9         }

   10 

   11         #region Private static method(-s)

   12         private static void WriteCacheHeaders(GetMediaStreamPipelineArgs args)

   13         {

   14             //Clear all headers to make sure any others are sent to the client

   15             args.OutputStream.Headers.Headers.Clear();

   16 

   17             //Sent the force download type to your client

   18             args.OutputStream.Headers.Add(“Content-Type”, “application/force-download”);

   19 

   20             //Pass the right username

   21             args.OutputStream.Headers.Add(“Content-Disposition”, “attachment; filename=” + GetFileName(args.MediaData.MediaItem));

   22 

   23             //Add the length of the file in bytes

   24             args.OutputStream.Headers.Add(“Content-Length”,  args.MediaData.MediaItem.Size.ToString());

   25 

   26             //Make the client aware of the binary stream

   27             args.OutputStream.Headers.Add(“Content-Transfer-Encoding”, “binary”);

   28         }

   29 

   30         private static string GetFileName(MediaItem mi)

   31         {

   32             //Get the item name

   33             string workName = mi.Name;

   34 

   35             //When the file  ends with its own extention, try to cut this part of

   36             if(workName.EndsWith(mi.Extension, StringComparison.CurrentCultureIgnoreCase))

   37             {

   38                 workName = workName.Substring(0, workName.Length – mi.Extension.Length).Trim();

   39             }

   40 

   41             //Replace the spaces with undersquares so browser compatibility is ensured

   42             workName = workName.Replace(‘ ‘, ‘_’);

   43 

   44             //Add the extension to the file

   45             workName = string.Concat(workName, “.”, mi.Extension);

   46 

   47             return workName;

   48         }

   49 

   50         private static bool GetBoolFromQueryString(string qsName, bool defaultValue)

   51         {

   52             string qsValue = global::Sitecore.Context.Request.QueryString.Get(qsName);

   53             if(!string.IsNullOrEmpty(qsValue))

   54             {

   55                 bool parsedValue;

   56                 if(bool.TryParse(qsValue, out parsedValue))

   57                 {

   58                     return parsedValue;

   59                 }

   60             }

   61             return defaultValue;

   62         }

   63         #endregion

   64     }

Configuring can be done in the getMediaStream-pipeline.

Note: Haven’t tested this solution with files larger then 2 Mb. Make sure to do some representive load testing when you are going to use this solution for larger files.