Sitecore and FxCop – Accessing Raw Field Values

This is the second post in the Sitecore and FxCop series. Read the first post here. 

The second rule I came up with has to do with how to access raw field values.

Let’s say we want to grab the raw value of the Title field on the current item. There’s two different options we can use:

var fieldValue = Sitecore.Context.Item.Fields["Title"].Value;

Which really isn’t correct – what if there is no Title field? Or what if we have a typo in the fieldname? We’d end up with a NullReferenceException. To get around this we could use:

var field = Sitecore.Context.Item.Fields["Title"];
if (field != null)
{
    var fieldValue = field.Value;
}

The other option is:

var fieldValue = Sitecore.Context.Item["Title"];

In this case, if there is no Title field, or if we have a typo in the fieldname, we’d get an empty string.

To be absolutely clear, this is only to get the raw field value.  To display it on the front end side of things usually one would use a FieldRenderer instead anyway.

So, the second option is shorter and safer. Seems like a good thing to check for.

In the Rules.xml we need to add the following to our existing <Rules> definitions:

<Rule TypeName="AccessRawFieldValueProperly" Category="Sitecore.BestPractice" CheckId="SC002">
  <Name>Get the raw field value properly</Name>
  <Description>
    Accessing the raw field value through the Field property on the item can throw NullReferenceExceptions when
    the fieldname changes, the field doesn't exist or there's a misspelling in the fieldname.
  </Description>
  <Url />
  <Resolution>
    Raw field value is accessed by Item.Fields["Fieldname"].Value. Raw field values should be accessed by Item["fieldname"]
  </Resolution>
  <Email />
  <MessageLevel Certainty="70">Error</MessageLevel>
  <FixCategories>Breaking</FixCategories>
  <Owner />
</Rule>

As always, the TypeName needs to match the name of the class.

internal sealed class AccessRawFieldValueProperly : BaseRule
{
  public AccessRawFieldValueProperly() : base("AccesssRawFieldValueProperly")
  {
  }

  public override ProblemCollection Check(Member member)
  {
    var method = member as Method;
    if (method != null)
    {
      VisitStatements(method.Body.Statements);
    }

    return this.Problems;
  }

  public override void VisitMethodCall(MethodCall methodCall)
  {
    var memberBinding = methodCall.Callee as MemberBinding;
    if (memberBinding != null)
    {
      var methodCalled = memberBinding.BoundMember as Method;
      if (methodCalled != null)
      {
        if (methodCalled.FullName == "Sitecore.Data.Fields.Field.get_Value")
        {
          Problems.Add(new Problem(GetResolution(), methodCall));
        }
      }
    }

    base.VisitMethodCall(methodCall);
  }
}

Then, when I have a solution with the following code:

public void SomeMethod()
{
  var rawFieldValue1 = Sitecore.Context.Item.Fields["fieldname"].Value;
  var rawFieldValue2 = Sitecore.Context.Item["fieldname"];
  var field = Sitecore.Context.Fields["fieldname"];
}

I would expect to get one error in FxCop. I still want to be able to grab the actual field of course.

The correct error showing up

When I have a couple more rules in here I’m thinking about releasing this to the Sitecore Marketplace, so your input is very welcome. Is there any rule you would like to see added?

Advertisements

11 thoughts on “Sitecore and FxCop – Accessing Raw Field Values

  1. Hi Johannes,

    I think there is a small mistake in the example code.
    You’re calling VisitStatements() from the Check() method, but the example only defines a VisitMethodCall() method.

    Excellent blog series so far.
    Really like your idea!

    Cheers,
    Ruud

  2. Hey Johannes,

    I’ve also been interested in using FXCop to enforce Sitecore standards.

    What are your thoughts on enforcing only one way to access the database? For example let’s look at 3 different lines of code I’ve see various developers do (sometimes on the same project):

    Sitecore.Configuration.Factory.GetDatabase(“master”);
    Sitecore.Configuration.Factory.GetDatabase(“web”);
    Sitecore.Context.Database

    To you, which would be the “correct” or recommended way to access the database (for example accessing items) throughout c#/sitecore architecture?

    • Hi Mike,

      It depends on what you want to accomplish.
      Personally, I tend to use Sitecore.Context.Database (well, or Sitecore.Context.ContentDatabase if it’s not null). That way, one doesn’t need to worry about PageMode when working with Context.Database. I also don’t like to have to worry about It also gets around the fact of accidentally calling the Master database in a Web environment and vice versa.

      Of course, when working with web services or when I want to get a specific database, I’ll have to use Factory.GetDatabase.
      However, I don’t usually use other methods (such as Sitecore.Data.Database.GetDatabase(“master”)).

      In short, just working with items I tend to use Sitecore.Context.Database, unless I need to target a specific database, in which case I use the Factory.

      • Thanks for the reply. So I was under the same assumption that generally when within a context in Sitecore code referencing an item via the master/web database (hard-coded string ‘web’ or ‘master’ passed into the constructor) could result in problems and instead using Sitecore.Context.Database would be ideal.

        ..As a result, I’m exploring writing the checking for this in FXCop so I can see when developers do it. What do you think?

      • Yeah, it might be a good rule – as long as you keep in mind that there’s actual correct usage of them.

        On a side note, I will be releasing this code as a shared source module as well, when I have a couple of other rules in there.

  3. Thanks Trayek. Generally I want my developers to use Sitecore.Context.Database in ALL cases unless a webservice, right?

    Out of pure curiosity, what other rules have you been thinking about? If I develop any of my own, I will tell you right away so you can determine if they’re worthy for your module 🙂

  4. Pingback: Sitecore and FxCop – Field Rules | Sitecore and such

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s