Home Contact Login Subscribe

Thursday, May 08, 2008

JOG - May 15, 2008 - Code Access Security for SharePoint


Come join co-founder Andrew Connell on Thursday, May 15, 2008 for an interesting session on CAS.  As we all know, Code Access Security gets much less attention than it deserves.  Part of the problem is because it seems so, well, mysterious.  Here's AC's take on dealing with CAS:

Understanding and Making Code Access Security Not so Intimidating

Ever dealt with that SecurityException error in the yellow-screen-of-death?  That's fun troubleshooting.  The easiest way to address it is to just bump the trust level up to WSS_Medium.  Full to throw your assembly into the GAC.  In this session, you'll learn how .NET's Code Access Security (CAS) works with respect to SharePoint, how to read policy files, and how to work with it in the most secure way possible.

Meeting Details:

Jacksonville Office Geeks (JOG) is also known as the JAXDUG Office Developer SIG.

Technorati Tags: ,,,

posted @ Thursday, May 08, 2008 12:43 AM | Feedback (2)

Saturday, April 26, 2008

Great Article about SharePoint Timer Jobs on MSDN


SharePoint guru Andrew Connell does it again with a great MSDN article that shows you how to create custom timer jobs in WSS 3.0.  Timer jobs are a great way to schedule long-running or periodic tasks in such a way that they are automatically coordinated with the server farm topology and can therefore take advantage of load balancing or can be directed to specific servers that are running the services they require.   Read about it on the MSDN site at http://msdn2.microsoft.com/en-us/library/cc406686.aspx.

 

Technorati Tags: , , ,

posted @ Saturday, April 26, 2008 4:37 AM | Feedback (0)

Tuesday, April 15, 2008

Jacksonville Office Geeks April 2008 Meeting: Developer Workshop - Using and Extending STSADM


JOGLOGOBIG STSADM.EXE is the extensible command-line utility that ships with Windows SharePoint Services and enables system administrators and developers to quickly perform tasks that would otherwise require many keystrokes in the browser.  With over 180 built-in commands and the ability to add your own custom commands, STSADM is truly the “SharePoint Power-Tool” and is an essential part of the core SharePoint developer skillset.   In this session, we’ll take a look under the covers to see just how STSADM works and we’ll walk through the process of creating some useful custom commands.  At the end of this session, you’ll have the code and the know-how to manage any SharePoint environment from the command line.

Presented by John Holliday on April 24, 2007. For more information & to RSVP (requested), click the following link:  http://www.clicktoattend.com/?id=127731

Technorati Tags: , , , , ,

posted @ Tuesday, April 15, 2008 5:06 PM | Feedback (0)

Wednesday, March 19, 2008

SharePoint Reflection - Working with Content Types


For the past several months, I've been experimenting with ways to use .NET reflection with the SharePoint API.  As I've mentioned before, I believe that .NET attributes can not only make it easier to build great SharePoint applications, but can also provide a foundation for building better development tools.

In this series of posts about the evolving SharePoint Reflection Framework, I'll continue to share the results of my research and I'll include links to sample code directly within each post.  As the code matures, I'll consider making it available on CodePlex so that others may contribute.  For now, let's just treat it as a "thought experiment" as my friend Andrew Connell likes to call it.

The sample code and the framework assembly can be downloaded here:

http://www.johnholliday.net/download/JohnHolliday.SharePoint.ContentTypes.zip.

There is also a short screencast (27 minutes) that shows how to use the framework which you can view here:

 

Now let's take a closer look at how we can apply .NET attributes to simplify working with content types. 

Some have asked, and you might also be wondering "Why do we need this?   Why not just use CAML to declare the content types and then simply publish them using a feature?  Why go to all the trouble of using this non-traditional approach?"

Well, there's nothing wrong with the traditional CAML-based approach.  There is ample support for it and with a few simple tools, it's pretty straight-forward once you get the hang of it.  But there are a number of limitations with the "code + markup" paradigm when it comes to reusability and extensibility.  The markup is "brittle" in the sense that subtle mistakes are hard to find.  True, you can preload the schema to help you remember what attributes go where, but there is no true intellisense and no strong typing to prevent those mistakes.  If you want to extend an existing content type, you have to  visit multiple files and switch back and forth between your event handler code and the markup.  You have to spend a good deal of time making sure that the code matches the properties that have been defined in the markup.

The unfortunate reality is that working directly with XML still requires a significant paradigm shift in the way most developers think.  With all the buzz about improving the SharePoint "developer experience", I keep thinking there must be a better way.

So, there are several goals for this experiment:

  1. We want to make it easier to declare content types in code.
  2. We want to eliminate the need to work directly in CAML or XML.
  3. We want to use the same coding idioms we are used to when working with other code.
  4. We want to make it easier to write custom event receivers for our content types.
  5. We want to make it easier to associate sub-components like document templates and XML documents with our content types.
  6. We want to be able to build libraries of reusable components that can be leveraged across multiple projects easily.
  7. We want to enable DRM for content type components at the assembly level so that developers can protect their intellectual property.

 

The SharePoint Reflection Framework

For this experiment, we'll construct a content type for an expense report in C#.  But we also want to work with the expense report content type in the same way we might work with other C# classes.  For instance, we might want to create a library of reusable content type classes for use in financial solutions. 

To achieve this, we need to have a set of attributes that we can attach to a class to "declare" the content type and its properties.

We can start simply by deriving a ContentType class from System.Attribute.  To control where and how it is used, we can mark it so that it can only be applied to classes and only once per class.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ContentType : Attribute
{
    public string Name { get; set; }
    public string BaseType { get; set; }
    public string Description { get; set; }
    public string DocumentTemplate { get; set; }
    public string Group { get; set; }
    public bool Hidden { get; set; }
    public bool Sealed { get; set; }
    // ...
}
Within this attribute class, we have properties that specify the various well-known components of a content type, such as its name, group, base type, etc.  These properties then show up as named properties of the attribute whenever it is applied to another class used to declare the content type itself.  For our expense report experiment, that class might look something like this:
 
namespace JohnHolliday.SharePoint.SampleContentTypes
{
    [ContentType(Name = "Expense Report",
        BaseType = "Document",
        Description = "A worksheet for recording expenses.",
        Group = "SharePoint Reflection Framework Samples",
        Hidden = false]
    public class ExpenseReport
    {
    }
}

Notice that we are basically specifying the same properties we would have to add to a <ContentType> element in CAML.  The difference is that here we get strong typing and intellisense support.  Notice also that we don't have to worry about constructing the content type identifier.  Instead, we just supply the base type and let the framework handle the details.

Next, within the content type declaration, we need to specify the fields that make up the type.  Here again, .Net reflection comes to our aid to make things easier.  What we really want is to declare the fields of the content type in the same way that we might declare properties for any C# class.  So, if we wanted to add a description field to the expense report content type, we would naturally want to do something like this:

[ContentType(Name = "Expense Report",
    BaseType = "Document",
    Description = "A worksheet for recording expenses.",
    Group = "SharePoint Reflection Framework Samples",
    Hidden = false]
public class ExpenseReport
{
    private string m_description=string.Empty;

    [FieldRef("Description")]
    public string Description {
        get { return m_description; }
        set { m_description=value; }
    }
}

Here, we can simply make use of a second attribute included in the framework to markup the properties we want to map to SharePoint fields.  The FieldRef attribute is provided for this purpose.  The framework supplies the necessary code to examine the ExpenseReport class, locate the mapped properties, determine their field types and link them automatically to the content type on creation.  For instance, if we add a DateTime property to the ExpenseReport class, we want it to surface in SharePoint not as text, but as a date field.   Similarly, the other field types can be automatically determined from the underlying property type.

Enumerations

We can extend this idea further to include built-in support for CHOICE fields if an enumerated type is mapped to a field.  For example, we might need to declare a ProjectTypeEnum enumeration and then map it to a ProjectType property as shown below. 

public enum ProjectTypeEnum
{
    Consulting,
    Training,
    Programming,
    Sales,
}

private ProjectTypeEnum m_projectType;
[FieldRef("ProjectType", DisplayName = "Project Type", Required = true,
    Description = "The project type for which expenses are being submitted.",
    Group = "Sales")]
public ProjectTypeEnum ProjectType
{
    get { return m_projectType; }
    set { m_projectType = value; }
}

 

In this case, the framework detects that the underlying data type of the property is an enumerated type and it then generates the appropriate choices automatically, as shown here.

Choice Fields

We can do a lot more with field references, but let's move on to the question of how to create the actual content type within the SharePoint environment.

Creating Instances

Typically, we'll be writing a FeatureActivated feature receiver or building a command-line utility, and we need to create a content type as part of the solution.  Ideally, we'd like to end up with an instance of SPContentType that we can work with.  So we really only need the framework to handle the dirty work of talking to the SharePoint API and then returning a properly constructed SPContentType object.  One way to implement this pattern is to provide a factory method on the ContentType attribute class that takes a reference to our implementation class and then gives us back an SPContentType object.  For the expense report content type, we might call it like this:

using (SPSite site = new SPSite("http://litwareinc.com")) {
    using (SPWeb web = site.OpenWeb()) {
        // Create the expense report content type.
        SPContentType ctExpenseReport = ContentType.Create(web, typeof(ExpenseReport));
        if (ctExpenseReport != null) {
            // do something with it
        }
    }
}

Note that the ExpenseReport class is completely independent of the SPContentType object it was used to create.  It can be implemented in a separate assembly.  Using this approach, we can easily build libraries of content types that can be reused across multiple solutions.  But there are still a couple of additional requirements we need to fulfill.  Namely, how do we handle item event receivers?  And what to do about the nested sub-components of a content type, such as document templates and XML documents?  These are critical requirements, because we want to apply the same coding paradigm we are used to for other C# classes.  We don't want to have to revert to using XML markup in order to specify event receivers and other elements.

Item Event Receivers

To specify event receivers for a content type in code, we need to add the appropriate entries to the EventReceivers collection of the SPContentType object.  When working with XML markup, this is done by creating a special XML document that specifies which event we want to capture and the assembly and class in which the event receiver method is implemented. 

To deal with event receivers in our ContentType attribute, we can take advantage of the fact that SharePoint provides an abstract class called SPItemEventReceiver that declares all of the event receiver methods.  By simply deriving our ExpenseReport class from SPItemEventReceiver, we get the correct method declarations in the base class and then we can selectively override the ones we want.  Instead of telling the framework explicitly which methods we are implementing as we would have to do with CAML, we can let the framework do the work for us and infer which methods have been implemented by examining the class via reflection.  So all we have to do to handle the ItemAdded event, for example, is add the derivation and override the ItemAdded method as shown in the following code.

 

[ContentType(Name = "Expense Report",
    BaseType = "Document",
    Description = "A worksheet for recording expenses.",
    Group = "SharePoint Reflection Framework Samples",
    Hidden = false)]
public class ExpenseReport : SPItemEventReceiver
{
    // ...properties

    public override void ItemAdded(SPItemEventProperties properties)
    {
        base.ItemAdded(properties);
        string message = string.Format("Expense report added to list: {0}",
              properties.ListTitle);
        EventLog.WriteEntry("SharePoint Reflection", message);
    }
}

Still, no CAML.  We are working entirely within a C# class and we have captured all of the information needed to create the content type and to install an event receiver for the ItemAdded event.  The framework looks at the ExpenseReport class and sees that only one of the abstract classes was implemented, so it creates an event receiver for that method only.  It knows which assembly the class is declared in, so it automatically assigns the assembly and class names.  If we want to add an event receiver for another event, such as ItemUpdated, we can simply add another override and implement the method.  The framework automatically registers it for us.

Document Templates and XML Documents

The thing about document templates and other kinds of files that we might need to associate with a content type is that they are files.  Ideally, we'd like to work with them as files without having to jump through hoops just to get SharePoint to recognize them.  Fortunately, Visual Studio has a nice feature that lets us access and work with files easily from within our code.  These are embedded resources.  If we change the build action for any given file within our project to EmbeddedResource we can reference it using a path expression of the form <folder name>.<sub folder name>.<...>.<filename>.<extension>.  So if we have a project folder named "DocumentTemplates" and a file in that folder named "ExpenseReport.xlsx", and both are part of a project named "SampleContentTypes", we could refer to the resource using the path "SampleContentTypes.DocumentTemplates.ExpenseReport.xlsx".

By extending the ContentType attribute to recognize and locate embedded resources, we can easily add document templates and other resources directly to our class declaration without having to worry about how they actually get copied into SharePoint.  Here again, we can delegate that responsibility to the framework and just focus on the content type implementation.

For consistency and to distinguish document templates specified as embedded resources from those specified with legitimate urls, I've added a "res://" prefix which the framework recognizes.  It then treats the url as a reference to an embedded resource and copies the file into the proper location when the content type is created.  Since it already knows where the resource is located, we can drop the assembly name and just specify the assembly-relative path to the resource file.  We end up with a declaration that looks like this:

[ContentType(Name = "Expense Report",
    BaseType = "Document",
    Description = "A worksheet for recording expenses.",
    Group = "SharePoint Reflection Framework Samples",
    Hidden = false,
    DocumentTemplate = "res://DocumentTemplates.ExpenseReport.xlsx")]
public class ExpenseReport : SPItemEventReceiver
{
    //...
}

Future Directions

As you can see, there is a lot of promise to this approach, but we've only begun to scratch the surface.  I'm currently working on one-way data binding of list items to properties in the implementation class whenever an event receiver method is called.  This would essentially let you reference the mapped properties just like other properties in your event receiver methods.  It would be one-way only because there might be times when you don't want those properties to get copied back into the list item automatically.  For that, you can always call into the SharePoint API.

There is a lot more we can do with content types as well as with other SharePoint objects that can really make our lives easier as SharePoint developers.  Give the code a spin and tell me what you think.  In the coming weeks, look for additional posts that will go into more capabilities of the framework. 

Stay tuned.

posted @ Wednesday, March 19, 2008 2:39 PM | Feedback (12)

Jacksonville Office Geeks March 2008 Meeting: Regulatory Compliance - Item Level Auditing in SharePoint


Our next meeting is Thursday, March 20, 2008.  We'll be talking about item level auditing and regulatory compliance. Here's an abstract:

Regulatory Compliance - Item Level Auditing in SharePoint

Speaker: John Holliday, MVP Office SharePoint Server


Dealing with regulatory compliance issues in the midst of an ever-increasing volume of content at least requires a robust method for tracking what happens to a document as it moves through a SharePoint portal. Windows SharePoint Services includes built-in functionality for keeping tabs on the "who, what, when and where" for every document in every document library, but this functionality is not enabled by default. In this session, we'll examine programming techniques for controlling the auditing support provided by WSS and we'll look at the enhanced audit reporting features provided by MOSS. We'll also explore strategies for implementing item-level auditing while minimizing its impact on the overall performance of a SharePoint farm.

 

 

 

Note: Jacksonville Office Geeks is also known as the JAXDUG Office Developer SIG.

Technorati Tags: , , , ,

posted @ Wednesday, March 19, 2008 12:51 PM | Feedback (0)

Saturday, February 09, 2008

ODC Architecture Track Sessions


Folks, ODC is almost upon us, and this time we have an architecture track that focuses on the Office System and OBAs (Office Business Apps) as a platform for building real world business solutions. I'll be delivering a session entitled "Building Collaborative BPM Solutions – Feb 13th, 10:30 – 11:45am". You can view the final list of track sessions at the following URL:

https://microsoft.crgevents.com/ODC2008/Content/default.aspx?p=7VE4KC.

See you in San Jose!

posted @ Saturday, February 09, 2008 10:33 PM | Feedback (0)

Thursday, February 07, 2008

OBA Book Available from MS Learning


In case you missed it, my most recent authoring adventure, 6 Microsoft Office Business Applications for Office SharePoint Server 2007 is now available from Microsoft Learning, Barnes & Noble, Amazon and Quantum Books. This was a collaborative effort with Rob Barker, Joanna Bichsel, Adam Buenz, Steve Fox, Bhushan Nene and Karthik Ravindran. If you're building OBAs or just want to get a practical perspective on what it takes to build Office Business Apps, then be sure to check it out!

posted @ Thursday, February 07, 2008 12:07 PM | Feedback (2)

Tuesday, February 05, 2008

The Passing of an Icon


Maharishi Mahesh Yogi passed away quietly today at his home in the Netherlands.  Though he influenced millions, including myself, through his Transcendental Meditation movement, like other great thinkers before him, his true brilliance may not be fully appreciated until long after his death.  I had the great good fortune to hear him speak on many occasions about the deep connection that exists between western science (the study of the observable universe) and Vedic Science (the study of consciousness - the observer), and I can say from my own experience that this was a truly remarkable man.  If you ever get a notion to delve into Vedic philosophy or to incorporate yoga and meditation into your daily routine, I can't recommend it highly enough.

posted @ Tuesday, February 05, 2008 10:49 PM | Feedback (1)

Tuesday, January 29, 2008

Get Ready for ODC2008


As the new year approaches... Wait! Is it 2008 yet? So much is happening - so fast! Do you ever get that feeling that you'll never catch up? I sure do. Time flies...

For the past few weeks, I've been busy writing chapters for a new book (more on that later), developing and experimenting with new toys and project ideas (lots to talk about) and getting ready for my ODC2008 sessions.

I'll be delivering three sessions this year. One in Karthik Ravindran's architecture track, one in Steve Fox's client track and one in Jerome Thiebaud's server track.

  • ARC303 - Building Collaborative BPM Solutions

This session will cover best practices for leveraging the Microsoft BPM platform offerings (Windows Workflow Foundation, BizTalk, SharePoint Workflow, and Windows Communications Foundation) to integrate comprehensive Business Process Management (BPM) capabilities into Business Solutions built on the Microsoft Office Platform/System. This session will help the audience gain a broad perspective of the BPM scenarios targeted by each component and will offer prescriptive guidance on choosing the right option(s) to address common solution requirements. This session will also show how the various components can interplay and add value to Office Business Applications.

  • CLI307 - Generating Enterprise Content using InfoPath 2007, SharePoint and the Microsoft SDK for Office Open XML Formats

This session will introduce the Microsoft SDK for Open XML formats and show how developers can use the SDK and InfoPath 2007 to generate Microsoft Office documents on the server from data stored in SharePoint form libraries.

  • SER401 - Building Document Management Solutions using Windows SharePoint Services 3.0 Content Types

Windows SharePoint Services 3.0 introduces a new concept call "Content Types" that will dramatically alter the Enterprise Content Management (ECM) landscape. On the surface, Content Types make it easier to encapsulate metadata, but there is a lot more going on under the covers. In this session, we'll take a deep dive into the world of content types and see how to declare them using XML and how to create them programmatically. Then we'll use content types to create a real-world document management solution with custom policies that we'll use to control every stage of the document lifecycle. At the end of this session, you will have a thorough understanding of what content types are with a deeper appreciation of the vale they bring to document management solution development.

I'm grateful for the opportunity to present these sessions (thanks to Karthik, Steve and Jerome), and it looks like this is shaping up to be a great conference. I'll be arriving early with my friend Andrew Connell if you want to just hang out. Otherwise, I'll look forward to seeing you at the conference!

posted @ Tuesday, January 29, 2008 9:13 AM | Feedback (0)

Tuesday, December 18, 2007

JOG: December 2007 Meeting - Generating SharePoint Workflow from Office Client Apps


This session will take a deep dive into Workflow Markup and explore how you can generate custom workflows from any client application using the built-in websvcWebPartPages web service provided by Windows SharePoint Services.  During the session, we will create a custom task pane in Microsoft Excel that generates an expense reporting workflow and attaches it to a SharePoint list.

  • Presented by: John Holliday
  • Date: Thursday, December 20, 2007
  • Location: Bank of America (9000 Southside Blvd., Building 500, Jacksonville, FL 32256)
  • Directions: Click Here for Directions
Technorati Tags: ,,,,

posted @ Tuesday, December 18, 2007 9:14 AM | Feedback (0)