Showing posts with label Linq2Sql. Show all posts
Showing posts with label Linq2Sql. Show all posts

Thursday, January 7, 2010

Adventures while building a Silverlight Enterprise application part #31

Today we want to look at an example I ran into where taking the time to think of good names for everything in your code can save the day.

First I'd like to explain my long absence. The last months of 2009 where obviously very busy for us, but besides that I've been moving to another house (sort of) and I've had a week off to finally have a bit of a rest. But on to more important things.

The story
For our new application I was working on some authorization logic in the service layer. We have a class that represents a user. I was implementing a method called IsUserAuthorized. When writing the virtual version of this in the base class, so all other business objects would be able to implement this behavior, I was thinking "I need to have the Guid identifying the user that should be authorized" and I named that parameter userId. Makes sense, right?

The problem
As I was implementing this method in the User class I simply used IntelliSense to generate the method stub for me and I started writing code. This is part of what I came up with at first:

var authorisations = from item in context.UserGroupAuthorisation
where context.UserGroupAuthorisation.Any(
i => i.Group.GroupId == item.Group.GroupId && i.Users.UserId == userId)
&& item.Users.UserId == this.UserId
select item;

It might seem a bit complex, but let me explain. What I'm doing here is, Because a user is a member of a group that user can also see other users in that group. So the determine if a user can see the user at hand I need to know what groups the user is a member of and see if any of these groups overlap with the groups of the user at hand. Basically, if the above query returns anything the user is allowed to request this user.

The solution
Now, from both the code and the explanation, you can see that it gets confusing, because we have two users in this story, who fill in different roles in this story. I was reading back my code to determine if I had done this the right way and I couldn't really grasp it. A simple tweak made a world of difference. Look at the revised code:

var authorisations = from item in context.UserGroupAuthorisation
where context.UserGroupAuthorisation.Any(
i => i.Group.GroupId == item.Group.GroupId && i.Users.UserId == requestingUserId)
&& item.Users.UserId == this.UserId
select item;

As you can see I renamed the parameter userId to requestingUserId. This has a more then expected impact on the readability of this code. Now you can see that our Lambda expression gets all the group authorizations for the requesting user and links them to the group authorizations in the query. Then all that is needed is to take only the authorizations for the user at hand, explicitly called by this.UserId so it's completely different from the parameter requestingUserId.

The conclusion
As you can see from the above example, having decent names, even for something small as a method parameter, can make all the difference when it comes to understanding code. May we all come up with better names!

Friday, August 21, 2009

Pimpin' the blog part #3

Today we'll look at how I've build my own RSS feed in ASP.NET 3.5 and using Linq2SQL.

Before we dive into that, I would like to announce that my articles are now fed trough this RSS feed to CodeProject.com. The latest of my articles (at least most of them) are now available there too. I would like to thank Shawn Ewington from the CodeProject for working with me an supporting me, so I could achieve this bigger audience.

Now, back to business. As you may remember from part #1 of this series, the first goal for me was to customize my RSS feed, so I could add categories to my feed without messing up my navigation. I also lined out the fases I would go trough to get to my new and improved blog and after leaving you in part #2 I reached step three, wich means I now have my content up and running in a database on the new platform and it gets updated trough RSS from the Blogger.com platform.

I've now used the code I wrote for part #2 as a starting point for building the new RSS feed. As I had a great experience with the SyndicationFeed class for parsing a feed, I figured I might as well use it to publish a feed as well. The general steps needed to get the feed published are these:
  1. Setup a SyndicationFeed object with some general information like title, author, etc.
  2. Load the articles from the database and convert them into feed items
  3. Publish the feed
The first step actually did take some work as I wanted a lot of things to be configurable trough my web.config and also it takes some extra code to set most of the properties. To help me out with loading these settings I've build a SyndicationSettings class which holds the constants for the config key names and accesses the ConfigurationManager to get the actual values. I've made it a static class, so it is as easy to use as possible.

Setting up the feed is done in the SetupFeed method:
private static SyndicationFeed SetupFeed()
{
SyndicationFeed feed = new SyndicationFeed();
SyndicationPerson person = new SyndicationPerson(SyndicationSettings.SyndicationPersonEmail,
SyndicationSettings.SyndicationPersonName, SyndicationSettings.SyndicationPersonUrl);
feed.Authors.Add(person);
feed.Contributors.Add(person);

feed.Categories.Add(new SyndicationCategory("CodeProject"));

feed.Copyright = new TextSyndicationContent(SyndicationSettings.Copyright,
TextSyndicationContentKind.Plaintext);
feed.Description = new TextSyndicationContent(SyndicationSettings.Description);
feed.Generator = GeneratorName;
feed.Id = SyndicationSettings.FeedId;
feed.Links.Add(new SyndicationLink(new Uri(SyndicationSettings.HomePageLink)));
feed.Title = new TextSyndicationContent(SyndicationSettings.FeedTitle);
return feed;
}

As you can see I've created a SyndicationPerson object to be reused both as the author and a contributor.

The next step is to load the articles from the database and convert them into SyndicationItem instances. First I needed to get them from the database, for which I expanded the functionality of the StorageConnection class I wrote in part #2. The basics are pretty straight forward, but as I was still fairly new to Linq2Sql I struggled a bit with getting the categories to load with the data automatically. Here is the GetArticles method from the StorageConnection:
public static List<Article> GetArticles(bool loadCategories, int maxNumberOfArticles)
{
List<Article> articles = new List<Article>();

DataLoadOptions dataLoadOptions = new DataLoadOptions();
if (loadCategories)
{
dataLoadOptions.LoadWith<Article>(article => article.ArticleCategories);
dataLoadOptions.LoadWith<ArticleCategory>(articleCategory => articleCategory.Category);
}
using (Developers42_DataClassesDataContext context = new Developers42_DataClassesDataContext())
{
context.LoadOptions = dataLoadOptions;
articles = context.Articles.OrderByDescending(article => article.PublicationDate).Take(
maxNumberOfArticles).ToList();
}
return articles;
}

I've used the LoadOptions property to let the Linq2Sql framework know I want to include both the ArticleCategory and the Article entities while loading the Articles. Further more I used the OrderByDescending method to specify that I want the Articles on PublicationDate and I used the Take method to specify that I only want to load up to 25 articles at a time.
Converting the Article objects into SyndicationItem objects is as simple as calling the constructor including most of the properties and then adding the categories.

As the final step all that needs to be done is to publish the result to the client. To do this, we need to first clear the existing response buffer, to make sure we don't send anything already in the template. Next we can simply create and XmlWriter that has the response stream as the underlying stream and call the SaveToRss20 method on the SyndicationFeed with the XmlWriter as a parameter. This is how the code looks:

XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
XmlWriter writer = XmlWriter.Create(Page.Response.OutputStream, settings);

Page.Response.ClearContent();
feed.SaveAsRss20(writer);
writer.Flush();

As you may have noticed, building your own RSS feed is easy when using the SyndicationFeed class. To help you even further I've included a link to the source here. It also includes the code from part #2 for parsing an RSS feed.

I hope this post was useful to you. Next time we'll look at parts of the new version of the Developers 42 blog.