Category Archives: C# Snippets

Sharepoint portal connection strings

How to pull connection string details out of a Sharepoint portal site.

using System;
using Microsoft.SharePoint.Portal;
using Microsoft.SharePoint.Portal.Topology;

namespace SPConnStrings
{
  ///
  /// Summary description for Class1.
  ///
  class Class1
  {
    ///
    /// The main entry point for the application.
    ///
    [STAThread]
    static void Main(string[] args)
    {
      //
      // TODO: Add code to start application here
      //
      TopologyManager topology = new TopologyManager();
      PortalSite portal = topology.PortalSites[new Uri("http://cleanportal")];
      Console.WriteLine("Site db :: " + portal.SiteDatabase.SqlConnectionString.ToString());
      Console.WriteLine("Profiles db :: " + portal.UserProfileDatabase.SqlConnectionString.ToString());
      Console.WriteLine("Services db :: " + portal.ServiceDatabase.SqlConnectionString.ToString());
      Console.ReadLine();
    }
  }
}

Sharepoint permissions and web parts

There is a strong argument against doing things like this, but there are times when you just have to bite the bullet and grant full access permissions to certain web parts without having to install them to the GAC. Here’s how.

The first requirement for this method is that your web parts must be strong named. I would recommend creating a new keyfile specifically for web part assembl
ies that you want to fully trust. Use the following command to do so.

sn.exe -k c:\keyfiles\FullTrustWebParts.snk

Apply this key file in the AssemblyInfo.cs file for your web part project

[assembly: AssemblyKeyFile(@"c:\keyfiles\FullTrustWebParts.snk")]

Build and deploy your project as normal.

Now for the fun part – configuring Sharepoint to accept the signed web parts as fully truted.

In the folder C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\60\CONFIG copy your wss_mediumtrust.config file to wss_trustsigned.config and then open the new file for editing.

Find the section that starts with the following

<codegroup class="FirstMatchCodeGroup" version="1" PermissionSetName="Nothing"> <imembershipcondition class="AllMembershipCondition" version="1" /&gt

and add the following immediately after this code

<codegroup class="UnionCodeGroup" version="1" PermissionSetName="FullTrust"> <imembershipcondition class="StrongNameMembershipCondition" version="1" PublicKeyBlob="...see note below..." /> </codegroup>

The test “…see code below…” needs to be replaced with the public key blob from your assembly. To find this string, use the following command

secutil.exe -hex -s <path to assembly>

Important : remove the leading 0x from this string

Save and close the new file.

Next, open up the Web.Config file from the root of your Sharepoint site. In my case, this resides at c:\inetpub\wwwroot\intranet\web.config

In this file, find the “securityPolicy” section. Copy one of the “trustLevel” nodes, and change the “name” attribute to “wss_trustsigned”, and also the policyFile attribute to reflect the path to your new policy file (ie. C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\60\CONFIG\wss_trustsigned.config)

Once you have added the policy setting, you will need to find the “trust” node within the “system.web” section. Change the value of the “level” attribute to “wss_trustsigned”. This is the value you set in the previous step.

Now save the file, and restart IIS. Your web parts should be fine now.

*NOTE* this has not been tested step by step from these instructions. I will chek it all this week, given the chance, and make any changes that might be necessary. I’m afraid that this is due to having to try to remember what a colleague did 12+ months ago. Ho-hum.

WMI Out Of Memory issues

I have been working on an automated way of deploying BizTalk assemblies, orchestrations and bindings without having to use NAnt or MSBuild this week. It has thrown up a problem that lots of people must have if they are doing a similar thing.

Many times, my scripts would fail periodically, but not in predictable places. After looking at the logs I generate, I noticed that there were a lot of “out of memory” errors caused by WMI operations. I needed a quick fix, so I came up with this (horrible and hacky) workaround.

Before each section of code, restart the “winmgmt” service. That’s it. The scripts now work flawlessly – or at least, they fail in predictable places now.

**EDIT**

I have just been pointed towards this page which details how to increase the amount of memory available to WMI from its default of 128MB.

Process.Start and required input

I had an issue with Process.Start today. I was trying to call an executable that requires the user to confirm the action with a keystroke, in this case “y”.

As far as I am aware, there is no mechanism within the .NET framework to deal with this kind of thing, so I had to resort to the following syntax:

echo y| cacls path /E /T /P username:F

Unfortunately, the command “echo” is a pseudo command contained within the command shell.

To get around this, I had to use the following for the process.

Process runner = new Process(); runner.StartInfo.FileName = "cmd.exe"; runner.StartInfo.Arguments = "/C echo y| cacls path /E /T /P username:F"; runner.Start();

There is probably a more elegant way to do this, but that’s what I came up with in the time allowed.

Return multiple values from a method

This falls under the category of “I would have known about this if I was not self-taught, and it would have saved me so much time.”

In general, the methods I have written in the past have only been able to cope with a single return value. This is not a problem if you want, for example, to return a value from a DataSet, or a simple transform. However, there are occasions where you need to do multiple operations on a single set of data. An example might be statistical analysis on a set of integers – return the average, the sum, minimum and maximum values, etc.

I discovered the out keyword today, and it used as follows.

private void GetStatistics(int value1, int value2, out int sum, out int difference) { sum = value1 + value2; if(value1 > value2) difference = value1 - value2; else difference = value2 - value1; } private void process_Click(object sender, System.EventArgs e) { int sum; int diff; GetStatistics(34,82,out sum,out diff); label1.Text = "Sum :: " + sum.ToString(); label2.Text = "Difference :: " + diff.ToString(); }

The out keyword specifies that the parameter is to be returned when the function completes. In this simple example, the result would be that label1 shows “Sum :: 116″, and label2 shows “Difference :: 48″. It is that easy.

You will notice that in this example, there is no return value (since it is a void function), but it can be amended to allow different method types.

private string GetStatistics(int value1, int value2, out int sum, out int difference) { sum = value1 + value2; if(value1 > value2) difference = value1 - value2; else difference = value2 - value1; return "I have finished that for you, sir"; } private void button1_Click(object sender, System.EventArgs e) { int sum; int diff; MessageBox.Show(GetStatistics(34,82,out sum,out diff)); label1.Text = "Sum :: " + sum.ToString(); label2.Text = "Difference :: " + diff.ToString(); }

In this example, you can see that the out parameters do not have to even be the same type as the method. Here we return a string from the method, alongside the sum and difference integer values.

Powerful, I think.

Web Service Portability (part 2)

Another thing that caught me out today… I deployed a couple of web services, and web form consumers of those services to a “Live” environment today, and was getting some strange behaviour. Because of the limited amount of fault tracking code in my application, I spent several hours trying to figure out what my actual error was.

Once I added some more debugging code, I was able to determine the problem, and that it stemmed from a simple source.

The error message I was presented with was
"File or assembly name <random characters>.dll, or one of its dependencies, was not found"

After a quick Google, I discovered that the service account that IIS runs as was not allowed read/write access to the temp directory. As a result it was unable to download executable code from the web service, and therefore died. Lots of resources say to ensure that the ASPNET account has privileges on windows\temp, but you should check that the account really is ASPNET, and that your system temp folder is windows\temp.

Web Service Portability

When you create an application that relies upon web services, the simplest way to define the location of those web services is by specifying them at design time. The problem, of course, is when you want to deploy a development web service on one server to a live environment on another server. The answer? At design time, specify the “URL Behaviour” property of the web reference to “Dynamic”. This will add en entry to the app.config (or web.config) file for each web reference that looks like the following…

<appSettings> <add key="Full.NameSpace.Of.Web.Reference" _ value="http://servername/webservicepath/servicename.asmx"/> </appSettings>

With this in place, it is possible to move the physical location of the web services around without having to recompile your client application.

*CAVEAT* I have heard rumour that if the name of the service includes the string “static”, this can break the functionality described above. I do not know for sure if this is the case, but it is a possible place to start debugging in the event of failure.

Delete an object from the IIS metabase

Simple enough to do, as long as you remember you have to remove it from the parent item’s children list.

public static void DeleteMetabaseObject(string metabasePath) { try { string deleteParent = metabasePath.Substring(0,metabasePath.LastIndexOf("/")); string deleteName = metabasePath.Substring(metabasePath.LastIndexOf("/") + 1); DirectoryEntry parent = new DirectoryEntry(deleteParent); DirectoryEntry childToDelete = new DirectoryEntry(metabasePath); parent.Children.Remove(childToDelete); parent.CommitChanges(); } catch(System.Runtime.InteropServices.COMException e1) { throw e1; } }

Create a new Virtual Directory in IIS via C#

The following method will create a new IIS Virtual Folder object, based on a path and a friendly name.
ServerID is the ID of the “Web Site” you want to work with in IIS.
VirtualDirName is the name of the Folder that will be available through IIS (eg. http://localhost/VirtualDirName)
Path is the physical location of the folder on the disk.
AppPool is the name of the application pool that your new folder will run under.
AccessScript is a boolean value to determine whther the folder will be allowed to access scripts
CreatePhysicalFolder is a boolean to tell the method whether it should create non-existent file system folders.

public static bool CreateNewVirtualDirectory(int ServerId, string VirtualDirName, string Path, _ string AppPool, bool AccessScript, bool CreatePhysicalFolder) { DirectoryEntry Parent = new DirectoryEntry(@"IIS://localhost/W3SVC/" + ServerId.ToString() + "/Root"); DirectoryEntry NewVirtualDir; NewVirtualDir = Parent.Children.Add(VirtualDirName, "IIsWebVirtualDir"); NewVirtualDir.Properties["Path"][ 0] = Path; New if(!Directory.Exists(Path)) { Directory.CreateDirectory(Path); return true; } } else { return true; } return true; }