Attention: We are retiring the ASP.NET Community Blogs. Learn more >

Fear and Loathing

Gonzo blogging from the Annie Leibovitz of the software development world.

  • More SharePoint Forums Web Part Fun

    Just a minor glitch and a quick update. Some people are experiencing problems with security and installation of the web part. Primarily this is usually caused by the AppPool id for the SharePoint site to be running as NETWORK_SERVICE (which generally doesn’t have any privileges). If you use a local or domain account, this problem should go away (and is a recommended setup anyways).

    Also on the point of hosting the Web Part. I built it so it can live anywhere (a portal area, a WSS site, a document library) however for Web Part Pages in Document Libraries, the forums are having a little trouble figuring out it’s own home. After posting a message or editing something in the Admin panel, you might find it “kicks” you out to the Document Library or the main site. I’ll see about fixing this in a drop later this week or early next (don’t want to do a release just for one bug) so if you can either host it on a WSS site (on the main page) or a Portal area, you’ll be laughing. Otherwise you might think things are behaving weirdly.

    Weirdly?

    Is that a word? Sounds like a member of the episode of the Flintstones where they had the creepy family.

    Weirdly Gruesome.

    Odd.

  • Forum irregularities

    First off, sorry if this week is going to be filled with posts about the forum web part. It's popular and I just want to make sure everyone gets it, gets it installed, and gets it working in their environment.

    There's some irregularity with adding the web part to a portal vs. a WSS site. The web part is designed for both but for some odd reason it behaves weirdly (yes, that's a technical term) when deployed to a portal (probably due to the fact that the user lists are different).

    In any case, you might get an error loading the web part, but just refresh the page (by visiting the link again) where you deployed it and it should appear normally.

    If you're an admin on a portal area and don't see the Admin option, email me and I'll send you info on how to access the list directly (if you haven't already figured it out) and you can edit yourself to be an admin (you still need update rights in that area to do this so it's not open).

    Again, most of the issues are due to the fact that all actions in the web part (creating lists, adding/editing entries across multiple lists) are always done by the AppPool user and not the user in the system (although the Web Part keeps track of who you are and distinguishes between you and the AppPool user). This was done just because I didn't want you, the user, to have to maintain security on 5 different lists.

    I think I made the right decision, but there's some fancy footwork that needs to be cleaned up here which will come in time.

  • SharePoint Forums Updates

    I haven’t got the site for submitting bugs, discussions, etc. for my SharePoint Forums Web Part but that should be along shortly. Some of you might be wondering where some of the features of the Web Part are (like RSS feeds). These are coming but due to time as I got into building it, I went for quality over quantity.

    Here’s a list of the features that are being worked on and those that are planned (my wishlist).

    Currently Being Worked On For Future Release

    • Import tool to read in and convert existing discussion list messages (not sure how the mapping to categories will go here)
    • Ability to sync a forum up to an external NNTP server and newsgroup(s)
    • Language support for more than just U.S. English
    • Topic/message search

    Wish List
    These are items that have been requested, were planned, but have yet to be scheduled or decided on.

    • RSS feeds (web part, forum, topic)
    • Email notifications from topics, replies, etc.
    • Locking of topics (so nobody but admin can add posts)
    • Password protect forum (not sure if this is needed)
    • Sticky topics/announcement type posts
    • Active topics list (return a list of all topics with replies)
    • Inactive topics
    • New topics (show topics since your last visit)
    • Print topics
    • Supports smileys/emoticons
    • Todays topics
    • Jump to forum feature (a small drop down box on the page to quickly navigate around)
    • Mark all unread messages read (messages don’t have a read/unread state now so this will be a large change)
    • Paged navigation of topics

    Some of these features will come automatically (like RSS and Email) with version 2.0 which will ship with SharePoint 2007 (and is being actively worked on so you’ll have a release as soon as the product is ready later this year). If you have any more feel free to send them my way.

    Expect a new release every 3–6 weeks (depending on my schedule). Once the new site is up, you’ll be able to add your own items, download the source code, etc.

  • SharePoint Forums... go get 'em

    I’m very happy to say that the SharePoint Forums Web Part is ready for you to install. I cleaned a few things up from the last week with the testers but most people reported no problems and only suggestions (which is always a good thing). There were a couple of problems with permissions however if you follow the installation instructions below you should be golden.

    I do apologize for not putting together an MSI or something. I did go down that path using WPPackager, however two problems. One is I couldn’t get the permission setup correct and the second thing is that the Forums uses a common library that I’m giving out which needs to go into the GAC but the Forum Web Part assemblies can go into the bin directory. I couldn’t find a way to split this up and then couldn’t get WPPackager to just package a regular file so it either meant doing it by hand (which is what I did) or building a two installers using two different tool sets.

    In any case, installation does require a bit of configuration but it’s painless. If some adventurous soul out there wants to put together an installer I’ll throw you a cool SharePoint prize.

    You can download version 1.0.0.0 of the Web Part from here. For those that have previous versions installed, please remove them and delete your forums. If you really want to retain the old forums I can tell you how to do this but email me privately as it involves some extra steps.

    Here are the web part installation instructions. These instructions are also in the zip in a text file called DRINKME.TXT.

    Step 1
    Install “BilSimser.SharePoint.Common.dll” to the GAC

    Step 2
    Copy "BilSimser.SharePoint.WebParts.Forums.dll" and "BilSimser.SharePoint.WebParts.Forums.Core.dll" to your SharePoint web site bin directory (if it's the default, it's c:\inetpub\wwwroot).

    Step 3
    Add the following SafeControl entries to your web.config file:
    <SafeControl Assembly="BilSimser.SharePoint.WebParts.Forums, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e516dadc23877c32" Namespace="BilSimser.SharePoint.WebParts.Forums.Controls" TypeName="*" />
    <SafeControl Assembly="BilSimser.SharePoint.WebParts.Forums, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e516dadc23877c32" Namespace="BilSimser.SharePoint.WebParts.Forums" TypeName="*" />
    <SafeControl Assembly="BilSimser.SharePoint.WebParts.Forums, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e516dadc23877c32" Namespace="BilSimser.SharePoint.WebParts.Forums.Controls.Common" TypeName="*" />
    <SafeControl Assembly="BilSimser.SharePoint.WebParts.Forums, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e516dadc23877c32" Namespace="BilSimser.SharePoint.WebParts.Forums.Controls.Base" TypeName="*" />

    Step 4
    Add the following to a custom policy file (PublicKeyBlob split for clarity but needs to be one line):
    <CodeGroup
     class="UnionCodeGroup"
     version="1"
     PermissionSetName="FullTrust">
    <IMembershipCondition
     version="1"
     class="StrongNameMembershipCondition"
     PublicKeyBlob="0024000004800000940000000602000000240000525341310004000001000100F15CA89A
    80D45C052CC5003DDAD661CEA98168E5B12A7BEC2A8B455D1E7D043C9248BC192A16B02B4D1CCF41738C31797
    CFFED01C70EE6247222243FA3B10706368EDE73C57BAF586582F83CB9391DA711DFF5B8169A9AD6169D6023B5
    C6572136233AC331010CE4C808143B2E2AB18FE59A872340DB76F71180623789336DAB">
    </IMembershipCondition>
    </CodeGroup>

    IMPORTANT!
    This entry needs to go AFTER the FirstMatchCodeGroup and BEFORE the ASP.NET UnionCodeGroup!

    Step 5
    iisreset (or recycle your AppPool)

    Step 6
    Import SharePointForums.dwp onto a WSS site or SPS area page where you are an Administrator.

    Step 7
    Configure, and have fun!

    I’ll post a quick set of docs (somewhere) on doing basic stuff but watch for blog entries on various tricks you can do. Email me at bsimser@shaw.ca if you have problems, questions, suggestions, small marsupials, concealed logging chains, etc.

  • Meet the "new" SharePoint Community

    SharePoint is all about community. Whether it’s forums or newsgroups or blogs, everyone is always trying to find information. This was difficult before and required ninja Google skills to find what you needed. Microsoft stepped up to the bat to rectify this problem with initiatives like Microsites and Communities. Unfortunately, the SharePoint community wasn’t that great and offered a few links that really didn’t help much.

    Now that’s changed with the launch of the new SharePoint Products and Technology Community.

    Here’s what the old community site looked like:

    sharetech_old

    And here’s a new one:

    sharetech_new

    A vast improvement.

    The new community has a set of small components that offer dynamic content. This content is pulled from various places so for example you can see the most active discussions from the SharePoint newsgroups (with links to that topic in the web based newsreader), the latest blogs, and links to all the SharePoint MVP profiles.

    Consider this your starting place to find SharePoint information in the future and check it out here.

  • SharePoint Forums and Common code

    Just a quick note that testing is going well by everyone and there are a few small things I’m fixing along the way. I’ll be doing the public release for next Monday (May 15) which gives me time to fixup any last minute problems and put things together in a nice installer for you guys and some much needed documentation. They’ll be a site setup just for the forums web part that will provide online documentation, a wiki, a place for you guys to submit bugs, etc. but this isn’t ready yet (but you’re going to love it when you see it).

    Also with the release of the forum web part is the release of a library that I’ve been building for awhile. It’s a common library with a set of classes, routines, etc. that you can use in your own web parts or SharePoint projects. It gets installed to the GAC with the forums and will be used in other projects I have coming soon. I’m hoping that the common library grows and provides some useful things for your projects. API documentation will be provided with this along with source code when the forums source code is released.

  • Looking for ChalkTalk ideas at TechEd 2006

    Hey guys, I’m going to be at the Office DevTrack area for most of TechEd 2006 next month (June) hanging out, talking, and generally telling you whatever you want to hear about SharePoint 2007. While we’re there, there are sometimes scheduled Chalk Talks. Chalk Talks are short sessions (no more than 20 minutes) with you, me, a few of your friends, and a whiteboard (or flipchart). We can discuss architecture, implementation, development, whatever. Just something short and focused and fun.

    I’m looking for some ideas on hosting a Chalk Talk or two while I’m there so if you’re interested in getting into something, email me (or leave a comment here) on something you’re interested in and I’ll see if I can schedule it in. I can’t promise we’ll get it slotted as there are only so many spots available, but if something interests you about Microsoft Office SharePoint 2007 (or 2003 for that matter, but we would prefer to talk about 2007) then now’s your chance to ring in.

    I’m also hosting a BOF session so that will cover talking about what to prepare for as a developer, but I’m open to anything in the Chalk Talk area (as long as it’s Office/SharePoint related). Also note that we haven’t confirmed the schedule of when we (the Office track guys, myself and AC and a couple of others) will be in the lounge but once it’s confirmed we’ll let you know when to avoid the area.

    Thanks!

     

  • Lost another camera

    I have the worst luck with cameras. On my trip to PDC last year, I lost my digital camera somewhere between the airport and my hotel going in. On Sunday I lost the replacement camera I bought down in L.A. (a Olympus C60, 6MP nice camera) on the way from the Vancouver airport to home.

    Oh well, guess it's off to buy another one. Any suggestions? I'm very happy with Olympus but willing to take a look at something else.

  • SharePoint Forums off to testing

    Whew. Finally. The forums have been sent off to the testers. I’ll be doing a few final changes this week while they have it for the public release later this week. Source code will be available in the near future, but watch for a special announcement about that (yes, the source will still be available). Here are some shots of the finished product that you’ll be getting soon.

    Multiple forums with categorization (setup to mimic some of the ASP.NET forums)

    forums_final

    Admin screen for managing forums, categories, and permissions

    forums_final2

  • Removing static calls in your Repositories

    I was putting together some code this morning for a demo and saw that my Repositories started to look a little wonky. I wasn't happy with the fact that I had static methods on all of them because this would make for testing difficult. After posting the question to the DDD mailing list, a couple of good ideas came up that I implemented in my solution.

    A Repository is a class that represents all objects of a certain type. It's basically a collection (sometimes an in-memory version of a database) but with querying capabilities. The machinery behind how it stores or retrieves them from whatever persistance layer is hidden from the client as it only deals with domain types.

    So in our client we would access the repository like so:

       48 public class MyClient

       49 {

       50     public void LoadCustomerList()

       51     {

       52         CustomerCollection coll = CustomerRepository.GetAll();

       53         DataGrid grid = new DataGrid();

       54         grid.DataSource = coll;

       55         grid.DataBind();

       56     }

       57 }

    Our client (say a web app but could be anything) needs to display a list of all the customers. It talks to the repository to retrieve that information (in the form of a CustomerCollection object, derived from CollectionBase). This removes the implementation of how a repository retrieves the data request from and we can work with domain objects.

    If you're going across multiple tiers, you might return a CustomerCollectionDto, an ArrayList, an Array of Dtos, or whatever you need but for the purpose of this example we're getting a collection of domain objects.

    As I started out, my repository looked like this:

       59 public class CustomerRepository

       60 {

       61     public static Customer GetById(int id)

       62     {

       63         CustomerDao dao = new CustomerDao();

       64         Customer obj = dao.FindById(id);

       65         return obj;

       66     }

       67 }

    This was typical and would provide me with a way to access whatever persistance layer I implemented in order to reconstitute my domain objects (in this case, as Customer). I started to add more methods but things started to smell.

       31 public class CustomerRepository

       32 {

       33     public static CustomerCollection GetAll()

       34     {

       35         CustomerDao dao = new CustomerDao();

       36         CustomerCollection coll = dao.GetAll();

       37         return coll;

       38     }

       39 

       40     public static Customer GetById(int id)

       41     {

       42         CustomerDao dao = new CustomerDao();

       43         Customer obj = dao.FindById(id);

       44         return obj;

       45     }

       46 }

    Now I've got duplication of my calls to my DAO as well as these static methods that are looking a little ugly. I could remove the code duplication by declaring the DAO in the class, but the methods are static so it would have to be static too. Also this is just plain difficult to test because I don't necessarily want to implement a full blown DAL just to test my repository.

    Enter the Registry pattern to the rescue. This is a class that acts as a gateway or controller class to all of your repositories (or whatever object you need to talk to). You create static accessors to the inner repositories, but the nice thing is we can use an interface to our repository which allows us to build any kind of registry so we can create some mock test objects without having to drag along extra infrastructure.

    Okay, we'll get our registry class started with some .NET plumbing:

       69 public class RepositoryRegistry

       70 {

       71     private static readonly RepositoryRegistry instance = new RepositoryRegistry();

       72 

       73     static RepositoryRegistry()

       74     {

       75     }

       76 

       77     protected RepositoryRegistry()

       78     {

       79     }

       80 

       81     private static RepositoryRegistry GetInstance()

       82     {

       83         return instance;

       84     }

       85 }

    Now we've got the beginning of our registry. The static instance variable is how we'll access it (as a singleton) and is set to readonly so it can only be created at startup. A private GetInstance() method allows us to access this as well as a static constructure to keep .NET happy.

    With the repository created, now we can add our CustomerRepository. This is done by a) creating a public property to access it and b) creating a protected method to instantiate it.

       69 public class RepositoryRegistry

       70 {

       71     protected CustomerRepository GetCustomerRepository()

       72     {

       73         return new CustomerRepository();

       74     }

       75 

       76     public static CustomerRepository CustomerRepository

       77     {

       78         get { return GetInstance().GetCustomerRepository(); }

       79     }

       80 }

    So the property is exposed publically and static (so we can call it from our client) but the implementation of the creation is done in the GetCustomerRepository method. This method is marked as protected so we can subclass the RepositoryRegistry and create say a MockRepositoryRegistry. Then we only have to implement (override) the GetCustomerRepository method and return whatever a CustomerRepository whatever way we want.

    Now we have two changes to make this work. First, we have to remove the static calls on our CustomerRepository because we don't need them anymore. Second we have to change our client call to get the collection of customers. Since we're removing the static calls in our Repository, we can remove the duplicate code to the DAL now and clean things up a little. Here's the updated CustomerRepository:

       31 public class CustomerRepository

       32 {

       33     private CustomerDao dao = new CustomerDao();

       34 

       35     public CustomerRepository()

       36     {

       37     }

       38 

       39     public CustomerCollection GetAll()

       40     {

       41         CustomerCollection coll = dao.GetAll();

       42         return coll;

       43     }

       44 

       45     public Customer GetById(int id)

       46     {

       47         Customer obj = dao.FindById(id);

       48         return obj;

       49     }

       50 }

    And now we can talk to the Registry class via our Client. Note that we're calling a static property on the class (CustomerRepository) but it's being created internally by the Registry class. So our new client code looks like this (only the call to get the collection has changed):

       86 public class MyClient

       87 {

       88     public void LoadCustomerList()

       89     {

       90         CustomerCollection coll = RepositoryRegistry.CustomerRepository.GetAll();

       91         DataGrid grid = new DataGrid();

       92         grid.DataSource = coll;

       93         grid.DataBind();

       94     }

       95 }

    Nice. So we still have a single call in our client (which is nice and readable) but we're getting rich objects returned from our domain and we don't need to know how the Registry is getting us the objects (or how the underlying Repository is either). This is a good way to remove statics from your repositories and keep your domain clean from persistence. It also gives you the flexibility to build any kind of implementation for testing.

    Other things you can do here is to build a repository interface and have it returned rather than the concrete class and maybe do something better through calling your persistance layer, but you get the idea.

    Many thanks to Ramon Leon, Greg Young, Stephen Molitor, Roger Stasko, and Steve Eichert for contributing to this as they really did the heavy lifting. I just did the grunt work to show you what it would look like in .NET.

    Enjoy!

    EDIT: Greg Young summed things up very nicely on his blog post recently that I missed (thanks Greg!):

    "The starting point to using repositories effectively in a domain is the creation of abstract contracts for the repositories. These abstract contracts should be the only publicly visible forms of our repositories. Internally we only use the abstract contracts to refer to our repositories and in many cases we also allow such things as dependency injection of repositories into our domain, we will generally use either a service locator or a static accessor to an instance. We also at this point create our first unit tests to test the abstract contract of a repository; we can at a later point use these unit tests as integration tests with a repository that is hooked to a real database."