Inconvenient programmatically provisioning Web Part instances
Back in October last year I started working with programmatically provisioning Web Part instances. The challenging part was that the assemblies containing the Web Parts’ code were located in the bin directory of the target Web Application. The custom STSADM command I was using for that purpose wasn’t able to resolve the Web Part type. Back then I have found a way to deal with it which I though was a working solution. Unfortunately: just last week I have stumbled upon the same situation: again.
The test case
Let’s recap the scenario: there is an assembly containing Web Parts’ code deployed to the bin directory of the Web Application. Let’s call it adventureworks.controls.dll. The assembly is signed. Then we have a custom STSADM command which provisions Web Part instances using the .webpart or .dwp files (something that resembles a lot Gary Lapointe’s gl-setwebpartstatecustom STSADM command). Let’s call it i-addwebpart. We have a subclassed and preconfigured Content Query Web Part exported to a .webpart file located at C:\wp.xml. What we want to do is to add an instance of this Web Part to a Publishing Page located at http://adventureworks.com/Pages/default.aspx. We call our custom STSADM command to get the things done:
c:\> stsadm.exe -o i-addwebpart -file c:\wp.xml → -url http://adventureworks.com/Pages/default.aspx → -zone MainWebPartZone -zoneindex 0
Instead of getting the expected “Operation completed successfully” all you see is the following error:
Error: Request for the permission of type 'Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=188.8.131.52, Culture=neutral, PublicKeyToken=71e9bce111e9429c' failed.
Back in October I faced exactly the same issue: importing Web Parts located in an assembly deployed to Web Application’s bin directory was resulting in exactly the same error. Back then I have done some research and found out that creating an application configuration file for STSADM.EXE telling STSADM where the assembly is located solves this issue. If it worked back then, how it’s possible that I’m experiencing the same issue in spite of having created a valid STSADM.EXE.CONFIG file?
Looking for the Holy Grail
I have spent a lot of time during the last couple of days trying to find out what was wrong. Reflecting SharePoint and ASP.NET code took me nowhere. I was instantiating internal methods and private properties for hours trying to figure out at what part things were going wrong. As I mentioned, at the end of the day I was back at the beginning: one issue and no solution.
In an “act of desperation” I have decided to copy all the contents of the web.config of the Web Application to my STSADM.EXE.CONFIG. I have extended these contents with a dependentAssembly section pointing to adventureworks.controls assembly:
<dependentAssembly> <assemblyIdentity name="adventureworks.controls" publicKeyToken="0000000000000000" /> <codeBase version="184.108.40.206" href="file:///C:\Inetpub\wwwroot\wss\→ VirtualDirectories\adventureworks.com80\bin\→ adventureworks.controls.dll" /> </dependentAssembly>
I ran the i-addwebpart command once again. Guess what: it worked! Another part of the research started: what did the web.config have to make STSADM.EXE help resolve the Web Part type?
By removing sections of web.config and running the i-addwebpart command, I have finished up with the following lines in the STSADM.EXE.CONFIG:
<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="Microsoft.SharePoint" publicKeyToken="71e9bce111e9429c" culture="neutral" /> <bindingRedirect oldVersion="220.127.116.11" newVersion="18.104.22.168" /> </dependentAssembly> <dependentAssembly xmlns="urn:schemas-microsoft-com:asm.v1"> <assemblyIdentity name="Microsoft.SharePoint.Portal" publicKeyToken="71e9bce111e9429c" culture="neutral" /> <bindingRedirect oldVersion="22.214.171.124" newVersion="126.96.36.199" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="adventureworks.controls" publicKeyToken="0000000000000000" /> <codeBase version="188.8.131.52" href="file:///C:\Inetpub\wwwroot\wss\→ VirtualDirectories\adventureworks.com80\bin\→ adventureworks.controls.dll" /> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
Having that in STSADM.EXE.CONFIG turned out to be sufficient to import instances of Web Parts located in assemblies deployed to Web Application bin directory.
So far this was one of the biggest inconveniences of SharePoint I have ever experienced: poor error, lot’s of debugging/reflecting, following a lot of different traces leading to nowhere and eventually solving the issue by a “wild guess”.
By the way: why the i-addwebpart and not gl-setwebpartstate?
For my test purposes I was using a Web Application using SSL. After running Gary’s gl-setwebpartstate command I got the following exception (most likely because I was using an untrusted self-made SSL certificate):
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
To run the test I have decided to make a me-ware custom STSADM.EXE command to do the job.