woensdag, december 12, 2007

dinsdag, oktober 02, 2007

Redirecting after using InfoPath Form (web-enabled) in Sharepoint 2007

  1. Use the Source query string: so the page will know where to navigate to after the form is closed or submitted (Watch Out: The URL must be in the same site collection or an error will be returned.)
  2. Add the OnClose event to the XmlFormView, add code to redirect after closing:
    Response.Redirect(http://www.dolmen.be);
    In the Infopath Form, you must add the Action: "Close this form: No Prompt" in the rules of the InfoPath Button, otherwise the OnClose event won't fire.

Source blogposts:

maandag, augustus 27, 2007

MCTS for .NET 2.0 Web applications (Exam 070-528)


Just like my colleague MaBal did, I passed the Microsoft.NET Framework 2.0 - Web-based Client Development (Exam 070-528) exam!

Now I can call myself: Microsoft Certified Technology Specialist for .NET framework 2.0 Web applications.

zondag, augustus 19, 2007

Query DataConnection in Infopath Web-enabled Form when selecting value of dropdownlost (with Managed Code)

You don't always need to load your dataconnection before the form is loaded (performance reasons), sometimes you want to load a different dataconnection when a certain value is selected. I use the example of a dropdownlist, and every value of the dropdownlist will load an other dataconnection into another dropdownlist.



Add the 2 dropdownlists, the second dropdownlist must have a connection with a datasource (I use an embedded Xml file dc.xml). When creating this dataconnection, please deselect the setting "Automatically retrieve dat when form is opened".




What you will need after you created the controls in infopath, open VSTA (alt+shift+F12). Add following code fragment into the InternalStartup method:

this.EventManager.XmlEvents["/my:myFields/my:Type"].Changed += new XmlChangedEventHandler(TypeChanged);

You also need to add the TypeChanged methods:

void TypeChanged(object sender,XmlEventArgs e)
{
string type = e.NewValue; //the selected value of the type dropdownlist

//I just added one dataconnection called dc (value when you select POST)
//You need to put here code (switch) for all the values in the type ddl
DataSource ds = this.DataSources[type];
DataConnection dc = ds.QueryConnection;

dc.Execute();
}


When you use the Execute method of a dataconnection, you must change following setting (it is like the ASP.NET AutoPostBack setting), otherwise your dataconnection will not be loaded!! (when you just changed a value of another field, you don't need to change this setting).




Change the standard option (postback settings): "Only when necessary for correct rendering of the form (recommended)" to "Always"


Remarks:
When you use Mananged Code in web-enabled form, uou must publish it as an administrator approved template (check out blogpost http://spsfactory.blogspot.com/2007/01/walkthrough-publishing-administrator.html )

maandag, augustus 13, 2007

Adding AppSettings to a Sharepoint Web Application Web.Config

I use this code to add key/values to the web.config during installation of features


(using Microsoft.SharePoint.Administration;)

string siteName = "http://moss";
SPSite site = .....;
SPWebApplication webApp = site.WebApplication;
System.Collections.ObjectModel.Collection allModifications= webApp.WebConfigModifications;

AddNewAppSetting(allModifications,"testkey1","testvalue1");
AddNewAppSetting(allModifications,"testkey2","testvalue2");

SPFarm.Local.Services.GetValue().ApplyWebConfigModifications();

------

private void AddNewAppSetting(System.Collections.ObjectModel.Collection allModifications,string name, string value)
{
SPWebConfigModification modification = new SPWebConfigModification(string.Format
("add[@key='{0}']", name), "/configuration/appSettings");

modification.Type =
SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
modification.Value = string.Format(CultureInfo.InvariantCulture,string.Format
("",name,value) );

if (allModifications.Contains(modification))
{
allModifications.Remove(modification);
}

allModifications.Add(modification);

}


Sources:

donderdag, juli 05, 2007

CAML and strange characters like '&'

Some day, my Caml Query failed with this exception:
"The property Query contains an invalid value."

The CAML XML:

<pre>
<Where>
<Eq>
<FieldRef Name='Summary'/><Value Type='Text'>jeroen & doreen></Value>
</Eq>
</Where>


I noticed the & and found out that the & character was the problem. Changing it into the encoded & gave the same problem... Thx to JOPX's connections in the Sharepoint world (of art;-) ) someone gave me a tip: try it with CDATA.....

So I check that out........ and it worked!!

So you need to put a CDATA tag around the text that can contain strange characters:


My new correct working CAML XML look like this:

<Where>
<Eq>
<FieldRef Name='Summary'/>
<Value Type='Text'> <![CDATA[jeroen & doreen]]> </Value>
</Eq>
</Where>


Some more info about CDATA:
Source: http://www.w3schools.com/
A CDATA section starts with "<![CDATA[" and ends with
"]]>":

<script>
<![CDATA[
function matchwo(a,b)
{
if (a < b && a < 0) then
{
return 1
}
else
{
return 0
}
}
]]>
</script>


In the example above, everything inside the CDATA section is ignored by
the parser.

Notes on CDATA sections:
A CDATA section cannot contain the string "]]>", therefore, nested CDATA sections are not allowed. Also make sure there are no spaces or line breaks inside the "]]>" string.

maandag, juni 25, 2007

Microsoft .NET Magazine #17: Legends never die on the front ?!

Today I spotted myself on the cover of the new Microsoft .NET Magazine....



I will post some more info when I have got the time for it....
Notice that JOPX has a nice cool earring.... ;)

Microsoft .NET Magazine:
http://www.microsoft.com/netherlands/msdn/netmagazine/default.aspx

woensdag, juni 06, 2007

Creating Managed Properties for use in SharePoint Server Enterprise Custom Search through Code

Use the following Code to add Managed Properties in Code, the Managed Properties are created from crawled properties (like an infopath published form)



//Get search Schema
ServerContext serverContext = ServerContext.GetContext("SharedServices1");
SearchContext searchContext = SearchContext.GetContext(serverContext);
Schema schema = new Schema(searchContext);

//Get the list of properties (here from a published infoPath Form), you want to use in search
StringCollection infoPathFormProperties = GetData.GetAllInfoPathPublishedFields();
// Create new ManagedProperties
foreach (string infoPathFormProperty in infoPathFormProperties)
{
string managedPropertyName = infoPathFormProperty;
string infoPathFormPropertyPublished = string.Format("ows_{0}", infoPathFormProperty); //infopath published fields will be added as ows_[NAME]

// If you create a prop that already exists, you will get an SqlException (duplicate key),so you need this check
if (!schema.AllManagedProperties.Contains(managedPropertyName))
{
ManagedProperty newManagedProperty = schema.AllManagedProperties.Create(managedPropertyName, ManagedDataType.Text);

// Get the (crawled) property you want to map in the ManagedProperty
CrawledProperty cprop = null;
foreach (CrawledProperty prop in schema.QueryCrawledProperties(infoPathFormPropertyPublished, 1000, Guid.NewGuid(), string.Empty, true))
{
//schema.GetCrawledProperty(Guid.NewGuid(), infoPathFormPropertyPublished, 0); //can't use this, you need also need the Guid and variantType, and you only know the name
//QueryCrawledProperties will be filtered on CONTAINING infoPathFormPropertyPublished value, so extra check if the Name is equal!
if (prop.Name == infoPathFormPropertyPublished)
{
cprop = prop;
break;
}
}

if (cprop != null)
{
// Map the crawled prop to the Managed Prop
MappingCollection mappings = new MappingCollection();
mappings.Add(new Mapping(cprop.Propset, cprop.Name, cprop.VariantType, newManagedProperty.PID));

newManagedProperty.SetMappings(mappings);

// Set Some other properties
newManagedProperty.FullTextQueriable = true;
newManagedProperty.EnabledForScoping = true;
newManagedProperty.Update();
}
else
{
MessageBox.Show(string.Format("Published Infopath field {0} not found",infoPathFormPropertyPublished));
}

}
else
{
MessageBox.Show(infoPathFormProperty +" already exists");
}
}





SOURCES:

maandag, mei 21, 2007

Some late Christmas gifts for Sharepoint Developers!

Thx to JOPX he made a post with some very usefull links for Sharepoint Developers, check out his blog for more tips, tricks, tools and fools ;-)

DEBUGGING TIPS:

CAML QUERY

QUERY SHAREPOINT

dinsdag, mei 15, 2007

SPSecurity.RunWithElevatedPrivileges to update SPRoleAssignment of an SPListItem

When you write custom code in Sharepoint webparts, your code will run with your credentials.
Not everybody has Full Control, so when a user has only read rights, the code will throw an access denied error when the code needs access to objects that are not in the scope of the user credentials.... (example: add the username in the ReadBy properties of an item).

What you need is impersonation, run your code with the help of a user who has just enough rights to run it. Sharepoint has a built-in function to accomplish this: SPSecurity.RunWithElevatedPrivileges, it runs with the System Account User.

Some things you should know when using SPSecurity.RunWithElevatedPrivileges:

  • in the delegate function, you must build a new SPSite/SPWeb object (like SPSite siteColl = new SPSite(App.SITE_COLLECTION_URL)) and you can't use the SPContext.Current.Web, because the SPContext runs with the current context (with current user).
  • Also set the AllowUnsafeUpdates property of the site/web where you will be updating/accessing stuff to true, to be sure you don't get an error like "The security validation for this page is invalid" (see more below). If you don't do it, you code will work, but when returning from the delegate function, the error will arise..

Code sample:

I run the "Elevated code" when the button btn is clicked in a webpart:


void btn_Click(object sender, EventArgs e)
{
   {
     SPSecurity.RunWithElevatedPrivileges(TestSec);
   }
   catch (Exception ex)
   {
     throw ex;
   }
}

public void TestSec()
  {
    SPSite siteColl = new SPSite(App.SITE_COLLECTION_URL);
    
SPWeb site = siteColl.AllWebs[App.WEB_NAME];
    SPList list = site.Lists["Test"];

    SPListItem testItem = list.GetItemById(1);
    site.AllowUnsafeUpdates = true;
    
SPRoleDefinition roleDefinitionContributor = site.RoleDefinitions.GetByType(SPRoleType.Contributor);
    SPRoleAssignment roleAssignment = new SPRoleAssignment("DOMAIN\\USERNAME", "", "", "");
    roleAssignment.RoleDefinitionBindings.Add(roleDefinitionContributor);
    ////Check for permission inheritance, and break if necessary
    if (!testItem.HasUniqueRoleAssignments)
    {
      testItem.BreakRoleInheritance(false); //pass true to copy role assignments from parent, false to start from scratch
    }
  testItem.RoleAssignments.Add(roleAssignment);
  testItem.Update();
  site.AllowUnsafeUpdates = false;
  siteColl.Close();
  site.Close();

}


Error when not setting AllowUnsafeUpdates = true:

Server Error in '/' Application.
--------------------------------------------------------------------------------
The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Runtime.InteropServices.COMException: The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:

[COMException (0x8102006d): The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.]
Microsoft.SharePoint.Library.SPRequestInternalClass.UpdateRoleAssignment(String bstrUrl, Guid& pguidScopeId, Int32 lPrincipalID, Object& pvarArrIdRolesToAdd, Object& pvarArrIdRolesToRemove) +0
Microsoft.SharePoint.Library.SPRequest.UpdateRoleAssignment(String bstrUrl, Guid& pguidScopeId, Int32 lPrincipalID, Object& pvarArrIdRolesToAdd, Object& pvarArrIdRolesToRemove) +119
[SPException: The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.]
OfficialMail.WebParts.TestWebPart.btn_Click(Object sender, EventArgs e) +94
System.Web.UI.WebControls.Button.OnClick(EventArgs e) +105
System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +107
System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +7
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +11
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5102

Sources:

maandag, mei 14, 2007

vrijdag, maart 02, 2007

Working with the Replicator in Sharepoint Workflows, some serialize issues & tricks

Before reading this post:

Keep in mind: A replicator is just a "workflow foreach".


When initializing a replicator you need to pass initiation data (like the foreach collection data). So if you want to pass a Contact for each replicated activity, you will set the initiationChildData (must implement IList) with Contact objects:
adding contacts like this: replicatorInitialChildData.Add(contact);

Sometimes you want the add your own classes to the List. You would except that this wouldn't be difficult, in fact it isn't:

Create the initiation data list with objects of your custom class:
IList replicatorInitialChildData = new List();
/ fill the list with the ApproverFlow objects
replicatorInitialChildData.Add(appFlowObj1);
replicatorInitialChildData.Add(appFlowObj2);


The code will compile, the workflow will succeed sometimes (when the replicator is used in Parallel execution), sometimes not (when the replicator is used in Sequence execution), after a while you will notice this kind of errors:

(in the log folder in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\LOGS)

Workflow Infrastructure 72eo Unexpected DehydrateInstance: System.Runtime.Serialization.SerializationException: End of
Stream encountered before parsing was completed. at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run() at
System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck,
Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) at
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean
fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) at
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream) at
System.Workflow.ComponentModel.Activity.Load(Stream stream,...

02/27/2007 14:50:31.00* w3wp.exe (0x0A98) 0x1700 Windows SharePoint Services Workflow Infrastructure
72eo Unexpected ... Activity outerActivity, IFormatter formatter) at
System.Workflow.ComponentModel.Activity.Load(Stream stream, Activity outerActivity) at
System.Workflow.Runtime.Hosting.WorkflowPersistenceService.RestoreFromDefaultSerializedForm(Byte[] activityBytes, Activity outerActivity)
at Microsoft.SharePoint.Workflow.SPWinOePersistenceService.LoadWorkflowInstanceState(Guid instanceId) at
System.Workflow.Runtime.WorkflowRuntime.InitializeExecutor(Guid instanceId, CreationContext context, WorkflowExecutor executor,
WorkflowInstance workflowInstance) at System.Workflow.Runtime.WorkflowRuntime.Load(Guid key, CreationContext context,
WorkflowInstance workflowInstance) at System.Workflow.Runtime.WorkflowRuntime.GetWorkflow(Guid instanceId) at
Microsoft.SharePoint.Workflow.SPWinO...

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. --->
System.InvalidOperationException: The platform does not know how to deserialize an object of type OfficialMail.Common.ApproverFlow+Approver.
The platform can deserialize primitive types such as strings, integers, and GUIDs; other
SPPersistedObjects or SPAutoserializingObjects; or collections of any of the above.
Consider redesigning your objects to store values in
one of these supported formats, or contact your software vendor for support.



You will notice the deserialize stuff.... If you think further, ..... whole the workflow idea is that every instance can be serialized or deserialized, because a workflow can wait for some other stuff, so objects will be saved somewhere (not in memory) when workflow is waiting.

When the replicator starts in parallel execution, no (de)serialize will occur because the workflow doens't need to serialize the objects, the replicator executes everything at once.
But when the replicator executes in sequence, it does need (de)serializing because the workflow will pause before executing the next step (so state is saved:(de)serializing occurs).


So when you want to add your own classes, keep in mind that your own class must be serializable.

Which types are serializable?
The platform can deserialize primitive types such as strings, integers, and GUIDs; other SPPersistedObjects or SPAutoserializingObjects; or collections of any of the above.

In one of the next blog posts, I will explain how to add/change data when the replicator is already running ...

dinsdag, februari 20, 2007

Team System : Team Explorer free download!

A reminder for myself ;-)

An essential client-side piece of Team System that installs as a Visual Studio 2005 add-in:
http://blogs.vertigosoftware.com/teamsystem/archive/2006/05/22/2778.aspx

maandag, januari 15, 2007

Handle the InfoPath Forms Services by yourself (in a Custom WebPart to view a web-enabled Infopath 2007 Form)

To understand this post well, please go through this post first:
- Hosting the InfoPath 2007 Form Editing Environment in a Custom Web Form

Sometimes you don't want to popup an error by InfoPath Forms Services (it will log this also in the EventLog), see image below. You want to catch the error in code and do some custom logging (or other stuff)


I will use the example when a dataconnection (webservices) in the form gives a time-out.

Preceding:
First keep in mind that we will bind the dataconnection-webservice to its control in code, so you have to deselect - Automatically retrieve data when form is opened (when adding a data-connection in InfoPath). Also don't forget to link the control with the dataconnection in infopath designer

What we gonna do in code:
- Add a handler that will get you into the Initialize methods of the XmlFormView
- Get the right dataconnection, execute it (so it will get the data and bind to the control)
- Add a "try/catch" block around this code

The code:


void viewform_Initialize(object sender, InitializeEventArgs e)
{
try
{
DataConnection dc = _viewform.XmlForm.DataSources["GetGAL"].QueryConnection;
dc.Execute();
}
catch (System.Net.WebException webEx)
{
WarmUpWebService();
ReloadWebPart();
//Log, ...
}
catch (Exception ex)
{
Logger.Log(ex, ...);
}
}


Some other InfoPath blogs:

woensdag, januari 10, 2007

Time-outs when using WebEnabled Infopath Form in Sharepoint 2007 WebParts

When you are using web-enabled infopath forms (that have dataconnections to webservices) in sharepoint 2007, you can get timeouts errors....

Example of an Time-out Exception:
Forms Services Runtime - Data Connections - TYPE: WARNING - EVENT 5566
The following query failed: GetSomething (User: MMMM\bbbbb, Form Name: formname, IP: , Request: http://serverZZZ/xxxx/yyyyy/composer.aspx?menu=3&Type=0, Form ID: urn:schemas-microsoft-com:office:infopath:xxxxxxx:-myXSD-2006-08-07T07-37-16, Type: DataAdapterException, Exception Message: The operation has timed outThe operation has timed out)

How to solve them?
  1. Check if your WebServices time-outs occur when you use the WebService directly (in a webbrowers), If so, you should change the timeout of the WebService in IIS Manager (InetMgr) or use more caching.

  2. If you are loading the Web-enabled InfoPath form into a custom webpart, you have to be sure that the following setting is used in the Form Library Advanced Settings page:
    Display as a Web Page (in stead of Open in the client application)


  3. Change the Data Connection Timeouts Settings. Open SharePoint 3.0 Central Administration: Goto Application Management > Configure InfoPath Forms Services
    Here you can change the Data Connection Timeouts Settings

Point 2 has fixed my problems...

maandag, januari 08, 2007

Problems starting VSTA in Infopath 2007 with Microsoft Office Server Sharepoint 2007 (.NET 3.0) installed *!!!FIXED!!!*

To fix the problem described below:

It worked for me when I did this:
uninstall .NET programmability support for .NET Framework version 2.0 and then reinstall it

(go to
Kristof his blog for full explanation)

When I want to add custom C# in an Infopath 2007 form, I get this error:


InfoPath cannot start Microsoft Visual Studio Tools for Applications.
To work with Visual Basic or C# code, Microsoft Visual Studio Tools for Applications (VSTA) is required. the Microsoft .NET Framework 2.0 and Microsoft Core XML Services 6.0 must be installed prior to installing VSTA. To install VSTA, open Add or Remove Programs, locate your 2007 Microsoft Office System installation, and then click Change


How should I make this work? Reinstalling some things? I think the .NET 3.0 will cause the problems....


This stuff is installed:


  • Microsoft .NET Compact Framework 1.0 SP3 Developer
  • Microsoft .NET Compact Framework 2.0
  • Microsoft .NET Framework 2.0
  • Microsoft .NET Framework 3.0
  • Microsoft Office Enterprise 2007
  • Microsoft Office Sharepoint Designer 2007
  • Microsoft Office Sharepoint Server 2007
  • Microsoft Visual Studio 2005 Professional Edition
  • Microsoft Visual Studio 2005 Team Explorer
  • Microsoft Visual Studio 2005 Tools for Office Runtime
  • Windows Server 2003 Service Pack 1
  • Regarding Workflow:
    Enterprise Content Management Starter Kit for 2007 Office System (beta 2 tr)
When I want to re-installing MSXML 6.0 I get this error:


Installation of MSXML 6.0 Parser failed because a higher version already exists on the machine. To proceed uninstall the higher version and then run MSXML 6.0 Parser Setup again



Kristof De Causemaeker add some more comments:
When you want to create an InfoPath Add-in project via VSTO, it also give errors...
I thinks that VSTO/VSTA in combination with .NET 3.0 and InfoPath 2007 will not work yet..... Maybe a Windows Registry problem?

maandag, januari 01, 2007

Welcome To 2007!

Happy New Year and welcome to the Year of Bond, James Bond ;-)