Thursday, July 28, 2011

The Mystery of SPWeb.SiteGroups and SPWeb.Groups

I've spend two days to find out how to create groups which is partaining just to Subsite. Everytime I created a group using SPWeb.SiteGroups.Add the group is associated with the parent site rather than subsite.

From documentation I realize
SPWeb.SiteGroups is associated with SiteCollection
SPWeb.Groups is associated with Web

So I attempted SPWeb.Groups.Add. And I encounter the following error message.

“You cannot add a group directly to the Groups collection. You can add a group to the SiteGroups collection.”

Damn!

To create a group for subsite, you have to create site groups first. After creating site group you have to add association of the group with sub site.

Someone from MSDN forum kind enough to give me this solution. I am just sharing it again to save the headache of others.

Pay attention to web.AssociatedGroups.Add. Without this function the group will not be associated to the subsite. :)

//Add the group to the SPWeb web
//This will add the SPGroup to SiteCollection
web.SiteGroups.Add(groupName, owner, defaultuser, description);

//Associate de group to the SPWeb.
//This will add the SPGroup to left side quicklaunch of Manage Groups page
web.AssociatedGroups.Add(web.SiteGroups[groupName]);
web.Update();

//Assignment of the roles.
//This is the actual permission/role assignment of SPGroup
SPRoleAssignment assignment = new SPRoleAssignment(web.SiteGroups[groupName]);
SPRoleDefinition roleApp = web.RoleDefinitions["Contribute"];
assignment.RoleDefinitionBindings.Add(roleApp);
web.RoleAssignments.Add(assignment);
web.Update();

http://social.technet.microsoft.com/Forums/en-US/sharepoint2010programming/thread/b6a7edda-e5fd-4a58-9273-e12705bec727

Thursday, July 7, 2011

Scanning through tags and notes, comments and User profile data in Sharepoint 2010

I've come across a task where by I need to write a timer job to scan through User profile data and all the social networking tags and notes to policing whether any user has put in any vulgarities or inappropriate comments. After going through the API and some of the testing on my own this is a small prototype of my findings. The program can tell which user has made what kind of changes for all these data. If anyone out there looking for something similar to what I needed to be done I guess this would help someone's live a little easier. :)

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Office.Server;
using Microsoft.Office.Server.Administration;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint;
using System.Web;
using Microsoft.Office.Server.SocialData;

namespace UserProfileChanges
{
class Program
{
static void Main(string[] args)
{
using (SPSite site = new SPSite("http://yourserver"))
{
SPServiceContext context = SPServiceContext.GetContext(site);
UserProfileManager profileManager =
new UserProfileManager(context);

// this gets some subset of changes to a user profile

DateTime startDate =
DateTime.UtcNow.Subtract(TimeSpan.FromDays(5));
UserProfileChangeQuery changeQuery =
new UserProfileChangeQuery(false, true);
UserProfileChangeToken changeToken =
new UserProfileChangeToken(startDate);
changeQuery.ChangeTokenStart = changeToken;
changeQuery.Anniversary = false;
changeQuery.SingleValueProperty = true;
changeQuery.MultiValueProperty = true;
changeQuery.DistributionListMembership = false;
changeQuery.SiteMembership = false;
changeQuery.UpdateMetadata = true;

UserProfileChangeCollection changes =
profileManager.GetChanges(changeQuery);
foreach (UserProfileChange change in changes)
{
Console.WriteLine("Changes occurs at "+change.EventTime.ToString());
if (change is UserProfilePropertyValueChange)
{
UserProfilePropertyValueChange propertyChange =
(UserProfilePropertyValueChange)change;
if (propertyChange.ChangeType.ToString() == "Metadata")
{
Console.WriteLine("Change Type " + propertyChange.ChangeType.ToString());
Console.WriteLine("Name " + propertyChange.ProfileProperty.Name);
Console.WriteLine("Account Name" + propertyChange.AccountName);
Microsoft.Office.Server.UserProfiles.UserProfile u = profileManager.GetUserProfile(propertyChange.AccountName);
Console.WriteLine("Property Value " + u[propertyChange.ProfileProperty.Name].ToString());
Console.WriteLine();
Console.WriteLine();
}
}
}

UserProfileManager myUserProfileManager = new UserProfileManager(context);
foreach (UserProfile myUserProfile in myUserProfileManager)
{
SocialTagManager mySocialTagManager = new SocialTagManager(context);
SocialTag[] tags = mySocialTagManager.GetTags(myUserProfile);
Console.WriteLine("Tags for user:");
foreach (SocialTag tag in tags)
{
Console.WriteLine(tag.Term.Name + ": " + tag.Url);
Console.WriteLine(tag.Owner.DisplayName);
}

SocialCommentManager mySocialCommentManager = new SocialCommentManager(context);
SocialComment[] comments = mySocialCommentManager.GetComments(myUserProfile);
Console.WriteLine("Comments for user:");
foreach (SocialComment comment in comments)
{
Console.WriteLine(comment.Url + ": " + comment.Comment);
Console.WriteLine(comment.Owner.DisplayName);
}
}


Console.Read();
}

}
}
}

Sunday, June 6, 2010

WCF: HTTP 407 Proxy Authentication Required

This error is really a big hassle for my web service program in our company. Our company use proxy and my program cannot go through if the proxy setting is being checked on the client PC. It took me quite awhile to research on how to resolve this issue until I come across this lovely article.. This really resolves the issue.

http://www.mikebevers.be/blog/2009/06/wcf-http-407-proxy-authentication-required/

I just simply need to add this in my app.config file

<system.net>
<defaultProxy useDefaultCredentials="true">
</system.net>

And as for WCF configuration we can keep the two attritubes

bypassProxyOnLocal="false"
useDefaultWebProxy="true"

if we want to enforce proxy on the web service

If we want to bypass proxy then we have to change it to

bypassProxyOnLocal="true"
useDefaultWebProxy="false"


And the solution will simply works like a charm. ;)

Tuesday, May 11, 2010

How to check if a double or integer or any numeric value is NULL

If you try to check on .NET using condition line

If myInteger Is Nothing=True Then

'Print something here

End If

Likely if the value of the integer is 0 (instead of real null value) the condition will become true and the code inside if statement will be executed. This is very fraustrating if the real purpose of the code is to check if the particular variable is really NULL

The better way to work around is to declare your integer as

Dim myInteger as Nullable(Of Integer)

or if it is double

Dim myDouble as Nullable(Of Double)

If you try to do the NULL test again using the code above, this time if the integer has value 0 the statement won't take it as true. Only if the integer is really NULL value the statement will be executed.

Just a little simple tricks. ;) If you don't know how to do it, it will take you about 10-20 minutes or so googling around and figuring out how this can be done.. justl ike me.. =D

How to copy file using copy.asmx sharepoint web service

To copy files first we need to add a web service in Visual Studio 2008. The link to add should be

http://sharepoint/sites/yoursite/_vti_bin/Copy.asmx

Just append the /_vti_bin/Copy.asmx behind the sharepoint sites that we need to copy file.

The next step is to configure NTLM authentication for sharepoint. (I assume you use the default NTLM authentication instead of the Kerberos. You will have to change the WCF configuration as follow in binding section

<binding name="CopySoap" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="67108864" maxBufferPoolSize="67108864" maxReceivedMessageSize="67108864"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="10000000" maxStringContentLength="10000000"
maxArrayLength="67108864" maxBytesPerRead="65536" maxNameTableCharCount="100000" />
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>

Take note of the clientCredentialType="Ntlm" setting at transport credential.

The following code will enable the user to copy file from 1 location to another

CopyIntoItemsLocal function did the copying of the file. If you want to copy the file from sharepointserver 1 to sharepointserver2 this method cannot be used. You have to use CopyIntoItems method instead. For my case, I am copying file within the same sharepoint server. So the code as follow

Imports System.Net
Imports System.IO
Imports System
Module Module1

Sub Main()

Dim copyService As CopyWebService.CopySoapClient = New CopyWebService.CopySoapClient()
copyService.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation
copyService.ClientCredentials.Windows.ClientCredential.Domain = "yourdomain"
copyService.ClientCredentials.Windows.ClientCredential.UserName = "adminuser"
copyService.ClientCredentials.Windows.ClientCredential.Password = "yourpassword"

Dim myCopyResult1 As New CopyWebService.CopyResult
Dim myCopyResultArray As CopyWebService.CopyResult() = {myCopyResult1}

Try

Dim copySource As String = "http://sharepoint/sites/mysite/Report/Test.xlsx"
Dim copyDest As String() = {"http://sharepoint/sites/mysite/Report/TestCopyFile.xlsx"}
Dim myUint As System.UInt32 = copyService.CopyIntoItemsLocal(myCopyResultArray, copySource, copyDest)
If myUint = 0 Then
Dim idx As Integer = 0
Dim myCopyResult As CopyWebService.CopyResult
For Each myCopyResult In myCopyResultArray
Dim opString As String = (idx + 1).ToString()
If myCopyResultArray(idx).ErrorMessage Is Nothing Then
Console.WriteLine("Copy Operation Ok")
Else
Console.WriteLine("Copy Operation fail")
End If
idx += 1
Next myCopyResult
End If
Catch exc As Exception
Dim idx As Integer = 0
Dim myCopyResult As CopyWebService.CopyResult
For Each myCopyResult In myCopyResultArray
idx += 1
If myCopyResult.DestinationUrl Is Nothing Then
Dim idxString As String = idx.ToString()
Console.WriteLine("Copy operation failed." + _
myCopyResult.ErrorMessage + myCopyResult.ErrorCode + _
"Description: " + exc.Message, "Exception")
End If
Next myCopyResult
End Try

End Sub

End Module

Tuesday, April 20, 2010

How to work around "This page allows a limit of 200 controls, and that limit has been exceeded" error in Sharepoint?

The way to work around is to change 1 of the configuration in web.config file for sharepoint. Change MaxControls to desire number in the configuration below.

<SafeMode MaxControls="200" CallStack="false" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="false">
<PageParserPaths />
</SafeMode>

Sunday, January 3, 2010

How to find out user permission in Sharepoint

Sometimes when we upload aspx pages with the custom application written for ourselves, we wish we can give certain controls and access rights of that aspx page based on the sharepoint sites.. The sample code below will help to bridge the gap between sharepoint permission and user uploaded aspx pages to sharepoint. We can find out the user's permission of the sharepoint within the aspx page





<script runat="server">
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

Dim username As String = Me.Page.User.Identity.Name
Dim url As String = SPContext.Current.Web.Url
usernameBox.Text = username
Dim site As New SPSite(url)

For Each web As SPWeb In site.AllWebs
If web.Url = url Then
For Each user As SPUser In web.AllUsers
If username = user.LoginName Then
Dim output As String = ""
Dim groupcount As Integer = user.Groups.Count

For Each group As SPGroup In user.Groups
output += group.Name & vbCr & vbLf
Next
Results.Text = ("This user belong to " & groupcount & " groups:" & vbCr & vbLf & vbCr & vbLf) + output
End If
Next
End If
Next
site.Dispose()
End Sub
</script>



<style type="text/css">
#form1
{
height: 300px;
}
</style>


<form id="form1" runat="server">
<?xml:namespace prefix = asp /><asp:label id="Label1" runat="server" text="Your Login Name is:"></asp:label>




<asp:textbox id="usernameBox" runat="server" width="362px"></asp:textbox>




<asp:label id="Label2" runat="server" text="You belong to the following groups:"></asp:label>




<asp:textbox id="Results" runat="server" width="366px" height="202px" textmode="MultiLine"></asp:textbox>
</form>