SharePoint with Attitude…

    Karla Ponce's Blog

    Browsing Posts in Code

    This post goes to a friend that needed to host a webpart in a page located in the _layouts folder.

    Application pages are generic pages that will not be customized, will be deployed only once per web server and will be used across multiple site collections (these pages reside in the layouts server folder).  Therefore if you need to create an application page, you either write inline code (only allowed in application pages, not in site pages) or write a code behind class. I really haven’t found a good requirement that justifies the need of a webpart inside an application page.

    Why would you need a webpart inside an application page? to me, if you need a webpart, then you’re looking for a site page, not an application page, anyways if somebody knows a good requirement for this please let me know.

    Back to the point, eventhough it is told that webparts cannot be added to application pages and that the only way to add the webpart is in the form of a web control; the truth is that you actually CAN add webparts to application pages, however you won’t be able to customize them using the browser and they can’t be inside a WebPartZone.

    If you’re adding a webpartzone with a webpart to your application page you’ll get an error “Unknown server tag WebPartZone”.

    Web parts inside an application page are called “static web parts”, and behave like normal controls; and web parts inside a webpartZone in site pages are called “Dynamic web parts” and can be added and dropped at runtime (Thanks to Serge Luca for these concepts).

    To add the web part just add it directly in MarkUp by registering the tag:

    <%@ Register TagPrefix="ABC" Namespace="Namespace" Assembly="Assembly" %>
    

    and directly adding the web part,

    <ABC:ClassName ID="ControlID" FrameType="None" runat="server" __WebPartId="YouWebPartGUID" WebPart="true" />

    As an example the next is an application page that contains a Content Editor Web Part:

    And this is how the page looks:

    hey Chris! I’m still waiting for the good business requirement of this! :)

    With the arrival of the Managed Metadata Service in SharePoint 2010 we know how useful and powerful this concept is to centrally define and manage terms that will be used as attributes for items in
    SharePoint.

    Using the Term Store in central Admin to create terms is very easy and straight forward. Creating Managed Metadata coulmns using the UI and adding items that use these columns is also a very easy.
    However when it comes to managing the Managed metadata service from the client side, what are out options?

    Unfortunately the SharePoint client object model does not support working with MMS taxonomy, fortunately SharePoint provides a web service to wotk with managed metadata: TaxonomyClientService.
    The TaxonomyClientService  provides the following methods:

      – AddTerms
      - GetChildTermsInTerm
      - GetChildTermsInTermSet
      - GetKeywordTermsByGuids
      - GetTermSets
      - GetTermsByLabel
    As you can see it does not provide a way to update or delete existing Terms.

    Creating Terms with the Client Object Model

    To add one or more terms to the term store we have to use the TaxonomyClientService.AddTerms() method,  this methos takes the following parameters:

    [WebMethodAttribute]
    public string AddTerms( Guid sharedServiceId, Guid termSetId, int lcid, string newTerms )

    • SharedServiceId. TermStore Id of TermSet to add Term in. Type: Guid
    • termSetId. Id of the TermSet that will contain the new term. Type: Guid
    • lid. The language that the label will be added in. Type: Int
    • newTerms. The XML of the new terms to be added. Type: String

    The XML for the newTerms parameter has to be in the following format:

    <newterms>
    <NewTerm label=\”TermValue1\” clientId=\”34\” parentTermid=\”8195c6aa-ce94-4588-9725-33cf96e82bcc\”></NewTerm>
    <NewTerm label=\”TermValue2\” clientId=\”34\” parentTermid=\”8195c6aa-ce94-4588-9725-33cf96e82bcc\”></NewTerm>
    </newterms>

    Using the Method:

    The method returns the GUID (in a string form) of the newly added Term.

    Get Terms with the Client Object Model

    To get a collection of all terms from the a TermSet we can use the TaxonomyClientService.GetTermSets() method, it takes the following parameters:

    [WebMethodAttribute]
    public string GetTermSets(string sharedServiceIds, string termSetIds, int lcid, string clientTimeStamps, string clientVersions, out string serverTermSetTimeStampXml)

    • sharedServiceIds. The ID of the Term Store. Type: String
    • termSetIds. The ID of the Term set to get the terms from. Type: String
    • lcid. LCID of language that labels will be returned in. Type: Int
    • clientTimeStamps. Collection of TimeStamps which are the last edit time of TermSets stored on the client. Type: String
    • clientVersions. Collection of versions of the server that each TermSet was downloaded from (always 1 unless the client doesn’t have the TermSet, then it is 0). Type: String
    • serverTermSetTimeStampXml. Returns the collection of TimeStamps of the last edit time of each TermSet. Type: String

    Using the method:

    The output is in the form:

    The definition of this XML is: (thanks to Solid Quality)

    Container: Container for all TermStores retrieved
    TermStore: Term store retrieved by ID
    TS: Term set retrieved by ID
    a9: TermSet ID
    a11: TermSet description
    a16: Submision Policy –> true = Open, false =Closed
    a12: TermSet name
    a68: TermSet contact email
    T: Term
    a9: Term ID
    LS: Label Set. Set of synonyms for Term
    TL: Label Term
    a32: Label name
    DS: Set of descriptions
    TD: Term description
    a11: Description text
    TMS: More information about Term Set
    TM:
    a24: TermSet Id
    a12: TermSet name
    a69: True of false. This term has children terms?. If true then appear a69 attribute, else don’t appear it.
    a25: Parent Term ID

    You can parse this html to get the term data that you’re looking for; for example if you’re looking for the term GUID:

    And that’s how we work with the Taxonomy MMS remotely, not as easy as using central admin but at least we have an option for working remotely.

    Cheers
    K

    If you’ve worked with the data form web part (or as some people call it: the data view web part, lol), you’ve probably noticed that if you enable “Sorting and Filtering on column headers” in the data view properties, it doesn’t actually behave as expected: Yes, it enables sorting and filtering in your columns, but if your columns are of a numeric type, then the sorting doesn’t actually work, it sorts all columns as if they were of a string type.

    Let’s take for example the ID field of a list items, the ID is an integer field. Now let’s create a DVWP to display the items from a list, including the ID, and then enable sorting. Now let’s sort the ID column and we notice that it is sorted in a wrong way, it is sorted as a string and not as a number.

    Well, this is a “bug” in the DVWP, by default it will always sort all columns as strings, if you want to fix this you have to do some extra work in the DVWP code. So this is what happens:
    First let’s remember how sorting works in XSLT: to sort we have to use the element. This element has the property “data-type”, this property specifies if the output should be sorted as text or as a number. As an example if we want to sort the ID field as a number we have to write this xslt code:

    Now, let’s go back to the DVWP sorting. When you enable sorting, the DVWP adds to the page some xslt code, including the following xsl parameter: text

    If you look at your xslt parameters you will see it in there, this parameter will be used as the data-type property for the element. We can see that the default value is text, so it doesn’t matter what type of field you sort, it will always be sorted as a string.
    This parameter is used Inside the “dvt_1.body” template :

    The way to solve this issue is to add a condition inside the template and verify which field is being sorted and depending on the field you specify “text” or “number” to the data-type property. This way your “dvt_1.body” template should look like this:

    Now the ID is sorted as a number:

    K

    I’m working on a Silverlight application that makes calls to WCF services to work with data, and today I ran into this error:

    System.ServiceModel.CommunicationException: An error occurred while trying to make a request to URI ‘http://SharePointDev:4444/_wcf/WCF_Services.svc’.
    This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services.
    You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent.
    This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute.
    Please see the inner exception for more details.
    —> System.Security.SecurityException —> System.Security.SecurityException: Security error.

    I remembered I had this issue some time ago and nonetheless I didn’t remember what the problem was or what the solution was, even thought the error is self explanatory…
    So after wasting time researching I found on the internet the solution, so this time I’m writing about it for my records. Dang! I’m a 25 year old with a memory of a 60 year old (with all the respect for the 60 year old people out there :-) …) hehe, I don’t like to waste time on these little errors, specially when I’m as busy as today.

    Anyway, the solution is the “clientaccesspolicy.xml” file. The error has to do with the cross-domain policy. We have to explicitly grant cross domain access to Silverlight (even if you are working with local apps), and the way to do it is by adding the “clientaccesspolicy.xml” file to the root level of the WCF service.

    Since my WCF is hosted in SharePoint and it is using a virtual path, Silverlight was looking for the file at the root level and not at the virtual path level, so you also have to take this in consideration. This is the blog that helped me with this issue for a better reference

    K

    Looking at a document library with workflows, I noticed that one of the instances of a workflow was in status “Error Occurred”. All of the tasks were Completed, but for an error in the code, the workflow didn’t end as expected and was showing the error status.

    The error itself was not a problem, it was fixed in the next version of the workflow, and for future instances, the workflow will end correctly. Nonetheless, the client didn’t want the error message to be displayed in the workflow.

     So what I needed to do was to change the workflow status. Using the user interface, the only option we have is to cancel the workflow. Thing that we didn’t want to do because not only we didn’t want to cancel the workflow (we wanted to complete it) but because canceling the workflow deletes all the tasks associated with the workflow, and of course that information needed to remain there.

     Immediately I looked at the object model, and to my surprise I didn’t find anything to be able to change the status of a workflow. The SPWorkflowManager let me Cancel the workflow, but that’s it, and again, we didn’t want to cancel the workflow, we wanted to finished correctly.

     After some research, and spending way too much time on this (thanks Microsoft!), I found that the way to change the status of a workflow is by using the AlterTask method of the SPWorkflowTask class, as if updating a Workflow Task, the only difference is the inclusion of this line of code:

    Done! Workflow Completed!

     The complete code to update the task is:

      Refer to my post Complete Workflow Task Programmatically to know more about updating workflow tasks.

    If you’re implementing branching logic, to submit a SharePoint survey you have to navigate to the last question and click the Finish button. This is how it behaves, it is designed so that the Finish button only appears in the last question, before that, you’re only allowed to save the survey.

    Saving the survey make it visible only to the owner of the survey, not even for the system account, and this is because when the survey is saved, it actually does not exist in the list yet. If you make a test and use the RunWithElevatedPrivileges to iterate in the survey list, you’ll notice that you won’t find a survey that has been saved by another user.

    For one of my projects I had a requirement to have the Finish button on every question, because it was not required for the user to respond to all questions, and the user needed to finish the survey at anytime.

    So, I added a new button to the survey question page, this button will contain the Finish functionality. But what is the Finish functionality? There is not Finish or submit option for the list item using the object model, when is it considered as finished? When I complete all questions? No, because some of them can be blank, Is only when you are on the last question that you see the Finish button, interesting.

    I consulted my good friend “Reflector” to see what is going on in there, the results: Survey Items have an internal method: “CheckIn()”, when you are in the last question and click finish, the item is checked in and actually created in the list. So bad that this Check in method is not public… anyways this is how I implemented the checkin for my new Finish button on the question page:

    I had a requirement to read the contents of Excel files located in a SharePoint library from a C# Application.

    The Server had installed the Office Primary Interop Assemblies (PIAs). PIAs are assemblies that let you work with COM objects exposed by the Office Applications,

    They contain the needed information that allows .NET managed code that runs under the common language runtime to call unmanaged code in Microsoft Office using the various Microsoft Office COM-based object model APIs.

    To read more about PIAs click here

     Having the PIAs installed (they are just assemblies), we can reference them from our Applications.

     For my requirement, I needed to use the Excel Interop assembly: Microsoft.Office.Interop.Excel.dll

     In the C# Application, having the reference to the Excel Interop assembly and adding the namespace to the project:  Using  Microsoft.Office.Interop.Excel;

     This is the code you need to read the excel file:

      

    And that’s it, the values from the excel file will be stored in an Array object, from there you can access the data and do all the manipulation/logic you need to do.

     I’ll meet the same requirement using Excel Services, I’ll update the results.

    One of my coworkers was getting an Access Denied error within the RunWithElevatedPrivileges block.

    I had this issue long time ago when I first used RunWithElevatedPrivileges  so I thought maybe it was because of the same reason, and yes, again and again, RunWithElevatedPrivileges seems to be giving everybody the same headache.

     Le’s say you have an event receiver using RunWithElevatedPrivileges  like this:

    The code looks good, the logic is good, no errors compiling, but if you debug you’ll see that the value of the User variable is not “System Account”!, as it should be, the user is the current user on the site executing the action, just as if you were not using RunWithElevatedPrivileges,  but why????

     Well, basically you just have to move all the objects from the current user to outside the RunWithElevatedPrivileges , otherwise the context automatically changes to the user firing the event. The correct code is:

    As simple as that, and it took me two days to found out! Crazy!

    I wanted to know the equivalent of SPWeb.EnsureUser() in web services and this is what I found:

    The people.asmx web service contains a method that let us do exactly the same than what EnsureUser() does. The method is:  ResolvePrincipals(), it resolves an e-mail address or other form of user identification into a PrincipalInfo object.

    One of the parameter let us indicate whether to add the user to the web if it does not exist already.

    This is the syntaxis:

    Parameters

    • principalKeys. Logon name of the principal.
    • principalType. SPPrincipalType object that specifies user scope and other information.
    • addToUserInfoList. Indicates whether to add the principal to a SPUserCollection that is associated with the Web site.

    Return Value: A list of PrincipalInfo objects that is indexed and accessed by the logon name in the AccountName field.

     To use it is very simple:

      Very useful!