Showing posts with label Code Samples. Show all posts
Showing posts with label Code Samples. Show all posts

Wednesday, 26 March 2014

Format date on textbox in Lightswitch HTML client

The HTML client for Ligthswitch is nice, except that not everything is that easy to obtain as in the Silverlight version. So is formatting dates on 'view' screens. Despite setting it at the entity in the 'Server' part of the project, it doesn't show up on the HTML output.
Solution:
Add a 'postRender' script to the date field(s) you like to format.

  • Therefore, go to the (view)screen where you like to format the date.
  • Select the field which shows a date. Let say 'StartDate'.
  • Click on 'Write code' on top of the window and select 'StartDate_postRender'.
  • Add the following piece of code:

myapp.ViewProject.StartDate_postRender = function (element, contentItem) {
    // Write code here.
    contentItem.dataBind("value", function (value) {
        if (value) {
            $(element).text(value.format("dd-MM-yyyy"));
        }
    })
};


Done.

Friday, 7 December 2012

Error Value: 2147942523 on Scheduled Task for Powershell


Situation: 
One of our clients where struggling with SSRS2008 R2 in SharePoint 2010 integrated mode (two server farm, both 64-bit Windows 2008 R2).
It is well known that this version SSRS 2008 R2 (v10) delivers a really bad performing webpart on the first report that is requested at the beginning of the day. For your information: The older v9 version performs much better as well as the newer version (of SSRS 2012).
However, I tried several solutions, without any luck. I found a solution on Pavel Pawlowski's blog (http://www.pawlowski.cz/2011/07/solving-issue-long-starting-report-ssrs-2008), which suggest to run a powershell script to stop/start the SSRS service, and load a report in a webclient (read more details on his post).
Problem:
I tried to run the scheduled task with the following statement:
"powershell.exe -noprofile -executionpolicy RemoteSigned -file c:\dnm\RestartSSRS.ps1"
It didn't work, it shows the following errors:
Task category: Action failed to start
Description: Task Scheduler failed to launch action “powershell.exe -noprofile -executionpolicy RemoteSigned -file c:\dnm\RestartSSRS.ps1? in instance “{46caf0b2-50df-49ad-90d6-0f4f9fd203ae}” of task “\SSRS Recycle”. Additional Data: Error Value: 2147942523.
Then I get:
Task category: Action start failed
Description: Task Scheduler failed to start instance “{46caf0b2-50df-49ad-90d6-0f4f9fd203ae}” of “\SSRS Recycle” task for user “customerdomain\Administrator” . Additional Data: Error Value: 2147942523
Solution:
I turns out that in this situation the Task Scheduler cannot fire the 64-bit version of powershell (which powershell.exe will do). You need to explicit point to the 32-bit version.
What I did was, edit the scheduled task, go to the action-tab and open the edit action window of the action.
On 'Program/script', I entered: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
On 'Add arguments (optional), I entered: -noprofile -executionpolicy RemoteSigned -file c:\myScripts\RestartSSRS.ps1

Done, that solved the "Error Value: 2147942523" problem for me.
And the solution Pavel Pawlowski gave, works also! All credits to him!

Tuesday, 16 October 2012

LINQ to SharePoint: linq query filter on multivalue lookup

Situation:
I have a SharePoint Foundation 2010 environment with a document library. One of the metadata on the documents is a multivalue lookup to a category list.
I used SPMetal to create entity classes for easy usage of linq to the different lists and libraries inside the SharePoint site.
Problem:
Inside a visual web part, I was trying to execute a linq query on the document library, filtering on a given category.
Example code:

QualityDataContext dc = new QualityDataContext(SPContext.Current.Web.Url);
// some other steps made
var mySelectedCat = dc.MyCategories.OrderBy(p => p.Title).Where(p => p.id == "CategoryOfInterestID")

var docs = dc.MyDocLib.OrderBy(p => p.Title).Where(p => p.Categories.Contains(mySelectedCat));

This goes wrong because in this situation linq is messing up with the "p.Categories" en the entity "mySelectedCat"

Solution:
I have searched a lot, without getting a right, easy solution. Some mentioned to use the 'old' "SPWeb, SPList, SPQuery and so on"-way. Others where trying to believe you that the sample above is working.
Sorry folks, it's not. The problem is that querying on the multivalue lookup just works after the data has been retrieved. So I uses the ToList() method to the 'docs' part, just before filtering. For performance reasons, I first get the whole list (I just needed the whole list) and then do the filtering on the moment I needed it.
So this results in the following piece of code that I am using to fill a tree view, grouped on main category and sub category with links to documents.
Note the 'ToList()' I am using, twice just straight in the beginning of the using section. This is doing the trick.

using (QualityDataContext dc = new QualityDataContext(SPContext.Current.Web.Url))
{
 var cats = dc.MyCategories.OrderBy(p => p.Title).ToList();
 var docs = dc.MyDocuments.OrderBy(p => p.Title).ToList();

 SPTreeView tv = new SPTreeView();

 var mainCat = cats.OrderBy(p => p.Category).GroupBy(p => p.Category);
 
 // Step through the main categories
 foreach (var item in mainCat)
 {
  TreeNode catNode = new TreeNode{ Text = item.Key, Value = item.Key };
  
  var subCats = cats.OrderBy(p => p.Title).Where(p => p.Category == item.Key);

  // Step through the sub categories
  foreach (var subCat in subCats)
  {
   TreeNode subCatnode = new TreeNode { Text = subCat.Title, Value = subCat.Id.ToString() };
   var subdocs = docs.Where(p => p.Categories.Contains(subCat));

   if (subdocs.Count() > 0)
   {
    foreach (var doc in subdocs)
    {
     string docUrl = doc.Path + "/" + doc.Naam;
     subCatnode.ChildNodes.Add(new TreeNode { Text = doc.Naam, ToolTip = doc.Title, NavigateUrl = docUrl, Target = "_blank" });
    }
    subCatnode.Collapse();
    catNode.ChildNodes.Add(subCatnode);
   }
  }
  tv.Nodes.Add(catNode);
 }
 this.Controls.Add(tv);

Tuesday, 25 September 2012

Report Server: Show/hide textbox by an expression

Today I was struggling with hiding a textbox on a report (in Report Builder) by using an expression. I tried to evaluate the number of subfunctions of a certain person. The evaluation worked, but the textbox didn't show up when 1 or more subfunctions were available.
The expression was:
=IIf((Count(Fields!Uid.Value, "dsSubFunctions")<1),False,True)
WRONG! The property you will set is named 'Hidden', so it's just the other way around:
=IIf((Count(Fields!Uid.Value, "dsSubFunctions")<1),True,False)
And stupid of me, it is just written right above the expression-textbox: 'Set the expression for: Hidden'

Anyway, just thought to share it, in case there are some more (lazy) programmers who don't read every single line of text Microsoft shows you :)

Wednesday, 19 September 2012

Cross-domain data with AJAX using JSON

I read some different blogs and sites about using JSON or JSONP in relation with AJAX requests in cross-domain environments.
I just want it to keep it as simple as possible.
Situation:
I have a local webservice, behind a firewall, which is only available from another website somewhere on the internet (ip-filtering). On that site I call the (local) webservice) using
$.ajax({
  type: "POST",
  url: 'http://<my url:portnumber>/myCustomService.asmx/SendMyRequest',
  data: "{name: '" + _name
  + "' , category: '" + _category
  + "' , address: '" + _address
  + "' , company: '" + _company + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
  // etc...

So, I figured out to use "access-control-allow-origin" with the value "*" as a custom header in IIS7.5
Problem:
However, adding the Acces-control-allow-origin=* doesn't work. After some struggling and some more research, in found the solution
Solution:
Besides this access-control-allow-origin, you need to add an extra entry, the "access-control-allow-headers" with value "content-type". So, just place inside your web.config the following data:

<configuration>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="access-control-allow-origin" value="*" />
        <add name="access-control-allow-headers" value="content-type" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

Tuesday, 10 July 2012

Problems with SPUtility.SendEmail in custom timer job

Last week I ran into a strange problem. I wrote a custom timer job which will send reminder emails to employees who haven't finished their task after a certain time.
Problem(s):
Sending emails is easy, by using the SPUtility.SendEmail function. Well, at least it should be easy. There are a lot of code samples, so search around for some if you need it. However, again I ran into a SharePoint problem. This function returns a boolean value and gave me 'false' all the time. I tried to use the ordinary mail method of System.Net.Mail. There I got an error about "Message rejected as spam by Content Filtering". Some research of the IT department on Exchange did not solve this problem.
Well, I went back to the SPUtility.SendEmail function. I turned out that using the StringDictionary gave some problems as well as using HTML tags. Using plane text and one of the other overloads that doesn't use the StringDictionary results in a successful send action. But I needed a formatted message (sending some links).
The LOG files gave some extra information on the 'false' action. And yes, it shows why it didn't send the messages: 550 5.7.1 Message rejected as spam by Content Filtering.
Solution:
The solution I found (here) was relatively easy. Bypassing the content filter for a specific email address (or even sender domain). To do this, you need to resort to the Exchange shell (EMS) to manage it.

  1. Click on Start > All Programs > Microsoft Exchange 20xx > Exchange Management Shell. Note, this works for at least Exchange 2007 and 2010 versions.
  2. Create the bypass for the 'from' email address you use when sending the email from a timer job:
    Set-ContentFilterConfig -BypassedSenders somebody1@mycompany.com, somebody2@mycompany.com
Note: You need to realize that spammers can spoof the 'from' address and this would allow spam to get thru.
So, after all, it was not really a SharePoint problem, but an Exchange 'problem'.

Thursday, 5 July 2012

Value does not fall within the expected range

Currently working on SharePoint and yep, running into strange problems and errors. A better name will be ShareProblems or SharePointless. However, just kidding a bit. But seriously, I run into the following situation:
Situation:
Running a webservice outside SharePoint which will receive data from a webform (on another server) in JSON format. The received data will be saved in a SharePoint list by using the client side object model. So far so good. The initial test where run by the administrator account (used for the installation and configuration of SharePoint). It worked fine. Because I have to run a workflow on 'new item created' on the SharePoint list, I needed a 'normal' account. The admin and service accounts are not allowed to start workflows. So, new AD account defined, gave the appropriate rights and voila... uh, not really.
Problem: 
Part of the code:

ListItemCreationInformation lici = new ListItemCreationInformation();
ListItem item = list.AddItem(lici);

item["Title"] = HttpUtility.UrlDecode(name);
item["Category"] = (categorie == "0") ? 15 : int.Parse(categorie);
item["Street"] = HttpUtility.UrlDecode(street);
item["Postal_x0020_Code"] = HttpUtility.UrlDecode(postalcode);

item.Update();
_clientContext.ExecuteQuery();


I got the return message: Value does not fall within the expected range.
The callstack was something like this:

at Microsoft.SharePoint.Client.ClientRequest.ProcessResponseStream(Stream responseStream) at Microsoft.SharePoint.Client.ClientRequest.ProcessResponse() at Microsoft.SharePoint.Client.ClientContext.ExecuteQuery() at DnmWebServices.MessagingService.SendRtvRequest(String name, String category, String street, String postalcode) in c:\inetpub\wwwroot\DnmWebServices\App_Code\MessagingService.cs:line 128
Line 128 in my case points to the _clientContext.ExecuteQuery.
Solution(s):
It seems there can be several causes.
1). Use of invalid field name. You need to use the internal field name! However, that was not the case in my situation.
2). Change the List View Lookup Threshold value of the web application. Default value is 8, I changed it to 20 and big surprise: it worked! Thanks to this post.
Note: My item has some lookup fields some of which some have more than 8 items.
Little conclusion: So it seems that when using (one of) the system admin accounts, this list view lookup threshold is ignored in one way. By using non-system admin accounts, it can be a show stopper.
Steps to edit this value:

  • Go to Central Administration > Application Management > Manage web applications
  • Select the appropriate web application (in my case the SharePoint - 80)
  • In the ribbon bar, select General Settings > Resourse Throttling
  • Search for the List View Lookup Threshold and change the value to 20.

Wednesday, 5 October 2011

MOSS 2007 - Upload size and HTTP-error 404.13

Today I discovered a strange behaviour of MOSS 2007 in combination with IIS 7. Normally you set the maximum upload size on web application level, inside the central administration. Guess what, that doesn't work at all when you are running MOSS 2007 on a IIS 7. You will raise into a "HTTP-error 404.13 Not Found". Thanks to internet, I found the solution (it worked for me, so give it a try).

Solution 1 - Changes for all web sites:
Next statement will set the maximum file upload size to 100MB. Note: the maxAllowedContentLength is in bytes!
%windir%\system32\inetsrv\appcmd set config -section:requestFiltering -requestLimits.maxAllowedContentLength:104857600
Solution 2 - Changes for a web app:

%windir%\system32\inetsrv\appcmd set config "Default Web Site/" -section:requestFiltering -requestLimits.maxAllowedContentLength:104857600
Just execute the statement in a command prompt.

Monday, 27 June 2011

Raise (custom) event after closing jQuery popBox

Recently I started to use the jQuery plugin popBox (http://plugins.jquery.com/project/popBox). This plugin provides a simple to use popup textarea extension for textboxes. The nice thing is that it works on hidden textboxes as well.

For my hour registration form I have some hidden textboxes to keep the form a bit clean. The form supplies textboxes for each day (see figure).
So for each day you can add hours, comment en log-info. The last two fields are hidden. To edit the comment and/or log-info you just press on the corresponding image.
Because these fields are invisible, you want to have some kind of indication if some text has been entered already or not. So I want to change the 'button'image if some text has been entered.
Raising an event seems to be a hard job, because you don't really access the (hidden) textbox, so their events are not raised. After some search and trial and error I found a solution.
First of all, let me show you how I attached the jQuery popBox plugin to my hidden comment and log-textboxes (see instructions at http://plugins.jquery.com/project/popBox). The hidden textboxes where called like txtNewMonComment, txtNewMonLog, txtNewTueComment etc.

1. I applied the popBox to all textboxes with class set to 'txtDailyComment':
$(document).ready(function () {
 //attach popBox jQuery plugin to all textboxes with class=txtDailyComment.
 $('.txtDailyComment').popBox();
});
2. The images that simulates a button are configured like this:
<img alt="Comment" src="/hrt/_layouts/images/DNM.WP.HourRegistrationGeneralForm/message_add.png"  onclick='SetTextboxFocus($(this));' id="btnNewMonComment" />
3. I wrote the SetTextboxFocus function to show the content of the corresponding hidden textbox:
function SetTextboxFocus(button) {
 var day = button.attr("id").substring(6, 9);
 var type = button.attr("alt");
 var control = "txtNew" + day + type;
 $("input[name=" + control + "]").focus();
}
So far is just like the instructions on the popBox plugin page.
4. The customization starts here and is quit simple. I wrote a function that I want to fire after closing the popBox. You can do whatever you want in this function. For demo reason I just show an alert:
function AfterTextboxUpdate() {
 alert('popBox is closed');
}
5. The popBox plugin supports option parameters. So I just add one of myself. I changed the popBox attach as written in step 1 as follows:
$(document).ready(function () {
 //attach popBox jQuery plugin to all textboxes with class=txtDailyComment.
 $('.txtDailyComment').popBox({ onclose: function () { AfterTextboxUpdate(); } });
});
6. The last step is to edit the popBox1.3.0.js file. Find the part where blur function is fired and add "options.onclose();" inside the if-section:
popBoxContainer.children().blur(function () {

 if (change) {

  $(this).parent().hide();
  $(this).parent().prev().hide();
  $(this).parent().prev().prev().val($(this).val().replace(/\n/g, options.newlineString));
  options.onclose();
 }
});
That's it. When you close the popBox, the AfterTextboxUpdate function will be fired.


Hope this helps you to get even more about this great jQuery plugin.

Tuesday, 22 March 2011

The query uses unsupported elements

I am using SPMetal for creating partial classes for accessing my SharePoint lists by code.
Today I was trying to run a Linq query in LinqPad on a SharePoint list (see here how to use LinqPad on SharePoint data). See query:
var q = from w in WorkItems
  where w.ShortUserID == "rob"
  where (((DateTime)(w.WorkDate)) >= firstDay 
     && ((DateTime)(w.WorkDate)) <= firstDay.AddDays(6))
  select new {w.Title, w.WorkDate, w.Hours, sprint = w.SprintItem.Title};
q.Dump();
Well, it's just an ordinary Linq query, but as always with SharePoint related programming, nothing goes well the first time. I got the following error message:
The query uses unsupported elements, such as references to more than one list, or the projection of a complete entity by using EntityRef/EntitySet
It has something to do with the 'sprint' information I needed. The 'SprintItem' is a property (Type of SprintItem object) of the WorkItem class. Somehow this will fail.
An explanation given by Paul Beck (see his blog):
ToList() method forces immediate query evaluation and returns the generic that contains the query result. As described in the MSDN article LINQ can't convert the LINQ to SharePoint into a CAML query so by using the ToList() method, the query is broken into 2 stages. This will apply to queries that use JOINS, UNIONS, and various other LINQ operators as described in the MSDN Unsupported LINQ queries article.
In his article he relates this problem with 'join'. However, I didn't use this keyword. Nevertheless his solution worked, I needed to put 'ToList()' right behind 'WorkItems' and the problem is solved. So the code will now looks like:
var q = from w in WorkItems.ToList()
  where w.ShortUserID == "rob"
  where (((DateTime)(w.WorkDate)) >= firstDay 
      && ((DateTime)(w.WorkDate)) <= firstDay.AddDays(6))
  select new {w.Title, w.WorkDate, w.Hours, sprint = w.SprintItem.Title};
q.Dump();

Thursday, 10 March 2011

LinqPad on SharePoint data

Linq to SharePoint is great! The SPMetal.exe is really easy to use (see here how to use it).
But I was struggling a bit to get the right Linq queries. So I thought, well let's use LinqPad. I ran into the following error message:
PropertyOrFieldNotInitializedException: The property or field has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.
I searched for a solution, but I didn't find one. Today I figured out how to use LinqPad to query on SharePoint data, without facing these security-IIS-related issues.
On CodePlex you can find the LinqPad Data Context Driver for SharePoint created by a guy named 'theiwaz'. Creating a new connection in LinqPad, using this driver did the trick. Read the documentation how to install and setup the configuration (very easy!).

In my situation, I ran into a small problem. The documentation shows a screenshot with a sample code, using "C# Expression" a the language.
When I tried that, it failed. I got the following message:
String was not recognized as a valid Boolean
 Changing the language to "C# Statement(s)" did the trick for me. I only need to rewrite the code a little bit. But that's actually a great advantage, because it now looks like the code as I will use inside my VS2010 project.
var q = from prod in Products
    where prod.Customer.Title == "DNM"
    select  prod.Title;

q.Dump(1);

Friday, 4 March 2011

SPException: Field type is not installed properly

During my trial to create a custom cascade filtering lookup field, I run into the following exception:
SPException: Field type is not installed properly
There are several possible situations that can cause this error. E.g. using the optional field SPQuery in the fldtype_.xml is not allowed for custom field (see also http://msdn.microsoft.com/en-us/library/aa544201.aspx).
However, this was not my issue. I made a little (stupid?) mistake in the xml file. The field FieldTypeClass should show the full class name (including the entire namespace) as well as the full assembly name (I forgot the class-part, as shown in bold). So it should look like this:
<Field Name="FieldTypeClass">Dnm.SP2010.CF.AutoFilteredLookup.AutoFilteredLookupField, Dnm.SP2010.CF.AutoFilteredLookup, Version=1.0.0.0, Culture=neutral, PublicKeyToken=93ec60d3306981cd</Field>

Wednesday, 2 March 2011

customerrors mode off not working on SharePoint 2010

During the developing of a custom field, I faced some errors, but the didn't work.
After some search, it seems that you have to do this trick on three locations. SharePoint 2010 has web.config files on the following locations:
  • C:\inetpub\wwwroot\wss\VirtualDirectories\80\
  • C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\CONFIG\
  • C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS
On all these locations you can find a web.config file.
Change customerrors to:
<customErrors mode="Off" />
and the SaveMode tag (if available) to:
<SafeMode MaxControls="200" CallStack="true" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="true">
as well as the compilation tag to:

<compilation batch="false" debug="true" optimizeCompilations="true">
This did the trick for me

Thursday, 14 October 2010

Change Default UserName in VMware

I was struggling a bit with an incorrect default username my VMware machine was starting with everytime. Everytime I started or reboot the machine, Windows automatically logged on with a default username I don't want to use. This is due to the 'personalize' option during creation of a virtual machine.
Therfore, I first thought it was an VMWare issue, but it turned out it isn't. You need to change something in the Windows registry.

Edit the following key:
HKEY_LOCAL_MACHINE\SOFTWARE\Mirosoft\Windows NT\CurrentVersion\WinLogon
Search for the key with the name DefaultUserName and change it to the account you want.

Friday, 24 September 2010

Userprofile picture through SSL

I have written an advanced contact web part. This web part shows the details of an user that is contactperson for that specific site. One of the options is showing the profile picture. Through the intranet it works fine. Through the extranet (which is available via SSL) it didn't work.

In the web part, I store the accountname of the user. When showing the web part, I will retrieve the details from the user profile, using the UserProfileManager and UserProfile (namespace: Microsoft.Office.Server.UserProfiles). The properties of the user are gotten from the property collection.
One of the properties is the "PictureUrl". I was assuming those url was server relative, but unfortunately it isn't. So I overcome this problem to create a Uri object, based on the retrieved PictureUrl and uses from that Uri object the PathAndQuery property. Using this value as an url for the image tag works perfectly fine.

Friday, 28 May 2010

Include or Exclude Users from SharePoint Profile Import

During a (default) import of user profiles (from Active Directory (AD)) inside SharePoint (MOSS) you will notice a bunch of user profiles you are not interested in (like system_mailbox, some dummy users as well as disabled accounts).
I was wondering if it would be possible to exclude these AD user profiles during the profile import in SharePoint. After a little search, I found the solution to obtain this.

You need to go to your SharedServiceProvider (from within the Central Administration). Navigate to 'User Profile and Properties' > 'Manage Connections'.
Here you will find the field called 'User filter'. The content will look like this (which is default):
(&(objectCategory=Person)(objectClass=User))

Between '(&' and the last ')' (let's say the filter placeholder) you can add fields you want to filter on. Add the following string just after the last fieldfilter to exclude those user accounts that are disabled in AD:
(!userAccountControl:1.2.840.113556.1.4.803:=2)
So the entire string will be like this:
(&(objectCategory=Person)(objectClass=User)(!userAccountControl:1.2.840.113556.1.4.803:=2))
If you also want to include only those user accounts where (e.g.) the company name is filled in, you need to include (company=*). In reverse, if you want to exclude those that have a company name, just place a exclamation mark right for company: (!company=*). The 'include' version will then look like this:
(&(objectCategory=Person)(objectClass=User)(company=*)(!userAccountControl:1.2.840.113556.1.4.803:=2))
An easy way to figure out to create your own filtersyntax (like company start with 'bla'), you can build easily a query inside AD which will show you the correct syntax.

Friday, 7 May 2010

Work around ServerContext en UserProfile troubles

I struggled some time with working with the UserProfile and ServerContext inside SharePoint (MOSS 2007).
I wrote a web part to show more details of a sitecontact. For that, I needed to get details from the UserProfile. The UserProfile was obtained from the UserProfileManager.
The code (web part) was running fine on the SharePoint server itself, but it failed on a client machine.
After struggling a lot, trying different suggestions (like fake SPContext and so on) today I found the solution. You need to use the SPSecurity.RunWithElevatedPrivileges method. RunWithElevatedPrivileges runs the code in the brackets under the SharePoint System Account.
So here is the piece of code I am using:

try
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(SPContext.Current.Site.ID))
{
ServerContext context = ServerContext.GetContext(site);
HttpContext currentContext = HttpContext.Current;
HttpContext.Current = null;

UserProfileManager profileManager =
new UserProfileManager(context);

UserProfile user =
profileManager.GetUserProfile("domain\\accountname");

PropertyCollection propCollection =
user.ProfileManager.Properties;

if (user != null && propCollection != null)
{
\\ do your stuff with the 'user'
}
HttpContext.Current = currentContext;
}
});
}
catch (Exception)
{
\\ handle the exception
}


I used this code for retrieving userprofile details. I didn't try to edit the user profile. But I assume it should work as well.

Wednesday, 5 May 2010

Deployment of a class library with WSPBuilder

This topic contains some points about deployment class library with WSPBuilder. For a couple of weeks I am working with WSPBuilder (http://www.codeplex.com/wspbuilder) for creating SharePoint web parts.
Due to the lack of some functionality, I wrote a class library which contains some extension methods for the SPWeb object. At that time the problems began.
Situation:
  • VMWare machine with MOSS 2007 on a Win2003 machine for development and test purposes
  • Visual Studio 2008 with WSPBuilder extension
  • Solution with several WSPBuilder web part projects
  • Custom class library SPExtensions.dll
Three of the WSPBuilder projects in my solution are using this class library with the extension methods in it. That works fine, until you are going to deploy it.
The deployment of the first WSPBuilder project deployed the class library into the GAC. This will affect the build process of the other two WSPBuilder projects. Those two wsp-packages do not have the class library dll in it. This happens even the referenced dll property "copy local" is set to "true". This was/is a real PITA! Because after updating the SPExtensions project, the new dll was not updated in the GAC for the 2nd and 3rd project (because the dll is not included in the wsp file).
So I want the SPExtentions.dll deployed to the WebApplication bin and not in the GAC. After some search and trial and errors I found the solution to get this job done.
  1. Make sure the SPExtensions.dll (or whatever your class library is called) is not present in the GAC anymore. You can use gacutil to uninstall the assembly.
  2. Created a '80' folder with a 'bin' subfolder inside all of the projects (e.g. ..\ProjectFolder\80\bin) that uses the SPExtensions.dll.
  3. Create for each of these project a post build event:
    move /Y "$(TargetDir)SPExtensions.dll" "$(ProjectDir)80\bin"
    NOTE: You should use the "move" command and not the xcopy. The WSPBuilder (by default) sets the DeploymentTarget of the assemblies found in folders, other than GAC and 80\bin to GlobalAssemblyCache. So make sure you move the SPExtensions.dll from the ProjectFolder\bin\release (or debug) to the 80\bin folder created in step 2.
  4. Now you can build the project, create the wsp-files and deploy (or upgrade) them. After step 3, I used the "clean" option, just to be sure that I do not get messed up with some left crap.

Tuesday, 13 April 2010

Format file size (C#)

This post is not spectacular, but might be useful for some of you. I wrote a simple function to format the file size like it is in the file explorer (21 KB, 1,23 MB etc). I needed this for showing the file size in a tooltip for a SharePoint treeview.


private string FileSizeFormat(long size)
{
const int KB = 1024;
const int MB = 1048576;
const int GB = 1073741824;

if (size < KB)
{
return string.Format("{0} bytes", size);
}
else if (size < MB)
{
return string.Format("{0} KB", (size / KB));
}
else if (size < GB)
{
return string.Format("{0:0.00} MB", (size / MB));
}
else
{
return string.Format("{0:0.00} GB", (size / GB));
}
}

Just enter the file size (which usually is a long) into this function, you get the appropriate format back.
Edit: Made the code a bit easier (thanks Frank!)

Friday, 26 March 2010

Improve performance of VMWare

For a while I am using VMware environments for SharePoint development projects. Last time, I was really struggling with performance issues. My host OS is Windows 7 (64-bit) with an Intel T7700 processor and 4 GB RAM. About every 10 minutes, the CPU of the virtual machine (Windows 2008 R2, 64-bit) was up to 100% caused by a variety of services (every time another one).
There are some improvements I have made which worked (at least) in my situation.
  • Configuration of the virus scanner.
    Exclude the VMware files from real-time protection and for the ThreatSense-engine
  • Add some parameters to the VMware configuration file (.vmx)
    - Disable page sharing (improves I/O). Add following line to the vmx-file:
    sched.mem.pshare.enable = "FALSE"
    - If you have enough free RAM for all planned concurrent VMs, be sure to disable memory trimming for guest OSes adding the following line to the virtual machine configuration (.vmx) file:
    memTrimRate="0"
  • A really performance hitter for virtual machines is a fragmented host OS disk. Be sure to schedule a disk defragmentation on your host OS a regular basis (best: daily)
  • See more tips here.
By now, I am a bit more happy