Friday, December 13, 2013

Specification Pattern & Client Object Model in SharePoint 2013

 

Hi, well if you guys are really wondering what does this mean and what problem it solves, let checkout the Google’s definition of it what it says

image

 

But still you must be thinking as to where does this fits in our day to day work?

All business problem comes with a detailed specification, but when we have to translate that into code, we often don’t do a good job in crafting them, we tend to ignore a repetitive pattern which can solve handling such specification in much nicer and cleaner way.

Let’s take a simple example,

We have a requirement where we need to verify if a List has following property set Title, Description

At simplest we would write a simple query

 

…..

Context _context = new Context(“Your_SharePoint_Site_Url”)

var result = _context.LoadQuery(_context.Web.Lists.Where(p=>p.Title == “SomeTitle”);

_context.ExecuteQuery();

 

well next day the requirement changes and you’ve been asked to write the similar condition for another module in project, what would u do, go and write a utility class copying over the above code and what !!! job done Smile.

and now you again get a requirement to validate Description property of the List, what would you do, simple copy over the function written in utility class change the where clause and you are done. Smart right? Well yes it really depends on the demand of situation how clean you really want the code.

According to me you are violating following principle from SOLID, like Single responsibility principle, Open Close Principle.

So how can we write the above specification so that we don’t violate SRP and OCP. Well the answer is Specification Pattern

Enough talk let get to code

We define abstract specification class with an abstract method

 public abstract class SpecificationBase<TEntity>
{
public abstract Expression<Func<TEntity, bool>> Predicate { get; }
}




Next we define concrete implementation of specification to which has single responsibility of defining the condition of one business problem.

public class ByListTitle : SpecificationBase<List>
{
private readonly string _title;

public ByListTitle(string title)
{
_title = title;
}

public override Expression<Func<List, bool>> Predicate
{
get
{
return p => p.Title == _title;
}
}
}



Thus now we have a single class which know how to handle a where condition to find title.


Note this is very simple example, think of situation where your business requirement demands to get its data from various sources, so this class can explicitly request that dependencies for the condition to be formulated.


Lets go back and change our initial code to work with the specification pattern.


 

var titleSpecification = new ByListTitle();

var result = _context.LoadQuery(_context.Web.Lists.Where(new ByListTitle("Class").Predicate));

_context.ExecuteQuery();



 


Note the above highlighted lines this is what usually your Where Clause takes a predicate.


 


Cool, well we haven’t done anything fancy here Smile finding a title by explicitly writing additional classes makes no sense, but i just want to remind you this is just a very simplistic example, but the concept can be equally applied with similar codebase to any such business validation component.


 


Let say now we again got requirement to build a complex logic (calling a web-service and some additional regular expression classes) to validate the Description of the List Smile and at the same time we would need to validate the Title. So what’s your take now, will you still say this is easy? i don’t think so, i think you’ll end up cluttering your code with all the logic required to make web-service call and calling the Regx utility.


Indeed, we must strive to stick to SRP and OCP and would not again want to violate such principle. So what would we do, create another specification class Smile this now adheres to SRP and OCP.

public class ByListDescription : SpecificationBase<List>
{
private readonly string _description;

public ByListDescription(string description)
{
_description = description;
}

public override Expression<Func<List, bool>> Predicate
{
get
{
// Code to Call WebService
// Code to call RegX Utility
return p => p.Description == _description;
}
}
}
Now its so easy to add the code logic of calling web-service call and regx utility without cluttering up the code.
But wait we haven’t finished its just one part of requirement covered, we also wanted to combine both the specifications so that 
we can validate both Title and Description at the same time.
Which essentially means we need to supply some kind of “And” logic here. Not to worry you don’t have to write additional code to set it up.
there is already a Predicate Builder present which can simplify and make your life easier Smile
 

So how does our code now look like

var predicates = PredicateBuilder.True<List>();
predicates = predicates.And(new ByListTitle("SomeTitle").Predicate)
.And(new ByListDescription("Some Des").Predicate);

_context.LoadQuery(_context.Web.Lists.Where(predicates));
_context.ExecuteQuery();




Let me take some time to explain the above code using PredicateBuilder


with predicate builder, if you want to build “And” condition then you would need to specify the object, with True extension which in our case “List”. and then wire-up the predicates (i.e. specifications) with “And” extension. which builds a predicate chain.


That’s it, now you have written a clean code adhering to SOLID principle and testable, extensible and maintainable code.


Any new specification can be easily handled just by adding a new class and you are good to go.


 


One more additional helper method if you would like to build such numerous predicates then you can make use of a simple method which can allow you to aggregate all the specifications.

protected bool Validate(params SpecificationBase<T>[] specificationsBase)
{
var pred = PredicateBuilder.True<T>();
pred = specificationsBase.Aggregate(pred, (current, specificationBase) => current.And(specificationBase.Predicate));
var result = _context.LoadQuery(_objectCollection.Where(pred));
_context.ExecuteQuery();
return result != null && result.Count() == 1;
}



Thanks


Akhilesh Nirapure


Wednesday, May 22, 2013

SharePoint 2013: SharePoint:AspMenu Styling (Quick Guide)

Quick note on how would you provide custom css to your Global Navigation in SharePoint 2013

You need to set following properties to provide custom CSS to Menu Item otherwise they won’t be picked up by SharePoint ASP Menu Control

1. UseSimpleRendering = False

2. RenderingMode = List

and then for your SharePoint AspMenu should look something like this

<SharePoint:AspMenu 
runat="server" UseSeparateCss="false"
AdjustForShowStartingNode="False" StaticDisplayLevels="2"
AccessKey="1" SkipLinkText="" EnableViewState="False"
MaximumDynamicDisplayLevels="0"
DataSourceID="topSiteMap" Orientation="Horizontal"
RenderingMode="List"
UseSimpleRendering="False"

ID="TopNavigationMenu">

<StaticMenuItemStyle CssClass="custom_class_1" />
<StaticSelectedStyle CssClass="custom_class_2" />

</SharePoint:AspMenu>
Also if you want more control over how your Global Navigation should render then make use use of 

1. <DynamicItemTemplate></DynamicItemTemplate>
2. <StaticItemTemplate></StaticItemTemplate>


 


Example

 <SharePoint:AspMenu 
runat="server" UseSeparateCss="false"
AdjustForShowStartingNode="False" StaticDisplayLevels="2"
AccessKey="1" SkipLinkText="" EnableViewState="False"
MaximumDynamicDisplayLevels="0"
DataSourceID="topSiteMap" Orientation="Horizontal"
RenderingMode="List"
UseSimpleRendering="False"
ID="TopNavigationMenu">

<StaticItemTemplate>
<li class="someclass">
<asp:HyperLink runat="Server" CssClass="SomeClass" ID="c_menuitem" NavigateUrl='<%# Eval("DataPath")%>' Text='<%# Eval("Text")%>' />
</li>
</StaticItemTemplate>

</SharePoint:AspMenu>





 




Again if this doesn’t suits your requirement then get your navigation built using repeater control, Bhavin has an excellent example


 


http://sharepoint2010customnavigation.blogspot.in/


With repeaters you will need to enable code blocks for master-page, here is how you do it


 


http://blog.shutupandcode.net/?p=646


http://blog.technock.net/2013/03/code-blocks-are-not-allowed-in-this.html


 

 
Hope this Helps !!!
 
Akhilesh Nirapure




 

Friday, May 10, 2013

SharePoint 2013 : Service Account & Permissions required for Search Service Application

 

Following Least Privilege Principle, i always wanted to nail down on permissions required to setup, manage and administer SharePoint, recently working quite a lot on ensuring how important it is working with a close environment which mimics Production environment which makes you sleep as you code won’t fail in such environment as you already tested and built code to very similar environment.

There has been good documentation on setting up SharePoint environment with detail account permission on Servers and SQL Server

Account permissions and security settings in SharePoint 2013

I found it really hard to nail down for Search Service Application, People have done quite a lot work to get the PowerShell scripts to deploy different search topology but i couldn’t find one where they are talking about very specific permissions required.

So i just wanted to document what I've experienced and got the search service application working without issues.

I already have my SharePoint Farm Build with best Practice and followed Least Privilege Principle.

Note: As per Microsoft documentation the Farm Account doesn’t need to be a local administrator, but it is required when you need to perform User Profile Synchronization. With such exception I’ve tried to get very similar workaround working for search. I’m going to setup default search topology as this is my development environment but still wanted to keep it inline with Least Privilege Principle.

Current environment

DC Server : Windows 2012, Hosting Active Directory Domain Service, DNS

APP Server : Windows 2012, SharePoint 2013, SQL Server 2012, all the service Applications.

For search Service Application, i created following Accounts and added them as Managed account.

ACCOUNT

Comments

WS_SEARCH_CRAWL

Windows Service OSearch15 / SharePoint Server Search 15

WS_SEARCH_HC

Windows Service SPSearchHostController / SharePoint Search Host Controller

AP_SEARCH_QSS

App pool for Query Site and Settings Web Service

AP_SEARCH_AWS

App pool for Search Admin Web Service

SP_SEARCH_DC

Service Account for Default Content Access

I like prefixing the accounts for what they are used for Smile

Following is the step i performed for setting up Search Service Application.

1. Logged in as Farm account, note: my farm account is added to local admin group as it is needed for profile synchronization.

2. Assigned

WS_SEARCH_HC to Windows Service - Search Host Controller Service

WS_SEARCH_CRAWL to Windows Service - SharePoint Server Search

CA—> Security –> Configure Managed Accounts.

3. Started following services from

CA –> System Settings –> Mange Services on Server

Search Host Controller Service

Search Query and Site Settings Service

SharePoint Server Search

4. Created Search Service Application and assigned respective service accounts (domain accounts) as below.

Search Service Account : WS_SEARCH_CRAWL

Application Pool for Search Admin Web Service : AP_SEARCH_AWS

Application Pool for Search Query and Site Settings Web Service : AP_SEARCH_QSS

5. Restarted my App Server.

6. Started getting error in log as access denied for Search Host controller not able to access Search_Service_Application_DB_{guid} so explicitly added the login rights for WS_SEARCH_HC –> Search_Service_Application_DB_{guid} and also gave SPSearchDBAdmin role

7. Restarted the server again to ensure things are smooth, again got errors, and it happened to be WS_SEARCH_CRAWL account doesn’t have SPSearchDBAdmin role on all the four search database, so gave/added the role.

8. Again started getting error in ULS log which was not quire really sure why but was related to gatherer and this was only solved by giving WS_SEARCH_CRAWL Account giving Local Admin access. Note once you give local admin rights to any account you need to restart/log-in/log-off once to take it into affect, so i again i restarted.

9. Well till now i was not getting any error in my ULS log, so i thought of changing my default content access account to SP_SEARCH_DC from WS_SEARCH_CRAWL which has higher rights now.

10. slowly after sometime i started getting error in ULS where the WS_SEARCH_HC service was not able to login on Search_Service_Application_DB_{GUID} which i gave along with SPSearchDBAdmin role.

11. I also need to give WS_SEARCH_HC permission on Search_Service_Application_LinksStore_{guid} with SPSearchDBAdmin role.

12. Again i restarted, and did a full crawl i don’t see a single error in my event log and search is working absolutely fine.

Hope to get more granular permission details from MS Documentations with proper justification soon so that should fix this workaround.

Thanks

Akhilesh

 

Monday, April 1, 2013

SharePoint Hosted App, App Part, Document Library Upload.aspx / EditForm.aspx and “X-Frame-Options”

 

Before we drill and talk further would like to take sometime to explain different pieces in the topic. Lets first look at X-Frame-Options.

X-Frame-Options : In a simplest way this is a response header which tells browser (client) that the Website doesn’t want its page (which is currently being accessed) to be shown in a IFrame so as to prevent Clickjacking (Wikipedia : http://en.wikipedia.org/wiki/Clickjacking).

So how do X-Frame-Options related to SharePoint App’s. Well every app developer in SharePoint 2013 is now familiar with the App Model Concept, it has its own App Web and isolated domain which is different then Hosting Web.

To enhance security in SharePoint 2013 by default the “X-Frame-Options” header is sent back with response If you open up SPRequestModule in your fav decompiler you’ll find below statement written in PreSendRequestHeaders method, which gets added to every response if the AllowFraming Flag is not found in the current context items collection.

   1:  if (!httpContext.Items.Contains(SPRequestModule.AllowFramingFlag) && SPRequestModule.ContextCompatibilityLevel != 14)
   2:                         
   3:   {
   4:                              
   5:     httpContext.Response.AddHeader("X-FRAME-OPTIONS", "SAMEORIGIN");
   6:                          
   7:   }

Wait a minute what does that mean, so can we override this and make these line skip for those pages which explicitly marks and request for exception? yes this can be done simply by adding AllowFraming WebPart on to the page which you want to be able to be accessed from within IFrame.


"AllowFraming” Webpart does nothing but adds a simple statement in on load.


protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    if (this.Context != null && !this.Context.Items.Contains(SPRequestModule.AllowFramingFlag))
    {
        this.Context.Items.Add(SPRequestModule.AllowFramingFlag, "1");
    }
    if (this.Visible)
    {
        this.Visible = false;
    }
}



Consider a requirement, you have to upload a document to Document library which is in App, and this App is hosted in an App Part on some page, sound pretty simple.


Just as expected you’ll just point to upload.aspx page of App Document Library which will look something like http://your-fancy-appurl/SomeApp/Lists/Documents/Forms/Upload.aspx and using SP.UI.ModalDialog.showModalDialog you can open the page Upload page in SharePoint dialog box, but you’ll be presented with  annoying error message that you cannot do that it’s because of X-Frame-Options header instructed the browser to do so.


Load denied by X-Frame-Options: http://your-fancy-app-url/_layouts/15/Upload.aspx?List={guid}&IsDlg=1 does not permit cross-origin framing.




Take a pause and you’ll be thinking is where did that _layout/15/Upload.aspx page came in picture (this I’ll explain in later post) and what it has to do with X-Frame-Options.


Investigating further, I opened Upload.aspx under layouts folder and had a look if it has got AllowFraming webpart added to it or not, and i couldn’t locate so i added that entry manually and again gave a try and voila it worked !!!! because now the SPRequestModule –> X-Frame-Options won’t get executed. Next moving further after uploading document i was redirected to EditForm.aspx and i was again shown the same error (highlighted above) but this time instead of Upload.aspx it was EditForm.aspx, so where do you find this now, its actually stored in DataBase and not in layouts which you can just go and make an entry and make it work.


Hold you horses dude, get back to basics, how does this EditForm.aspx gets created? If you look at the schema.xml file of document library the below section where it is all written


<Forms>
      <Form Type="DisplayForm" SetupPath="pages\form.aspx" Url="Forms/DispForm.aspx" WebPartZoneID="Main" />
      <Form Type="EditForm" SetupPath="pages\form.aspx" Url="Forms/EditForm.aspx" WebPartZoneID="Main" />
      <Form Type="NewForm" Url="Forms/Upload.aspx" WebPartZoneID="Main" />
</Forms>



These forms are generated based on forms.aspx a template page which is in pages folder under 15/Template. Well now i again had a look to form.aspx and i again couldn’t locate the AllowFraming webpart, so i added one there again. So in order to regenerate my EditForm.aspx from the same form.aspx i need to re-deploy my app and now everything worked in my App in an App Part.


But is it a good practice No !!!  Ninjayou shouldn’t be modifying Baring teeth smilethese pages to make these solution work, so what’s next


A more elegant approach would be to use HttpModule and trap BeginRequest Event and make it work.


   1:      public class ZSFramingModule : IHttpModule
   2:      {
   3:          public void Dispose()
   4:          {
   5:          }
   6:   
   7:          public void Init(HttpApplication context)
   8:          {
   9:             context.BeginRequest += OnBeginRequest;
  10:              
  11:          }
  12:   
  13:          private void OnBeginRequest(object sender, EventArgs e)
  14:          {
  15:              HttpApplication l_application = (HttpApplication)sender;
  16:   
  17:              if (l_application.Request.Url.ToString().ToLower().Contains(@"/_layouts/15/upload.aspx")
  18:                                                  ||
  19:                  l_application.Request.Url.ToString().ToLower().Contains(@"editform.aspx"))
  20:              {
  21:                  HttpContext.Current.Items.Add("AllowFraming", "1");
  22:              }
  23:   
  24:          }
  25:      }



Hope this helps someone Smile 


 


Happy SharePointing !!!