How to Create Custom Content Types with Code for SharePoint 2010

Creating content types is one of the fundamental features of SharePoint, and although you can create your own content types through the user interface of SharePoint, I'd like to show you a couple options on how you can create your own content types using code. I am going to jump right in, so if you need a refresher on what content types are, please review Kelly Rusk's article on content types.

Option 1: Custom Content Types (via a Content Type project)

The first (and probably the easiest) way to create a custom content type is to use Visual Studio 2010 to create a special project type of type Content Type. I'm going to create a custom content type named MovieData, which will have a choice column that will allow selection of a movie genre, when creating/uploading a document.

Launch Visual Studio 2010 and create a new project. Click on the installed project templates to display the templates in the SharePoint 2010 section, and select the template named Content Type. Give the project the name MovieData and click the OK button.

The SharePoint Customization Wizard opens, which will display a series of steps you need to provide information for, so Visual Studio can configure your project properly. On the first screen, enter the URL of the SharePoint site you want this content type to be deployed to. You should also select the Deploy as a farm solution radio button. Press the Next button to continue.

The next screen requires that you choose which content type to inherit the content type from. We want to inherit from the Document content type, so select Document from the dropdown list, and press the Finish button. Visual Studio will now create the project, and we are ready to finish coding our custom content type.

You will notice that for the Content Type project template, Visual Studio creates an elements.xml file as part of the project. This is the only file we will need to modify to complete our custom content type. Open the elements.xml file, and under the ContentType node, set the Name attribute to 'MovieData'. You can optionally set the Description attribute value to whatever you like, and if you wish to have the content type be displayed in a specific content type group, you can modify the Group attribute value. Note that the ID attribute value represents the GUID value of the content type we inherited from (the Document content type).

The next step is to create the Genre column that will be part of our MovieData content type. To do this, add a Field element inside the Elements node, right before the ContentType node. Set the Name and DisplayName attribute values to 'Genre', and make the column a choice column by setting the Type attribute to 'Choice'. You also need to give the field a unique ID value (a GUID), which you can use the GUIDGEN tool to do this for you.

Since the column we are adding is a choice column, we now need to add entries that will be displayed when the user is selecting an entry. Add a CHOICES node inside the Field element, and then add one or more CHOICE nodes inside the CHOICES node.

Once you have this column defined, you must add a field reference so the column can be displayed as part of the content type. Add a FieldRef element inside of the FieldRefs node, as seen here:

Make sure you use the same GUID that you created when you created the Field element, and give the Name and DisplayName attributes a value of 'Genre'. Save the elements.xml file when you are finished.

The project is now ready to be compiled and deployed to our SharePoint site. Right mouse click the project in Solution Explorer, and select Deploy. Visual Studio will compile the project, deploy the content type (as a Feature), and automatically activate it at the site level.

At this point, our custom content type is ready to use, but first we need to enable it in the document library that we want to use it in. I have created a normal document library in my SharePoint site named Movies. Navigate to the Document Library Settings page, and click on Advanced Settings. Enable management of content types, and click OK. This allows us to add our content type for this document library, so we can classify documents with this content type.

When you return to the Document Library Settings page, you will notice that under the Content Types section, there is the Add from existing site content types link. Click on this link to add our MovieData custom content type to this library.

I have also specified that our MovieData content type is the default content type by making it the first in the list of content types (selecting '1' in the Position from Top selection), under the Change new button order and default content type link. Click OK when finished.

That's it! We are now ready to upload (or create) a document to our library, and our content type will be used when uploading/creating the document. You will notice that a dialog is displayed when I upload a document, allowing selection of a Genre metadata field when uploading the document.

Option 2: Custom Content Types (via a blank SharePoint project)

The second way to create a custom content type is to do it with SharePoint object model code. The code will be deployed as a feature also, but the content type will be created when the feature is activated. This has the advantage that if you need to do anything custom to your content type before it gets created, you can handle that with code.

I am going to create the same MovieData content type that I created in Option 1, so you can see the differences in how the content type is created.

Launch Visual Studio 2010 and create a new project. Click on the installed project templates to display the templates in the SharePoint 2010 section, and select the template named Empty SharePoint Project. Give the project the name MovieData and click the OK button. You will notice that Visual Studio only asks you to specify whether the project should be deployed in a farm or sandbox solution (select the farm solution). Visual Studio doesn't ask you for any additional information when creating the project, as it did in Option 1. An empty SharePoint project assumes you will handle all the configurations yourself.

The next step is to create a feature, as this is how we will deploy our custom content type. Right mouse click the Features node in Solution Explorer, and click on Add Feature. This will create a feature in the project and open the designer page for the Feature1.feature file. We want to add code to the events that fire when the feature is activated/deactivated, so in order to do that we need to add an event receiver to the feature. Right mouse click the Feature1.feature file in Solution Explorer, and click on Add Event Receiver:

Visual Studio creates a Feature1.EventReceiver.cs file, which contains the event handlers for the FeatureActivated, FeatureDeactivating, FeatureInstalled, FeatureUninstalling, and FeatureUpgrading events. We are only going to add code to the FeatureActivated and FeatureDeactivating events. Uncomment the FeatureActivated event, and add the following code snippet:

SPWeb thisWeb = (SPWeb)properties.Feature.Parent;
thisWeb.AllowUnsafeUpdates = true;

SPContentTypeCollection contentTypes = thisWeb.ContentTypes;
SPContentType parent = thisWeb.ContentTypes["Document"];
SPContentTypeId parentID = parent.Id;

SPContentType MovieDataCT = new SPContentType(contentTypes[parentID], contentTypes, "MovieData");
contentTypes.Add(MovieDataCT);

string GenreField = thisWeb.Fields.Add("Genre", SPFieldType.Choice, false);
SPFieldChoice genre = (SPFieldChoice)thisWeb.Fields.GetFieldByInternalName(GenreField);
genre.Choices.Add("Comedy");
genre.Choices.Add("Documentary");
genre.Choices.Add("Drama");
genre.Choices.Add("Science Fiction");
genre.Choices.Add("Western");
genre.Update();

SPFieldLink genreLink = new SPFieldLink(genre);
MovieDataCT.FieldLinks.Add(genreLink);
MovieDataCT.Update();

SPList MovieList = thisWeb.Lists["Movies"];
MovieList.ContentTypesEnabled = true;
MovieList.Update();
MovieList.ContentTypes.Add(MovieDataCT);
MovieList.Update();

SPContentTypeCollection listCTs = MovieList.ContentTypes;

System.Collections.Generic.IList newOrder = new System.Collections.Generic.List();
newOrder.Add(listCTs["MovieData"]);
newOrder.Add(listCTs["Document"]);

MovieList.RootFolder.UniqueContentTypeOrder = newOrder;
MovieList.RootFolder.Update();

This code will execute when the feature is activated, and is responsible for all the steps of creating our custom content type. Let's go through each area of the code.

SPWeb thisWeb = (SPWeb)properties.Feature.Parent;
thisWeb.AllowUnsafeUpdates = true;

SPContentTypeCollection contentTypes = thisWeb.ContentTypes;
SPContentType parent = thisWeb.ContentTypes["Document"];
SPContentTypeId parentID = parent.Id;

SPContentType MovieDataCT = new SPContentType(contentTypes[parentID], contentTypes, "MovieData");
contentTypes.Add(MovieDataCT);

The first thing the code does is get a reference to the SharePoint site and set the AllowUnsafeUpdates property, so we can modify the site through code. We then need to reference the Document content type defined, so we can create our custom content type, inheriting from the Document content type. Once we have this, we then create our new content type called MovieData, and add it to the content type collection defined for our SharePoint site.

SPWeb thisWeb = (SPWeb)properties.Feature.Parent;
string GenreField = thisWeb.Fields.Add("Genre", SPFieldType.Choice, false);
SPFieldChoice genre = (SPFieldChoice)thisWeb.Fields.GetFieldByInternalName(GenreField);
genre.Choices.Add("Comedy");
genre.Choices.Add("Documentary");
genre.Choices.Add("Drama");
genre.Choices.Add("Science Fiction");
genre.Choices.Add("Western");
genre.Update();

The next step is to create the Genre site column that is part of our MovieData content type. This will be a Choice column, so we will instantiate a variable of type SPFieldChoice class to create the column of the proper type. We also need to add some choices to be available, and then finally calling Update() will create the site column on the SharePoint site.

Once the site column is created, we need to link it to our content type. This is done with a SPFieldLink class, specifying the site column to link. The code adds this to the FieldLinks collection of our content type, and then calling Update() on our content type actually creates the custom content type on the SharePoint site.

SPWeb thisWeb = (SPWeb)properties.Feature.Parent;
SPList MovieList = thisWeb.Lists["Movies"];
MovieList.ContentTypesEnabled = true;
MovieList.Update();
MovieList.ContentTypes.Add(MovieDataCT);
MovieList.Update();

Now that our content type has been created, we can now use it in our Movies document library. In order to do this, the code first makes sure that content type management is enabled for our document library, and then adds the content type to the document library. Note that we need the call to the Update() method after setting the ContentTypesEnabled flag to true. If we omit this, then adding the content type to our document library would throw an exception, as content type management has not been enabled.

SPWeb thisWeb = (SPWeb)properties.Feature.Parent;
SPContentTypeCollection listCTs = MovieList.ContentTypes;

System.Collections.Generic.IList newOrder = new System.Collections.Generic.List();
newOrder.Add(listCTs["MovieData"]);
newOrder.Add(listCTs["Document"]);

MovieList.RootFolder.UniqueContentTypeOrder = newOrder;
MovieList.RootFolder.Update();

The final step that the code takes is to set our MovieData content type as the default content type for the Movies document library. This is done by creating a generic list variable of type SPContentType, and adding the existing content types for our document library to it. What is important to remember here is the order in which the content types are listed in the generic list variable, as SharePoint considers the first content type in the list to be the default. The code builds this list and replaces the existing list in our document library by replacing the UniqueContentTypeOrder variable. Calling Update() on the RootFolder commits the changes back to SharePoint.

Since we are creating a content type when a feature is being activated, it makes good sense that we clean up after ourselves when the feature is deactivated. Uncomment the FeatureDeactivating event handler, and add the following code snippet:

SPWeb thisWeb = (SPWeb)properties.Feature.Parent;
thisWeb.AllowUnsafeUpdates = true;

SPContentTypeCollection contentTypes = thisWeb.ContentTypes;
SPContentType MovieDataCT = thisWeb.ContentTypes["MovieData"];
SPContentTypeId MovieDataCTID = MovieDataCT.Id;

SPList MovieList = thisWeb.Lists["Movies"];
SPContentTypeId listCTID = MovieList.ContentTypes["MovieData"].Id;

// Delete any list items of our content type first
foreach (SPListItem item in MovieList.Items)
{
if (item.ContentTypeId == listCTID)
item.Delete();
}

MovieList.ContentTypes["MovieData"].Delete();
MovieList.Update();

SPContentTypeCollection listCTs = MovieList.ContentTypes;

thisWeb.ContentTypes.Delete(MovieDataCTID);
thisWeb.Update();

thisWeb.Fields["Genre"].Delete();
thisWeb.Update();

This code snippet handles all the steps needed to remove the MovieData custom content type, as well as the Genre site column from our SharePoint site. Note that before the content type can be removed, the code goes through the Movies document library and deletes any documents that have been classified with our custom content type.

In conclusion, I've shown you two different options on how to create custom content types with code. The first option is the quickest way to accomplish this, and the second option gives you more control and flexibility, if you need to add any custom functionality or logic when implementing your custom content types.



How to Allow anonymous access to SharePoint application pages in the _layouts directory

Often times, you need to add your own custom application pages (aspx) to SharePoint, which are deployed to the '_layouts' directory. These types of pages could consist of a custom login page, maintenance pages, or even complete web applications that you'll have live in SharePoint. But what if your web application has an authentication provider set up, such as Claims or Windows? In this article, I'll show you how easy it is to allow anonymous access to these pages without forcing a user to log in.

Create the project

  1. In Visual Studio 2010, create a new "Empty SharePoint Project" and name it "MyAnonymousWebPages".
    Click OK
  2. Enter your SharePoint site
  3. Select "Deploy as a farm solution"

Adding the custom Pages

Next, we need to map the 'layouts' directory to our project, so our files are deployed
there.

  1. Right click on the project name 'MyAnonymousWebPages' > Add > SharePoint "Layouts"
    Mapped Folder
  2. SharePoint will automatically add a folder under 'layouts' with the name of our
    project. Right click on this folder >Add > New Item > Application Page
  3. Name the page "HelloWorld.aspx"
  4. Your project should now look like this:

Allowing anonymous access

So far, we haven't done anything special. The steps we've taken is the basic approach
to adding custom application pages. In the following steps, we will inherit from "UnsecuredLayoutsPageBase". This is a base class for application pages that do not require the user to have any permissions.

  1. Open up HelloWorld.aspx.cs
  2. By default, the page is inherited from "LayoutsPageBase". Change the inheritance
    from "LayoutsPageBase" to "UnsecuredLayoutsPageBase".

    public partial class HelloWorld : UnsecuredLayoutsPageBase
  3. Next, we need to override a property of the UnsecuredLayoutsPageBase, to allow the
    anonymous access. Be sure to change the 'getter' to return true

    protected override bool AllowAnonymousAccess { get { return true; } }
  4. Add some content to your markup in the 'PlaceHolderMain'

Deploy the solution

  1. Right click on your project name, and select 'Deploy'
  2. Once deployment is complete, browse to your page by navigating to
    http://{yourSharePointUrl}/_layouts/MyAnonymousWebPages/HelloWorld.aspx
  3. See your custom page, like below (notice, by default, the ApplicationPage template
    in Visual Studio is designed to automatically inherit from the master page. You
    could instead replace the markup with markup from a standard aspx page template).





How to Rename the SharePoint Search Databases

If you have created the SharePoint Search Service Application using the GUI in SharePoint you have probably noticed that it has added some ugly GUIDs on the end of your database names. In this blog post I will show you how to get rid of them.

Renaming the Crawl Store and Property database will be pretty easy but the Admin database will take a little bit of work.

Renaming the Crawl Store and Property database

1.Open Central Administration and go to manage service applications. Now select your Search Service Application and hit manage.

2.At the bottom of the page and click modify in the Search topology Section.

3.Click on the Edit Properties for the crawl database.

4. On the Edit Crawl Database Screen go to the Database Name Field. Here you can highlight the GUID and delete it off the end of your database then click ok.

5. You can now repeat steps 3 and 4 for the property database.

Renaming the Search Admin Database

If you try to edit the Admin database you will notice that it is greyed out and you can't change it using the GUI. In order to change it we will need to use the SQL Server Managment Studio as well as powershell.

1. Open SQL server managment studio and find your search admin database. If you are not sure which one is your admin database you can find it in the Search Service application at the bottom of the page.

2. Back up the admin Database. You can do this by right clicking on the database selecting tasks then Back Up…

3. Now right click on on the Database folder and select Restore Database.

4. In the restore database window select From Device. Then click the radio button and select the backup of the admin database you just made. Now that you have the backup selected enter the new name you would like for the database in the to database field. Now you can click OK then click OK again at the database restored successfully screen.

5. Now get back on the SharePoint server and open the SharePoint Managment Shell as Administrator.

6. Now enter the following line into the PowerShell to set the identity of your Search Service Application:

$searchssa=Get-SPEnterpriseSearchServiceApplication -identity "Your Search Service Application".

7. Next we will want to pause the Search Service Application before we add the database. We will do this with the following PowerShell command:

$searchssa.Pause()

8. Now we are going to add set our newly named database as the Search Admin database. We will do this with the following PowerShell command:

$searchssa | Set-SPEnterpriseSearchServiceApplication -DatabaseName "Your newly named SharePoint Admin DB" -DatabaseServer "Your SQL Server"

9. Now we will want to resume our Search Service Application. We will do this with the following PowerShell command:

$searchssa.Resume()

10. Now go back to your Search Service Application and check your databases. The GUIDS will all be gone.

11. The database may look like it is no longer in SharePoint but if you run the command you will see that it still is:

get-spdatabase | Select Name, ID

12. Mark the ID for the old database from above then run this PowerShell command:

$olddb=get-spdatabase <ID of old DB>

13. Next we want to delete the old database so we will run the PowerShell command:

$olddb.Delete()

14. Now that we have deleted the old admin database from SharePoint the last step is to delete the old database from SQL. To do this we go into SQL Server Managment Studio right click on the old database and select delete.

15. On the next screen check the close existing connections box then click ok.





How to Migrate All Users From OCS Environment To Lync Server 2010 Pool With One PowerShell Command

Migrate All Users From OCS Environment To Lync Server 2010 Pool With One PowerShell Command

If your organization is undertaking a migration from Microsoft Office Communications Server 2007 R2 to Lync Server 2010, at some point you will be tasked with migrating all existing user accounts (and assoc. contacts / groups) from one platform to another. Below is a PowerShell command (to be executed from the Lync Server Command Shell) that will query for all users hosted on the OCS platform and then move all returned results to the specified Lync Server pool.

Get-CSUser -OnOfficeCommunicationsServer | Move-CSLegacyUser -Target "lyncpool01.microsoft.com"





Things to note when installing Service Pack 1 for SharePoint 2010

Here are a few things to watch out for that I have seen create some major issues when installing Service Pack 1 for SharePoint 2010.


1. Make sure you have all the Service Pack 1 updates you need

When installing Service Pack 1 you need to make sure you have all the right Service Pack 1 upgrades. Unfortunately, Language Packs are all individual and there is a Foundation and a Server for each one.

2. List of the SharePoint 2010 SP1 downloads:

3. Stop the User Profile synchronization service

There have been a lot of issues when installing service pack 1 related to the user profile service. Stop any running synchronizations and stop the user profile synchronization this will help to avoid these errors from happening.

4. Restart your Servers

Make sure that you restart your servers after installing all of the foundation updates and then again after installing the server updates. If you do not restart you servers you can run it to some challenging issues.

5. Cache issues

Sometimes after installing a service pack to a server you will run the configuration wizard and it will give you an error that the service pack is not installed on the server. This issue will persist even after hitting the refresh button on the configuration wizard. To resolve this issue run the powershell command below from the SharePoint Management Console. This will reset the cache file that the configuration wizard is looking to.

Get-spproduct-local

6. The Configuration Wizard Fails

There is a good chance when you are doing the SP1 upgrade that the Configuration Wizard will fail on one of your servers. If it does run the psconfig.exe command (from the 14 hive bin folder) shown below:

.\psconfig.exe –cmd upgrade –inplace b2b –force -wait


 


Enabling Lync Server 2010 for Lync Mobile Clients

As the Lync mobile clients are released so are the server side setup notes. This article will go through the steps for setting up your environment and make it ready for the Lync mobile clients.

Note: This post will be updated as the Lync community get more hands on with the service. Last update 23.12.2011

Lync Mobile features

Lync mobile client is released for Windows Phone 7, iPhone, iPad, Android and later on Nokia (Symbian). The feature set is about the same accross the platforms. There is no ability to view meeting content, video or do voice over IP. The main features is therefore

  • IM and presence
  • One Click join meetings
  • Call via work

For a detailed feature list see the TechNet article: http://technet.microsoft.com/en-us/library/hh691004.aspx

Planning for Lync Mobility

If you have a multi-homed Front End server the Mobility Service (Mcx) may sometimes fail

  • Reason: When calculating routing for a Mobility request the service makes a call to read DNS settings of the registered adapter. In some instances it is possible for the non-registered adapter to be returned.
  • This causes routing of the request to fail This is regardless subnet configuration on the second NIC
  • There should be a forthcoming Release Note or KB Article on this topic

If you use a Director it must be updated the same way as for a Front End

If you plan to support Lync Mobility and Push Notifications over a Wi-Fi you need to

Prerequisites

This Lync Mobility guide requires that your Lync solution is deployed with Lync Edge server and Reverse Proxy. This guide will only talk about Lync Mobility specific configuration

Install CU4 (November release) or later in you Lync infrastructure: http://go.microsoft.com/fwlink/?LinkID=208564.

IIS 7.5 is recommended because of some high load request limitations

If you use Hardware Load Balancer

  • You must ensure that cookie-based persistence on a per port basis for external ports 4443 and 8080 on the hardware load balancer is configured
  • For Lync Server 2010 it is important to use cookie-based persistence so that multiple connections from a single client are sent to one server to maintain session state
  • For details on how to configure, see Load Balancing Requirements.

Install the IIS feature Dynamic Content Compression (Web-Dyn-Compression) on all involved Front End servers

  • Server 2008: ServerManagerCMD.exe –Install Web-Dyn-Compression
  • Server 2008 R2: Import-Module ServerManager; Add-WindowsFeature Web-Dyn-Compression

Enabling Lync Mobility

Configure Lync Mobility Autodiscover CNAME DNS records

  • Internal: lyncdiscoverinternal.sipdomain.com
  • External: lyncdiscover.sipdomain.com
    • Point it to your Reverse Proxy FQDN if using SSL or a new publishing rule and IP if you are using port 80
    • To find you reverse proxy FQDN use this PowerShell oneliner on your Front End server
      • Get-CsService -WebServer | ft ABHandlerExternalUri

Configure listening ports for the Mobility Service (Mcx)

  • Verify that your server version is correct by running PowerShell cmdlet: Get-CsServerVersion
    • Version should be 4.0.7577.0 or newer
  • In PowerShell run the following cmdlet for internal and external listening port
    • Set-CsWebServer –Identity <internal FE Pool FQDN> -McxSipPrimaryListeningPort 5086 -McxSipExternalListeningPort 5087
  • Publish the updates to the CMS database
    • Enable-CsTopology –verbose

Download and enable the Lync Mobility

  • Do not install, but download the McxStandalone.msi and place it in the following folder on all Front End servers and Directors
  • Run the Lync Server Deployment wizard, found under Administrative tools-> Lync Server
    • In the wizard click Install or update Lync Server System
    • Choose Step 2: Setup or Remove Lync Server components
    • This will reconfigure the Lync Services on the Front End with the new listening ports
  • Verify that the server is configured correct, open IIS and check for Autodiscover and Mcx Vdirs

Update certificates on Front End and Edge/TMG

  • Still in the Lync Server Deployment Wizard choose step 3: Request, Install or Assign Certificates
  • You need to request a new certificate with the new name, make sure you get all additional SAN entries from the old certificate
  • If you use the same certificate on all Front End services you can use this PS onliner to get a list of your certificates SAN's
    • On FE: Get-CsCertificate -Type default | Select-Object -ExpandProperty AlternativeNames
  • If you use the same certificate on Edge and TMG you can run the below command to get all SAN's
    • On Edge: Get-CsCertificate -Type DataEdgeExternal | Select-Object -ExpandProperty AlternativeNames
  • To reissue the certificates using PowerShell see Ari Protheroe's blog post: http://ariprotheroe.wordpress.com/2011/12/10/reissuing-certificates-for-lync-mobile/

Configuring Push Notification

  • Push Notification is used by the Mobility Service to send notifications to Apple and Microsoft phones that has the Lync application running in the background to wake them up
  • To enable push notification run the following cmdlet:
    • Set-CsPushNotificationConfiguration -EnableApplePushNotificationService $True -EnableMicrosoftPushNotificationService $True
  • You need to enable federation with Office365 as a hosted provider if you have not already done so
    • New-CsHostingProvider -Identity "LyncOnline" -Enabled $True -ProxyFqdn "sipfed.online.lync.com" -VerificationLevel UseSourceVerification
  • You then need to set up a hosting proivder between your organization and the Push Notification Service at Lync Online
    • New-CsAllowedDomain -Identity "push.lync.com"

Publishing externally

There is two possibilities when publishing Lync Mobility through a reverse proxy

  • Publish through port 80 using the same IP as your existing Lync publishing rule
    • Pros: you don't have to update on your reverse proxy certificate with an extra SAN name
    • Cons: you need to open port 80->8080 on a new rule and it is not recommende to do this by Microsoft
    • Result: discovery information for you Lync mobile clients will get information about logon server unencrypted, the rest is encrypted the usual way
  • Publish through port 443 using the same IP as your existing Lync publishing rule
    • Pros: All traffic will be encrypted, you just need to add lyncdiscover.sipdomain.com to public name on the publishing rule
    • Cons: You need to add an extra SAN name for lyncdiscover.sipdomain.com on your reverse proxy certificate
    • Result: all traffic are encrypted
  • Take a look at Adam Jacobs blogpost at the bottom for how to create a new rule

Testing and Troubleshooting

I have written a blogpost on how to test and troubleshoot Lync Mobile and Mobility here: Lync Server Mobility Troubleshooting Tips: http://msunified.net/2011/12/23/lync-server-mobility-troubleshooting-tips/

How to test the services

You can test that the services are working correct by accessing some URLs

To check that Autodiscover is working as expected, check the Autodiscover urls in a webbrowser

  • Get-CsService -WebServer | fl autodiscover* to find the urls
  • Example: https://<Webservices URL>/autodiscover/autodiscoverservice.svc/root/

To check that the mobility service is working use the following url

  • https://<FE pool FQDN>/mcx/mcxservice.svc

You can test the Push Notificaton Service using the following cmdlet where sip.sipdomain.com is you AccessEdgeFQDN

  • Test-CsFederatedPartner –TargetFqdn <internal edge fqdn> –Domain push.lync.com –ProxyFqdn sipfed.online.lync.com
  • Test-CsMcxPushNotification –AccessEdgeFqdn <internal edge fqdn>
  • NOTE: you may get a 30008 error when running Test-CsMcxPushNotification, but it is working anyway

You can test the Mobility Service using the following script, at this time it does not work with preconfigured CsHealthMonitoringConfiguration

1 $passwd1 = ConvertTo-SecureString "Password01" -AsPlainText -Force $passwd2 = ConvertTo-SecureString "Password02" -AsPlainText -Force
2 $tuc1 = New-Object Management.Automation.PSCredential("contoso\UserName1", $passwd1)
3 $tuc2 = New-Object Management.Automation.PSCredential("contoso\UserName2", $passwd2)
4 Test-CsMcxP2PIM -TargetFqdn pool01.contoso.com -SenderSipAddress sip:UserName1@contoso.com -SenderCredential $tuc1 -ReceiverSipAddress sip:UserName2@contoso.com -ReceiverCredential $tuc2 –v

Monitoring the Mobility Performance

There are several places you can monitor Mobility, here from TechNet:

References

MVP Adam Jacob's blog: http://imaucblog.com/archive/2011/12/09/step-by-step-microsoft-lync-2010-lync-mobility-mcx-installation-guide/
Ben Lee's blog: https://www.bibble-it.com/2011/12/10/configuring-lync-mobility-part-1
MVP Jeff Schertz's blog: http://blog.schertz.name/2011/12/deploying-the-lync-2010-mobility-service/
Lync Server Mobility Troubleshooting Tips: http://msunified.net/2011/12/23/lync-server-mobility-troubleshooting-tips/
Microsoft Lync Server 2010 Mobility Guide: http://www.microsoft.com/download/en/details.aspx?id=28355
Planning for Mobility: http://go.microsoft.com/fwlink/?LinkId=235303
Deploying Mobility: http://go.microsoft.com/fwlink/?LinkId=235304
Monitoring Mobility for Performance: http://go.microsoft.com/fwlink/?LinkId=235305





How to configure Lync Server 2010 features

Now that Lync has gone RTM and Virtual Launch is done we need to get down to business and deploy Lync to the general masses. During the time of Beta, RC and early RTM a lot of great blog articles were published about features and how to configure them. I wanted to collect the posts I find interesting here so I have them all in one place when I deploy Lync Server to my customers. I will update this article with new posts as I find them or when they get published.

Last updated: 16.10.2011





How to resolve the DelayActivity bug in SharePoint 2010 Workflows

I recently came across a problem using DelayActivity objects in custom SharePoint 2010 workflows that I'd like to discuss here, in the hopes of saving others the hours of investigation that I went through to resolve the problem (and to remind myself of the solution if I encounter this problem on a future project).

Using DelayActivity objects is pretty cool, as it allows your custom workflows to delay for a specified period of time before continuing execution. Unfortunately, the problem I was experiencing was that the workflow would never wake up after the DelayActivity.TimeoutDuration value expired.

Searching on the Internet gives a number of posts, with varying suggestions for both SharePoint 2007 and 2010. Since I'm working with SharePoint 2010, I ignored the posts on 2007, and focused on the suggestions for 2010. One of the best ones is here:

http://www.dev4side.com/community/blog/2010/12/1/bug-using-delay-activity-on-sharepoint-2010-workflow.aspx

I followed the instructions to this, and initially it worked just fine. However, as I continued my development I noticed that the problem would reappear, so this made me think that the suggested resolution was not the root cause, and that some other resolution needed to happen to definitively fix this problem.

It turns out that one final step is missing: if you are in the midst of a development cycle (as I was), you must run IISReset and restart the SharePoint Timer Service each time after you redeploy your workflow. Once I realized (and tested) this, my workflow functioned properly.

I hope this helps others when they are using DelayActivity objects in custom workflows.





How to Create Custom Edit Forms with InfoPath in SharePoint 2010

Users have the ability to display and edit properties (known as metadata) for items in SharePoint document libraries and lists. This is standard functionality that comes with SharePoint, and SharePoint provides a standard form when displaying/edit an item.

SharePoint also provides the ability for power users or developers to customize these display/edit forms, using InfoPath. I am going to run through the steps to customize a SharePoint 2010 list, to create a custom display and edit form. I will be using InfoPath 2010 (along with Visual Studio 2010) to demonstrate how you can call a web service method from the custom InfoPath form.

Customizing a SharePoint 2010 List

When you create a list in SharePoint 2010, a standard display/edit form is used, so the first step in customizing a list to use your InfoPath form is to navigate to the SharePoint list, and click on the List tab in the ribbon. This will display ribbon items for the list, and you can click on the Customize Form button, in the Customize List section (Figure 1).

Figure 1: Customize Form ribbon button for a SharePoint list

Once you do this, SharePoint creates a custom template with InfoPath 2010, based on the current columns defined for your list. You can use SharePoint Designer 2010 to verify whether a SharePoint list is using a customized list, as seen in Figure 2 (Figure 3 shows a list that does NOT have a customized InfoPath form):

Figure 2: SharePoint list with a Customized InfoPath 2010 Form

Figure 3: SharePoint list without a Customized InfoPath 2010 Form

When you click the Customize Form button in the ribbon, InfoPath 2010 Designer will open up with the customized form template created for you. At this point, you should make your modifications to the form (we will discuss this in more detail in the next section) and publish the form back to the SharePoint list. One thing to remember is that if you do not publish the form back to the list at this point (you will be prompted if you exit the form), SharePoint will not save the form template as a customized form, meaning your list will continue to use the default form.

For my example list (named TestCustomEditForm), I just published the custom InfoPath 2010 form template back to the list without making any modifications. Once this was completed, clicking on an item in the library displayed my custom form, as seen in Figures 4 and 5. The next section will discuss how to design more advanced changes to the customized form template.

Figure 4: Customized View Item Screen for a SharePoint list

Figure 5: Customized Edit Item Screen for a SharePoint list

Designing a Custom Display/Edit Form with InfoPath 2010

Once you have created a custom form template using InfoPath 2010, there are a lot of options available to you to design the form to your specifications. I am going to show you three things you can do to customize your form template: Adding a custom field that is a lookup to another SharePoint list, creating different views for the Display, Edit and New forms, and calling a web service method to retrieve data in a column when the form loads.

Adding Custom Fields

Adding a custom field is done in InfoPath 2010 Designer, and is very easy to do. Design your form template and in the lower right panel, there is an Actions section. You can click on the Add Field link, and a dialog to add your field information will be displayed (Figure 6).

Figure 6: Adding a Custom Field

Enter your information about the field you are adding, and press OK to add the field. In my example, I am adding a Genre field, which is a lookup to a SharePoint list called Genre. Selecting a value of Lookup (Information in a SharePoint list) in the Data Type entry field will configure the field to be a lookup to a SharePoint list. I also selected Genre from the Get Information From field, which appears after you select the Lookup data type.

After you have entered all the information for your field and clicked OK, the field will appear at the bottom of the Fields section. You can now drag and drop the custom field onto the form design surface, and InfoPath will create the appropriate control for you. In my example, since the Genre field is a lookup to a SharePoint list, InfoPath creates a dropdown control when I drag and drop the field to the design surface (see Figure 7).

Figure 7: Adding a Control for a Custom Field

You can now publish the modified form template to SharePoint, and you will see the Genre column added, as well as the field displayed when viewing/editing an item. Figures 8 and 9 show the list after these changes.

Figure 8: Update SharePoint list with a Custom Column

Figure 9: View Item with a Custom Column

Customizing Different Views

If you need to customize the different views (View/Edit/New Item) for a SharePoint list, you can accomplish that by creating different views in the form template in InfoPath. For my example, I created three (3) views in InfoPath: Display Item, Edit Item and New Item. The only difference between these views is the label for the Title field (of course, in a real-world scenario, your changes would be more extensive).

After these views are created, publish the form back to SharePoint, and in order to "wire up" the different views to the custom pages being used, you need to modify the web part in the different custom forms created (when you originally clicked Customize Form for the list). This is done by clicking on the Modify Form Web Parts (under the Customize List section in the ribbon) to display the different custom forms created (See Figure 10).

Figure 10: Modifying Form Web Parts

The web part properties for each Item form (not the Default forms) needs to be modified to display the proper view. For example, Figure 11 shows the custom form for New Items. Under the Edit tab in the ribbon, select the current view to display that view in the page.

Figure 11: Selecting the View for the Web Part

You also need to modify the web part properties for the web part on the page, as seen in Figure 12. Click on the Options tab in the ribbon (under Web Part Tools), and select the appropriate view you created (from InfoPath), under the Views dropdown. Apply the change and Stop Editing to finish with your changes.

Figure 12: Modifying Web Part Properties for the Web Part

Once you make these changes for each of the views, you can see the changes when you display, edit or create a new item, as shown in Figures 13 and 14. Notice that SharePoint automatically makes the controls read only (or editable), depending on which view is being displayed.

Figure 13: Customized View Item Form

Figure 14: Customized Edit Item Form

Calling a Web Service Method from a Custom Form

Another powerful customization is the ability to call a custom web service method (to retrieve data for a field, for example). Before you can allow your custom InfoPath form to call a web service method, you need to verify the Cross-Domain Access for User Form Templates option is selected (Figure 15). This setting is found in Central Administration, under the Configure InfoPath Forms Services area (look in the General Application Settings section).

Figure 15: Customized Edit Item Form

In order to call a web service method, a data connection must first be configured in the InfoPath form template. Make sure you select a connection to receive data, and select SOAP Web service in the Data Connection Wizard (Figures 16, 17).

Figure 16: Receive Data Connection in Data Connection Wizard

Figure 17: Data Source selection in Data Connection Wizard

To complete the data connection for your web service, enter the URL to the web service and select the web service method you are using. For my example, I'm using a method titled HelloWorld, which takes no input parameters and returns a simple string value.

Once you've created this connection, you need to convert it to use a data connection file (UDCX file). This is needed for security purposes, so that the user is not prompted for credentials. Click on the Convert to Connection File button in the Data Connections window (Figure 18) for your newly-created web service connection. A dialog will appear, prompting for a URL to the data connection file (Figure 19). Enter the path and file name to a data connection file that will be created when you click the OK button. For my example, I created a Data Connection library earlier named DataConnections, and used the URL to that library when creating the UDCX file.

Figure 18: Converting a Data Connection to use a Connection File

Figure 19: Convert Data Connection Dialog

At this point, your web service method is configured for use in the template, so the final step is to wire up the method to a field on the form. For my example, I created another string field (named HelloWorld) and added a text box on the design surface. I then set the default value of the text box to be the string returned from the HelloWorld web service method. This was done by entering the Formula Editor and clicking the Insert Field or Group button to allow selection of the return value from my web service method. Please make sure you select your web service method in the Fields dropdown (it will be marked as a Secondary Data Source), and that you select the appropriate field from the dataFields node in the schema (for my example, the string being returned is title HelloWorldResult, under the HelloWorldResponse node).

Figure 20: Selecting Output from Web Service Method

Click OK to save the changes, save and republish the form template, and when you display/edit an item in the list, your web service method will be called and displayed on the dialog (Figure 21).

Figure 21: Displaying Customized Form with a Web Service call

Moving a Customized Display/Edit Form to Another Environment

So far, we've discussed how to create a customized display/edit form, and I've shown you some powerful customizations you can make to your form. You may be wondering how to deploy this custom form from a development environment to a different environment (staging and/or production). I have found that the process is a bit different than you would expect.

Normally, when InfoPath form templates are created in a development environment, it's a simple matter to "repoint" the publishing URL to your target environment and republish the template. Unfortunately, since this form template is going against a SharePoint list, we do not have access to repoint the publishing URL to a list in the target environment. Due to this limitation, the only way to get your custom form to a different environment is to save your customized list (which will include the form template and any content you might want to include) to a list template. You can then install this list template on your target environment, and create a list in that environment, based on the list template. The only other changes you would need to make is to repoint your web service method call (if you're using one) to the web service in your target environment. You would do this by editing and republishing the InfoPath form template in your target environment.

Conclusion

Customizing the display/edit forms for SharePoint 2010 lists and document libraries is simple and provides a new level of customizing your SharePoint environment. Adding a bit of custom code can take this customization even further, if you need additional functionality not available with just SharePoint lists. I hope this article has helped you understand how to customize the display/edit forms using InfoPath 2010, and if you have any additions, I would love to hear about them.