Home | Blog | Screencasts | Projects
# Tuesday, October 20, 2009

Nice message after installing Visual Studio 2010 Beta 2:

 

BetaErrorMsg

 

Everything is OK? … must be an error :)

Tuesday, October 20, 2009 12:34:00 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
VS 2010
# Saturday, October 17, 2009

I came across a rather interesting problem the other day (interesting enough to blog anyway).

We have a development server that we are building some SharePoint web parts on, all of the developers have local admin rights to the box. We asked a normal user to have a look at some functionality that should be available to them, but when they browsed to the site they got a 403 forbidden error message. However when the developer requested that very same page it rendered fine. The weird thing was that if the original user (not the dev) then requested the page once again, it all rendered fine.

We had a look in the SharePoint Logs and found that the assembly in the bin folder was denying access to the non developer, but once a dev hit the box the assembly was loaded fine and stayed in memory until the app pool was recycled.

So the solution was to grant all users access to the bin directory. This wouldn’t be an issue in production because we will eventually GAC deploy these assemblies.

But I did think it was a fun little exercise to track down the root cause.

Saturday, October 17, 2009 4:30:00 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Tip | Work
# Tuesday, September 22, 2009

Windows 7 contains a really nice tool called the Problem Steps Recorder:

 

It can be found via the Windows 7 start menu by typing ‘problem step’

image

 

Once it’s running you get the following UI:

 

 image

 

From here you can record all the clicks and keystrokes that your undertaking, you can even add comments to parts of your display. It finally saves the file as a zip file, which contains a .mht file that can be viewed in your browser. This output file will list things like version numbers of applications running as well as a range of screenshots of each major activity recorded.

 

Now this is all well and good for sorting your mum’s computer problems, but as an IT pro who has had to document some awfully boring processes, I really think this tool will help me the next time I need to document the install of some software, or some mundane configuration change.

Tuesday, September 22, 2009 2:25:00 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Tip | Windows 7

I’ve been working on a project that involves implementing a blogging system inside SharePoint, the out of the box SharePoint blogging system was unsuitable and the Community Kit for SharePoint didn’t solve our issues.

So the system we developed was lightly based on the open source .NET Blog Engine which includes comprehensive support for the MetaWebBlog API. This API allows a interaction with a blogging system so that blog posts can be added, deleted and updated, but it also provides provisions for managing things like categories and comments.

The main motivation for supporting the MetaWebBlog API is Windows Live Writer (WLW) this great tool really makes publishing to a blog a simple task. So I happily added the MetaWebBlog API and quickly found that windows live writer doesn’t support windows authentication. WLW supports a nice feature called Really Simple Discovery (RSD) where it can just be pointed to a blog’s home page and it can get all the configuration needs. By not supporting windows authentication we lost the auto discovery features.

 

So I could still enable anonymous access to the MetaWebBlog.axd and wlwriter.xml (a file that tells WLW what capabilities your blog has), so now with some manual steps in WLW I could select the MetaWebBlog API and give it the url to use. My next problem was that my blogging system was all based around windows authentication. Every user has a blog that is based around their network credentials, I needed my metawebblog API implementation to validate the user to the windows network:

 

With the following P/Invoke definitions:

 

[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
 int dwLogonType, int dwLogonProvider, ref IntPtr phToken);                

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
 int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle); 
 

Now in all of my metawebblog API calls I could use a method like:

 

 

                string username = string.Empty;
                string password = input.Password;
                string domain = string.Empty;

                if (input.UserName.Contains(\\))
                {
                    string[] usernameParts = input.UserName.Split('\\');
                    if (usernameParts.Length > 1)
                    {
                        domain = usernameParts[0];
                        username = usernameParts[1];
                    }
                }
                else
                {
                    username = input.UserName;
                }

                IntPtr tokenHandle = IntPtr.Zero;

                bool returnValue = LogonUser(username, domain, password,3, 0, ref tokenHandle);

                if (returnValue == false)
                {
                    //error not a valid user .. return
                    throw new MetaWeblogException("11", "User authentication failed");
                }
                
                    if (tokenHandle != IntPtr.Zero)
                        CloseHandle(tokenHandle);

This code will return an invalid authentication message to WLW if the user doesn’t provide the correct domain, username and password (you could easily remove the need for a domain, I needed to keep it).

I’d like to say that its all good but really end users won’t go to the effort of following steps to configure WLW, the RSD is a killer feature in making web blogs accessible to end users. Fingers crossed that WLW will support windows authentication in a future version.

Tuesday, September 22, 2009 1:32:00 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Tip

We’ve all probably worked on projects in the last 5 years or so that have involved reworking applications that were once built in MS access, in my case it was an access system that stored important safety testing information that was captured in an engineering workshop. It was originally designed and built by a mechanical engineer, who didn’t know much about database design.

The system was redeveloped for a number of reasons including:

  • The data couldn’t be shared, it was locked away on a PC in the workshop, no analysis of the data could be performed.
  • It didn’t scale well, only one user at a time could access it.

There are lots of other reasons why MS access shouldn’t be used for this type of information, but my point was that Access is a pretty poor tool for critical business information because it was difficult for the business to access this information. I think most people would share this view.

Lets compare a couple of scenarios with SharePoint as the tool, so all the information would be stored in a list:

  • The data can be shared by webservices and RSS, with effort.
  • It can scale, multiple users can access it at the same time.

But is the business data in a SharePoint list really easier to work with?

Can it:

  • Be used in SQL Server analysis cube?
  • Easily used in Reporting Services?
  • Joined with other business data to see correlations?
  • Perform complex real world queries?
  • Do you really want to model your business data based on the limitations of SharePoint?

The answer is no.

 

I still think that business data needs to live in a system designed for business data, i.e. A database: SQL Server.

From here it can be queried, joined and more importantly shared, whether that be back into SharePoint or any other tool that supports a database (Reporting Services, Performance Point, Analysis Services etc).

 

So now that brings me back to my comparison with MS Access, we are now doing lots of work moving systems away from MS Access, will we be doing the same thing in 5 years time, moving our SharePoint lists away from SharePoint?

 

I think SharePoint lists have their place, no question, but not for line of business data. Keep the SP lists for trivial data that is not important to the overall operation of your business.

Tuesday, September 22, 2009 12:43:00 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint
# Monday, September 21, 2009

With the upcoming SharePoint conference releasing information about SharePoint 2010, it won’t be too long before everyone will be looking at the product. Interestingly SharePoint 2010 is 64 bit only, this will have an impact on developers using Virtual PC 2007, which only supports 32 bit guest OS’s.

However windows 7 and Server 2008 R2 supports boot to VHD, this provides the ability to create a single VHD file that can booted. Once you’ve booted up the VHD your computer has access to all of it’s CPU cores, which is a major win. I’ve read that the performance hit of virtualising the file system to write to the VHD is around 5%, so it’s barely noticeable. Most importantly you can boot into a 64 bit OS where SharePoint 2010 can be installed.

To recap, the advantages of boot to VHD:

  • Can run 64 bit machines
  • Access to all CPU cores
  • Still keep portability by way of VHD files

Disadvantages

  • Can’t multitask with the primary OS, the VHD OS is the primary OS
  • Need to upgrade to windows 7 or server 2008 R2 (Not really a disadvantage, but might be an issue in corporate environments)
Monday, September 21, 2009 10:49:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
SP 2010 | Windows 7
# Saturday, June 13, 2009

By default SharePoint will use impersonation, so the web.config file will have the setting:

<identity impersonate="true" />

 

This means that if you try and connect to a SQL server database from say a custom web part, the connection will appear to SQL server as the user that requested the page. This is very useful if you care about the actual user, so for example if the database has permissions set based on this assumption.

However it is often useful to have just the application pool account connect to the SQL Server database or you may wish to give the application pool account permissions to connect to active directory but not every user.

It this case you will need to impersonate the application pool account. There is a bit of code floating around the web that uses P/Invoke to call ReverToSelf() from the advapi32.dll. It turns out it’s simpler than that:

 

using (HostingEnvironment.Impersonate()) 
{
 
    // access external resource as app pool account
 
}
 

 

The HostingEnvironment.Impersonate() will do the same thing that as a call to RevertToSelf().

 

If you like me and organise your data access calls into nice methods that perform a discrete action such as:

public static void DeleteUser(int userID)
{
 
//do some database access
 
}

 

You might be really loathed to wrap all these methods with the same code like:

public static void DeleteUser(int userID)
{
 
   using(HostingEnvironment.Impersonate())
   {
      //do some database access
   }
}

 

Instead you might like to take a look at what a project such as PostSharp can offer:

 

"You can make your own custom attributes that will really add new behaviors to your code! This is sometimes called aspect-oriented programming (AOP) or policy injection."

 

This means that you can define your own attribute that will have code that will run on any invocation of your code:

public class ImpersonateAttribute : OnMethodInvocationAspect
{
    public override void OnInvocation(MethodInvocationEventArgs eventArgs)
    {
        using(HostingEnvironment.Impersonate())
        {
            eventArgs.Proceed();
        }
    }
}

 

So our code then looks like this:

[ImpersonateAttribute]
public static void DeleteUser(int userID)
{
   //do some database access    
}

 

Much easier to maintain. Now every bit of code with this attribute will run as the application pool account.

Saturday, June 13, 2009 11:16:09 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint

I came across an interesting problem recently deploying an ASP.NET application to the ISV directory in CRM 4, the ASP.NET application was working fine using the Cassini web server inside of Visual Studio, but when it was deployed to the ISV directory on the CRM server it failed to run.

Basically any postback caused the web forms to loose all it’s current data, so things like dropdown lists would end up blank.

It was pretty obvious that this was caused by ViewState being turned off.

The default web.config file of CRM looks like:

 

<pages buffer="true" enableSessionState="false" enableViewState="false" validateRequest="false"/>

 

Since the ISV directory inherits from this web.config file, all the applications in the ISV directory will also have viewstate disabled.

 

So just add the following line to your web.config file in the ISV directory:

 

<pages enableViewState="true"/>

 

Personally I don’t really see the need to enable viewstate, in most cases it isn’t needed if the programmer understands it’s purpose, but sometimes your just trying to deploy code that someone else wrote.

Saturday, June 13, 2009 10:46:28 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
CRM | setup
# Saturday, June 06, 2009

A lot of functionality can be added to CRM with JavaScript, if your like me and do the bulk of your normal web development JavaScript with a toolkit like JQuery, you will quickly miss the power and ease of doing things without it. The good news is that it is pretty easy to load JQuery into the page:

 

image

 

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = '/ISV/jquery.js';
script.onreadystatechange = function()
{
if(this.readyState == "complete" || this.readyState == "loaded")
   setupPage();
};
 
var head = document.getElementsByTagName('head')[0];
 
head.appendChild(script);

 

Now you can use the setupPage() function with all your familiar JQuery goodness.

Saturday, June 06, 2009 9:12:47 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | CRM | JQuery
# Sunday, April 26, 2009

We needed the basic ability to redirect specific users to a different page. I first took a look at Adam Buenz excellent Redirection web part but we thought that it might be a little bit complex for our content authors to use, so I put together a really simple web part that gives the user the ability to select the users or groups via the standard SharePoint people picker interface.

 

image

 

The idea is that you can select a number of groups or users to apply the redirection to, this could be as broad as all authenticated users or refined to a single user. Of course you need a way edit the web part, so another people picker dialog allows the user to select users or groups that this redirect does not apply to. If they match the exclusion, the web part will present them with the text ‘This account was excluded from redirection to <url>’. This exclusion group is normally the content authors.

 

image

 

It is possible to put a number of these web parts on the same page, so if for example you wanted to redirect to a number of different sites based on AD group or user accounts, this should work fine.

 

First step, as always is to add the solution to SharePoint, once the solution is deployed, be sure to activate the ‘Redirector web part’ feature at the site level:

 

image

 

Once that is done, it’s just a matter of selecting the ‘Redirect web part’ from the web part gallery:

 

image

 

Hopefully you’ll find some use for it. The source code can be downloaded here and the WSP can be found here.

 

The code for this web part is fairly straight forward, I have a tool part that uses the SharePoint  PeopleEditor control. This control has a property to return the selection of groups or accounts as a comma separated string. With this string I can then do a search to see if the current user is in the group like:

        private bool IsUserIn(string commaSeperatedList)
        {
            bool isMatch = false;

            if (commaSeperatedList != string.Empty)
            {
                foreach (string group in commaSeperatedList.Split(','))
                {
                    if (Page.User.IsInRole(group) || Page.User.Identity.Name == group)
                    {
                        isMatch = true;
                    }
                }
            }
            return isMatch;
        }

 

So the web parts main logic looks like:

 

            bool redirectMatch = false;
            bool exclusionMatch = false;

            redirectMatch = IsUserIn(selectedADVal);
            exclusionMatch = IsUserIn(excludeADVal);
                   

            if (redirectMatch == true && exclusionMatch == false)
            {
                Page.Response.Redirect( redirectUrl);
            }
            else
           
{
                if (redirectMatch)
                {
                    outputCtrl.Text = "This account was excluded from redirection to " + redirectUrl;
                }
            }

Sunday, April 26, 2009 12:23:41 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | MOSS | Sharepoint
# Saturday, April 25, 2009

CRM 4 has lots of excellent customization options, one of which is the auto-numbering of entities:

 

image

 

The Settings – Administration section allows you to setup some options for auto-numbering your entities, you can choose the prefix, and the suffix length:

 

image

 

This is pretty powerful, but how would approach this problem if you needed your entities to have a more complex numbering scheme? Being a developer, everything looks like a development task to me. So I would start with a plugin that implements the IPlugin interface:

 

       public class AutoNumber : IPlugin

 

Then we need to implement the Execute method such as:

 

        public void Execute(IPluginExecutionContext context)
        {
           
            if (context.InputParameters.Properties.Contains("Target"))
            {
                DynamicEntity entity = (DynamicEntity)context.InputParameters.Properties["Target"];

                if (entity != null)
                {
                    if (!entity.Properties.Contains("AttributeName"))
                    {
                        entity.Properties.Add(new StringProperty("AttributeName", GetAutoNumber()));

                    }
                }
            }
        }

 

So the above code will check to make sure our input properties contains the ‘Target’ parameter, this will be the entity that is affected by the plugin. From here we can cast it to a DynamicEntity  which will make it easier to work with. Once we have an instance of DynamicEntity the whole task of updating and attributes becomes trivial, the above code just creates a new property and calls some method that will generate the complex AutoNumber.

 

Once the plugin has been developed, the next important step is to register the plugin. The best tool for the job is probably the CRM Plugin Registration Tool:

 

PlugIn_thumb

 

The first step is to register the plugin assembly:

 

image

 

This will prompt you with a form that allows you to select the assembly and the location it will be stored i.e. Database, file system or GAC.

 

Once the assembly has been registered we can register a ‘new step’, this is done from the same menu as the assembly registration.

You will be prompted to fill out the following form:

 

image

 

For our plugin we will choose the following options:

Message: Create  (since we are doing an auto number, it makes sense to only run the plugin at the create stage)

Primary Entity:  Your choice

Plugin: Your assembly that was loaded at the previous step

Post Stage: we want to run it after the entity has been created, otherwise the built in CRM auto numbering will overwrite our value.

Synchronous: lets fire the event synchronously, no reason not to, the end user will be presented with a consistent interface this way.

Step Deployment: your choice

Triggering Pipeline: Parent

 

As you can see its all fairly simple and straight forward, now you can have an auto number that be what ever you need, it might be simple like some combination of a financial year or complex where a lookup to some external system needs to take place, but at the end of the day at least there is a nice mechanism in place to help you out.

Saturday, April 25, 2009 6:50:35 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [1] - Trackback
code | CRM

By default when you edit the tool part settings of a SharePoint web part and you click on the ‘…’ if the property is a string, you will get the default property builder:

 

image

 

Clicking the above ‘…’ will launch the default string property builder:

Standard SharePoint Property Text Builder

 

This popup is actually the ‘zoombldr.aspx’ page located in the _layouts virtual directory.

 

There are a few problems with this builder, well it’s not so much the builder, the string property’s of the web part are serialised in a manner that strips out carriage returns. So if you were to spend time formatting the contents of this dialog, it will get wiped out when you save the contents. This is most apparent when you edit the XSLT of the core search results web part.

 

How can you override this property?

 

The key is to make use of the HtmlDesigner attribute on your web part property. There are two ways to make use of the attribute, the first way is to explicitly define the page which you want to load (i.e. change ‘url to page’):

 

        [System.Web.UI.WebControls.WebParts.WebBrowsable(true),
        System.Web.UI.WebControls.WebParts.WebDisplayName("Template"),
        System.Web.UI.WebControls.WebParts.WebDescription(""),
        System.Web.UI.WebControls.WebParts.Personalizable(
        System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared),
        System.ComponentModel.Category("Settings"),
        System.ComponentModel.DefaultValue("")
        ]
        [HtmlDesignerAttribute("url to page", DialogFeatures = "dialogHeight:500px;dialogWidth:650px;help:no;status:no;resizable:yes")]
        public string CustomProp
        {
            get { return customProp; }
            set { customProp = value; }
        }

 

Notice that you could also modify the parameters that get passed into the JavaScript popup window creation script, in the case above I have made the popup window larger than the default size. The problem with the above approach is that the URL that gets passed as the first parameter to the HtmlDesignerAttribute must be a constant value, since it’s used in the attribute declaration. However Microsoft have provided us with a nice way to change this behaviour.

 

        [System.Web.UI.WebControls.WebParts.WebBrowsable(true),
        System.Web.UI.WebControls.WebParts.WebDisplayName("Template"),
        System.Web.UI.WebControls.WebParts.WebDescription(""),
        System.Web.UI.WebControls.WebParts.Personalizable(
        System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared),
        System.ComponentModel.Category("Settings"),
        System.ComponentModel.DefaultValue("")
        ]
        [HtmlDesignerAttribute(BrowserBuilderType.Dynamic, DialogFeatures = dialogHeight:500px;dialogWidth:650px;help:no;status:no;resizable:yes")]
        public string CustomProp
        {
            get { return customProp; }
            set { customProp = value; }
        }

 

I’ve now added the BrowserBuilderType.Dynamic option. To get this to work, we now need to override the GetCustomBuilder method of your web part:

 

         protected override string GetCustomBuilder(stringpropertyName)
        {
            if(propertyName == "CustomProp")
            {
                return"url.aspx?"+ "some custom params";
            }
            return base.GetCustomBuilder(propertyName);
        }

 

Now every property that has BrowserBuilderType.Dynamic passed into the HtmlDesignerAttribute will get passed into the GetCustomBuilder method, this gives you the chance to create a URL that passes parameters to your custom builder page.

 

Ok, so now you got the web part covered, what about the JavaScript that needs to run on your custom property builder page?

 

The best thing to do is to look at the current zoomdldr.aspx page, when the page loads you can get the current arguments from:

 

window.dialogArguments

 

Then to save the arguments, save the string value back to:

 

window.returnValue

 

 

Now that you’ve got a fair idea about creating custom property builders, you can create builders that are specific to you needs, below is a screenshot of a property builder form that lets the user enter some c# code that gets compiled an injected into the web part, the need was to provide a nice interface that the end user (i.e. a programmer) could use. The property builder uses the EditArea control to format the code nicely. The user can then click the compile button which will do a compilation of the code and report any errors. I’ve also added some JavaScript code to get around the removal of the carriage return characters, which was a major pain point for us.

 

Custom Property Builder

 

 

This approach will give you the power to create property builders that more closely suit your needs and goals.

Saturday, April 25, 2009 12:44:51 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | Tip
# Tuesday, April 21, 2009

There is always lots of criticism about SharePoint from developers, things like bloated pages etc. But there is lots of good stuff in SharePoint, so I thought it might be fun to come up with a list of things that a typical asp.net application might be able to look at SharePoint for guidance.

 

1. Search - Have a good search story

We now have a whole generation that have grown up using a search engine, they expect a search box that they can type free form data, so by far the biggest feature that ASP.NET applications could learn a lot is the search capability of SharePoint. The good news is that you could use a product like search server express to crawl parts of your application and then use the search server web services like I did with my ASP.NET MVC search engine example.

 

2. Extensibility – Make your system extensible where it makes sense

SharePoint has a number of extensibility points like Features, Site Definitions, Web Parts which all work in different ways to allow fine grade control over the system. The model that SharePoint provides works well for the tasks that it is trying to achieve, your ASP.NET application may benefit from a plugin model that a framework like MEF provides, where crazy things like plugins for plugins are supported. Maybe you want to expose a RESTful service via ADO.NET Data Services, in any case extensibility has proved for many web applications (twitter, facebook) to be an important consideration.

 

3. Workflow - Hosting done right

Workflow has become a hot topic in recent years, lots of tasks are well suited to be modelled with a workflow, I’m sure your ASP.NET application has some actions that need some auditing or approval before action can be taken. SharePoint does a particularly good job at hosting Window Workflow Foundation, even if we exclude the building of custom workflow’s on the fly in SharePoint Designer, a great deal can be taken away from the way SharePoint has implemented WorkFlow, it’s made it simple for most users to understand.

 

4. Well designed API  

Well not everyone would agree with the ‘well designed’ bit, but for the most part you can achieve almost all the administrative activities from the API. Although a well built ASP.NET application should in theory have loosely coupled components that should facilitate an API, in practice most ASP.NET applications have code thrown all over the place, with event handlers performing data access etc. Ideally the well designed API should fit with the Extensibility point from number two, it’s no good having an extensible system if the API is unusable.

 

5. Background Processes – How do you handle them?

One thing that SharePoint does particularly well is the background processing of tasks like Active Directory imports, site cleanup processes and scheduled emails. The API from the above point extends to the scheduling plugin’s as well, the main point here is that SharePoint runs these tasks as a windows service, this is in contrast to applications like DotNetNuke which do background and scheduled processing on the application OnStart event. Both are valid approaches given certain circumstances, my point is that the difference between a professional product like SharePoint and a custom ASP.NET application is the little house keeping items, SharePoint tries to take care of it all, so should your ASP.NET application.

 

6. Integration with the Microsoft Software Ecosystem

SharePoint being a Microsoft product plays nice with other Microsoft systems, your ASP.NET application can do the same, things like using Exchange for email events to support incoming email. Making use of active directory groups for authentication and authorisation or even for organisation charts and manager notifications, this integration is what really differentiates Microsoft’s products and makes people feel more comfortable. Does your ASP.NET application provide custom WMI performance counters for it’s operations?

Tuesday, April 21, 2009 10:48:44 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [1] - Trackback
Misc
Statistics
Total Posts: 191
This Year: 0
This Month: 0
This Week: 0
Comments: 41