Pages

Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

November 29, 2016

How To Show Solution Name For Each Feature In SharePoint





The objective:
Ever occurred to you that you loose track of what solutions relates to what features enabled at site or site collection level? Yeah I've been in that situation too.
The objective is to add new field to Site features & Site Collection features page (/_layouts/ManageFeatures.aspx) showing a link of Solution name for each feature.

Introduction:
First, let's have a look for on urls of different pages:
Site features:         /_layouts/ManageFeatures.aspx
Site Coll. features: /_layouts/ManageFeatures.aspx?Scope=Site
WebApp features: /_admin/ManageWebAppFeatures.aspx?WebApplicationId={Id}&IsDlg=1
 (from CA -> select WebApp -> Manage Features)
Farm features:       /_admin/ManageFarmFeatures.aspx
 (from CA -> System Settings -> Manage farm features)

In this post, I am going to customize 'ManageFeatures.aspx' page only. However, the same procedure below can be applied to other pages. (Note: influenced by code from following post , I decided that I should start customizing my solution http://blogs.msdn.com/b/varun_malhotra/archive/2012/01/31/sharepoint-2010-get-solution-file-name-from-feature-activated.aspx).


OOB Page Details:
Let's first understand contents of ManageFeatures.aspx page and how it works:


- Fields: FeatureIcon(image), FeatureTitleDescription(Text), FeatureActiveButton(button), FeatureActiveState(text)


- Page calls a user control (~/_controltemplates/FeatureActivator.ascx) to render the table of features
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
 <wssuc:FeatureActivator runat="server" ID="featact" />
 <SharePoint:FormDigest runat=server />
</asp:Content>


- Page also calls another control ( ~/_controltemplates/FeatureActivatorItem.ascx) to do the feature logic
<AlternatingItemTemplate>
  <wssuc:FeatureActivatorItem
   DataItem='<%# Container.DataItem %>'
   AlternatingItem="true"
   runat="server"
/>


The feature logic is at code files:
- Microsoft.SharePoint.WebControls.FeatureActivator.cs
- Microsoft.SharePoint.WebControls.FeatureActivatorItem.cs


Customization Steps for SP2010 & SP2013:

1. First, make sure you backup the original manageFeatures.aspx page & user controls files (FeatureActivator.ascx & FeatureActivatorItem.ascx).


2. Make a copy for the following: page & user controls, then rename all with postfix with "Ex":
 ManageFeaturesEx.aspx, FeatureActivatorEx.ascx, FeatureActivatorItemEx.ascx

3. Do the following changes to edit 3 files:

- In ManageFeaturesEx.aspx file:
 Set the Src parameter to refer to FeatureActivatorEx.ascx
 <%@ Register TagPrefix="wssuc" TagName="FeatureActivator" src="~/_controltemplates/FeatureActivatorEx.ascx" %>

- In FeatureActivator.ascx file:

    1. Set the Src parameter to refer to FeatureActivatoritemEx.ascx
    <%@ Register TagPrefix="wssuc" TagName="FeatureActivatorItem" src="~/_controltemplates/FeatureActivatorItemEx.ascx"     %>

    2. Add new column header ("Solution") under <colgroup> add: <col width="10%" />

    3. Add new column content:
    *** For SP2010 ***
    Under <tr> add:       
      <th scope="col" id="FeatureSolution" class="ms-vh2" style="padding-bottom: 4px"><SharePoint:EncodedLiteral             runat="server" text="From Solution" EncodeMethod='HtmlEncode'/></th>

    *** For SP2013 ***
    Under <tr> add:       
      <th scope="col" id="FeatureSolution" class="ms-vh2-nofilter" style="padding-bottom: 4px"><SharePoint:EncodedLiteral         runat="server" text="From Solution" EncodeMethod='HtmlEncode'/></th>

- In FeatureActivatorItem.ascx file:
    1. Only for SP2013: First Add these 2 lines to import SharePoint namespaces
    <%@ Import Namespace="Microsoft.SharePoint" %>
    <%@ Import Namespace="Microsoft.SharePoint.Administration" %>

    2. insert the following code in page after the header tags & before first <td> tag:
    <script runat = "server">
        SPSite Site = SPContext.Current.Site;
        SPSolutionCollection FarmSolutions = SPContext.Current.Site.WebApplication.Farm.Solutions;
       
        private string getSolutionNameFromFeatureDef(SPFeatureDefinition featDef)
        {
        string result = string.Empty;
        Guid FeatureSolutionID = featDef.SolutionId;
        if (FeatureSolutionID != Guid.Empty)
        {
            SPSolution solution = FarmSolutions[FeatureSolutionID];
            if (solution != null)
            {
                result = solution.SolutionFile.DisplayName;
            }
        }
        return (result);
        }

        public string getSolutionName()
        {
        string result = string.Empty;
        try
        {
            Guid FeatureID = new Guid(this.FeatureId);
            SPFeatureDefinition CurrentFeatureDefinition;
            SPFeature CurrentFeature = Site.Features[FeatureID];
            if (CurrentFeature != null)
            {
                // feature is activated at site collection
                CurrentFeatureDefinition = CurrentFeature.Definition;
            }
            else
            {
                // feature is activated at Farm or other level
                CurrentFeatureDefinition = SPFarm.Local.FeatureDefinitions[FeatureID];
            }
            result = getSolutionNameFromFeatureDef(CurrentFeatureDefinition);
        }
        catch (System.Exception)
        {
            // do nothing when exception
        }       
        return (result);
       }
    </script>

    3. Then add a new <td> cell at the end of file:
      <td class="<% Response.Write(this.CssClass); %>" style="padding-top: 4px; padding-bottom: 4px; ">
            <table width="100%" cellpadding="0" cellspacing="0" border="0">
            <tr><td class="ms-vb2"><% Response.Write(getSolutionName());%></td></tr>
            </table>
    </td>


    Note: for SP2013 make sure to postfix any '_layouts/' with '15' to target the new hive


4. Copy the 3 files to hive (14 for SP2010 or 15 for SP2013) in all related WFE servers:
 - Copy controls FeatureActivatorEx.ascx, FeatureActivatorItemEx.ascx to \TEMPLATE\CONTROLTEMPLATES folder
- Copy page ManageFeaturesEx.aspx to \TEMPLATE\LAYOUTS folder

That's it! no need for IIS reset. Now you can enjoy having the solution info across all sites collection & site features across the farm.

Note: the solutions column will be empty when no wsp found for target feature (example: for OOB MS features that were stapled in with site definition). Also, solutions column will not support user solutions (sandboxed solutions).



October 20, 2014

Error: The Security Validation For This Page Is Invalid



Scenario:
The user is trying to edit a list item in page, via a custom web part, and the context is already under system account elevation (using SPSecurity.RunWithElevatedPrivilages() method).


Causes:
This error can occur due to one of the following reasons:

  1. Security/authentication problem: Can be fixed by delegation, and using ‘Web.AllowUnsafeUpdates’ & ‘web.Site.WebApplication.FormDigestSettings’ setting.
  2. Breaking role inheritance problem: In code, breaking the role inheritance internally flips the ‘AllowUnsafeUpdate’ flag to false, so it has to be explicitly set to true. See http://support.microsoft.com/default.aspx?scid=kb;EN-US;970192
  3. Page timeout problem:Where user took so long to upload the attachments. See http://support.microsoft.com/kb/888828

Solution:
Actually the code already applied point 1 above. It appeared that the code internally was doing other operations right before list item save, those operations were flipping the 'AllowUnsafeUpdate' flag without an alarm.. so the solution is simply to switch it back to 'true' before the save!





October 6, 2014

Tabs in MVC 5 Using JQuery UI



Here is how to implement tabs inside MVC 5 project using jQuery UI library.

Steps To Do It:

1. Install jquery ui (combined library) to get the js files and base theme


These files will be added by the Nuget:
jquery-ui-1.11.1.js
jquery-ui.min-1.11.1.js


2. From jquery UI website, make a custom download including the tabs widget and the desired theme (for example: 'Cupertino ' theme). Then add the file 'jquery-ui.css' to project under '/Contents' folder:


3. Add the following changes inside the <head> section in /Shared/_Layout.cshtml view file (Note that 2 file bundles (/bundles/jquery & /bundles/bootstrap) already exist in layout view but should be moved from bottom to top of the page):

@*moved from bottom of page*@
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")

<link rel="stylesheet" href="/Content/jquery-ui.css" />

<script src="/Scripts/jquery-ui-1.11.1.js"></script>

@*style for vertical tabs*@
<style>
.ui-tabs-vertical .ui-tabs-nav {
padding: .2em .1em .2em .2em;
float: left;
width: 12em;
}
.ui-tabs-vertical .ui-tabs-nav li {
clear: left;
width: 100%;
border-bottom-width: 1px !important;
border-right-width: 0 !important;
margin: 0 -1px .2em 0;
}
.ui-tabs-vertical .ui-tabs-nav li a {
display: block;
}
.ui-tabs-vertical .ui-tabs-nav li.ui-tabs-active {
padding-bottom: 0;
padding-right: .1em;
border-right-width: 1px;
border-right-width: 1px;
}
.ui-tabs-vertical .ui-tabs-panel {
padding: 1em;
float: right;
width: 40em;
}
</style>


4.  In /Home/index.cshtml view file: replace existing code with code below (where 'TabsSet1' is for horizontal tabs, & 'TabsSet2' is for vertical tabs):

@{  
 ViewBag.Title = "Home Page";
}

<title>@ViewBag.Title</title>

<h2 class="demoHeaders">IBR Testing JQuery UI Tabs</h2>

<div id="TabsSet1">
<ul>
<li><a href="#tabs-test">Test</a></li>
<li><a href="/home/About">About</a></li>
<li><a href="/Home/Contact">Contacts</a></li>
</ul>
<div id="tabs-test">
<h1>Welcome to this test tab</h1>
</div>
</div>

<br/><br/>

<div id="TabsSet2">
<ul>
<li><a href="/Home/About">About Us</a></li>
<li><a href="/Home/Contact">Contacts</a></li>
<li><a href="/Product/Index">Our Products</a></li>
<li><a href="#tabs-5">Tab X</a></li>
<li><a href="#tabs-6">Tab Y</a></li>
</ul>
<div id="tabs-5">
<h1>This is another Main tab</h1>
</div>
<div id="tabs-6">
<h1>Some Tab 2</h1>
</div>
</div>

<script>
$(function () {
$("#TabsSet1").tabs();
$("#TabsSet2").tabs().addClass("ui-tabs-vertical ui-helper-clearfix");
$("#TabsSet2 li").removeClass("ui-corner-top").addClass("ui-corner-left");
});
</script>


Notes:
- Tabs can redirect to an MVC action (ex: href="/Home/Contact") or to another div content (ex: href="#tabs-5")
- Extra work required for adjusting the content for vertical tabs when page width is too small because the content div will overlap the tab boundaries.



A useful reference:
http://vizagtechie.blogspot.mx/2012/10/aspnet-mvc-dynamic-tab-using-jquery-ui.html?view=snapshot