Tuesday, 30 November 2010

Sharepoint Solution Debug or Release build

Today I just come across very unusual sharepoint development snag. I was adding some functionality to a exsiting sharepoint site. I found that the project is releasing 'Debug' build configuration. So I changed the build to a 'Release' build configuration. Compiled successfully but build failed with following error message:
"mySite.wsp" does not appear to be a valid upgrade for solution "mySite.wsp".The two solutions must have the same resource types (global or Web-application scoped)

Compared the new manifest file with old manifest file, Bang! they are hugely different. New manifest file has DeploymentTarget: GlobalAssemblyCache and it does not have CodeAccessSecurity section at all.

Confused! 've not changed anything in the solution. Still gone through everything, to check what could be changing the deployment target.

So rolled back my change(Release->Debug) and rebuilt. Build and deployment successful without a noise.

I'm using wspbuilder to build sharepoint solution from Visual Studio(VS) project.

The default behaviour of WSPBuilder is as follows:
Building sharepoint solution from VS Solution with Build configuration = Debug generates Sharepoint solution with DeploymentTarget=WebApplication
And similarly:
VS Solution with Build configuration = Release generates Sharepoint solution with DeploymentTarget=GlobalAssemblyCache


Tuesday, 23 February 2010

Behind the scene: Property promotion in Infopath

Infopath form has a beautiful feature to promote form fields. When a form is published to a sharepoint document library these promoted fields are available as additional column. This is all good and simple. I'm not going to dig into that in details here.

What I'm trying to focus here is when multiple forms are published to same document library. What happens to these promoted fields. Is the sharepoint list smart enough to figure-out the common columns?

Sharepoint treats all column same and independently. If all attributes are same for a set of promoted filed then they represent same column.

When fields are promoted in Infopath it generates some map behind the scene. This can be viewed in the manifest file using any text of xml editor. For every promoted field it generates a unique id (GUID). And a second map, that maps each promoted to a column. Columns are identified by another GUID.

So every time a new property promotion happens a new set of mapping gets generated. When this happens in two different form naturally all GUID will be different. Therefore even if two form have field with same display name when the are promoted they will generate two different set of mapping guid. And therefore after attaching to a list this fields will be displayed as separate column. Matter of fact it will look like duplicate column. But one of them will display value depending of the content type the current line item is generated from.

The solution is simple. Open the manifest file and make sure common fields have same filed Id and column id. Simply copy one set of mapping from one file and use it for another file. do remember to make sure local form filed reference is correct. I mean it's is referring to the correct local filed in each manifest file.

Republish the form and this time you will see list item generated from both content type are populating same column.

One thing to remember sharepoint will not automatically remove existing set of columns. I mean once you publish one content type and create any list item all columns related to this content type get permanently added to the list. They may not be visible to the current view but they are there. To remove this old column reference you have to recreate the column.
Simply download all item from the list. Recreate the list. republish your content type and upload old item again.

Column and list item realignment will not remove existing column. It will only populate all columns relevant and available with existing items.


Example of column mapping from a manifest file looks like this:


<xsf2:listPropertiesExtension>
<xsf2:fieldsExtension>
<xsf2:fieldExtension columnId="{afd78356-f9c9-4211-8167-7d7d70dc67fd}" readWrite="no" columnName="{E28D210E-FF60-401D-A63A-40AECE533A43}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{26612320-1611-4f71-9197-0382144f7b9a}" readWrite="no" columnName="{32F2028F-BEF8-4B2C-AAE4-9F0753930D7A}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{1DAB9B48-2D1A-47b3-878C-8E84F0D211BA}" readWrite="no" columnName="{5A28EC4B-B173-466F-8814-849B4F932146}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{7cfc7f24-852d-4f78-b1b2-e0e68176d9ba}" readWrite="no" columnName="{D9F232A3-DD04-4B4D-9813-9E15E6549AB7}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{c4e0f350-52cc-4ede-904c-dd71a3d11f7d}" readWrite="no" columnName="{A04C8AD0-074F-4160-8577-E298532A11BA}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{1DAB9B48-2D1A-47b3-878C-8E84F0D211BA}" readWrite="yes" columnName="{0ACC2AC8-0890-496B-B524-D6FA0498C818}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{260962da-788e-458a-82a5-e03bb7f6dc52}" readWrite="yes" columnName="{051DFADD-706C-411B-9A4E-7ABA223CAEA9}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{212ec377-84c6-4c00-ad22-2cab2550fb50}" readWrite="yes" columnName="{00BF28EE-3601-42BA-A1F1-24C74B5A9B35}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{2fdeded3-4b03-47af-8ac6-ca411d5603d4}" readWrite="yes" columnName="{91BB41AA-AD25-4C47-BFE8-E04F175F5AC2}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{bb97a85d-0ee4-46ef-b1f1-0748cfa4c137}" readWrite="yes" columnName="{B463F993-2DAF-47E7-83D0-FD3837044858}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{475a6571-ba0e-4d56-9364-d2ac728a323b}" readWrite="yes" columnName="{8B0055A4-7AE8-4C8F-882C-F0C5E01C90C4}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{fce73a96-7bfa-44e9-8d1b-25d4aaa449ca}" readWrite="yes" columnName="{9535DA33-113B-4091-89AB-4ADC104A0F13}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{2958362e-25af-4d8e-9938-50622a1c0e61}" readWrite="yes" columnName="{C8ECE69F-C5C9-47AF-8E40-17CE03D7F5C4}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{0f26d0d9-9f4f-4de6-829d-a1994b26f7d7}" readWrite="no" columnName="{62A5E596-8726-4BBA-862C-3298BAB6808F}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{19b6647c-8672-46f4-b4da-60c74da4cb04}" readWrite="no" columnName="{F086DE11-7848-40B4-95C4-B1A3CCE1374D}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{9930e1c1-3067-47c1-ab8d-3eeb98679c3f}" readWrite="no" columnName="{B78D2E7D-C8AF-40BB-BAD4-D6D17156A91D}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{b1733cd8-b3ce-42a6-990a-0b9a5955da5c}" readWrite="yes" columnName="{BABE6BC6-F248-4E36-8B86-215345352F89}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{5e295b7a-4849-464e-9d56-92bef86869eb}" readWrite="yes" columnName="{25CF762C-D3BB-4F01-BEA8-7F76C4E09914}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{7f358004-05e4-42ac-9fde-a253039e19ce}" readWrite="yes" columnName="{58E519A7-7FA5-4D37-BF5D-F3057BB2D719}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{33a7da72-2997-4ebf-ad89-9603a478fad2}" readWrite="yes" columnName="{DFB32035-E22F-4EA7-8ED7-D36EFC99586A}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{5571ace5-1274-4388-b2e6-02ea6c3c7c76}" readWrite="yes" columnName="{22D6961D-13BD-465F-8C30-FEF5B0FFC0B0}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{230448c7-3b5b-40e1-8242-dba5c11656ad}" readWrite="yes" columnName="{14CB66B0-EA81-4B26-8ABF-E30C50B61DAB}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{7205c21c-5eae-44b1-9b0e-787bb36de370}" readWrite="no" columnName="{E6B623CF-F7CD-41D5-9059-EC84FD4AD026}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="" readWrite="no" columnName="{C08C7115-ED51-4445-985A-0C747741F8BB}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{eeccc9d8-3a7d-4fb9-9e12-3d72daa3c619}" readWrite="no" columnName="{C1EB52D6-7B01-4A00-BB60-F4279372861A}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{27d7764c-ccfc-433d-828d-56beb602062a}" readWrite="no" columnName="{5FA48CEA-E192-4854-B862-70DBBDAEDBDE}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{40577009-e6a2-44aa-b034-029c61e23f1d}" readWrite="no" columnName="{72522D66-2E9E-4BAA-9C84-8D9BF5F44A37}"></xsf2:fieldExtension>
<xsf2:fieldExtension columnId="{dc455fba-75ab-40e2-8a54-d83ad8d70a6a}" readWrite="no" columnName="{AC0CDC6B-C9B3-4E4A-B341-AC5CC6408CBD}"></xsf2:fieldExtension>
</xsf2:fieldsExtension>
</xsf2:listPropertiesExtension>



And the fields mapping is as follows:

<xsf:listProperties>
<xsf:fields>
<xsf:field name="Reference" columnName="{D9F232A3-DD04-4B4D-9813-9E15E6549AB7}" node="/my:myFields/my:referenceNumber" type="xsd:string"></xsf:field>
<xsf:field name="Job Title" columnName="{A04C8AD0-074F-4160-8577-E298532A11BA}" node="/my:myFields/my:jobTitle" type="xsd:string"></xsf:field>
<xsf:field name="Status" columnName="{0ACC2AC8-0890-496B-B524-D6FA0498C818}" node="/my:myFields/my:status" type="xsd:string"></xsf:field>
<xsf:field name="Business Unit" columnName="{C8ECE69F-C5C9-47AF-8E40-17CE03D7F5C4}" node="/my:myFields/my:businessUnit" type="xsd:string"></xsf:field>
<xsf:field name="Annual Salary" columnName="{62A5E596-8726-4BBA-862C-3298BAB6808F}" node="/my:myFields/my:annualSalary" type="xsd:double"></xsf:field>
<xsf:field name="Country" columnName="{F086DE11-7848-40B4-95C4-B1A3CCE1374D}" node="/my:myFields/my:country" type="xsd:string"></xsf:field>
<xsf:field name="Assigned To" columnName="{BABE6BC6-F248-4E36-8B86-215345352F89}" node="/my:myFields/my:assignedTo" type="xsd:string"></xsf:field>
<xsf:field name="FDGroup Name" columnName="{25CF762C-D3BB-4F01-BEA8-7F76C4E09914}" node="/my:myFields/my:FDGroupName" type="xsd:string"></xsf:field>
<xsf:field name="HRGroup Name" columnName="{58E519A7-7FA5-4D37-BF5D-F3057BB2D719}" node="/my:myFields/my:HRGroupName" type="xsd:string"></xsf:field>
<xsf:field name="MDGroup Name" columnName="{DFB32035-E22F-4EA7-8ED7-D36EFC99586A}" node="/my:myFields/my:MDGroupName" type="xsd:string"></xsf:field>
<xsf:field name="CEOGroup Name" columnName="{22D6961D-13BD-465F-8C30-FEF5B0FFC0B0}" node="/my:myFields/my:CEOGroupName" type="xsd:string"></xsf:field>
<xsf:field name="Submitter Login Name" columnName="{14CB66B0-EA81-4B26-8ABF-E30C50B61DAB}" node="/my:myFields/my:submitterLoginName" type="xsd:string"></xsf:field>
<xsf:field name="Division" columnName="{E6B623CF-F7CD-41D5-9059-EC84FD4AD026}" node="/my:myFields/my:division" type="xsd:string"></xsf:field>
<xsf:field name="Last Modified Login Name" columnName="{C1EB52D6-7B01-4A00-BB60-F4279372861A}" node="/my:myFields/my:LastModifiedLoginName" type="xsd:string"></xsf:field>
<xsf:field name="Current Salary" columnName="{5FA48CEA-E192-4854-B862-70DBBDAEDBDE}" node="/my:myFields/my:currentSalary" type="xsd:double"></xsf:field>
<xsf:field name="Staff Name" columnName="{72522D66-2E9E-4BAA-9C84-8D9BF5F44A37}" node="/my:myFields/my:candidateName" type="xsd:string"></xsf:field>
<xsf:field name="Currency" columnName="{AC0CDC6B-C9B3-4E4A-B341-AC5CC6408CBD}" node="/my:myFields/my:salaryCurrency" type="xsd:string"></xsf:field>
</xsf:fields>
</xsf:listProperties>

There is an unclosed literal string. Line 1, position 411.


I was recently quite scared to see an exception message thrown up from my Infopath form published to a sharepoint list. And most interestingly while I was trying to the same operation from Infopath designer preview, form was working correctly without any exception.
After a bit of search here and there I could not find any solution.
Suddenly I realised that the event causing this exception trying to use a filed which does not exist in the form.

So if you are seeing the same error message most probably your code is trying to access a field that does not exist or you have misspelled the name.

------------ exception message ------------

There is an unclosed literal string. Line 1, position 411.

System.Xml.XmlException: There is an unclosed literal string. Line 1, position 411.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
at System.Xml.XmlTextReaderImpl.ParseAttributeValueSlow(Int32 curPos, Char quoteChar, NodeData attr)
at System.Xml.XmlTextReaderImpl.ParseAttributes()
at System.Xml.XmlTextReaderImpl.ParseElement()
at System.Xml.XmlTextReaderImpl.ParseElementContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlLoader.LoadNode(Boolean skipOverWhitespace)
at System.Xml.XmlLoader.LoadDocSequence(XmlDocument parentDoc)
at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
at System.Xml.XmlDocument.Load(XmlReader reader)
at Microsoft.Office.InfoPath.Server.Xml.InfoPathXmlDocument.Load(XmlReader reader)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DataObject.<>c__DisplayClass3.<.ctor>b__0()
at Microsoft.Office.Server.Diagnostics.FirstChanceHandler.ExceptionFilter(Boolean fRethrowException, TryBlock tryBlock, FilterBlock filter, CatchBlock catchBlock, FinallyBlock finallyBlock)
at Microsoft.Office.Server.Diagnostics.ULS.SendWatsonOnExceptionTag(ULSTagID tagID, ULSCat categoryID, String output, Boolean fRethrowException, TryBlock tryBlock, CatchBlock catchBlock, FinallyBlock finallyBlock)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DataObject..ctor(EnhancedBinaryReader reader, Solution solution)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DataObjects.<>c__DisplayClass2.<.ctor>b__0(EnhancedBinaryReader innerReader, DataObject& newObject)
at Microsoft.Office.InfoPath.Server.Serialization.EnhancedBinaryReader.ReadObjectMap[KeyT,ValueT](Dictionary`2 map, ItemReaderDelegate`1 readKey, ItemReaderDelegate`1 readValue)
at Microsoft.Office.InfoPath.Server.Serialization.EnhancedBinaryReader.ReadObjectMap[ValueT](Dictionary`2 map, ItemReaderDelegate`1 readValue)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DataObjects..ctor(EnhancedBinaryReader reader, Solution solution)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DocumentSessionState.DesterilizeVersion1(EnhancedBinaryReader reader, Solution solution)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DocumentSessionState..ctor(EnhancedBinaryReader reader, Solution solution)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DocumentSessionState.CreateFromByteArray(Byte[] serializedSessionState, Byte[] serializedVersionState, Solution solution)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.DocumentSessionStateManager.GetSessionState(HttpContext context, String editingSessionID, Solution solution)
at Microsoft.Office.InfoPath.Server.DocumentLifetime.Document.LoadFromSession(HttpContext context, SPSite contextSite, EventLogStart eventLogStart, Solution solution)
at Microsoft.Office.InfoPath.Server.Controls.PostbackPage.<>c__DisplayClass1.b__0()


Thursday, 10 December 2009

How to Create new sharepoint site

Creating sharepoint site is very easy. Following image steps will show you how to do it.

Step 1: Open sharepoint Central Administration and click Application management as shown in the picture bellow.


Step 2: Choose the ‘Create of Extend Web Application’ link from ‘Sharepoint Web Application Management’.


Step 3: Click ‘Create a new Web application’ link


Step 4: Create Web application form will pre-populate all fields. You can choose the default value in most cases. Note the port number. You will need this to access the site. If you want to access using more readable name, create a DSN entry for your site and use that as host header in the following form. I’ve choose Network Service account for Application pool authentication. It’s a preferable option for me, and I would suggest you to use it. If want more restricted access you can specify the username and password. Form will pickup the default content database server name from sharepoint farm configuration. Click okay when you are happy with the information.


Step 5: Step 4 creates a web end point to attach your website to. You actual site has not been created yet. If you try to brow the url as you just created, it will show an error message. Site is not available yet. This step will create the site. Sharepoint come with a bunch of template to create your site from. Go to Application Management and Click ‘Create Site Collection’ in sharepoint site management section.


This will take you to Create Site Collection page.

Step 6: In Create site collection page, choose the web application you want to add the site. (shown in red circle in following diagram).


Choose a suitable title for your site. This title will be displayed in almost every page of your site. Add a description. This description will be displayed in the home page. Choose the template for your site. Following example shows team site template. You can choose whatever template is suitable for your purpose. Click ok and your site is ready to use( off course you have to wait for the working icon to stop J).


Monday, 30 November 2009

Finding Program Equivalent of Share point UI Actions

Have you ever wondered all the functions you want to do is available in the sharepoint pages, through UI, but you can't find the API to do it pragmatically. I'm here to reveal the secret to find all the sharepoitn supported method calls that you are hunting for ages.

You will need .NET developers Bramastra(The ultimate wepone), the Red Gate's .NET Reflector. you can download this from http://www.red-gate.com/products/reflector/

Now you are ready for the discovery of your lifetime.

We will run through the steps using an example. In our case lets say we want to find out how to remove a workflow association with no new instance option. If you directly look in the SPWorkflowAssociation class, there is a remove association option but it does not have a option for No New instance. We are going to find it how Sharepoint does it.

Before we start, let's list out all the location where to look for web pages source and assemblies:
  • Web pages:
  1. \Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS
  2. \Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\ADMIN
  • Assemblies
  1. \WINDOWS\assembly
  2. \Inetpub\wwwroot\wss\VirtualDirectories\[yourwebsitename or port]\_app_bin
Step 1:Lets remove the association using UI.

Open List setting









Open workflow setting










Click the remove workflwo link







This the page we have to look care fully. This page has multiple radio button for complete removal, no new instance and allow new instance. Form is simple. From address bar lets note down the aspx page name, i.e. RemWrkfl.aspx.
We can find this file in \Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS

Open this file in any text editor. First couple of line are of our interest. First line will tell the assembly file name this page uses for code behind. And the second line will show the class name i.e Microsoft.SharePoint.ApplicationPages.RemWrkflPage for our example.

We can also find that the Ok button in the form invokes BtnSubmit_Click method.

Lets open the assembly using Reflector. We can find the assembly in \Inetpub\wwwroot\wss\VirtualDirectories\[yourwebsitename or port]\_app_bin. In our case the assembly name is Microsoft.SharePoint.ApplicationPages.dll

After you drill down to the Microsoft.SharePoint. ApplicationPages.RemWrkflPage class and BtnSubmit_Click event handler the code looks like as shown in the image on the right side.
If we look carefully, we ca see that for No New Instance option it's simply setting association.Enabled = false;

So that's the magical thing. We have to disable the association instead of removing it.
We are done!



And using the same approach you can discover all functionality, as long as an example is available.

A bit of caution, some MOSS functionality is not developed using managed code. You wont be able to see code for those functionality.

Tuesday, 29 September 2009

How to keep infopath form in source control

Microsoft infopath form saved with .xsn extension. This is a binary format. If you add a xsn file to source control, you will have record of different version of the form, but you won't be getting the change details.

This can be solved easily by doing it little bit differently. xsn files are basically cab file. And it contains lots of xml, xsd, image and other files. The good thing is Infopath provides a option to save files in its source form, i.e. instead of one big xsn(cab) file, you can save all internal files separately in one location. In that case most of those files are text file. And source control will be able to track all changes in the file.
Save As Source Files option available in the File menu as shown in the image.
And it looks like the image in right.
number of files and types depends on the content of the form. It will always have a manifest file(xsf). Right Click on the manifest file and choose design to open the form in design mode.
There will be xsd files for every data connection/data types. There will be one xsl files for each view, and all images displayed in the form etc.

This makes version controlling worthwhile. Doing this you can merge between branches meaningfully.

One last thing whenever this form is published it will be published as .xsn file in its publish location.

Infopath forn and Branching


Combination of Microsoft Infopath form and source control could turn into a editing hell, specially if that involves branching and merging.
Infopath forms keeps track of where it has been published before and where from it was published. Therefore if the form is moved it gives warning like the one bellow:
This is exactly the same thing happens when source is branched from trunk and is being opened from branch.
Click okay and form is displayed in editable mode. So far it's all right. But when the from is being published again from branch infopath form will ask for saving the file before it can be published even if there has not been any change in the form.
Depending on the user preference, if the always save checkbox is ticked earlier, this dialog box will not appear, instead it will open the file save dialog directly.
That's where the confusion is. In regular publish from does not display the save as box. User can easily confuse about whether that is the publish location it's talking about or the source location.
Infact that's what happened to me. I save the file to it's publish location and then publish it to the same location.
The funniest thing is I've lost all my work. It simply published and stored the original file. All changes are overwritten.

To avoid such loss , I recommend, any time if you move a infopath form do the following thing first:
  • Save the form again to it's new source, make sure path is selected correctly
  • publish to the correct location

I hope this writing will help some one from loosing their days work, just because infopath form doesn't like to move around.