Tuesday, 18 September 2012

How to reset all validators and validation summary on asp.net page

How to reset all validators and validation summary on asp.net page 


<script type="text/javascript">
    function Page_ClientValidateReset() {
        if (typeof (Page_Validators) != "undefined") {
            for (var i = 0; i < Page_Validators.length; i++) {
                var validator = Page_Validators[i]; 
                validator.isvalid = true;
                ValidatorUpdateDisplay(validator);
            }
        }
 $("[id$=Validationsummary]").html("");  
    }
</script>
 
 Click to view detail

Thursday, 13 September 2012

LINQ TO SHAREPOINT: WORKING WITH CREATED, CREATEDBY, MODIFIED AND MODIFIEDBY








LINQ to SharePoint is a great tool to perform queries against a SharePoint server since the 2010 version
Unlike the classical CAML queries, it allows to use a strongly-typed entity model and LINQ query syntax to
 query list data.


The SPMetal command
The first step to use LINQ to SharePoint is to run the SPMetal tool in order to create the entity model from an
 existent SharePoint site. This tool is located at 14\bin. Here’s a sample on how to use it:
SPMetal /web:http://mysharepointsite:9999 /code:Model.cs
This command will create a C# code file containing the entity model, in 14\bin\Model.cs. After adding this file
to our project, we can perform queries using LINQ to SharePoint. For example, this server-side code, outputs the
 titles for all the items in “MyList” where the title length is at least 10 characters long:
StringBuilder output = new StringBuilder();
using (ModelDataContext model = new ModelDataContext(SPContext.Current.Site.Url))
{
    foreach (MyListItem itemWithoutTitle in model.MyList.Where(x => x.Title.Length >= 10))
    {
        output.AppendLine(itemWithoutTitle.Title);
    }
}
The missing fields
By default, the Created, CreatedBy, Modified and ModifiedBy fields are not created by SPMetal. However,
the framework offers a way of extending the object-relational mapping system of the LINQ to SharePoint provider.
In other words, we can easily use those fields after telling LINQ to SharePoint how to retrieve and update them from
 the content database.
We will extend the base entity class of our model (“Item” class) in a new code file (we can call it “ModelExtensions.cs”
 for example):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Linq;
using Microsoft.SharePoint;
public partial class Item : ICustomMapping
{
    [CustomMapping(Columns = new String[] { "Modified", "Created", "Editor"
"Author" })]
   public void MapFrom(object listItem)
    {
        SPListItem item = (SPListItem)listItem;
        this.Modified = (DateTime)item["Modified"];
        this.Created = (DateTime)item["Created"];
        this.CreatedBy = (string)item["Author"];
        this.ModifiedBy = (string)item["Editor"];
    }
    public void MapTo(object listItem)
    {
        SPListItem item = (SPListItem)listItem;
        item["Modified"] = this.Modified;
        item["Created"] = this.Created;
        item["Author"] = this.CreatedBy;
        item["Editor"] = this.ModifiedBy;
    }
    public void Resolve(RefreshMode mode, object originalListItem, object databaseObject)
    {
        SPListItem originalItem = (SPListItem)originalListItem;
        SPListItem databaseItem = (SPListItem)databaseObject;
        DateTime originalModifiedValue = (DateTime)originalItem["Modified"];
        DateTime dbModifiedValue = (DateTime)databaseItem["Modified"];
        DateTime originalCreatedValue = (DateTime)originalItem["Created"];
        DateTime dbCreatedValue = (DateTime)databaseItem["Created"];
        string originalCreatedByValue = (string)originalItem["Author"];
        string dbCreatedByValue = (string)databaseItem["Author"];
        string originalModifiedByValue = (string)originalItem["Editor"];
        string dbModifiedByValue = (string)databaseItem["Editor"];
        if (mode == RefreshMode.OverwriteCurrentValues)
        {
            this.Modified = dbModifiedValue;
            this.Created = dbCreatedValue;
            this.CreatedBy = dbCreatedByValue;
            this.ModifiedBy = dbModifiedByValue;
        }
        else if (mode == RefreshMode.KeepCurrentValues)
        {
            databaseItem["Modified"] = this.Modified;
            databaseItem["Created"] = this.Created;
            databaseItem["Author"] = this.CreatedBy;
            databaseItem["Editor"] = this.ModifiedBy;
        }
        else if (mode == RefreshMode.KeepChanges)
        {
            if (this.Modified != originalModifiedValue)
            {
                databaseItem["Modified"] = this.Modified;
            }
            else if (this.Modified == originalModifiedValue && this.Modified != dbModifiedValue)
            {
                this.Modified = dbModifiedValue;
            }
            if (this.Created != originalCreatedValue)
            {
                databaseItem["Created"] = this.Created;
            }
            else if (this.Created == originalCreatedValue && this.Created != dbCreatedValue)
            {
                this.Created = dbCreatedValue;
            }
            if (this.CreatedBy != originalCreatedByValue)
            {
                databaseItem["Author"] = this.CreatedBy;
            }
            else if (this.CreatedBy == originalCreatedByValue && this.CreatedBy != dbCreatedByValue)
            {
                this.CreatedBy = dbCreatedByValue;
            }
            if (this.ModifiedBy != originalModifiedByValue)
            {
                databaseItem["Editor"] = this.ModifiedBy;
            }
            else if (this.ModifiedBy == originalModifiedByValue && this.ModifiedBy != dbModifiedByValue)
            {
                this.ModifiedBy = dbModifiedByValue;
            }
        }
    }
    public DateTime Modified { get; set; }
    public DateTime Created { get; set; }
    public string CreatedBy { get; set; }
    public string ModifiedBy { get; set; }
}
For extended information of how the ICustomMapping interface works, you can check these MSDN articles: ICustomMapping Members and RefreshMode Enumeration.
After adding this file to our project, we can use Modified, Created, CreatedBy and ModifiedBy in our queries:
StringBuilder output = new StringBuilder();
using (ModelDataContext model = new ModelDataContext(SPContext.Current.Site.Url))
{
    DateTime date = DateTime.Parse(“Thu, 05 May 2011 12:46:00 GMT”);
    foreach (MyListItem itemCreatedAfterDate in model.MyList.Where(x => x.Created > date))
    {
        output.AppendLine(itemCreatedAfterDate.Title);
    }
}
Keep in mind that the Author and Editor fields identify users. These strings may have more information than what
 you need. An easy way of parsing this string to extract the information you need is to create a new SPFieldUserValue
with the current SPWeb and the string. Then you can extract the actual SPUser from SPFieldUserValue.User.
I hope you find this code useful as I do. Enjoy!

Sunday, 9 September 2012

Adding functionalities to pages by inheriting PublishingLayoutPage


If you have worked a lot with MOSS you probably know how to make new page layouts. But if you create new page layouts you might sometimes wonder that how could I add some common functionalities to my page layout pages. One example could be localization. You have decided that Variations isn't the way to go in your case, but you still want to have different site structures for different languages... and of course you want to have texts localized. Or you want to change your master page for some reason on the fly... one example could be for printing reasons. Or even wilder... you want to change you page layout to another! You could do this kind of stuff pretty easily if you create your own PublishingLayoutPage class that has support your new functionalities. I'm going to explain how you can do that with SharePoint Designer and Visual Studio.

Create new class that will extend the functionality of PublishingLayoutPage

I started my journey by creating new Class Library project. I named it "Microsoft.MCS.Common" (since I work in MCS inside Microsoft... cool naming right :-). I added new class and named it PublishingLayoutPageEx. I inherited that from PublishingLayoutPage which is class behind page layouts. Where did I got that class name? Well I just opened ArticleLeft.aspx with SharePoint Designer and checked the first line:

<%@ Page language="C#" Inherits="Microsoft.SharePoint.Publishing.PublishingLayoutPage, Microsoft.SharePoint.Publishing, Version=12.0.0.0,Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
So it was pretty obvious that if I want to extend the functionality of the basic publishing page, I needed to inherit from it.
At this point my code looked like this (not much since we just started):
 1  using System;
 2  using System.Collections.Generic;
 3  using System.Text;
 4  using System.Web.UI;
 5  using System.Globalization;
 6  using System.Threading;
 7  using Microsoft.SharePoint.Publishing;
 8  using Microsoft.SharePoint;
 9
10  namespace Microsoft.MCS.Common
11  {
12    public class PublishingLayoutPageEx : PublishingLayoutPage
13    {
14      public PublishingLayoutPageEx()
15        : base()
16      {
17      }
18    }
19  }

And now I'm ready to test my new class in action. I just added strong name key, compiled and put it in the GAC. And then I changed the ArticleLeft.aspx to use my new class:
<%@ Page language="C#" Inherits="Microsoft.MCS.Common.PublishingLayoutPageEx, Microsoft.MCS.Common,Version=1.0.0.0, Culture=neutral,PublicKeyToken=b1e9400215c03709" %>
<small sidetrack to .NET Reflector>
If you're interestested in the stuff that's implemented in PublishingLayoutPage, then you can play around with incredible tool: Lutz Roeder's NET Reflector:
In just few clicks we can see that there is some MasterPageFile retrieving in OnPreInit:

</small sidetrack to .NET Reflector>

If you now try your new PublishingLayoutPageEx in action you'll get this kind of error message:

Server Error in '/' Application.

Parser Error

Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.

Parser Error Message: The base type 'Microsoft.MCS.Common.PublishingLayoutPageEx' is not allowed for this page. The type is not registered as safe.

Source Error:


 <%@ Page language="C#"   Inherits="Microsoft.MCS.Common.PublishingLayoutPageEx,Microsoft.MCS.Common,Version=1.0.0.0,Culture=neutral,PublicKeyToken=b1e9400215c03709" %>
 <%@ Register Tagprefix="SharePointWebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
 <%@ Register Tagprefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="PublishingNavigation" Namespace="Microsoft.SharePoint.Publishing.Navigation" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<asp:Content ContentPlaceholderID="PlaceHolderPageTitle" runat="server">

Source File: /_catalogs/masterpage/ArticleLeft.aspx    Line: 1


Version Information: Microsoft .NET Framework Version:2.0.50727.42; ASP.NET Version:2.0.50727.210

That only means that we need to mark that component as Safe so that SharePoint will load it. Let's just modify our applications web.config file by adding following line in there:
<SafeControl Assembly="Microsoft.MCS.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b1e9400215c03709" Namespace="Microsoft.MCS.Common" TypeName="PublishingLayoutPageEx" Safe="True" AllowRemoteDesigner="true" />
And then hit F5 in your browser and you should be all set. Now you have base what we're going to extend in next.

Add localization support to your pages

If you haven't played with ASP.NET Resource files, then you should take small detour into www.asp.net localization quickstart.
So now you know about .RESX files :-) I created Example.resx, Example.en-US.resx and Example.fi-FI. I have added only two words to the resource files:
  1. House:
    • en-US: House
    • fi-FI: Talo
  2. You:
    • en-US: You
    • fi-FI: Sinä
I copied those resource files to my applications App_GlobalResouces folder:
C:\Inetpub\wwwroot\wss\VirtualDirectories\80\App_GlobalResources
Now I modified my default_Janne.master page so that it would receive text from my resource files. I added following line just before </body> in master page.
<asp:Literal ID="house" runat="server" Text="<%$Resources:Example,House%>" /> <-> <asp:Literal ID="you" runat="server" Text="<%$Resources:Example,You%>" />
We have now added resource files and modified master page so that it will take text from our resource file. Let's just add code to our new class so that we could change the language on the fly.
 1  using System;
 2  using System.Collections.Generic;
 3  using System.Text;
 4  using System.Web.UI;
 5  using System.Globalization;
 6  using System.Threading;
 7  using Microsoft.SharePoint.Publishing;
 8  using Microsoft.SharePoint;
 9
10  namespace Microsoft.MCS.Common
11  {
12    public class PublishingLayoutPageEx : PublishingLayoutPage
13    {
14      public PublishingLayoutPageEx()
15        : base()
16      {
17      }
18
19      protected override void OnPreInit()
20      {
21         base.OnPreInit();
22         this.InitializeCulture();
23      }
24
25      protected override void InitializeCulture()
26      {
27         if (Request["mylang"] != null)
28         {
29           Thread.CurrentThread.CurrentCulture = new CultureInfo(Request"mylang"].ToString());
30           Thread.CurrentThread.CurrentUICulture = new CultureInfo(Request["mylang"].ToString());
31         }
32
33         base.InitializeCulture();
34      }
35    }
36  }

And now we can change the language from URL:

Here is result without the mylang parameter:

Of course you might not want to change your language by url parameter :-) This is just sample that you CAN do that. Maybe it would be much wiser to use some kind of site structure for localization. But I'll leave that to you...

Change master page on the fly

Now we want to make something fancier... like changing the master page on the fly. You could want to use this for print layouts, smaller screen, mobile etc. But anyway.. You just might want to do that sometimes :-)
So let's throw some code in here and see what happens:
...
 1      protected override void OnPreInit()
 2      {
 3         base.OnPreInit();
 4         if (Request["Print"] != null)
 5         {
 6           this.MasterPageFile = "/_catalogs/masterpage/BlueBand.master";
 7         }
 8      }
... 
On lines 4 to 6 we have just check that if there is mysterious Print parameter set. If that is set, we'll change the master page to nicely hardcode one. Let's see what happens on our browser:

So the result is quite easy to see... our master page changed from default_janne.master to BlueBand.master.

Change the page layout

Before I start... I'm going to give credit of this idea to Vesa Juvonen (colleague of mine at MCS who also works with SharePoint). He said that this would be interesting thing to checkout. And since I happened to have some code ready we tried this stuff on my environment. But he's going to create full solution of this page layout change and publish it in his blog. So you probably want to check that place out too. Okay.. but let's get back to the subject.
This might sound a bit strange but still... sometimes you might want to change page layout after the page has been created. Consider the Article Page content type which is OOB content type in SharePoint. It has 4 different kind of page layouts. User could have selected Image on right layout and has filled the page with data. After a while you want to change it to another layout.... BUT there isn't easy way to do that... unless we'll extend our nice class again.
Idea is take (again) some nice url parameter that tells the destination page layout. In this example I'll just take integer which is used to get the correct page layout from array of possible page layouts of this content type. And yes... I know that this code sample has a lot to improve... It just gives you ideas.
Let's throw some code in here and see what happens:
...
 1      protected override void OnPreInit()
 2      {
 3        SPContext current = SPContext.Current;
 4        if (current != null &&
 5            Request["changepagelayout"] != null &&
 6            Request["done"] == null)
 7        {
 8          SPWeb web = current.Web;
 9          // We need to allow unsafe updates in order to do this: 10          web.AllowUnsafeUpdates = true;
11          web.Update();
12       
13          PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);
14          PageLayout[] layouts = publishingWeb.GetAvailablePageLayouts(current.ListItem.ContentType.Parent.Id);
15          PublishingPage publishingPage = PublishingPage.GetPublishingPage(current.ListItem);
16          publishingPage.CheckOut();
17          // This is the magic:18          publishingPage.Layout = layouts[Convert.ToInt32(Request["changepagelayout"])];
19          publishingPage.Update();
20          publishingPage.CheckIn("We have changed page layout");
21       
22          SPFile file = current.ListItem.File;
23          file.Publish("Publishing after page layout change");
24          // We have content approval on: 25          file.Approve("Approving the page layout change");
26          Response.Redirect(Request.Url + "&done=true");
27        }
28        base.OnPreInit(e);
29      }
... 
And you can right away see from code that there isn't any checks or any error handling. So this code is only for demonstration purposes and you shouldn't take it any other way.... but here we can see the results after user has type in parameter changepagelayout=1 (Image on left):

And here is page if parameter is 2 (Image on right).

If you look at the code on line 14 where page layouts are retrieved... I'm using Parent of the current content type. You might ask why... But the reason is simple since your content type from the list actually inherits the Article Page content type from Site collection level. So if you would use ListItem.ContentType you wouldn't get those 4 page layouts of Article Page. Insted you need to get the parent of the content type in the list and then you get 4 different page layouts. Makes sense if you think how inheritance in SharePoint works.
If you wonder that done parameter I'm using... It is just helper to avoid recursive page layout change ;-)
Note: If you look at the code you probably already noticed that it's not changing the layout for this rendering... it has changed the page layout permanently. Of course you can change it back if you want to.

Summary

You can use a lot of stuff from ASP.NET right in your SharePoint page layouts. I can't even imagine all the capabilities of this but I'm just going to give you brief list what I can think of now:
1) Localization:
  • This one is obvious :-) I live in Finland and we need to deal with this in every project.
2) Change the master page
  • Print layouts
  • Mobile UIs
3) Change page layout
  • If you had created page but you later on want to change to more suitable one... here's how you can do it

I hope you got the idea of this post. I know I could improve those samples a lot, but I just wanted to share my idea and give you the opportunity to make it much better than I did.

Anyways... happy hacking!

Thursday, 6 September 2012

SP 2010: Getting started with LINQ to SharePoint in SharePoint 2010

Introduction

In SharePoint 2010 you now have the ability to use LINQ syntax to fetch items from your lists instead of using the "traditional" approach of CAML queries. (Including SPSiteDataQuery and SPQuery objects)
In this article I will give you a brief introduction to how you can get started using LINQ queries in SharePoint, also known as LINQ to SharePoint.

Basics of LINQ?

As a prerequisite to this article, I’m going to imply that you know what LINQ is and how to write basic LINQ queries in any .NET application already. I’m not going to dive into the details about LINQ or the syntax itself here – please see MSDN for that!

LINQ to SharePoint!

In order to work with LINQ in SharePoint 2010, we need use a tool called SPMetal.exe which resides in the 14bin folder. This tool is used to generate some entity classes which Visual Studio 2010 can use to get IntelliSense, and allows for LINQ-based queries to be performed on your lists.
Noteworthy:
  • LINQ to SharePoint queries are translated to proper CAML queries
  • CAML queries are in turn later translated to SQL queries

SPMetal.exe

Using the tool called SPMetal, we generate our entity-classes that are needed to perform these object oriented queries toward our SharePoint server.
These are the required steps to get hooked up:
    image
  1. Launch a cmd-window and navigate to C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions14bin
    image
  2. Run the following command to utilize the SPMetal.exe tool with the following syntax:
    1. SPMetal.exe /web:http://yoursite /code:C:YourEntityFile.cs
    2. Example:
      image
  3. Now navigate to C: (or wherever you chose to output your file) and make sure the file has been generated:
    image
  4. Open up the file and take a look at the content that SPMetal now have provided us with:

    Note that the class name is now MyEntitiesDataContext. It’s based on the name you specify as your code file in the SPMetal.exe command line tool. If you were to use /code:C:Awesome.cs instead, it would generate a class called AwesomeDataContext.
With that done – all we need to do is import it to one of our projects and use it!

Visual Studio 2010 – Let’s create a sample Web Part that utilizes LINQ to SharePoint

In this sample I will create a simple Web Part that will use LINQ to SharePoint syntax to fetch some information from the Announcements list. A basic sample I use in my training classes as well, and should be fairly easy to grasp!
  1. Create a new project (I’m going to create a new Visual Web Part project)
  2. Import your DataContext-file by choosing your Project -> Add -> Existing Item:
  3. Specify your file (mine is called MyEntities.cs):
  4. Make sure it’s properly placed in your project structure – then we’re good to go:
    image
Alright – that’s easy enough. Thus far we have created an entity file using SPMetal.exe and now we have successfully imported it into our project.

Add proper references

Now in order to use LINQ to SharePoint, you also need to reference the Microsoft.SharePoint.Linq assembly. Point to references, right-click and choose "Add Reference" and select the Microsoft.SharePoint.Linq.dll file:
image
In your code, reference the assemblies:
image

Ready to code?

What you should’ve done up until now is this:
  1. Generate your entities using the SPMetal.exe tool
  2. Reference the newly created file from your SharePoint project
  3. Make sure you’re using the proper references for System.Linq and Microsoft.SharePoint.Linq
  4. Be ready to code :-)

Code!

In my example I will have a Visual Web Part that will use LINQ to SharePoint to fetch all Announcements from my Announcement-list and work with those results. If you want to see the entire project, look at the bottom of this article where you can download it.
image

IntelliSense!

While you code your queries using LINQ to SharePoint, you will now have access to IntelliSense, which you did not have with CAML queries:
image
I’m going to leave it at that – very (very) easy to get started with LINQ to SharePoint, and all you really need to know is to start using the SPMetal tool to generate your entity classes and hook’em up with Visual Studio to start coding.


The two following questions are quite popular in my SharePoint 2010 developer training classes, so I ought to answer them right here.
  1. "What does LINQ to SharePoint really do?"
  2. "Can I see the CAML query generated by the LINQ to SharePoint query?"
The answer is simple: Yes, you can see the results of your generated LINQ query by using the Log property of your DataContext object.

What CAML lied behind my LINQ to SharePoint query?

In order to fetch the CAML query that lies behind your LINQ query, all you need is to work with the .Log object of your DataContext.
See this simple example, which simply outputs the CAML query to an XML-file for easy reading:
image
This will essentially generate the following content in the file C:MyEntitiesDataContextQuery.xml:
image
As you can see, the LINQ to SharePoint query is automatically turned into a CAML Query.

Summary

Yep, all you need is the .Log property to fetch the CAML query from your LINQ statement. In my sample I’m outputting it to a file called C:MyEntitiesDataContextQuery.xml.
You could of course output it in any other way you want – not just a physical file on the file system. The Log property is of the type TextWriter.