“Activate on Default” confusion and features scoped at Web Application level

by Radi Atanassov 23. July 2011 05:59

When creating SharePoint features in Visual Studio 2010, one of the settings that defaults to True is “Activate on Default”.

image

There is a lot of confusion as to what this setting actually does:

  • It ONLY applies to features scoped at Farm and Web Application levels. You can still modify it for other features, but it doesn’t do anything.
  • Any feature (Farm or WebApplication) with that setting set to True will automatically activate when you deploy the WSP solution, no matter which way you deploy it (Install-SPSolution, stsasm.exe, Central Administration)

This setting is not related to the deployment configuration settings in Visual Studio 2010:

clip_image001

These features will still activate, even if VS’s deployment configuration is set to “No Activation”.

Where can this be an inconvenience?

When you create features that deploy Timer Jobs at the Web Application level, you really want to have “Activate on Default” set to False. Otherwise, your feature will be activated on ALL web applications. I did some tests and found out that even if your WSP Solution is not global and is deployed to a specific Web Application, your feature will still get activated. Dangerous, you really want your Timer Jobs to be running where they are meant to run, i.e. don’t deploy Timer Jobs to Central Administration unless you really need to.

If you are ever trying to find out why your Timer Jobs are “attached” to all web applications, this might be why.

Tags: , , , , ,

English

Fun with HTTP Handlers, Security Validations, FormDigest, AllowUnsafeUpdates, jQuery, AJAX and POST parameters in SharePoint

by Ради Атанасов 23. April 2011 23:47

Ever seen this error message?

System.Exception: Microsoft.SharePoint.SPException: The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.

It is usually related to a missing SharePoint FormDigest control, or updates to the DB on an HTTP GET request. You might hear people saying you should set AllowUnsafeUpdates to true, but in the case of a POST request that is not the best thing you could do. The best resource that you could ever read on the topic is written a while back (in 2008!) by a good friend of mine and ex colleague - Hristo Pavlov. These two posts are your best starting point if you want to understand what these items are for and how they achieve their purpose.

What You Need To Know About AllowUnsafeUpdates (Part 1)

What You Need To Know About AllowUnsafeUpdates (Part 2)

Generally speaking, AllowUnsafeUpdates = true on POST shouldn’t be required at all. I was working with my team on an HTTP Handler living in the SharePoint Layouts folder and it was failing with the security validation exception. In a typical ASPX web page you would include the SharePoint FormDigest control and SharePoint will handle it from there onwards:

<SharePoint:FormDigest runat="server"/>

 

You will notice the output of this control is a hidden <input> like this one:

 

<input name="__REQUESTDIGEST" id="__REQUESTDIGEST" type="hidden" value="0xDA527A96…A23,22 Apr 2011 14:17:06 -0000"/>

 

SharePoint will use this control (in particular the parameter __REQUESTDIGEST) and validate the “FormDigest”. You can explicitly call the SPUtility.ValidateFormDigest() helper method achieves the same. (See Hristo’s blog posts for more info on how it works). It basically takes the __REQUESTDIGEST value and validates it on the request object.

 

But in an HTTP Handler you don’t have the <SharePoint:FormDigest /> control as there is no ASPX. Developers can get the handler working by setting AllowUnsafeUpdates on the SPWeb object, but this should be avoided when it could (see Hristo’s post on why it is not good). If you are making a POST request, pass in the __REQUESTDIGEST and make sure you call the SPUtility.ValidateFormDigest() method before you do any DB updates.

 

If you want to call your handler asynchronously with AJAX, lets say with jQuery, this adds another level of complexity. You have to pass in the __REQUESTDIGEST parameter for SPUtility.ValidateFormDigest() to succeed. I personally found documentation on the $.ajax jQuery method quite poor, but here is a JavaScript example on how to use it and pass the __REQUESTDIGEST <input/> value:

function UploadFileAsync() {

    var listId = $("input[id$='hdnListID']").val();

 

    $.ajax({

        type: "POST",

        url: "/_layouts/Handlers/FileUpload.ashx?ListID=" + listId,

        contentType: "application/x-www-form-urlencoded",

        data: "__REQUESTDIGEST=" + $("#__REQUESTDIGEST").val(),

        timeout: 30000,

        success: function (response) {

            alert(response);

        },

        error: function (x, t, m) {

            if (t === "timeout") {

                alert("got timeout");

            }

            else {

                alert(t);

            }

        }

    });

}

A few things are important and worth mentioning. In the “data” parameter I get the value of __REQUESTDIGEST and pass it in the POST request. (NOTE: you may want to improve the $(“#__RE..”) selector to get only input/hidden elements and be better performing). This will allow SPUtility.ValidateFormDigest() to pass successfully. If ever in doubt, open the request with Fiddler and validate the contents, you should see something like this:

clip_image001

The other important point is the contentType parameter. For me this did not work when set to “text/plain; charset=utf8”. I didn’t have enough time to figure out why, but “application/x-www-form-urlencoded” succeeded successfully.

Hope this helps!

Tags: , , , ,

Custom Upload Controls and the Maximum File Upload Size

by Ради Атанасов 23. April 2011 09:36

If you’re creating a custom page or control that uploads files from a users PC (or somewhere else) you may get this error if the file is too big:

System.Web.HttpException: Maximum request length exceeded.

This is an ASP.NET error before the request is being handled by SharePoint (you can follow the stack trace to understand it a bit more). The challenge developers are facing is handling the exception and producing a nice & customized error message to users. You can easily overcome the problem by modifying the web.config of the Web Application, but that is not good practice and you have to worry about reproducing the modification for scalability and backup/restore purposes.

In a typical custom solution there is a nice solution to this problem. If you use Application Pages (those ASPX files that live in {SharePoint Root}\Templates\Layouts) you can place a web.config in your solution folder within the Layouts folder. Your web.config will go in:

14\TEMPLATE\LAYOUTS\CustomSolutionFolder\web.config

Here’s what you need in the web.config:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>

<configuration>

  <location path="CustomUploadPage.aspx">

    <system.web>

      <httpRuntime maxRequestLength="2097151" />

    </system.web>

  </location>

</configuration>

web.config’s are very flexible and the location element lets you apply your change exactly on the file that you need. This will work even if you are using an ASCX control located in the _CONTROLTEMPLATES folder. It is also a great approach as it can be packed into WSP’s and be part of an enterprise solution.

The number 2097151 is 2GB (boundary), the maximum SharePoint supported file size. It may be good to reduce this depending on your example.

The next point worth mentioning here is that the above setting alone won’t let you upload files over 50MB unless you configure the Web Application to allow it.

clip_image001

If the Web Application setting is below your file size you will get this exception:

Microsoft.SharePoint.SPException: The specified file is larger than the maximum supported file size.
NOTE: it has an ErrorCode of 2147024872

The good news is that you can handle the above exception with a simple Try…Catch, and that is all you need to facilitate a friendly, customized error message.

Hope this helps!

Tags: , , ,

SharePoint Forums - Why they matter

by Radi Atanassov 30. January 2011 06:58

WARNING: "How cool am I?" post.

I've always wanted to spend some time on the SharePoint forums, just to see the fun and benefits of being a "regular".

I put some initiative into it and, I have to say, the forums are more than what I expected.

Here is why I think the forums are important for the community and every SharePoint expert out there:

  • When preparing an answer, you think about the issues and concepts around the asked question. This educates you. I answer to people, and when I do so I look over my notes on the topic. I have a huge arsenal of material on SharePoint concepts from which I pull out info and I always look up on a search engine to find anything recent. Going over knowledge and blogs is a learning experience. The end result - I am a better SharePoint expert.
  • You see trends of problems. This helps you understand common misconceptions so you can address them through blogs or open-source solutions. You see the biggest problems of the product, and the most often encountered headaches. You end up knowing more about your ecosystem.
  • You help people and they say thanks. And this makes you feel good. It also raises your profile, which is important for the self-development of everyone.
  • And of course, you get the opportunity to ask a question. If you are lucky, someone might even answer within minutes. No support ticket could do this for you.

A screenshot from my activity (taken today):

image

Which forums do I like? I'm currently a big fan of SharePoint 2010 General Questions and Answers as the questions cover everything and anything. People seem to ask all kinds of stuff here, configuring, development, architecture, search , PowerShell, you name it. I also poke around the others, but that one is my favorite.

How much time does it take? Not much - I answer questions while I wait for something else. Either a person, a task, a system job or an email. Answering a question takes a few minutes if you know the answer. What could cost you time is researching a problem, but hey, that is my job. I should know, so I don't mind looking into issues or concepts that I don't know the answer to. Either way, it is time which I am happy to give.

Last point - people ask me questions ALL the time. I always give them the answer, but ask them to post the question to the forums so everyone could benefit from my answer.

So don't think about it, post a question :)

See you on the forums!

Tags: , ,

English

Използване на LINQ to XML върху резултатите от SharePoint Web Services

by Ради Атанасов 18. March 2010 03:02

Когато работиме със Silverlight имаме възможност да използваме LINQ to XML за извличане на данни от резултатите от SharePoint Web Services. Тези дни разгледах LINQ to XML и никога повече не бих работил с XmlDocument обектите (:

Ето няколко примера:

GetListItems() – това е метод от Lists.asmx, и ето му отговора:

<listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"
xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<rs:data ItemCount="13">
   <z:row ... ows_ContentType="Task" ows_Title="New Task 1" ... />
   ... more rows here
</rs:data>
</listitems>

За да извлечем заглавията на list items и да ги подредим в List<string> обект:

private List<string> ProcessListResults(SPListsWS.GetListItemsCompletedEventArgs e)
{
    string result = e.Result.ToString();
 
    XNamespace ns = "#RowsetSchema";
    XElement results = new XElement(e.Result);
 
    var listItems = from x in results.Descendants(ns + "row")
                    where x.Attribute("ows_Title") != null
                    select x;
 
    List<string> itemsList = new List<string>();
 
    foreach (var item in listItems)
    {
        string title = item.Attribute("ows_Title").Value;
        itemsList.Add(title);
    }
    return itemsList;
}

GetUserInfo() – Този метод е от usergroup.asmx и ни дава информация за user в текущия SPSite обект (взима го от скрития user list). Ето отговора:

<GetUserInfo xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/">
  <User ID="7" Sid="S-1-5-21-347908140-582334945-263120918-1111" Name="Radi"
    LoginName="DEV\radi" Email="" Notes="" IsSiteAdmin="False"
    IsDomainGroup="False" />
</GetUserInfo>

 

И как извлиам LoginName:

public static string GetLoginFromServiceResponse(XElement result)
{
    XNamespace ns = "http://schemas.microsoft.com/sharepoint/soap/directory/";
 
    XName xUser = XName.Get("User", ns.NamespaceName);
    XName xUserInfo = XName.Get("GetUserInfo", ns.NamespaceName);
 
    XElement user = result.Element(xUser);
 
    if (user != null) {  return user.Attribute("LoginName").Value; }
 
    return null;
}

Това което подавам на метода е “e.Result.ToString()” от отговора.

Очаквайте още!

Tags: , , , ,

Using LINQ to XML to process SharePoint web service responses in Silverlight

by Ради Атанасов 18. March 2010 02:53

Since working with LINQ to XML, I’ve totally fallen in love with it and could never go back to working with the XmlDocument objects.

Here are a few code snippets that can help you out. It is so simple once you get a hang of it.

GetListItems() – this Lists.asmx method returns the following response:

<listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"
xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<rs:data ItemCount="13">
   <z:row ... ows_ContentType="Task" ows_Title="New Task 1" ... />
   ... more rows here
</rs:data>
</listitems>

To get the value of the title into a List<string> object:

private List<string> ProcessListResults(SPListsWS.GetListItemsCompletedEventArgs e)
{
    string result = e.Result.ToString();
 
    XNamespace ns = "#RowsetSchema";
    XElement results = new XElement(e.Result);
 
    var listItems = from x in results.Descendants(ns + "row")
                    where x.Attribute("ows_Title") != null
                    select x;
 
    List<string> itemsList = new List<string>();
 
    foreach (var item in listItems)
    {
        string title = item.Attribute("ows_Title").Value;
        itemsList.Add(title);
    }
    return itemsList;
}

GetUserInfo() – this method is inside usergroup.asmx and gives us information regarding a user in an SPSite object. The response:

<GetUserInfo xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/">
  <User ID="7" Sid="S-1-5-21-347908140-582334945-263120918-1111" Name="Radi"
    LoginName="DEV\radi" Email="" Notes="" IsSiteAdmin="False"
    IsDomainGroup="False" />
</GetUserInfo>

 

To get the LoginName:

public static string GetLoginFromServiceResponse(XElement result)
{
    XNamespace ns = "http://schemas.microsoft.com/sharepoint/soap/directory/";
 
    XName xUser = XName.Get("User", ns.NamespaceName);
    XName xUserInfo = XName.Get("GetUserInfo", ns.NamespaceName);
 
    XElement user = result.Element(xUser);
 
    if (user != null) {  return user.Attribute("LoginName").Value; }
 
    return null;
}

The passed in “result” is derived from e.Result.ToString().

Hope this helps!

Tags: , , , ,

SharePoint meets LINQ to XML: CAML заявки за работа с Lists.asmx

by Ради Атанасов 18. March 2010 01:28

Напоследък ми се налага да работя с LINQ to XML за интеграционни сценарии включващи Silverlight и SharePoint. LINQ to XML е страхотно – сравнително по-добре от създаване на XML чрез обекти като XmlDocument.

Ето пример – повиквам GetListItems() метода на Lists.asmx. Със следният код извличам list items от Task списъка създадени от специфичен user. Този пример би трябвало да работи както за WSS v3, така и за MSF v4.

XElement query = new XElement("Query",
        new XElement("Where",
            new XElement("Eq",
                new XElement("FieldRef", new XAttribute("Name", "Author"), new XAttribute("LookupId", "True")),
                new XElement("Value", new XAttribute("Type", "User"), userID)
)));


XElement queryOptions = new XElement("QueryOptions");
XElement viewFields = new XElement("ViewFields");

_listService.GetListItemsAsync("Tasks", null,
    query, viewFields, "100", queryOptions, null, null);

userID e SharePoint ID-то на потребителя, за който искам да видя резултатите. Можете да получите тази информация от usergroup.asmx.

Успех!

Tags: , , , ,

SharePoint meets LINQ to XML: Building a CAML Query and calling Lists.asmx

by Ради Атанасов 18. March 2010 01:20

I’ve been playing around with LINQ to XML and Silverlight recently, and it is absolutely awesome! The amount of code you have to write compared to working with XML DOM objects like XmlDocument is extremely minimised.

Here is an example on calling the GetListItems() method of Lists.asmx. I am returning the top 100 items in a Task list that are created by a particular user. This code example should be compatible for both WSS v3 and MSF v4.

XElement query = new XElement("Query",
        new XElement("Where",
            new XElement("Eq",
                new XElement("FieldRef", new XAttribute("Name", "Author"), new XAttribute("LookupId", "True")),
                new XElement("Value", new XAttribute("Type", "User"), userID)
)));


XElement queryOptions = new XElement("QueryOptions");
XElement viewFields = new XElement("ViewFields");

_listService.GetListItemsAsync("Tasks", null,
    query, viewFields, "100", queryOptions, null, null);

userID is the SharePoint user value within the current SPSite. You can get this with the usergroup.asmx service.

Hope this helps!

Tags: , , , ,

Forcing the DIP to load when a Word Document loads from SharePoint

by Ради Атанасов 20. February 2010 22:47

I was working on a project and I had custom content types defined in a feature. These content types had document templates, and I wanted to control the Document Information Panel (DIP) when a document is opened in Word.

The following code snippet takes an SPContentType object and adds a custom XSN element to the content types XmlDocuments collection. Setting the openByDefault value to “True” will force the DIP to open when the document loads. I use a FeatureReceiver to run this code against a newly provisioned Content Type.

public static void ConfigureContentTypes(SPContentType ct)
{
    XmlDocument doc = GetCustomXsnDocument();
 
    ct.XmlDocuments.Add(doc);
    ct.Update(true);
}
 
private static XmlDocument GetCustomXsnDocument()
{
    XmlDocument doc = new XmlDocument();
    
    string xml = "<customXsn xmlns=\"http://schemas.microsoft.com/office/2006/metadata/customXsn\"><xsnLocation></xsnLocation><cached>True</cached><openByDefault>True</openByDefault><xsnScope></xsnScope></customXsn>";
 
    doc.LoadXml(xml);
    return doc;
}

You can find information about the child CustomXsn elements on this MSDN link: Content Type Document Information Panel Schema

Hope this helps.

Tags: , , ,

Автоматично показване на DIP когато се отваря Word документ

by Ради Атанасов 20. February 2010 22:45

Работя по един проект, в който имам дефинирани Content Types в Feature. Тези Content Types имат различни document templates, и ми се наложи да конфигурирам Document Information Panel (DIP) да се отваря автоматично. Това става лесно чрез интерфейса, но трябваше да е част от автоматизиран деплоймент.

В следващия код показвам как става това. Подаваме SPContentType обект, на който му се дефинира нов CustomXsn елемент в своята XmlDocuments колекция. Ако под-елемента openByDefault е “True”, DIP ще се покаже при отварянето на документа. Използвам FeatureReceiver за прекарам мойте Content Types през този статичен метод:

public static void ConfigureContentTypes(SPContentType ct)
{
    XmlDocument doc = GetCustomXsnDocument();
 
    ct.XmlDocuments.Add(doc);
    ct.Update(true);
}
 
private static XmlDocument GetCustomXsnDocument()
{
    XmlDocument doc = new XmlDocument();
    
    string xml = "<customXsn xmlns=\"http://schemas.microsoft.com/office/2006/metadata/customXsn\"><xsnLocation></xsnLocation><cached>True</cached><openByDefault>True</openByDefault><xsnScope></xsnScope></customXsn>";
 
    doc.LoadXml(xml);
    return doc;
}

Можете да намерите повече информация за CustomXsn елемента на този MSDN линк: Content Type Document Information Panel Schema

Дано това помогне на някой.

Tags: , , ,

Microsoft Certified Master

SharePoint Server MVP

Radi Atanassov SharePoint MVP

About Me

SharePoint architect, consultant and solution developer. Owner and Chief SharePoint Architect of OneBit Software.

Аз съм консултант, архитект и разработчик на SharePoint решения. Собственик и Главен Архитект на OneBit Software.

Feeds

Get RSS Feed (Bulgarian)
Get RSS Feed (English)    
Get RSS Feed  (Both)        

I blog about technical concepts in English, as they benefit the whole community, but sometimes I blog about stuff specific to Bulgaria, and those I post in Bulgarian. The above feed URL's let you choose what to subscribe to.

My SharePoint Forum Activity

SharePoint User Group Bulgaria

login